| 8187 | } |
| 8188 | |
| 8189 | function parseRows(text, f) { |
| 8190 | var rows = [], // output rows |
| 8191 | N = text.length, |
| 8192 | I = 0, // current character index |
| 8193 | n = 0, // current line number |
| 8194 | t, // current token |
| 8195 | eof = N <= 0, // current token followed by EOF? |
| 8196 | eol = false; // current token followed by EOL? |
| 8197 | |
| 8198 | // Strip the trailing newline. |
| 8199 | if (text.charCodeAt(N - 1) === NEWLINE) --N; |
| 8200 | if (text.charCodeAt(N - 1) === RETURN) --N; |
| 8201 | |
| 8202 | function token() { |
| 8203 | if (eof) return EOF; |
| 8204 | if (eol) return eol = false, EOL; |
| 8205 | |
| 8206 | // Unescape quotes. |
| 8207 | var i, j = I, c; |
| 8208 | if (text.charCodeAt(j) === QUOTE) { |
| 8209 | while (I++ < N && text.charCodeAt(I) !== QUOTE || text.charCodeAt(++I) === QUOTE); |
| 8210 | if ((i = I) >= N) eof = true; |
| 8211 | else if ((c = text.charCodeAt(I++)) === NEWLINE) eol = true; |
| 8212 | else if (c === RETURN) { eol = true; if (text.charCodeAt(I) === NEWLINE) ++I; } |
| 8213 | return text.slice(j + 1, i - 1).replace(/""/g, "\""); |
| 8214 | } |
| 8215 | |
| 8216 | // Find next delimiter or newline. |
| 8217 | while (I < N) { |
| 8218 | if ((c = text.charCodeAt(i = I++)) === NEWLINE) eol = true; |
| 8219 | else if (c === RETURN) { eol = true; if (text.charCodeAt(I) === NEWLINE) ++I; } |
| 8220 | else if (c !== DELIMITER) continue; |
| 8221 | return text.slice(j, i); |
| 8222 | } |
| 8223 | |
| 8224 | // Return last token before EOF. |
| 8225 | return eof = true, text.slice(j, N); |
| 8226 | } |
| 8227 | |
| 8228 | while ((t = token()) !== EOF) { |
| 8229 | var row = []; |
| 8230 | while (t !== EOL && t !== EOF) row.push(t), t = token(); |
| 8231 | if (f && (row = f(row, n++)) == null) continue; |
| 8232 | rows.push(row); |
| 8233 | } |
| 8234 | |
| 8235 | return rows; |
| 8236 | } |
| 8237 | |
| 8238 | function preformatBody(rows, columns) { |
| 8239 | return rows.map(function(row) { |