Esempio n. 1
0
void Parser::prase_option() {
    bool old = skip_newline(false);
    ptr<Token> token = cur();
    eat();

    switch (token->type()) {
    case TOKEN_REQUEST_NAME:
        token = cur();
        eat();
        if (token->type() != TOKEN_CONST_STRING) {
            log_expect(token->loc(), "const string");
        }
        the_request_name = token->text();
        break;
    case TOKEN_RESPONSE_NAME:
        token = cur();
        eat();
        if (token->type() != TOKEN_CONST_STRING) {
            log_expect(token->loc(), "const string");
        }
        the_response_name = token->text();
        break;
    default:
        log_expect(token->loc(), "default_base or request_base or response_base");
    }

    token = cur();
    eat();

    if (!token->is_eol()) {
        log_expect(token->loc(), "eol");
    }
    skip_newline(old);
}
Esempio n. 2
0
t_ast                   *parse_input(s_lexer                    *lex)
{
  s_token               *tok = NULL;
  t_ast                 *ast = NULL;

  tok = skip_newline(lex);
  if (NULL == tok)
    return (NULL);

  ast = parse_list(lex);

  tok = skip_newline(lex);

  return (ast);
}
void HashtableTextDump::check_version(const char* ver) {
  int len = (int)strlen(ver);
  corrupted_if(remain() < len);
  if (strncmp(_p, ver, len) != 0) {
    quit("wrong version of hashtable dump file", _filename);
  }
  _p += len;
  skip_newline();
}
void HashtableTextDump::scan_prefix_type() {
  _p ++;
  if (strncmp(_p, "SECTION: String", 15) == 0) {
    _p += 15;
    _prefix_type = StringPrefix;
  } else if (strncmp(_p, "SECTION: Symbol", 15) == 0) {
    _p += 15;
    _prefix_type = SymbolPrefix;
  } else {
    _prefix_type = Unknown;
  }
  skip_newline();
}
Esempio n. 5
0
gchar* rnd_string_from_file(gchar *path) {
    FILE *file;
    struct stat buf;
    long int rnd;
    gchar* str = (gchar*)xcalloc(500, sizeof(gchar));

    stat(path, &buf);

    file = fopen(path, "r");
    rnd = random() % (int)buf.st_size;
    fseek(file, rnd, SEEK_SET);

    fgets(str, 500, file);
    // КОСТЫЫЫЫЛЬ! FIXME
    fgets(str, 500, file);

    return skip_newline(str);
}
Esempio n. 6
0
/*
 *   Skip to the start of the next line 
 */
static void skip_to_next_line(utf8_ptr *p, size_t *rem)
{
    /* find the next line-ending sequence */
    for ( ; *rem != 0 ; p->inc(rem))
    {
        /* get the current character */
        wchar_t ch = p->getch();

        /* check to see if we've reached a newline yet */
        if (is_vspace(ch))
        {
            /* skip the entire newline sequence */
            skip_newline(p, rem);

            /* we're done looking for the end of the line */
            break;
        }
    }
}
void HashtableTextDump::get_utf8(char* utf8_buffer, int utf8_length) {
  // cache in local vars
  const char* from = _p;
  const char* end = _end;
  char* to = utf8_buffer;
  int n = utf8_length;

  for (; n > 0 && from < end; n--) {
    if (*from != '\\') {
      *to++ = *from++;
    } else {
      corrupted_if(from + 2 > end);
      char c = from[1];
      from += 2;
      switch (c) {
      case 'x':
        {
          jchar value = unescape(from, end, 2);
          from += 2;
          assert(value <= 0xff, "sanity");
          *to++ = (char)(value & 0xff);
        }
        break;
      case 't':  *to++ = '\t'; break;
      case 'n':  *to++ = '\n'; break;
      case 'r':  *to++ = '\r'; break;
      case '\\': *to++ = '\\'; break;
      default:
        corrupted(_p, "Unsupported character");
      }
    }
  }
  corrupted_if(n > 0); // expected more chars but file has ended
  _p = from;
  skip_newline();
}
Esempio n. 8
0
/*
 *   Parse a file 
 */
int CTadsGameInfo::parse_file(osfildef *fp, unsigned long res_seek_pos,
                              unsigned long res_size)
{
    /* find the tail of the existing list */
    tads_valinfo *last_val;
    for (last_val = first_val_ ; last_val != 0 && last_val->nxt != 0 ;
         last_val = last_val->nxt) ;
    
    /* we found the resource - seek to it in the file */
    if (osfseek(fp, res_seek_pos, OSFSK_SET))
        return FALSE;

    /* 
     *   Allocate a block of memory for loading the game information.  The
     *   game information resource is typically fairly small, so for
     *   simplicity we'll just allocate a single block of memory and load
     *   the whole resource into the block.  Allocate space for one extra
     *   byte, so that we can ensure we have a newline at the end of the
     *   buffer.  
     */
    buf_ = (char *)osmalloc(res_size + 1);
    if (buf_ == 0)
        return FALSE;

    /* read the data */
    if (osfrb(fp, buf_, res_size))
        return FALSE;

    /* 
     *   store an extra newline at the end of the buffer, so that we can be
     *   certain that the last line ends in a newline - at worst, this will
     *   add an extra blank line to the end, but since we ignore blank lines
     *   this will do no harm 
     */
    buf_[res_size++] = '\n';

    /* parse the data */
    utf8_ptr p(buf_);
    for (size_t rem = res_size ; rem != 0 ; )
    {
        /* skip any leading whitespace */
        while (rem != 0 && is_space(p.getch()))
            p.inc(&rem);

        /* if the line starts with '#', it's a comment, so skip it */
        if (rem != 0 && p.getch() == '#')
        {
            /* skip the entire line, and go back for the next one */
            skip_to_next_line(&p, &rem);
            continue;
        }

        /* we must have the start of a name - note it */
        utf8_ptr name_start = p;

        /* skip ahead to a space or colon */
        while (rem != 0 && p.getch() != ':' && !is_hspace(p.getch()))
            p.inc(&rem);

        /* note the length of the name */
        size_t name_len = p.getptr() - name_start.getptr();

        /* skip any whitespace before the presumed colon */
        while (rem != 0 && is_hspace(p.getch()))
            p.inc(&rem);

        /* if we're not at a colon, the line is ill-formed, so skip it */
        if (rem == 0 || p.getch() != ':')
        {
            /* skip the entire line, and go back for the next one */
            skip_to_next_line(&p, &rem);
            continue;
        }

        /* skip the colon and any whitespace immediately after it */
        for (p.inc(&rem) ; rem != 0 && is_hspace(p.getch()) ; p.inc(&rem)) ;

        /* 
         *   Whatever terminated the name, replace it with a null character
         *   - this is safe, since we at least have a colon character to
         *   replace, and we've already skipped it so we can overwrite it
         *   now.  A null character in utf-8 is simply a single zero byte,
         *   so we can store our byte directly without worrying about any
         *   utf-8 multi-byte strangeness.  
         */
        *(name_start.getptr() + name_len) = '\0';

        /* note where the value starts */
        utf8_ptr val_start = p;

        /* set up to write to the buffer at the current point */
        utf8_ptr dst = p;

        /*
         *   Now find the end of the value.  The value can span multiple
         *   lines; if we find a newline followed by a space, it means that
         *   the next line is a continuation of the current value, and that
         *   the entire sequence of newlines and immediately following
         *   whitespace should be converted to a single space in the value.
         *   
         *   Note that we copy the transformed value directly over the old
         *   version of the value in the buffer.  This is safe because the
         *   transformation can only remove characters - we merely collapse
         *   each newline-whitespace sequence into a single space.  
         */
        while (rem != 0)
        {
            /* get this character */
            wchar_t ch = p.getch();
            
            /* check for a newline */
            if (is_vspace(ch))
            {
                /* 
                 *   it's a newline - skip it (and any other characters in
                 *   the newline sequence) 
                 */
                skip_newline(&p, &rem);

                /* 
                 *   if there's no leading whitespace on the next line,
                 *   we've reached the end of this value
                 */
                if (rem == 0 || !is_hspace(p.getch()))
                {
                    /* 
                     *   no whitespace -> end of the value - stop scanning
                     *   the value 
                     */
                    break;
                }

                /* skip leading whitespace on the line */
                while (rem != 0 && is_hspace(p.getch()))
                    p.inc(&rem);

                /* 
                 *   add a single whitespace character to the output for the
                 *   entire sequence of the newline plus the leading
                 *   whitespace on the line 
                 */
                dst.setch(' ');
            }
            else if (ch == 0)
            {
                /* change null bytes to spaces */
                dst.setch(' ');

                /* skip this character */
                p.inc(&rem);
            }
            else
            {
                /* it's not a newline - simply copy it out and keep going */
                dst.setch(ch);

                /* skip this character */
                p.inc(&rem);
            }
        }

        /* 
         *   Store a null terminator at the end of the value (it's safe to
         *   write this to the buffer because at worst it'll overwrite the
         *   newline at the end of the last line, which we've already
         *   skipped in the source).  Note that we obtain the length of the
         *   value string before storing the null terminator, because we
         *   don't want to count the null byte in the value's length.  
         */
        dst.setch('\0');

        /* 
         *   Create a new value list entry.  Point the entry directly into
         *   our buffer, since we're keeping the buffer around as long as
         *   the value list is around. 
         */
        tads_valinfo *val_info =
            (tads_valinfo *)osmalloc(sizeof(tads_valinfo));
        val_info->name = name_start.getptr();
        val_info->name_len = name_len;
        val_info->val = store_value(val_start.getptr(),
                                    dst.getptr() - val_start.getptr());
        val_info->nxt = 0;

        /* link the new value at the end of our list */
        if (last_val != 0)
            last_val->nxt = val_info;
        else
            first_val_ = val_info;
        last_val = val_info;
    }

    /* success */
    return TRUE;
}
Esempio n. 9
0
bool Parser::parse() {
    skip_newline(false);

    while (1) {
        ptr<Token> token = cur();
        if (!token->type()) {
            break;
        }
        eat();
        if (*token == '\n') {
            continue;
        }

        if (*token == TOKEN_INCLUDE) {
            bool old_skip_newline = skip_newline();
            skip_newline(false);
            token = cur();
            if (*token == TOKEN_CONST_STRING && look()->is_eol()) {
                eat();
                eat();
                skip_newline(old_skip_newline);
                ptr<Path> path = object<Path>(token->text());
                if (_input.is_root()) {
                    _symbols.exportSymbol(object<IncludeTree>(path));
                }
                _input.load(path);
            }
            else {
                log_expect(token->loc(), "string eol");
            }
            continue;
        }
        SegmentToken *seg = nullptr; 
        if (token->type() == TOKEN_SEGMENT) {
            seg = static_cast<SegmentToken*>(token.get());
            if (!seg->name()) {
                bool old_skip_newline = skip_newline();
                skip_newline(false);
                if (!look()->is_eol()) {
                    log_expect(token->loc(), "eol");
                }
                skip_newline(old_skip_newline);
                eat();
            }
            else {
                seg = nullptr;
            }
        }

        switch (_phase) {
        case PARSE_PHASE_HEAD:
            if (seg) {
                _phase = PARSE_PHASE_BODY;
                continue;
            }
            skip_newline(false);
            parse_head(token); 
            break;
        case PARSE_PHASE_BODY:
            if (seg) {
                _phase = PARSE_PHASE_TAIL;
                continue;
            }
            skip_newline(true);
            parse_body(token);
            break;
        case PARSE_PHASE_TAIL:
            if (seg) {
                log_error(token->loc(), "too more segment declear.");
            }
            skip_newline(false);
            parse_tail(token);
            break;
        }
    }
    return true; 
}
Esempio n. 10
0
static int read_bytes(readstat_por_ctx_t *ctx, void *dst, size_t len) {
    int bytes_left = len;
    int offset = 0;
    char buf[82];
    int i;
    while (bytes_left > POR_LINE_LENGTH - ctx->pos) {
        int line_len = POR_LINE_LENGTH - ctx->pos;
        if (read(ctx->fd, buf, line_len) == -1)
            return -1;

        for (i=0; i<line_len; i++) {
            if (buf[i] == '\n' || (buf[i] == '\r' && buf[i+1] == '\n')) {
                break;
            }
        }
        for (; i<line_len; i++) {
            buf[i] = ctx->space;
            if (lseek(ctx->fd, -1, SEEK_CUR) == -1)
                return -1;
        }
        if (skip_newline(ctx->fd) == -1)
            return -1;

        memcpy((char *)dst + offset, buf, line_len);

        ctx->pos = 0;

        offset += line_len;
        bytes_left -= line_len;
    }
    if (bytes_left) {
        if (read(ctx->fd, buf, bytes_left) == -1)
            return -1;

        for (i=0; i<bytes_left; i++) {
            if (buf[i] == '\n' || (buf[i] == '\r' && buf[i+1] == '\n')) {
                break;
            }
        }
        if (i == bytes_left) {
            ctx->pos += bytes_left;
        } else {
            ctx->pos = 0;
        }
        for (; i<bytes_left; i++) {
            buf[i] = ctx->space;
            if (lseek(ctx->fd, -1, SEEK_CUR) == -1)
                return -1;
        }
        memcpy((char *)dst + offset, buf, bytes_left);

        offset += bytes_left;

        if (ctx->pos == POR_LINE_LENGTH) {
            if (skip_newline(ctx->fd) == -1)
                return -1;
            ctx->pos = 0;
        }
    }

    return offset;
}
Esempio n. 11
0
/* Remove any line continuation characters in the shader, (whether in
 * preprocessing directives or in GLSL code).
 */
static char *
remove_line_continuations(glcpp_parser_t *ctx, const char *shader)
{
	struct _mesa_string_buffer *sb =
		_mesa_string_buffer_create(ctx, INITIAL_PP_OUTPUT_BUF_SIZE);

	const char *backslash, *newline, *search_start;
        const char *cr, *lf;
        char newline_separator[3];
	int collapsed_newlines = 0;
	int separator_len;

	backslash = strchr(shader, '\\');

	/* No line continuations were found in this shader, our job is done */
	if (backslash == NULL)
		return (char *) shader;

	search_start = shader;

	/* Determine what flavor of newlines this shader is using. GLSL
	 * provides for 4 different possible ways to separate lines, (using
	 * one or two characters):
	 *
	 *	"\n" (line-feed, like Linux, Unix, and new Mac OS)
	 *	"\r" (carriage-return, like old Mac files)
	 *	"\r\n" (carriage-return + line-feed, like DOS files)
	 *	"\n\r" (line-feed + carriage-return, like nothing, really)
	 *
	 * This code explicitly supports a shader that uses a mixture of
	 * newline terminators and will properly handle line continuation
	 * backslashes followed by any of the above.
	 *
	 * But, since we must also insert additional newlines in the output
	 * (for any collapsed lines) we attempt to maintain consistency by
	 * examining the first encountered newline terminator, and using the
	 * same terminator for any newlines we insert.
	 */
	cr = strchr(search_start, '\r');
	lf = strchr(search_start, '\n');

	newline_separator[0] = '\n';
	newline_separator[1] = '\0';
	newline_separator[2] = '\0';

	if (cr == NULL) {
		/* Nothing to do. */
	} else if (lf == NULL) {
		newline_separator[0] = '\r';
	} else if (lf == cr + 1) {
		newline_separator[0] = '\r';
		newline_separator[1] = '\n';
	} else if (cr == lf + 1) {
		newline_separator[0] = '\n';
		newline_separator[1] = '\r';
	}
	separator_len = strlen(newline_separator);

	while (true) {
		/* If we have previously collapsed any line-continuations,
		 * then we want to insert additional newlines at the next
		 * occurrence of a newline character to avoid changing any
		 * line numbers.
		 */
		if (collapsed_newlines) {
			cr = strchr (search_start, '\r');
			lf = strchr (search_start, '\n');
			if (cr && lf)
				newline = cr < lf ? cr : lf;
			else if (cr)
				newline = cr;
			else
				newline = lf;
			if (newline &&
			    (backslash == NULL || newline < backslash))
			{
				_mesa_string_buffer_append_len(sb, shader,
							       newline - shader + 1);
				while (collapsed_newlines) {
					_mesa_string_buffer_append_len(sb,
								       newline_separator,
								       separator_len);
					collapsed_newlines--;
				}
				shader = skip_newline (newline);
				search_start = shader;
			}
		}

		search_start = backslash + 1;

		if (backslash == NULL)
			break;

		/* At each line continuation, (backslash followed by a
		 * newline), copy all preceding text to the output, then
		 * advance the shader pointer to the character after the
		 * newline.
		 */
		if (backslash[1] == '\r' || backslash[1] == '\n')
		{
			collapsed_newlines++;
			_mesa_string_buffer_append_len(sb, shader, backslash - shader);
			shader = skip_newline (backslash + 1);
			search_start = shader;
		}

		backslash = strchr(search_start, '\\');
	}

	_mesa_string_buffer_append(sb, shader);

	return sb->buf;
}
/* reads an entire attribute from the input buffer, leaving p pointing
   at the start of the next line (past the \r\n) */
static EVCardAttribute*
read_attribute (char **p)
{
	char *attr_group = NULL;
	char *attr_name = NULL;
	EVCardAttribute *attr = NULL;
	GString *str;
	char *lp;
	gboolean is_qp = FALSE;

	/* first read in the group/name */
	str = g_string_new ("");
	for( lp =  skip_newline( *p, is_qp );
	     *lp != '\n' && *lp != '\r' && *lp != '\0';
	     lp = skip_newline( lp, is_qp ) ) {

		if (*lp == ':' || *lp == ';') {
			if (str->len != 0) {
				/* we've got a name, break out to the value/attribute parsing */
				attr_name = g_string_free (str, FALSE);
				break;
			}
			else {
				/* a line of the form:
				 * (group.)?[:;]
				 *
				 * since we don't have an attribute
				 * name, skip to the end of the line
				 * and try again.
				 */
				g_string_free (str, TRUE);
				*p = lp;
				skip_to_next_line(p);
				goto lose;
			}
		}
		else if (*lp == '.') {
			if (attr_group) {
				g_warning ("extra `.' in attribute specification.  ignoring extra group `%s'",
					   str->str);
				g_string_free (str, TRUE);
				str = g_string_new ("");
			}
			if (str->len != 0) {
				attr_group = g_string_free (str, FALSE);
				str = g_string_new ("");
			}
		}
		else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
			g_string_append_unichar (str, g_utf8_get_char (lp));
		}
		else {
			g_warning ("invalid character found in attribute group/name");
			g_string_free (str, TRUE);
			*p = lp;
			skip_to_next_line(p);
			goto lose;
		}

		lp = g_utf8_next_char(lp);
	}

	if (!attr_name) {
		skip_to_next_line (p);
		goto lose;
	}

	attr = e_vcard_attribute_new (attr_group, attr_name);
	g_free (attr_group);
	g_free (attr_name);

	if (*lp == ';') {
		/* skip past the ';' */
		lp = g_utf8_next_char(lp);
		read_attribute_params (attr, &lp, &is_qp);
		if (is_qp)
			attr->encoding = EVC_ENCODING_RAW;
	}
	if (*lp == ':') {
		/* skip past the ':' */
		lp = g_utf8_next_char(lp);
		read_attribute_value (attr, &lp, is_qp);
	}

	*p = lp;

	if (!attr->values)
		goto lose;

	return attr;
 lose:
	if (attr)
		e_vcard_attribute_free (attr);
	return NULL;
}
static void
read_attribute_params (EVCardAttribute *attr, char **p, gboolean *quoted_printable)
{
	char *lp;
	GString *str;
	EVCardAttributeParam *param = NULL;
	gboolean in_quote = FALSE;

	str = g_string_new ("");
	for( lp =  skip_newline( *p, *quoted_printable );
	     *lp != '\n' && *lp != '\r' && *lp != '\0';
	     lp = skip_newline( lp, *quoted_printable ) ) {

		if (*lp == '"') {
			in_quote = !in_quote;
			lp = g_utf8_next_char (lp);
		}
		else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
			g_string_append_unichar (str, g_utf8_get_char (lp));
			lp = g_utf8_next_char (lp);
		}
		/* accumulate until we hit the '=' or ';'.  If we hit
		 * a '=' the string contains the parameter name.  if
		 * we hit a ';' the string contains the parameter
		 * value and the name is either ENCODING (if value ==
		 * QUOTED-PRINTABLE) or TYPE (in any other case.)
		 */
		else if (*lp == '=') {
			if (str->len > 0) {
				param = e_vcard_attribute_param_new (str->str);
				g_string_assign (str, "");
				lp = g_utf8_next_char (lp);
			}
			else {
				skip_until (&lp, ":;");
				if (*lp == ';') {
					lp = g_utf8_next_char (lp);

				} else if (*lp == ':') {
					/* do nothing */

				} else {
					skip_to_next_line( &lp );
					break;
				}
			}
		}
		else if (*lp == ';' || *lp == ':' || *lp == ',') {
			gboolean colon = (*lp == ':');
			gboolean comma = (*lp == ',');

			if (param) {
				if (str->len > 0) {
					e_vcard_attribute_param_add_value (param, str->str);
					g_string_assign (str, "");
					if (!colon)
						lp = g_utf8_next_char (lp);
				}
				else {
					/* we've got a parameter of the form:
					 * PARAM=(.*,)?[:;]
					 * so what we do depends on if there are already values
					 * for the parameter.  If there are, we just finish
					 * this parameter and skip past the offending character
					 * (unless it's the ':'). If there aren't values, we free
					 * the parameter then skip past the character.
					 */
					if (!param->values) {
						e_vcard_attribute_param_free (param);
						param = NULL;
						if (!colon)
							lp = g_utf8_next_char (lp);
					}
				}

				if (param
				    && !g_ascii_strcasecmp (param->name, "encoding")
				    && !g_ascii_strcasecmp (param->values->data, "quoted-printable")) {
					*quoted_printable = TRUE;
					e_vcard_attribute_param_free (param);
					param = NULL;
				}
			}
			else {
				if (str->len > 0) {
					char *param_name;
					if (!g_ascii_strcasecmp (str->str,
								 "quoted-printable")) {
						param_name = "ENCODING";
						*quoted_printable = TRUE;
					}
					/* apple's broken addressbook app outputs naked BASE64
					   parameters, which aren't even vcard 3.0 compliant. */
					else if (!g_ascii_strcasecmp (str->str,
								      "base64")) {
						param_name = "ENCODING";
						g_string_assign (str, "b");
					}
					else {
						param_name = "TYPE";
					}

					if (param_name) {
						param = e_vcard_attribute_param_new (param_name);
						e_vcard_attribute_param_add_value (param, str->str);
					}
					g_string_assign (str, "");
					if (!colon)
						lp = g_utf8_next_char (lp);
				}
				else {
					/* we've got an attribute with a truly empty
					   attribute parameter.  So it's of the form:

					   ATTR;[PARAM=value;]*;[PARAM=value;]*:

					   (note the extra ';')

					   the only thing to do here is, well.. nothing.
					   we skip over the character if it's not a colon,
					   and the rest is handled for us: We'll either
					   continue through the loop again if we hit a ';',
					   or we'll break out correct below if it was a ':' */
					if (!colon)
						lp = g_utf8_next_char (lp);
				}
			}
			if (param && !comma) {
				e_vcard_attribute_add_param (attr, param);
				param = NULL;
			}
			if (colon)
				break;
		}
		else {
			g_warning ("invalid character found in parameter spec");
			g_string_assign (str, "");
			/*			skip_until (&lp, ":;"); */

			skip_to_next_line( &lp );
		}
	}

	if (str)
		g_string_free (str, TRUE);

	*p = lp;
}
static void
read_attribute_value (EVCardAttribute *attr, char **p, gboolean quoted_printable)
{
	char *lp = *p;
	GString *str;

	/* read in the value */
	str = g_string_new ("");
	for( lp =  skip_newline( *p, quoted_printable );
	     *lp != '\n' && *lp != '\r' && *lp != '\0';
	     lp = skip_newline( lp, quoted_printable ) ) {

		if (*lp == '=' && quoted_printable) {
			char a, b;
			if ((a = *(++lp)) == '\0') break;
			if ((b = *(++lp)) == '\0') break;
			if (isxdigit(a) && isxdigit (b)) {
				char c;

				a = tolower (a);
				b = tolower (b);

				c = (((a>='a'?a-'a'+10:a-'0')&0x0f) << 4)
					| ((b>='a'?b-'a'+10:b-'0')&0x0f);

				g_string_append_c (str, c); /* add decoded byte (this is not a unicode yet) */
			}
			else
				{
					g_string_append_c (str, a);
					g_string_append_c (str, b);
				}

			lp++;

		} else if (*lp == '\\') {
			/* convert back to the non-escaped version of
			   the characters */
			lp = g_utf8_next_char(lp);
			if (*lp == '\0') {
				g_string_append_c (str, '\\');
				break;
			}

			/* beware, there might be a line break due to folding,
			 * need next real character
			 */
			lp = skip_newline (lp, quoted_printable);

			switch (*lp) {
			case 'n': g_string_append_c (str, '\n'); break;
			case 'N': g_string_append_c (str, '\n'); break;
			case 'r': g_string_append_c (str, '\r'); break;
			case 'R': g_string_append_c (str, '\r'); break;
			case ';': g_string_append_c (str, ';'); break;
			case ',': g_string_append_c (str, ','); break;
			case '\\': g_string_append_c (str, '\\'); break;
			default:
				g_warning ("invalid escape, passing it through");
				g_string_append_c (str, '\\');
				g_string_append_unichar (str, g_utf8_get_char(lp));
				break;
			}
			lp = g_utf8_next_char(lp);
		}
		else if ((*lp == ';') ||
			 (*lp == ',' && !g_ascii_strcasecmp (attr->name, "CATEGORIES"))) {
			e_vcard_attribute_add_value (attr, str->str);
			g_string_assign (str, "");
			lp = g_utf8_next_char(lp);
		}
		else {
			g_string_append_unichar (str, g_utf8_get_char (lp));
			lp = g_utf8_next_char(lp);
		}
	}
	if (str) {
		e_vcard_attribute_add_value (attr, str->str);
		g_string_free (str, TRUE);
	}

	skip_to_next_line( &lp );

	*p = lp;
}