+ case EOF:
+ /* File ended mid way through quoted item */
+ list = g_list_append (list, parse_field (string->str));
+ state = DONE;
+ break;
+ default:
+ string = g_string_append_c (string, c);
+ state = NORMAL;
+ break;
+ }
+ break;
+
+ case QUOTED_ESCAPED:
+ switch (c) {
+ case EOF:
+ /* File ended mid way through quoted item */
+ list = g_list_append (list, parse_field (string->str));
+ state = DONE;
+ break;
+ default:
+ string = g_string_append_c (string, c);
+ state = QUOTED;
+ break;
+ }
+ break;
+
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ }
+ g_string_free( string, TRUE );
+
+ return list;
+}
+
+/*---------------------------------------------------------------------------*/
+/* PRIVATE. Parse field. */
+/* */
+/* - Strip leading and trailing white space, unless quoted. */
+/* - Strip CR, unless escaped. */
+/* - Expand '\n' and '\t' into newline and tab characters. */
+/* - Remove quotes, unless escaped (\" anywhere or "" within quotes) */
+/*---------------------------------------------------------------------------*/
+static gchar *
+parse_field (gchar *raw_field)
+{
+ GString *string;
+ gchar *pass1_field, *c, *field;
+ enum { NORMAL, NORMAL_ESCAPED, QUOTED, QUOTED_ESCAPED, QUOTED_QUOTE1} state;
+
+
+ /*
+ * Pass 1: remove leading and trailing spaces.
+ */
+ pass1_field = g_strdup (raw_field);
+ g_strstrip (pass1_field);
+
+ /*
+ * Pass 2: resolve quoting and escaping.
+ */
+ state = NORMAL;
+ string = g_string_new( "" );
+ for ( c=pass1_field; *c != 0; c++ )
+ {
+ switch (state) {
+
+ case NORMAL:
+ switch (*c) {
+ case '\\':
+ state = NORMAL_ESCAPED;
+ break;
+ case '"':
+ state = QUOTED;
+ break;
+ case '\r':
+ /* Strip CR. */
+ break;
+ default:
+ string = g_string_append_c (string, *c);
+ break;
+ }
+ break;
+
+ case NORMAL_ESCAPED:
+ switch (*c) {