Thread: [q-lang-cvs] q-csv csv.c,1.11,1.12 csv.q,1.11,1.12
Brought to you by:
agraef
From: RER <ed...@us...> - 2008-01-22 16:45:39
|
Update of /cvsroot/q-lang/q-csv In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv8598 Modified Files: csv.c csv.q Log Message: Changed module to be loosely compatible with Python's CSV module Index: csv.c =================================================================== RCS file: /cvsroot/q-lang/q-csv/csv.c,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** csv.c 18 Jan 2008 21:34:13 -0000 1.11 --- csv.c 22 Jan 2008 16:45:16 -0000 1.12 *************** *** 28,31 **** --- 28,32 ---- #define FORCEQUOTE 0 #define AUTOQUOTE 1 + #define NOQUOTE 2 /* fread_block reads embbeded '\n's. *************** *** 36,44 **** { FILE *fp; ! char *bf, *tb, *s_dl, *s; ! int n_q = 0, n_s_dl; long sz = BSIZE, n = 0; ! if (argc != 2 || !isfile(argv[0], &fp) || !isstr(argv[1], &s_dl)) return __FAIL; --- 37,47 ---- { FILE *fp; ! char *bf, *tb, *qt_s, *s; ! int qt_cnt = 0, n_qt_s; long sz = BSIZE, n = 0; ! if (argc != 2 ! || !isfile(argv[0], &fp) ! || !isstr(argv[1], &qt_s)) return __FAIL; *************** *** 46,50 **** return __ERROR; ! n_s_dl = strlen(s_dl); while (1) { s = bf + n; --- 49,53 ---- return __ERROR; ! n_qt_s = strlen(qt_s); while (1) { s = bf + n; *************** *** 64,77 **** goto fini; n += strlen(s); ! if (!*(bf+n-1) == '\n') continue; while (*s) { ! if (!strncmp(s, s_dl, n_s_dl)) { ! ++n_q; ! s += n_s_dl; } else ++s; } ! if (!(n_q & 1)) { fini: s = to_utf8(bf, NULL); --- 67,80 ---- goto fini; n += strlen(s); ! if (*(bf+n-1) != '\n') continue; while (*s) { ! if (!strncmp(s, qt_s, n_qt_s)) { ! ++qt_cnt; ! s += n_qt_s; } else ++s; } ! if (!(qt_cnt & 1)) { fini: s = to_utf8(bf, NULL); *************** *** 141,147 **** FUNCTION(csv, csvstr_to_tuple, argc, argv) { ! int n, cvt_f, fld_sz = 256, n_fld, rec_sz = 64, n_ws = 0, ! n_rec = 0, n_s_dl, n_fld_dl, st = 0; ! char *fld, *tfld, *fldp, *s, *fld_dl, *s_dl, errmsg[80]; expr *xs, *rec, *trec; char *sp; --- 144,153 ---- FUNCTION(csv, csvstr_to_tuple, argc, argv) { ! int n, st = 0, fld_sz = 256, n_fld, rec_sz = 64, n_ws = 0, n_rec = 0, ! n_delimiter, n_escape, n_quote, n_lineterm, skipspace_f, ! esc_eq_quote; ! char *fld, *tfld, *fldp, *s, errmsg[80], ! *delimiter, *escape, *quote, *lineterm; ! long quoting; expr *xs, *rec, *trec; char *sp; *************** *** 149,156 **** if (argc != 2 || !istuple(argv[0], &n, &xs) ! || n != 3 ! || !isbool(xs[0], &cvt_f) ! || !isstr(xs[1], &fld_dl) ! || !isstr(xs[2], &s_dl) || !isstr(argv[1], &s)) return __FAIL; --- 155,165 ---- if (argc != 2 || !istuple(argv[0], &n, &xs) ! || n != 6 ! || !isstr(xs[0], &delimiter) ! || !isstr(xs[1], &escape) ! || !isstr(xs[2], "e) ! || !isint(xs[3], "ing) ! || !isstr(xs[4], &lineterm) ! || !isbool(xs[5], &skipspace_f) || !isstr(argv[1], &s)) return __FAIL; *************** *** 164,169 **** } ! n_s_dl = strlen(s_dl); ! n_fld_dl = strlen(fld_dl); fldp = fld; while (st < 10) { --- 173,181 ---- } ! n_delimiter = strlen(delimiter); ! n_escape = strlen(escape); ! n_quote = strlen(quote); ! esc_eq_quote = !strcmp(escape, quote); ! n_lineterm = strlen(lineterm); fldp = fld; while (st < 10) { *************** *** 172,187 **** fldp = fld; n_fld = 0; ! if (!strncmp(s, fld_dl, n_fld_dl)) { *fldp = 0; putrec(FORCEQUOTE); ! s += n_fld_dl; ! } else if (!strncmp(s, s_dl, n_s_dl)) { ! s += n_s_dl; st = 1; ! } else if (!*s || *s == '\n' || *s == EOF) { ! putrec(FORCEQUOTE); st = 10; ! } else if (isspace(*s)) { ++s; } else { putfld(1); --- 184,201 ---- fldp = fld; n_fld = 0; ! if (!strncmp(s, delimiter, n_delimiter)) { *fldp = 0; putrec(FORCEQUOTE); ! s += n_delimiter; ! } else if (!strncmp(s, quote, n_quote)) { ! s += n_quote; st = 1; ! } else if (!*s || *s == EOF || !strncmp(s, lineterm, n_lineterm)) { st = 10; ! } else if (isspace(*s) && skipspace_f) { ++s; + } else if (!strncmp(s, escape, n_escape)) { + sprintf(errmsg, "Column %d: Unexpected escape.", n_fld+1); + st = 20; } else { putfld(1); *************** *** 191,200 **** break; case 1: ! if (!strncmp(s, s_dl, n_s_dl)) { ! s += n_s_dl; st = 2; } else if (!*s || *s == EOF) { ! sprintf(errmsg, "Column %d: Expected {%s}.", n_fld+1, s_dl); st = 20; } else { putfld(1); --- 205,218 ---- break; case 1: ! if (!strncmp(s, quote, n_quote)) { ! s += n_quote; st = 2; } else if (!*s || *s == EOF) { ! sprintf(errmsg, "Column %d: Expected {%s}.", n_fld+1, quote); st = 20; + } else if (!strncmp(s, escape, n_escape)) { + s += n_escape; + putfld(1); + ++s; } else { putfld(1); *************** *** 203,215 **** break; case 2: ! if (!strncmp(s, s_dl, n_s_dl)) { ! putfld(n_s_dl); ! s += n_s_dl; st = 1; ! } else if (!strncmp(s, fld_dl, n_fld_dl)) { putrec(FORCEQUOTE); ! s += n_fld_dl; st = 0; ! } else if (!*s || *s == '\n' || *s == EOF) { putrec(FORCEQUOTE); st = 10; --- 221,233 ---- break; case 2: ! if (!strncmp(s, quote, n_quote) && esc_eq_quote) { ! putfld(n_quote); ! s += n_quote; st = 1; ! } else if (!strncmp(s, delimiter, n_delimiter)) { putrec(FORCEQUOTE); ! s += n_delimiter; st = 0; ! } else if (!*s || *s == EOF || !strncmp(s, lineterm, n_lineterm)) { putrec(FORCEQUOTE); st = 10; *************** *** 218,229 **** st = 3; } else { ! sprintf(errmsg, "Column %d: Expected {%s}.", n_fld+1, fld_dl); st = 20; } break; case 3: ! if (!strncmp(s, fld_dl, n_fld_dl)) { putrec(FORCEQUOTE); ! s += n_fld_dl; st = 0; } else if (!*s || *s == '\n' || *s == EOF) { --- 236,247 ---- st = 3; } else { ! sprintf(errmsg, "Column %d: Expected {%s}.", n_fld+1, delimiter); st = 20; } break; case 3: ! if (!strncmp(s, delimiter, n_delimiter)) { putrec(FORCEQUOTE); ! s += n_delimiter; st = 0; } else if (!*s || *s == '\n' || *s == EOF) { *************** *** 233,252 **** ++s; } else { ! sprintf(errmsg, "Column %d: Expected {%s}.", n_fld+1, fld_dl); st = 20; } break; case 4: ! if (!strncmp(s, s_dl, n_s_dl)) { ! sprintf(errmsg, "Column %d: Expected {%s}.", n_fld+1, fld_dl); st = 20; ! } else if (!strncmp(s, fld_dl, n_fld_dl)) { fldp -= n_ws; n_fld -= n_ws; ! putrec(cvt_f); ! s += n_fld_dl; st = 0; ! } else if (!*s || *s == '\n' || *s == EOF) { ! putrec(cvt_f); st = 10; } else if (isspace(*s)) { --- 251,270 ---- ++s; } else { ! sprintf(errmsg, "Column %d: Expected {%s}.", n_fld+1, delimiter); st = 20; } break; case 4: ! if (!strncmp(s, quote, n_quote) || !strncmp(s, escape, n_escape)) { ! sprintf(errmsg, "Column %d: Expected {%s}.", n_fld+1, delimiter); st = 20; ! } else if (!strncmp(s, delimiter, n_delimiter)) { fldp -= n_ws; n_fld -= n_ws; ! putrec(quoting); ! s += n_delimiter; st = 0; ! } else if (!*s || *s == EOF || !strncmp(s, lineterm, n_lineterm)) { ! putrec(quoting); st = 10; } else if (isspace(*s)) { *************** *** 288,296 **** ! #define insert_num \ mrk = len; \ len += strlen(tb); \ resize_str; \ ! strncpy(t, tb, len - mrk) /* convert tuple to csv string --- 306,314 ---- ! #define insert \ mrk = len; \ len += strlen(tb); \ resize_str; \ ! strncpy(t, tb, len - mrk) /* convert tuple to csv string *************** *** 310,316 **** FUNCTION (csv, tuple_to_csvstr, argc, argv) { ! int i, n, sz = 256, mrk, n_q, len = 0, cvt_f, n_s_dl, n_fld_dl; ! char *s, *ts, *p, *sval, *s_dl, *fld_dl, tb[48], errmsg[80]; ! long ival; double dval; expr *xs, *ys; --- 328,336 ---- FUNCTION (csv, tuple_to_csvstr, argc, argv) { ! int i, n, k, sz = 256, mrk, quote_cnt, delim_cnt, lineterm_cnt, ! len = 0, skipspace_f, n_escape, n_quote, n_delimiter, n_lineterm; ! char *s, *ts, *p, *sval, tb[48], errmsg[80], ! *escape, *quote, *delimiter, *lineterm; ! long ival, quoting; double dval; expr *xs, *ys; *************** *** 319,376 **** if (argc != 2 || !istuple(argv[0], &i, &ys) ! || i != 3 ! || !isbool(ys[0], &cvt_f) /* unquote flag */ ! || !isstr(ys[1], &fld_dl) ! || !isstr(ys[2], &s_dl) ! || !istuple(argv[1], &n, &xs)) return __FAIL; if (!(s = (char *)malloc(sz))) return __ERROR; ! n_s_dl = strlen(s_dl); ! n_fld_dl = strlen(fld_dl); for (i = 0; i < n; ++i) { if (isint(xs[i], &ival)) { ! if (cvt_f) ! sprintf(tb, "%d%s", ival, fld_dl); else ! sprintf(tb, "%s%d%s%s", s_dl, ival, s_dl, fld_dl); ! insert_num; } else if (isfloat(xs[i], &dval)) { ! if (cvt_f) ! sprintf(tb, "%.16g%s", dval, fld_dl); else ! sprintf(tb, "%s%.16g%s%s", s_dl, dval, s_dl, fld_dl); ! insert_num; } else if (isstr(xs[i], &sval)) { ! n_q = 0; p = sval; ! while (*p) { ! if (!strncmp(p, s_dl, n_s_dl)) ! ++n_q; ! ++p; ! } mrk = len; - /* strlen + double s_dls + dquotes + fld_dl */ - len += (p - sval + 1) + n_s_dl*(1 + n_q) + n_fld_dl; - resize_str; - p = sval; - strncpy(t, s_dl, n_s_dl); - t += n_s_dl; while (*p) { ! if (!strncmp(p, s_dl, n_s_dl)) { ! strncpy(t, s_dl, n_s_dl); ! t += n_s_dl; ! strncpy(t, s_dl, n_s_dl); ! t += n_s_dl; ! p += n_s_dl; ! } else ! *t++ = *p++; } ! strncpy(t, s_dl, n_s_dl); ! t += n_s_dl; ! strncpy(t, fld_dl, n_fld_dl); ! t += n_fld_dl; } else { sprintf(errmsg, "Field %d: Invalid conversion type.", i+1); --- 339,433 ---- if (argc != 2 || !istuple(argv[0], &i, &ys) ! || i != 6 ! || !isstr(ys[0], &delimiter) ! || !isstr(ys[1], &escape) ! || !isstr(ys[2], "e) ! || !isint(ys[3], "ing) ! || !isstr(ys[4], &lineterm) ! || !isbool(ys[5], &skipspace_f) ! || !istuple(argv[1], &n, &xs)) { return __FAIL; + } if (!(s = (char *)malloc(sz))) return __ERROR; ! n_escape = strlen(escape); ! n_quote = strlen(quote); ! n_delimiter = strlen(delimiter); ! n_lineterm = strlen(lineterm); for (i = 0; i < n; ++i) { if (isint(xs[i], &ival)) { ! if (!quoting) ! sprintf(tb, "%s%d%s%s", quote, ival, quote, delimiter); else ! sprintf(tb, "%d%s", ival, delimiter); ! insert; } else if (isfloat(xs[i], &dval)) { ! if (!quoting) ! sprintf(tb, "%s%.16g%s%s", quote, dval, quote, delimiter); else ! sprintf(tb, "%.16g%s", dval, delimiter); ! insert; } else if (isstr(xs[i], &sval)) { ! quote_cnt = 0; ! delim_cnt = 0; ! lineterm_cnt = 0; p = sval; ! if (skipspace_f && quoting == NOQUOTE) ! while (isspace(*p) ! && strncmp(p, quote, n_delimiter) ! && strncmp(p, delimiter, n_delimiter) ! && strncmp(p, lineterm, n_lineterm)) { ! ++p; ! } ! k = p - sval; mrk = len; while (*p) { ! if (!strncmp(p, quote, n_quote)) { ! ++quote_cnt; ! p += n_quote; ! len += n_escape + n_quote; ! } else if (!strncmp(p, delimiter, n_delimiter)) { ! ++delim_cnt; ! p += n_delimiter; ! len += n_delimiter; ! } else if (!strncmp(p, lineterm, n_lineterm)) { ! ++lineterm_cnt; ! p += n_lineterm; ! len += n_lineterm; ! } else { ! ++len; ! ++p; ! } } ! len += n_delimiter; ! p = sval + k; ! if (quoting==NOQUOTE && !(quote_cnt + delim_cnt + lineterm_cnt)) { ! resize_str; ! k = len-mrk-1; ! strncpy(t, p, k); ! t += k; ! } else { ! /* Add space for surrounding quotes */ ! len += n_quote << 1; ! resize_str; ! strncpy(t, quote, n_quote); ! t += n_quote; ! while (*p) { ! if (!strncmp(p, quote, n_quote)) { ! strncpy(t, escape, n_escape); ! t += n_escape; ! strncpy(t, quote, n_quote); ! t += n_quote; ! p += n_quote; ! } else ! *t++ = *p++; ! } ! strncpy(t, quote, n_quote); ! t += n_quote; ! } ! strncpy(t, delimiter, n_delimiter); ! t += n_delimiter; } else { sprintf(errmsg, "Field %d: Invalid conversion type.", i+1); *************** *** 378,392 **** } } ! mrk = (len -= n_fld_dl - 2); /* write over last fld_dl */ ! #if defined (_WIN32) ! resize_str; ! #else /* Unix and Linux */ ! ++len; /* guarantee enough space for for \r\n */ resize_str; ! *(t-2) = '\r'; ! #endif ! *(t-1) = '\n'; ! *t = 0; ! s = realloc(s, len); ! return mkstr(s); } --- 435,444 ---- } } ! mrk = (len -= n_delimiter); /* write over last delimiter */ ! len += n_lineterm; resize_str; ! strcpy(t, lineterm); ! if (!(t = strdup(s))) ! return __ERROR; ! return mkstr(t); } Index: csv.q =================================================================== RCS file: /cvsroot/q-lang/q-csv/csv.q,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** csv.q 18 Jan 2008 21:34:13 -0000 1.11 --- csv.q 22 Jan 2008 16:45:16 -0000 1.12 *************** *** 19,206 **** /* The CSV library provides an interface to read and write comma separated ! value files. The reading and writing functions abide by RFC 4180 ! (http://www.ietf.org/rfc/rfc4180.txt) except for additional parameters ! that allow field delimiters and quote delimiters to be changed. */ ! ! public extern fread_csvstr FILE STRDELIM; ! /* Read a CSV record from a file (including embedded new lines). ! FILE: file to be read from ! STRDELIM: string delimiter used in the CSV format ! ! NOTE: fread_csvstr does not take into account badly formatted records. ! csvstr_to_tuple is necessary for error checking. ! */ ! ! public extern tuple_to_csvstr ARGS REC; ! /* Convert a tuple (record) to a CSV string ! ARGS: tuple (auto conversion flag, field delimiter, string delimiter) ! REC: tuple of fields to be converted to CSV format ! ! NOTES ! (1) REC must contain ONLY strings, integers, and floating point numbers. ! If a field is some other type, the 'csv_error MSG' rule is invoked. ! (2) When the auto conversion flag is false, ALL fields are strings. ! */ ! ! public extern csvstr_to_tuple ARGS STR; ! /* Convert CSV string to a tuple (record). ! ARGS: tuple (auto conversion flag, field delimiter, string delimiter) ! STR: CSV string to be converted to a tuple ! NOTES ! (1) When the auto conversion flag is false, all fields are strings. ! (2) The 'csv_error MSG' rule is invoked on improperly formatted strings. ! */ public csv_error MSG; /* User may define csv_error for custom error handling. */ ! /* String functions */ ! public sreadcsv_data ARGS; ! sreadcsv_data S:String ! = csvstr_to_tuple (true, ",", "\"") S; ! sreadcsv_data (S:String, FieldDelim:String) ! = csvstr_to_tuple (true, FieldDelim, "\"") S; ! sreadcsv_data (S:String, FieldDelim:String, StrDelim:String) ! = csvstr_to_tuple (true, FieldDelim, StrDelim) S; ! ! public sreadcsv_string ARGS; ! sreadcsv_string S:String ! = csvstr_to_tuple (false, ",", "\"") S; ! sreadcsv_string (S:String, FieldDelim:String) ! = csvstr_to_tuple (false, FieldDelim, "\"") S; ! sreadcsv_string (S:String, FieldDelim:String, StrDelim:String) ! = csvstr_to_tuple (false, FieldDelim, StrDelim) S; ! ! public sreadcsvlist_data ARGS; ! sreadcsvlist_data L:List ! = map (csvstr_to_tuple (true, ",", "\"")) L; ! sreadcsvlist_data (S:String, FieldDelim:String) ! = map (csvstr_to_tuple (true, FieldDelim, "\"")) L; ! sreadcsvlist_data (S:String, FieldDelim:String, StrDelim:String) ! = map (csvstr_to_tuple (true, FieldDelim, StrDelim)) L; ! ! public sreadcsvlist_string ARGS; ! sreadcsvlist_string L:List ! = map (csvstr_to_tuple (false, ",", "\"")) L; ! sreadcsvlist_string (S:String, FieldDelim:String) ! = map (csvstr_to_tuple (false, FieldDelim, "\"")) L; ! sreadcsvlist_string (S:String, FieldDelim:String, StrDelim:String) ! = map (csvstr_to_tuple (false, FieldDelim, StrDelim)) L; ! ! public swritecsv_data ARGS; ! swritecsv_data (Rec:Tuple, FieldDelim:String, StrDelim:String) ! = tuple_to_csvstr (true, FieldDelim, StrDelim) Tec; ! swritecsv_data (Rec:Tuple, FieldDelim:String) ! = tuple_to_csvstr (true, FieldDelim, "\"") Rec; ! swritecsv_data Rec:Tuple ! = tuple_to_csvstr (true, ",", "\"") Rec; ! ! public swritecsv_string ARGS; ! swritecsv_string (Rec:Tuple, FieldDelim:String, StrDelim:String) ! = tuple_to_csvstr (false, FieldDelim, StrDelim) Rec; ! swritecsv_string (Rec:Tuple, FieldDelim:String) ! = tuple_to_csvstr (false, FieldDelim, "\"") Rec; ! swritecsv_string Rec:Tuple ! = tuple_to_csvstr (false, ",", "\"") Rec; ! ! public swritecsvlist_data ARGS; ! swritecsvlist_data L:List ! = map (tuple_to_csvstr (true, ",", "\"")) L; ! swritecsvlist_data (L:List, FieldDelim:String) ! = map (tuple_to_csvstr (true, FieldDelim, "\"")) L; ! swritecsvlist_data (L:List, FieldDelim:String, StrDelim:String) ! = map (tuple_to_csvstr (true, FieldDelim, StrDelim)) L; ! public swritecsvlist_string ARGS; ! swritecsvlist_string L:List ! = map (tuple_to_csvstr (false, ",", "\"")) L; ! swritecsvlist_string (L:List, FieldDelim:String) ! = map (tuple_to_csvstr (false, FieldDelim, "\"")) L; ! swritecsvlist_string (L:List, FieldDelim:String, StrDelim:String) ! = map (tuple_to_csvstr (false, FieldDelim, StrDelim)) L; ! public freadcsv_data ARGS; ! /* Read one CSV record from the file with number conversion. */ ! freadcsv_data F:File ! = csvstr_to_tuple (true, ",", "\"") (fread_csvstr F "\""); ! freadcsv_data (F:File, FieldDelim:String) ! = csvstr_to_tuple (true, FieldDelim, "\"") (fread_csvstr F "\""); ! freadcsv_data (F:File, FieldDelim:String, StrDelim:String) ! = csvstr_to_tuple (true, FieldDelim, StrDelim) (fread_csvstr F StrDelim); ! public freadcsv_string ARGS; ! /* Read one CSV record from the file without number conversion. */ ! freadcsv_string F:File ! = csvstr_to_tuple (false, ",", "\"") (fread_csvstr F "\""); ! freadcsv_string (F:File, FieldDelim:String) ! = csvstr_to_tuple (false, FieldDelim, "\"") (fread_csvstr F "\""); ! freadcsv_string (F:File, FieldDelim:String, StrDelim:String) ! = csvstr_to_tuple (false, ",", "\"") (fread_csvstr F StrDelim); ! public freadcsvlist_data ARGS, freadcsvlist_string ARGS; ! /* Read an entire file of records into a list of tuples. */ ! freadcsvlist_data F:File ! = [] if feof F; ! = [freadcsv_data F | freadcsvlist_data F]; ! freadcsvlist_data (F:File, FieldDelim:String) ! = [] if feof F; ! = [freadcsv_data (F, FieldDelim) ! | freadcsvlist_data (F, FieldDelim)]; ! freadcsvlist_data (F:File, FieldDelim:String, StrDelim:String) ! = [] if feof F; ! = [freadcsv_data (F, FieldDelim, StrDelim) ! | freadcsvlist_data (F, FieldDelim, StrDelim)]; ! freadcsvlist_string F:File ! = [] if feof F; ! = [freadcsv_string F | freadcsvlist_data F]; ! freadcsvlist_string (F:File, FieldDelim:String) ! = [] if feof F; ! = [freadcsv_string (F, FieldDelim) ! | freadcsvlist_string (F, FieldDelim)]; ! freadcsvlist_string (F:File, FieldDelim:String, StrDelim:String) ! = [] if feof F; ! = [freadcsv_string (F, FieldDelim, StrDelim) ! | freadcsvlist_string (F, FieldDelim, StrDelim)]; ! public fwritecsv_data FILE REC; ! /* Write one CSV record to a file with number conversion. */ ! fwritecsv_data F:File Rec:Tuple ! = fwrites F (tuple_to_csvstr (true, ",", "\"") Rec); ! fwritecsv_data (F:File, FieldDelim:String) Rec:Tuple ! = fwrites F (tuple_to_csvstr (true, FieldDelim, "\"") Rec); ! fwritecsv_data (F:File, FieldDelim:String, StrDelim:String) Rec:Tuple ! = fwrites F (tuple_to_csvstr (true, FieldDelim, StrDelim) Rec); ! public fwritecsv_string FILE REC; ! /* Write one CSV record to a file without number conversion. */ ! fwritecsv_string F:File Rec:Tuple ! = fwrites F (tuple_to_csvstr (false, ",", "\"") Rec); ! fwritecsv_string (F:File, FieldDelim:String) Rec:Tuple ! = fwrites F (tuple_to_csvstr (false, FieldDelim, "\"") Rec); ! fwritecsv_string (F:File, FieldDelim:String, StrDelim:String) Rec:Tuple ! = fwrites F (tuple_to_csvstr (false, FieldDelim, StrDelim) Rec); ! public fwritecsvlist_data FILE LIST, fwritecsvlist_string ARGS; ! /* Write a list of tuples to a CSV formatted file. */ ! fwritecsvlist_data F:File L:List ! = do (fwritecsv_data F) L; ! fwritecsvlist_data (F:File, FieldDelim:String) L:List ! = do (fwritecsv_data (F, FieldDelim)) L; ! fwritecsvlist_data (F:File, FieldDelim:String, StrDelim:String) L:List ! = do (fwritecsv_data (F, FieldDelim, StrDelim)) L; ! fwritecsvlist_string F:File L:List ! = do (fwritecsv_string F) L; ! fwritecsvlist_string (F:File, FieldDelim:String) L:List ! = do (fwritecsv_string (F, FieldDelim)) L; ! fwritecsvlist_string (F:File, FieldDelim:String, StrDelim:String) L:List ! = do (fwritecsv_string (F, FieldDelim, StrDelim)) L; \ No newline at end of file --- 19,157 ---- /* The CSV library provides an interface to read and write comma separated ! value files. The reading and writing functions are loosely based on ! Python's csv module (http://docs.python.org/lib/module-csv.html) */ ! private extern fread_csvstr FILE QUOTE; ! private extern tuple_to_csvstr ARGS REC; ! private extern csvstr_to_tuple ARGS STR; public csv_error MSG; /* User may define csv_error for custom error handling. */ ! from dict import dict, insert, vals, member; ! /* Dialect Options */ ! public const var ! csv_delimiter = 0, /* Field delimiter. Defaults to ",". */ ! csv_escape = 1, /* Embedded escape character. Defaults to "\"". ! Reading: The escape character is dropped and ! the next char is inserted into the field. ! Writing: The escape character is written into the ! output stream. */ ! csv_quote = 2, /* Quote character. Defaults to "\"". ! Note: If embedded quotes are doubled, csv_escape ! must equal csv_quote. */ ! csv_quoting = 3, /* Quoting options: Defaults to quote_strings. ! If csv_quote_all, ! Reading: all fields are read as strings. ! Writing: all fields are quoted. ! If csv_quote_strings, ! Reading: integers and floats are converted. ! Writing: integers and floats are unquoted. ! If csv_quote_none, ! Reading: ntegers and floats are converted. ! Writing: all fields are unquoted except for ! those containing embedded quotes or ! newlines. */ ! csv_lineterminator = 4, /* Record terminator. Defaults to "\r\n" */ ! csv_skipspace = 5, /* Skip white space flag. Defaults to true. ! Reading/Writing: If true, white spaces before ! fields are removed. Quoted fields retain white ! space. */ + /* Constants used by csv quoting */ + csv_quote_all = 0, /* Quote every field */ + csv_quote_strings = 1, /* Quote only strings */ + csv_quote_none = 2; /* Quote only fields with embedded field delimeters, + line terminators, or escaped quotes. */ ! /* Defaults to RFC 4180 (http://www.ietf.org/rfc/rfc4180.txt) */ ! def DEFAULTS ! = dict [csv_delimiter, ","; ! csv_escape, "\""; ! csv_quote, "\""; ! csv_quoting, csv_quote_strings; ! csv_lineterminator, "\r\n"; ! csv_skipspace, true]; ! /* Create a dialect base on the list of dialect options given above */ ! public csv_dialect OPTS; ! csv_dialect Opts:List ! = tuple $ vals ! $ foldl insert (insert DEFAULTS (csv_escape, D!csv_quote)) $ Opts ! if (member D csv_quote) and then (not member D csv_escape) ! where D = dict Opts; ! = tuple $ vals $ foldl insert DEFAULTS $ Opts; ! /* Standard CSV format */ ! public rfc4180_dialect; ! rfc4180_dialect = csv_dialect []; ! public unix_dialect; ! unix_dialect = csv_dialect [csv_lineterminator,"\n";]; ! /* Convert a tuple (record) to a CSV string ! Dialect: CSV format specification. If none is given, defaults to ! rfc4180_dialect. ! Rec: Tuple of fields to be converted to CSV format. ! NOTE: REC must contain ONLY strings, integers, and floating point numbers. ! If a field is some other type, the 'csv_error MSG' rule is invoked. ! */ ! public swritecsv ARGS; ! swritecsv (Dialect:Tuple, Rec:Tuple) ! = tuple_to_csvstr Dialect Rec; ! swritecsv Rec:Tuple ! = tuple_to_csvstr rfc4180_dialect Rec; ! /* Convert a list of tuples to a list of CSV formated strings. */ ! public swritecsvlist ARGS; ! swritecsvlist (Dialect:Tuple, L:List) ! = map (tuple_to_csvstr Dialect) L; ! swritecsvlist L:List ! = map (tuple_to_csvstr rfc4180_dialect) L; ! /* Convert a tuple (record) to a CSV string ! Dialect: CSV format specification. If none is given, defaults to ! rfc4180_dialect. ! Rec: Tuple of fields to be converted to CSV format. ! NOTE: The 'csv_error MSG' rule is invoked on improperly formatted strings. ! */ ! public sreadcsv ARGS; ! sreadcsv (Rec:Tuple, Dialect:Tuple) ! = csvstr_to_tuple Dialect Rec; ! sreadcsv Rec:Tuple ! = csvstr_to_tuple rfc4180_dialect Rec; ! /* Convert a list of CSV formated strings to a list of tuples */ ! public sreadcsvlist ARGS; ! sreadcsvlist (L:List, Dialect:Tuple) ! = map (csvstr_to_tuple Dialect) L; ! sreadcsvlist L:List ! = map (csvstr_to_tuple rfc4180_dialect) L; ! /* File handling functions */ ! public freadcsv ARGS; ! freadcsv (F:File, Dialect:Tuple) ! = csvstr_to_tuple Dialect $ fread_csvstr F (Dialect!csv_quote); ! freadcsv F:File ! = csvstr_to_tuple rfc4180_dialect $ fread_csvstr F "\""; ! public fwritecsv ARGS REC; ! fwritecsv (F:File, Dialect:Tuple) Rec:Tuple ! = fwrites F $ tuple_to_csvstr Dialect Rec; ! fwritecsv F:File Rec:Tuple ! = fwrites F $ tuple_to_csvstr rfc4180_dialect Rec; ! public freadcsvlist ARGS; ! freadcsvlist (F:File, Dialect:Tuple) ! = [freadcsv (F, Dialect) | freadcsvlist (F, Dialect)]; ! freadcsvlist F:File ! = [freadcsv F | freadcsvlist F]; ! public fwritecsvlist ARGS REC; ! fwritecsvlist (F:File, Dialect:Tuple) L:List ! = do (fwritecsv F Dialect) L; ! fwritecsvlist F:File L:List ! = do (fwritecsv F) L; \ No newline at end of file |