fixed 2 bugs: the sheet range check code was broken an extra delimiter was printed on every line in delimiter mode added options to to disable quoting of text strings, and specify ranges of columns in the same way as existing worksheets specs. I have a suspicion that I am the only one who uses this but it helps me surf the tsunami of Excel reports I get every month. -Steve Reference: /n/sources/patch/applied/xls-fixes Date: Thu Mar 12 13:26:30 CET 2009 Signed-off-by: steve@quintile.net --- /sys/src/cmd/aux/msexceltables.c Thu Mar 12 13:25:35 2009 +++ /sys/src/cmd/aux/msexceltables.c Thu Mar 12 13:25:32 2009 @@ -54,6 +54,7 @@ static int All = 0; // dump all sheet types, Worksheets only by default static char *Delim = " "; // field delimiter static char *Sheetrange = nil; // range of sheets wanted +static char *Columnrange = nil; // range of collums wanted static int Debug = 0; // file scope @@ -65,6 +66,7 @@ static int *Xf; // array of extended format indices static int Nxf = 0; // # of above static Biobuf *bo; // stdout (sic) +static int Doquote = 1; // quote text fields if they are rc(1) unfriendly // table scope static int Width[Nwidths]; // array of colum widths @@ -85,6 +87,47 @@ [0x2a] "#N/A!", // argument of function not available }; +int +wanted(char *range, int here) +{ + int n, s; + char *p; + + if (! range) + return 1; + + s = -1; + p = range; + while(1){ + n = strtol(p, &p, 10); + switch(*p){ + case 0: + if(n == here) + return 1; + if(s != -1 && here > s && here < n) + return 1; + return 0; + case ',': + if(n == here) + return 1; + if(s != -1 && here > s && here < n) + return 1; + s = -1; + p++; + break; + case '-': + if(n == here) + return 1; + s = n; + p++; + break; + default: + sysfatal("%s malformed range spec", range); + break; + } + } +} + void cell(int r, int c, int f, int type, void *val) @@ -214,11 +257,22 @@ dump(void) { Row *r; - Col *c; - int i, min, max; + Col *c, *c1; + char *strfmt; + int i, n, last, min, max; + + if(Doquote) + strfmt = "%-*.*q"; + else + strfmt = "%-*.*s"; for(r = Root; r; r = r->next){ + n = 1; for(c = r->col; c; c = c->next){ + n++; + if(! wanted(Columnrange, n)) + continue; + if(c->c < 0 || c->c >= Nwidths || (min = Width[c->c]) == 0) min = Defwidth; if((c->next && c->c == c->next->c) || Nopad) @@ -235,28 +289,35 @@ numfmt(Xf[c->f], min, max, c->number); break; case Tlabel: - Bprint(bo, "%-*.*q", min, max, c->label); + Bprint(bo, strfmt, min, max, c->label); break; case Tbool: - Bprint(bo, "%-*.*s", min, max, (c->bool)? "True": "False"); + Bprint(bo, strfmt, min, max, (c->bool)? "True": "False"); break; case Tindex: if(c->index < 0 || c->index >= Nstrtab) sysfatal("SST string out of range - corrupt file?"); - Bprint(bo, "%-*.*q", min, max, Strtab[c->index]); + Bprint(bo, strfmt, min, max, Strtab[c->index]); break; case Terror: if(c->error < 0 || c->error >= nelem(Errmsgs) || !Errmsgs[c->error]) Bprint(bo, "#ERR=%d", c->index); else - Bprint(bo, "%-*.*q", min, max, Errmsgs[c->error]); + Bprint(bo, strfmt, min, max, Errmsgs[c->error]); break; default: sysfatal("cannot happen error"); break; } - if(c->next){ + last = 1; + for(i = n+1, c1 = c->next; c1; c1 = c1->next, i++) + if(wanted(Columnrange, i)){ + last = 0; + break; + } + + if(! last){ if(c->next->c == c->c) // bar charts Bprint(bo, "="); else{ @@ -587,40 +648,6 @@ Datemode = gint(b, 2); } -int -wanted(char *range, int sheet) -{ - int i, j; - char *p; - - if (! range) - return 1; - - p = range; - while(*p){ - i = strtol(p, &p, 10); - switch(*p){ - case '\0': - case ',': - if (i == sheet) - return 1; - break; - case '-': - j = strtol(p+1, &p, 10); - if(sheet >= i && sheet <= j) - return 1; - - break; - default: - sysfatal(" %s malformed range spec", range); - break; - } - if (*p == ',') - p++; - } - return 0; -} - void eof(Biff *b) { @@ -751,7 +778,7 @@ void usage(void) { - fprint(2, "usage: %s [-Dant] [-w worksheets] [-d delim] /mnt/doc/Workbook\n", argv0); + fprint(2, "usage: %s [-Danqt] [-w worksheets] [-c columns] [-d delim] /mnt/doc/Workbook\n", argv0); exits("usage"); } @@ -768,6 +795,9 @@ case 'a': All = 1; break; + case 'q': + Doquote = 0; + break; case 'd': Delim = EARGF(usage()); break; @@ -776,6 +806,9 @@ break; case 't': Trunc = 1; + break; + case 'c': + Columnrange = EARGF(usage()); break; case 'w': Sheetrange = EARGF(usage()); --- /sys/man/1/doc2txt Thu Mar 12 13:25:38 2009 +++ /sys/man/1/doc2txt Thu Mar 12 13:25:36 2009 @@ -35,11 +35,14 @@ .br .B aux/msexceltables [ -.B -aDnt +.B -qaDnt ] [ .B -d .I delim ] [ +.B -c +.I column-range +] [ .B -w .I worksheet-range ] @@ -95,26 +98,38 @@ .B -D Enables debugging output. .TP +.BI -c " range +.I Range +is a comma-separated list of column numbers and ranges. +Ranges are separated by dashes. +Limit processing to just those columns named; +by default all columns are output. +.TP .B -n -Disables field padding to column width. +Disables field padding to column width. +.TP +.B -q +Disable quoting of textural fields (see +.IR quote (2).) .TP .B -t Truncate fields to the column width. .TP -.BI -w " pages -.I Pages -is a comma-separated list of page numbers and ranges. -Ranges are separated by dashes. -Limit processing to just those pages named; -by default all tabular sheets are output. +.BI -w " range +.I Range +is a comma-separated list of worksheet numbers and ranges, this +limits the sheets output using the same syntax as the +.B -c +option above. Suppressed chart pages are always included in the sheet count. .SH EXAMPLE Extract pieces of an MS Excel spreadsheet. .PD 0 .IP .EX +.SM aux/olefs report.xls -msexceltables -w 1,7,9-14,3-4 -n -d '@' /mnt/doc/Workbook +msexceltables -q -w 1,7,9-14 -c 3-5 -n -d '@' /mnt/doc/Workbook > rpt.txt unmount /mnt/doc .EE .PD