5 public int UnescapeString(char * d, char * s, int len)
9 while(j < len && (ch = s[j]))
16 case 'n': d[k] = '\n'; break;
17 case 't': d[k] = '\t'; break;
18 case 'a': d[k] = '\a'; break;
19 case 'b': d[k] = '\b'; break;
20 case 'f': d[k] = '\f'; break;
21 case 'r': d[k] = '\r'; break;
22 case 'v': d[k] = '\v'; break;
23 case '\\': d[k] = '\\'; break;
24 case '\"': d[k] = '\"'; break;
25 case '\'': d[k] = '\''; break;
26 default: d[k] = '\\'; d[k] = ch;
38 // to be moved in ecere?
39 public class FileHandler
49 public struct CSVParserParameters
53 int expectedFieldCount;
54 bool tolerateNewLineInValues;
56 bool lastFieldEndsWithNewLine;
61 CSVParserParameters classicParameters = { ',', '\"', 0, false };
63 public struct CSVParserState
71 public class CSVParser : public FileHandler
74 CSVParserParameters options { ',', '\"', 0, false };
77 void PrintMessage(typed_object object, ...)
81 va_start(args, object);
82 PrintStdArgsToBuffer(buffer, sizeof(buffer), object, args);
87 virtual void OnMessage(const String message)
89 ::PrintLn(this._class.name, ": ", message,
90 " lineNum=", info.lineNum,
91 " charNum=", info.charNum,
92 " rowNum=", info.rowNum,
93 " fieldNum=", info.fieldNum);
96 virtual bool OnRowStrings(Array<String> strings);
98 virtual void Process()
100 bool quoted = false, status = true;
101 bool escaped = false;
102 Array<String> values { };
103 bool started = false;
104 int start = 0, end = 0;
106 Array<char> buffer { minAllocSize = 4096 };
113 while(!file.Eof() && status)
119 offset = readCount - start;
120 if(offset > buffer.minAllocSize / 2)
121 buffer.minAllocSize += 4096;
122 memmove(&buffer[0], &buffer[start], offset);
127 readCount = offset + file.Read(&buffer[offset], 1, buffer.minAllocSize - offset);
128 for(c = offset; c < readCount && status; c++)
134 bool inTextQuote = false;
136 if(options.lastFieldEndsWithNewLine && info.fieldNum == options.expectedFieldCount - 1 && ch == '\"' && info.charNum > 0)
139 if(!inTextQuote && !escaped && ch == options.valueQuotes)
141 if(buffer[c+1] == options.valueQuotes)
149 if(!escaped && options.escaped && ch == '\\')
156 if(ch == options.valueQuotes)
162 //else if(ch == options.fieldSeparator || ch == '\n')
163 else if(ch == options.fieldSeparator ||
164 (ch == '\n' && (!options.tolerateNewLineInValues || info.fieldNum >= options.expectedFieldCount-1)))
166 if(values.count < options.expectedFieldCount)
168 int len = started ? (end-start) : 0;
169 String value = new char[len+1];
170 if(options.escaped) // Escaped with a backslash
171 UnescapeString(value, &buffer[start], len);
175 memcpy(value, &buffer[start], len);
177 while((dq = strstr(value, "\"\"")))
179 memmove(dq + 1, dq + 2, len - (uint)(dq + 2 - value) + 1);
193 status = OnRowStrings(values);
209 if(ch == '\r' || ch == '\n')
219 String value = new char[len+1];
221 UnescapeString(value, &buffer[start], len);
225 memcpy(value, &buffer[start], len);
227 while((dq = strstr(value, "\"\"")))
229 memmove(dq + 1, dq + 2, len - (uint)(dq + 2 - value) + 1);
236 if(values.count && status)
238 status = OnRowStrings(values);