#ifdef DMALLOC #include "dmalloc.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "default.h" #include "display.h" #include "eval.h" #include "htmlio.h" #include "latex.h" #include "context.h" #include "main.h" #include "misc.h" #include "sc.h" #include "scanner.h" #include "utf8.h" #include "parser.h" #include "sheet.h" #include "wk1.h" #include "xdr.h" /* variables */ /*{{{*/ char helpfile[PATH_MAX]; bool batch = false; unsigned int batchln=0; PrecisionLevel def_precision = DEF_PRECISION; StringFormat quote = DIRECT_STRING; bool header = true; bool always_redraw = false; int debug_level = 0; static bool usexdr = false; /*}}}*/ void moveto(Sheet *sheet, CoordT x, CoordT y, CoordT z) { bool need_redraw = false; bool need_cell = false; CoordT xdir = x > sheet->cur[X] ? 1 : -1; if (x >= 0 && x != sheet->cur[X]) { need_cell = true; sheet->cur[X] = x; } if (y >= 0 && y != sheet->cur[Y]) { need_cell = true; sheet->cur[Y] = y; } if (z >= 0 && z != sheet->cur[Z]) { need_redraw = true; sheet->cur[Z] = z; } while (sheet->cur[X] > 0 && shadowed(sheet, sheet->cur)) sheet->cur[X] += xdir; if (getmarkstate(sheet) == MARKING) LOCATION_GETS(sheet->mark2, sheet->cur); if (sheet->cur[X] <= sheet->offx && sheet->offx > 0) { need_redraw = true; sheet->offx = (sheet->cur[X] > 0) ? sheet->cur[X]-1 : 0; } if (sheet->cur[Y] <= sheet->offy && sheet->offy > 0) { need_redraw = true; sheet->offy = (sheet->cur[Y] > 0) ? sheet->cur[Y]-1 : 0; } if (sheet->cur[X] >= sheet->offx + sheet->maxx) { need_redraw = true; sheet->offx = sheet->cur[X] - sheet->maxx + 2; } if (sheet->cur[Y] >= sheet->offy + sheet->maxy) { need_redraw = true; sheet->offy = sheet->cur[Y] - sheet->maxy + 2; } if (need_redraw) redraw_sheet(sheet); else if (need_cell) redraw_cell(sheet, sheet->cur); } void movetoloc(Sheet *sheet, const Location dest) { moveto(sheet, dest[X], dest[Y], dest[Z]); } void relmoveto(Sheet *sheet, CoordT x, CoordT y, CoordT z) { moveto(sheet, sheet->cur[X]+x, sheet->cur[Y]+y, (z?sheet->cur[Z]+z:-1)); } /* line_numedit -- number line editor function */ /*{{{*/ static int line_numedit(int *n, const char *prompt) { assert(prompt != NULL); char buf[20]; Token *t = NULLTOKEN; sprintf(buf, "%d", *n); char *s = buf + strlen(buf); do { free(t); size_t x = (size_t)(s - buf); size_t offx = 0; int c = line_edit((Sheet*)0, buf, sizeof(buf), prompt, &x, &offx); if (c < 0) return c; s = buf; t = scan_integer(&s); } while (*s != '\0'); if (t == NULLTOKEN) *n = -1; else { *n = (int)(t->u.integer); free(t); } return 0; } /*}}}*/ /* line_lidedit -- label identifier line editor function */ /*{{{*/ static int line_idedit(char *ident, size_t size, const char *prompt, size_t *x, size_t *offx) { Token *t = NULLTOKEN; char *s = ident + strlen(ident); do { free(t); *x = (size_t)(s - ident); int c = line_edit((Sheet*)0, ident, size, prompt, x, offx); if (c < 0) return c; s = ident; t = scan_ident(&s); } while (*s != '\0' || t == NULLTOKEN || t->type != LIDENT); free(t); return 0; } /*}}}*/ /* doanyway -- ask if action should be done despite unsaved changes */ /*{{{*/ bool doanyway(Sheet *sheet, const char *msg) { if (sheet->changed && line_ok(msg, 0) <= 0) return false; return true; } /*}}}*/ /* do_edit -- set or modify cell contents */ /*{{{*/ static int do_edit(Sheet *cursheet, Key c, char *expr, TokVariety tv) { const char *promptfor[] = { [BASE_CONT] = _("Cell contents"), [ITER_CONT] = _("Clocked cell contents"), [STYLE_CONT] = _("Style expression") }; Location scur; Cell *cell = curcell(cursheet); Token newcont; if (locked(cell)) line_msg(_("Edit cell:"),_("Cell is locked")); else { newcont.type = EMPTY; LOCATION_GETS(scur, cursheet->cur); if (expr) { char *s = expr; Token **t = scan(&s); if (*s != '\0') { if (t == EMPTY_TVEC) line_msg(promptfor[tv], "XXX invalid expression"); else { newcont = eval_safe(t, LITERAL); if (newcont.type == EEK) line_msg(promptfor[tv], "XXX unparseable expression"); } } tvecfree(t); } else { Token cntt; size_t offx = 0; char buf[1024]; char *s = NULL; if (c == K_NONE) { cntt = gettok(cell, tv); printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, -1, TRUNCATED_ERROR, &cntt); s = buf+strlen(buf); } else if (c == K_BACKSPACE) { cntt = gettok(cell, tv); printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, -1, TRUNCATED_ERROR, &cntt); if (strlen(buf)) *mbspos(buf+strlen(buf),-1)='\0'; s = buf+strlen(buf); } else if (c == K_DC) { cntt = gettok(cell, tv); printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, -1, TRUNCATED_ERROR, &cntt); memmove(buf,mbspos(buf,1),strlen(mbspos(buf,1))+1); s = buf; } else if (isalpha(c)) { buf[0] = '"'; buf[1] = (char)c; buf[2] = 0; s=buf+2; } else { if (c < 256) buf[0] = (char)c; else buf[0] = 0; buf[1]='\0'; s=buf+1; } do { tfree(&newcont); newcont.type = EEK; newcont.u.err = (char *)0; size_t x = mbslen(buf)-mbslen(s); int r = line_edit(cursheet, buf, sizeof(buf), promptfor[tv], &x, &offx); if (r < 0) return r; s = buf; if (buf[0] == '"' && buf[strlen(buf)-1] != '"' && strlen(buf)+1 < sizeof(buf)) { buf[strlen(buf)+1] = 0; buf[strlen(buf)] = '"'; } Token **t = scan(&s); if (t != EMPTY_TVEC) { newcont = eval_safe(t, LITERAL); } tvecfree(t); } while (*s != '\0' && newcont.type == EEK); } movetoloc(cursheet, scur); puttok(cursheet, cursheet->cur, newcont, tv); forceupdate(cursheet); } return 0; } /*}}}*/ /* do_label -- modify cell label */ /*{{{*/ static int do_label(Sheet *sheet) { /* variables */ /*{{{*/ char buf[1024],oldlabel[1024]; size_t edx,offx,ok; Token t; Location w; int tried; int c; /*}}}*/ assert(sheet != (Sheet*)0); do_mark(sheet, GET_MARK_ALL); if (SAME_LOC(sheet->mark1,sheet->mark2) && locked(CELL_AT(sheet, sheet->mark1))) { line_msg(_("Cell label:"),_("Cell is locked")); } else { ok=edx=offx=0; (void)strcpy(buf, getlabel(curcell(sheet))); (void)strcpy(oldlabel, buf); tried = 0; do { if (tried) { line_msg(_("Cell label:"), _("Label already in use")); } if ((c=line_idedit(buf,sizeof(buf),_("Cell label:"),&edx,&offx))<0) return c; tried = 1; if (buf[0]=='\0') ok=1; else { ok=((t=findlabel(sheet,buf)).type==EEK || (t.type == LOCATION && SAME_LOC(t.u.location, sheet->cur))); tfree(&t); } } while (!ok); setlabel(sheet, sheet->cur, buf,1); if (buf[0] != '\0' && oldlabel[0] != '\0') for (ALL_LOCS_IN_REGION(sheet,w)) relabel(sheet, w, oldlabel, buf); cachelabels(sheet); forceupdate(sheet); } return -1; } /*}}}*/ /* do_columnwidth -- set the column width */ /*{{{*/ static int do_columnwidth(Sheet *cursheet) { do_mark(cursheet, GET_MARK_CUR); int n = (int)columnwidth(cursheet, cursheet->mark1[X], cursheet->mark1[Z]); do { int c = line_numedit(&n, _("Column width:")); if (c < 0) return c; } while (n <= 0); /*}}}*/ for (int x = cursheet->mark1[X]; x <= cursheet->mark2[X]; ++x) for (int z = cursheet->mark1[Z]; z <= cursheet->mark2[Z]; ++z) setwidth(cursheet,x,z,(ColWidT)n); return -1; } /*}}}*/ /* do_attribute -- set cell attributes */ /*{{{*/ static void do_attribute(Sheet *cursheet, Key action) { Location w; Adjust adj = LEFT; FloatFormat ff = FLT_DECIMAL; do_mark(cursheet, GET_MARK_CUR); bool onecell = SAME_LOC(cursheet->mark1, cursheet->mark2); Cell *fcell = safe_cell_at(cursheet, cursheet->mark1); Style fs = getstyle(cursheet, cursheet->mark1); bool changed = false; if (action != ADJUST_LOCK && onecell && locked(fcell)) { line_msg(_("Cell attribute:"),_("Cell is locked")); return; } ColorAspect ca = FOREGROUND; switch ((int)action) { case ADJUST_CENTER: ++adj; /* FALL THROUGH */ case ADJUST_RIGHT: ++adj; /* FALL THROUGH */ case ADJUST_LEFT: { const char *templ = _("Change adjustment of block to %s?"); char *prompt = malloc(strlen(templ) + MAX_ADJUST_NAME_LENGTH + 1); sprintf(prompt, templ, Adjust_Name[adj]); if (!onecell && line_ok(prompt, 0) <= 0) break; for (ALL_LOCS_IN_REGION(cursheet,w)) changed = setadjust(cursheet, w, adj) || changed; break; } /* set float format */ /*{{{*/ case ADJUST_HEXACT: ++ff; /* FALL THROUGH */ case ADJUST_COMPACT: ++ff; /* FALL THROUGH */ case ADJUST_SCIENTIFIC: ++ff; /* FALL THROUGH */ case ADJUST_DECIMAL: { const char* templ = _("Change float format of block to %s?"); char *prompt = malloc(strlen(templ) + MAX_FLOATFORM_NAME_LENGTH +1); sprintf(prompt, templ, FloatFormat_Name[ff]); if (!onecell && line_ok(prompt, 0) <= 0) break; for (ALL_LOCS_IN_REGION(cursheet,w)) changed = setfltformat(cursheet, w, ff) || changed; break; } /*}}}*/ /* 5 -- set precision */ /*{{{*/ case ADJUST_PRECISION: { int n = fs.precision; const char* prompt = _("Precision for block:"); if (onecell) prompt = _("Precision for cell:"); int c = line_numedit(&n, prompt); if (c < 0) return; for (ALL_LOCS_IN_REGION(cursheet,w)) changed = setprecision(cursheet, w, (PrecisionLevel)n) || changed; break; } /*}}}*/ /* Set a color */ /*{{{*/ case ADJUST_BACKGROUND: ca = BACKGROUND; /* FALL THROUGH */ case ADJUST_FOREGROUND: { int n = fs.aspect[ca]; const char* prompt = _("%s for block:"); if (onecell) prompt = _("%s for cell:"); char pbuf[256]; sprintf(pbuf, prompt, ColorAspect_Name[ca]); int c = line_numedit(&n, pbuf); if (c < 0) return; for (ALL_LOCS_IN_REGION(cursheet,w)) changed = setcolor(cursheet, w, ca, (ColorNum)n) || changed; break; } /* 6 -- shadow */ /*{{{*/ case ADJUST_SHADOW: { Location rt; LOCATION_GETS(rt, cursheet->mark1); ++rt[X]; int n = 0; if (!(fs.shadowed) && !shadowed(cursheet, rt)) n = 1; if (!onecell) n = line_binary(_("Set block to:"), _("uU)nshadowed"), _("sS)hadowed"), n); if (cursheet->mark1[X] == 0 && n == 1) { line_msg(_("Shadow cell:"),_("You can not shadow cells in column 0")); break; } if (n >= 0) { for (ALL_LOCS_IN_REGION(cursheet,w)) { Location assoc; if (n == 0) { LOCATION_GETS(assoc, w); if (!shadowed(cursheet, assoc)) assoc[X]++; for (; shadowed(cursheet, assoc); assoc[X]++) changed = shadow(cursheet, assoc, false) || changed; } else if (w[X] > 0) changed = shadow(cursheet, w, true) || changed; } } if (n > 0) do_mark(cursheet, UNMARKED); break; } /*}}}*/ /* 7 -- transparent */ /*{{{*/ case ADJUST_TRANSPARENT: { int n; if (onecell) n = !(fs.transparent); else n = line_binary(_("Set block to:"), _("pP)rotected"), _("tT)ransparent:"), !(fs.transparent)); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) changed = maketrans(cursheet, w, n) || changed; break; } /*}}}*/ case ADJUST_DIM: /*{{{*/ { int n = !(fs.dim); if (!onecell) n = line_binary(_("Set block brightness to:"), _("rR)egular"), _("dD)im"), n); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) changed = makedim(cursheet, w, n) || changed; break; } /*}}}*/ case ADJUST_BOLD: /*{{{*/ { int n = !(fs.bold); if (!onecell) n = line_binary(_("Set block weight to:"), _("rR)egular"), _("bB)old"), n); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) changed = embolden(cursheet, w, n) || changed; break; } /*}}}*/ case ADJUST_ITALIC: /*{{{*/ { int n = !(fs.italic); if (!onecell) n = line_binary(_("Set block font to:"), _("rR)oman"), _("iI)talic"), n); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) changed = italicize(cursheet, w, n) || changed; break; } /*}}}*/ /* 9 -- underline */ /*{{{*/ case ADJUST_UNDERLINE: { int n; if (onecell) n = !(fs.underline); else n = line_binary(_("Set block to:"), _("nN)ot underline"), _("uU)nderline"), !(fs.underline)); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) changed = underline(cursheet, w, n) || changed; break; } /*}}}*/ /* 1 -- edit label and goto end */ /*{{{*/ case ADJUST_LABEL: { do_label(cursheet); return; } /*}}}*/ /* 2 -- lock */ /*{{{*/ case ADJUST_LOCK: { int n; if (onecell) n = !locked(fcell); else n = line_binary(_("Set block to:"), _("uU)nlocked"), _("lL)ocked"), !locked(fcell)); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) changed = lockcell(cursheet, w, n) || changed; break; } /*}}}*/ /* 3 -- ignore */ /*{{{*/ case ADJUST_IGNORE: { int n; if (onecell) n = !ignored(fcell); else n = line_binary(_("Set block to:"), _("cC)omputed"), _("iI)gnored"), !ignored(fcell)); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) changed = igncell(cursheet, w, n) || changed; break; } /*}}}*/ /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } if (changed) forceupdate(cursheet); } /*}}}*/ /* do_saveport -- save sheet as portable ASCII file */ /*{{{*/ static int do_saveport(Sheet *cursheet, const char *name) { char buf[PATH_MAX]; const char *msg; unsigned int count; if (!name) name = cursheet->name; if ((msg = saveport(cursheet, name, &count))) { line_msg(_("Save sheet to ASCII file:"),msg); return -2; } snprintf(buf, sizeof(buf), _("%u cells written"), count); if (!batch) line_msg(_("Save sheet to ASCII file:"),buf); return -1; } /*}}}*/ /* do_savetbl -- save sheet as tbl file */ /*{{{*/ static int do_savetbl(Sheet *cursheet, const char *name) { char buf[PATH_MAX]; const char *msg; int standalone=0; unsigned int count; do_mark(cursheet, GET_MARK_ALL); if (!name) { name = cursheet->name; if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone; } if ((msg = savetbl(cursheet, name, !standalone, cursheet->mark1, cursheet->mark2, &count))) { line_msg(_("Save in tbl format to file:"),msg); return -2; } snprintf(buf, sizeof(buf), _("%u cells written"), count); if (!batch) line_msg(_("Save in tbl format to file:"), buf); return -1; } /*}}}*/ /* do_savelatex -- save sheet as LaTeX file */ /*{{{*/ static int do_savelatex(Sheet *cursheet, const char *name) { char buf[PATH_MAX]; const char *msg; int standalone=0; unsigned int count; do_mark(cursheet, GET_MARK_ALL); if (!name) { name = cursheet->name; if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone; } if ((msg = savelatex(cursheet, name, !standalone, cursheet->mark1, cursheet->mark2, &count))) { line_msg(_("Save in LaTeX format to file:"),msg); return -2; } snprintf(buf, sizeof(buf), _("%u cells written"), count); if (!batch) line_msg(_("Save in LaTeX format to file:"), buf); return -1; } /*}}}*/ /* do_savecontext -- save sheet as ConTeXt file */ /*{{{*/ static int do_savecontext(Sheet *cursheet, const char *name) { char buf[PATH_MAX]; const char *msg; int standalone=0; unsigned int count; do_mark(cursheet, GET_MARK_ALL); if (!name) { name = cursheet->name; if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone; } if ((msg = savecontext(cursheet, name, !standalone, cursheet->mark1, cursheet->mark2, &count))) { line_msg(_("Save in ConTeXt format to file:"),msg); return -2; } snprintf(buf, sizeof(buf), _("%u cells written"), count); if (!batch) line_msg(_("Save in ConTeXt format to file:"), buf); return -1; } /*}}}*/ /* do_savehtml -- save sheet as HTML file */ /*{{{*/ static int do_savehtml(Sheet *cursheet, const char *name) { char buf[PATH_MAX]; const char *msg; int standalone=0; unsigned int count; do_mark(cursheet, GET_MARK_ALL); if (!name) { name = cursheet->name; if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone; } if ((msg = savehtml(cursheet, name, !standalone, cursheet->mark1, cursheet->mark2, &count))) { line_msg(_("Save in HTML format to file:"),msg); return -2; } snprintf(buf, sizeof(buf), _("%u cells written"), count); if (!batch) line_msg(_("Save in HTML format to file:"), buf); return -1; } /*}}}*/ /* do_savetext -- save sheet as formatted text file */ /*{{{*/ static int do_savetext(Sheet *cursheet, const char *name) { char buf[PATH_MAX]; const char *msg; unsigned int count; do_mark(cursheet, GET_MARK_ALL); if (!name) name = cursheet->name; if ((msg = savetext(cursheet, name, cursheet->mark1, cursheet->mark2, &count))) { line_msg(_("Save in plain text format to file:"),msg); return -2; } snprintf(buf, sizeof(buf), _("%u cells written"), count); if (!batch) line_msg(_("Save in plain text format to file:"), buf); return -1; } /*}}}*/ /* do_savecsv -- save sheet as CSV file */ /*{{{*/ static int do_savecsv(Sheet *cursheet, const char *name) { do_mark(cursheet, GET_MARK_ALL); if (!name) name = cursheet->name; const char *menu[] = { _("cC)omma (,)"), _("sS)emicolon (;)"), _("tT)ab (\\t)"), NULL }; const char seps[4] = ",;\t"; int sep = line_menu(_("Choose separator:"), menu, 0); if (sep < 0) return sep; unsigned int count; const char *msg; if ((msg = savecsv(cursheet, name, seps[sep], cursheet->mark1, cursheet->mark2, &count))) { line_msg(_("Save in CSV format to file:"), msg); return -2; } char buf[1024]; snprintf(buf, sizeof(buf), _("%u cells written"), count); if (!batch) line_msg(_("Save in CSV format to file:"), buf); return -1; } /*}}}*/ /* do_loadxdr -- load sheet from XDR file */ /*{{{*/ static int do_loadxdr(Sheet *cursheet) { const char *msg; if ((msg=loadxdr(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from XDR file:"),msg); return -1; } /*}}}*/ /* do_loadport -- load sheet from portable ASCII file */ /*{{{*/ static int do_loadport(Sheet *cursheet) { const char *msg; /*}}}*/ if ((msg=loadport(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from ASCII file:"),msg); return -1; } /*}}}*/ /* do_loadsc -- load sheet from SC file */ /*{{{*/ static int do_loadsc(Sheet *cursheet) { const char *msg; if ((msg=loadsc(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from SC file:"),msg); return -1; } /*}}}*/ /* do_loadwk1 -- load sheet from WK1 file */ /*{{{*/ static int do_loadwk1(Sheet *cursheet) { const char *msg; if ((msg=loadwk1(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from WK1 file:"),msg); return -1; } /*}}}*/ /* do_loadcsv -- load/merge sheet from CSV file */ /*{{{*/ static int do_loadcsv(Sheet *cursheet) { const char *msg; if ((msg=loadcsv(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from CSV file:"),msg); return -1; } /*}}}*/ /* do_mark -- set mark */ /*{{{*/ void do_mark(Sheet *cursheet, MarkState ms) { MarkState ps = getmarkstate(cursheet); if (ms == MARK_CYCLE) { if (ps == UNMARKED) ms = MARKING; else ms = ps + 1; } if (ps == ms) return; switch (ms) { case MARKING: { LOCATION_GETS(cursheet->mark1, cursheet->cur); LOCATION_GETS(cursheet->mark2, cursheet->cur); break; } case UNMARKED: break; case MARKED: case GET_MARK_CUR: case GET_MARK_ALL: { switch (ps) { case MARKED: { ms = MARKED; break; } case MARKING: { poscorners(cursheet->mark1, cursheet->mark2); ms = MARKED; break; } case UNMARKED: { if (ms == GET_MARK_CUR) { LOCATION_GETS(cursheet->mark1, cursheet->cur); LOCATION_GETS(cursheet->mark2, cursheet->cur); ms = UNMARKED; } else if (ms == GET_MARK_ALL) { OLOCATION(cursheet->mark1); for (Dimensions dd = X; dd < HYPER; ++dd) cursheet->mark2[dd] = (CoordT)(cursheet->dim[dd] - 1); ms = UNMARKED; } else assert(ms == MARKED); break; } default: assert(0); } break; } default: assert(0); } cursheet->marking = ms; } /*}}}*/ static int do_name(Sheet *cursheet); /* do_save -- save sheet */ /*{{{*/ static int do_save(Sheet *cursheet) { const char *ext = cursheet->name; if (ext==(char*)0) return do_name(cursheet); ext += strlen(ext)-1; if (!strcmp(ext-3, ".tbl")) return do_savetbl(cursheet, NULL); if (!strcmp(ext-5, ".latex")) return do_savelatex(cursheet, NULL); if (!strcmp(ext-4, ".html")) return do_savehtml(cursheet, NULL); if (!strcmp(ext-3, ".csv")) return do_savecsv(cursheet, NULL); if (!strcmp(ext-3, ".txt")) return do_savetext(cursheet, NULL); if (!strcmp(ext-3, ".tex")) return do_savecontext(cursheet, NULL); return do_saveport(cursheet, NULL); } /*}}}*/ /* do_name -- (re)name sheet */ /*{{{*/ static int do_name(Sheet *cursheet) { const char *name; name = line_file(cursheet->name, _("Teapot ASCII \t*.tpa\ntbl \t*.tbl\nLaTeX \t*.latex\nHTML \t*.html\nCSV \t*.csv\nFormatted ASCII \t*.txt\nConTeXt \t*.tex"), _("New file name:"), 1); if (!name) return -1; if (cursheet->name!=(char*)0) free(cursheet->name); cursheet->name=strdup(name); return do_save(cursheet); } /*}}}*/ /* do_load -- load sheet */ /*{{{*/ static int do_load(Sheet *cursheet) { const char *name, *ext; if (doanyway(cursheet, _("Sheet modified, load new file anyway?")) != 1) return -1; name = line_file(cursheet->name, _("Teapot ASCII \t*.tpa\n" "CSV \t*.csv\n" "Legacy binary Teapot \t*.tp\n" "SC Spreadsheet Calculator \t*.sc\n" "Lotus 1-2-3 \t*.wk1\n" ), _("Load sheet:"), 0); if (!name) return -1; if (cursheet->name!=(char*)0) free(cursheet->name); cursheet->name=strdup(name); ext = name+strlen(name)-1; if (!strcmp(ext-2, ".tp")) return do_loadxdr(cursheet); if (!strcmp(ext-2, ".sc")) return do_loadsc(cursheet); if (!strcmp(ext-3, ".wk1")) return do_loadwk1(cursheet); if (!strcmp(ext-3, ".csv")) return do_loadcsv(cursheet); return do_loadport(cursheet); } /*}}}*/ /* do_clear -- clear block */ /*{{{*/ static int do_clear(Sheet *sheet) { /* variables */ /*{{{*/ Location w; bool onecell; int c; /*}}}*/ do_mark(sheet, GET_MARK_CUR); onecell = SAME_LOC(sheet->mark1, sheet->mark2); if (onecell && locked(CELL_AT(sheet, sheet->mark1))) line_msg(_("Clear cell:"),_("Cell is locked")); else { if (!onecell) { if ((c=line_ok(_("Clear block:"),0))<0) return c; else if (c!=1) return -1; } for (ALL_LOCS_IN_REGION(sheet, w)) freecellofsheet(sheet, w); cachelabels(sheet); forceupdate(sheet); } return -1; } /*}}}*/ /* do_insert -- insert block */ /*{{{*/ static int do_insert(Sheet *sheet) { const char* menu[] = { [X] = _("cC)olumn"), [Y] = _("rR)ow"),[Z] = _("lL)ayer"), NULL }; int repl = line_menu(_("Insert:"), menu, 0); if (repl < 0) return repl; assert(repl < HYPER); Dimensions reply = (Dimensions)repl; do_mark(sheet, GET_MARK_CUR); Location beg, end; LOCATION_GETS(beg, sheet->mark1); LOCATION_GETS(end, sheet->mark2); bool onecell = SAME_LOC(beg, end); if (onecell) /* ask if current cell or whole dimension should be used */ /*{{{*/ { const char *menu2[3]; /* show menu */ /*{{{*/ switch (reply) { case X: menu2[0] = _("wW)hole column"); break; case Y: menu2[0] = _("wW)hole line"); break; case Z: menu2[0] = _("wW)hole layer"); break; case HYPER: assert(0); } menu2[1] = _("sS)ingle cell"); menu2[2] = NULL; int r = line_menu(_("Insert:"), menu2, 0); /*}}}*/ switch (r) { case 0: /* use whole dimension */ /*{{{*/ { switch (reply) { case X: /* use whole column */ beg[Y] = 0; end[Y] = (CoordT)(sheet->dim[Y]); break; case Y: /* use whole line */ beg[X] = 0; end[X] = (CoordT)(sheet->dim[X]); break; case Z: /* use whole layer */ beg[X] = 0; end[X] = (CoordT)(sheet->dim[X]); beg[Y] = 0; end[Y] = (CoordT)(sheet->dim[Y]); break; case HYPER: assert(0); } break; } /*}}}*/ case 1: /* use current cell */ break; /* -2,-1 -- go up or abort */ case -2: case -1: return r; /* default -- should not happen */ default: assert(0); } /*}}}*/ } /*}}}*/ insertcube(sheet, beg, end, reply); return 0; } /*}}}*/ /* do_delete -- delete block */ /*{{{*/ static int do_delete(Sheet *sheet) { firstmenu: /* ask for direction of deletion */ /*{{{*/ assert(sheet != (Sheet*)0); const char* menu[] = { [X] = _("cC)olumn"), [Y] = _("rR)ow"), [Z] = _("lL)ayer"), NULL }; int repl = line_menu(_("Delete:"), menu, 0); if (repl < 0) return repl; assert(repl < HYPER); Dimensions reply = (Dimensions)repl; /*}}}*/ do_mark(sheet, GET_MARK_CUR); Location beg, end; LOCATION_GETS(beg, sheet->mark1); LOCATION_GETS(end, sheet->mark2); bool onecell = SAME_LOC(beg, end); if (onecell) /* ask if range is the current cell or whole dimension should be used */ /*{{{*/ { const char *menu2[3]; /* show menu */ /*{{{*/ switch (reply) { case X: menu2[0] = _("wW)hole column"); break; case Y: menu2[0] = _("wW)hole line"); break; case Z: menu2[0] = _("wW)hole layer"); break; case HYPER: assert(0); } menu2[1] = _("sS)ingle cell"); menu2[2] = NULL; int r = line_menu(_("Delete:"), menu2, 0); /*}}}*/ switch (r) { /* 0 -- use whole dimension */ /*{{{*/ case 0: { switch (reply) { case X: /* use whole column */ beg[Y] = 0; end[Y] = (CoordT)(sheet->dim[Y]); break; case Y: /* use whole line */ beg[X] = 0; end[X] = (CoordT)(sheet->dim[X]); break; case 2: /* use whole layer */ beg[X] = 0; end[X] = (CoordT)(sheet->dim[X]); beg[Y] = 0; end[Y] = (CoordT)(sheet->dim[Y]); break; case HYPER: assert(0); } break; } /*}}}*/ case 1: /* use current cell */ break; case -1: /* abort */ return -1; case -2: goto firstmenu; default: assert(0); } /*}}}*/ } /*}}}*/ deletecube(sheet, beg, end, reply); return 0; } /*}}}*/ /* do_move -- copy or move a block */ /*{{{*/ static int do_move(Sheet *sheet, int copy, int force) { int c; c=-1; if (getmarkstate(sheet) == UNMARKED) line_msg(copy ? _("Copy block:") : _("Move block:"),_("No block marked")); else if (force || (c=line_ok(copy ? _("Copy block:") : _("Move block:"),0))==1) { do_mark(sheet, MARKED); moveblock(sheet, sheet->mark1, sheet->mark2, sheet->cur, copy); if (!copy) sheet->marking = UNMARKED; } if (c<0) return c; else return 0; } /*}}}*/ /* do_fill -- fill a block */ /*{{{*/ static int do_fill(Sheet *sheet) { if (getmarkstate(sheet) == UNMARKED) line_msg(_("Fill block:"), _("No block marked")); else { do_mark(sheet, MARKED); int cols = 1, rows = 1, layers = 1; firstmenu: do { int c = line_numedit(&cols, _("Number of column-wise repetitions:")); if (c < 0) return c; } while (cols <= 0); secondmenu: do { int c = line_numedit(&rows, _("Number of row-wise repetitions:")); if (c == -1) return -1; else if (c == -2) goto firstmenu; } while (rows <= 0); do { int c = line_numedit(&layers, _("Number of depth-wise repetitions:")); if (c == -1) return -1; else if (c == -2) goto secondmenu; } while (layers <= 0); Location wid; LOCATION_GETS(wid, sheet->mark2); LOCATION_SUB(wid, sheet->mark1); wid[X]++; wid[Y]++; wid[Z]++; Location go; go[Z] = sheet->cur[Z]; for (int z = 0; z < layers; ++z, go[Z] += wid[Z]) { go[Y] = sheet->cur[Y]; for (int y = 0; y < rows; ++y, go[Y] += wid[Y]) { go[X] = sheet->cur[X]; for (int x = 0; x < cols; ++x, go[X] += wid[X]) moveblock(sheet, sheet->mark1, sheet->mark2, go, 1); } } } return -1; } /*}}}*/ /* fill the entire marked region using the current cell */ void fillwith(Sheet *she) { do_mark(she, GET_MARK_ALL); Cell *src = curcell(she); Location dest; bool scan_labels = (src != NULLCELL && getlabel(src) != (const char*)0); /* the following is safe since we have handled copying a cell to itself */ for (ALL_LOCS_IN_REGION(she, dest)) copycelltosheet(src, she, dest, ALTER_LABEL); if (scan_labels) cachelabels(she); forceupdate(she); } /* do_sort -- sort block */ /*{{{*/ static int do_sort(Sheet *sheet) { do_mark(sheet, GET_MARK_ALL); /* build menus */ /*{{{*/ const char* menu1[] = { [X] = _("cC)olumn"), [Y] = _("rR)ow"), [Z] = _("dD)epth"), NULL }; const char* menu2[] = { _("sS)ort region"), _("aA)dd key"), NULL }; const char* menu3[] = { _("aA)scending"), _("dD)escending"), NULL }; /*}}}*/ Dimensions in_dir = HYPER; int dir; /* ask for sort direction */ /*{{{*/ zero: dir = line_menu(_("Sort block:"), menu1, 0); if (dir < 0) return dir; assert(dir < HYPER); in_dir = (Dimensions)dir; int last = 0; /*}}}*/ Sortkey sk[MAX_SORTKEYS]; unsigned int key = 0; bool doit = false; do { /* ask for positions */ /*{{{*/ one: sk[key].soff[X] = 0; if (in_dir != X) do { int c = line_numedit(&(sk[key].soff[X]), _("X position of key vector:")); if (c == -1) return -1; else if (c == -2) switch (last) { case -1: return -2; case 0: goto zero; case 2: goto two; case 3: goto three; case 5: goto five; } } while (sk[key].soff[X] < 0); last = 1; two: sk[key].soff[Y] = 0; if (in_dir != Y) do { int c = line_numedit(&(sk[key].soff[Y]), _("Y position of key vector:")); if (c == -1) return -1; else if (c == -2) switch (last) { case -1: return -2; case 0: goto zero; case 1: goto one; case 3: goto three; case 5: goto five; default: assert(0); } } while (sk[key].soff[Y] < 0); last = 2; three: sk[key].soff[Z] = 0; if (in_dir != Z) do { int c = line_numedit(&(sk[key].soff[Y]), _("Z position of key vector:")); if (c == -1) return -1; else if (c == -2) switch (last) { case -1: return -2; case 0: goto zero; case 1: goto one; case 2: goto two; case 5: goto five; default: assert(0); } } while (sk[key].soff[Z] < 0); last = 3; /*}}}*/ /* ask for sort key */ /*{{{*/ four: sk[key].sortkey=0; int ckey = line_menu(_("Sort block:"), menu3, 0); switch (ckey) { case 0: sk[key].sortkey |= ASCENDING; break; case 1: sk[key].sortkey &= ~ASCENDING; break; case -1: return -1; case -2: switch (last) { case -1: return -2; case 1: goto one; case 2: goto two; case 3: goto three; default: assert(0); } default: assert(0); } last = 4; /*}}}*/ ++key; five: if (key == MAX_SORTKEYS) /* ask for sort comfirmation */ /*{{{*/ { int c = line_ok(_("Sort block:"), 0); if (c == -1) return -1; else if (c == -2) goto four; else if (c == 0) doit = true; } /*}}}*/ else /* ask for sort or adding another key */ /*{{{*/ switch (line_menu(_("Sort block:"), menu2, 0)) { case 0: doit = true; break; case 1: doit = false; break; case -1: return -1; case -2: goto four; default: assert(0); } /*}}}*/ last = 5; } while (!doit); const char *msg = sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key); if (msg != NULL) { line_msg(_("Sort block:"), msg); return -1; } return 0; } /*}}}*/ /* do_batchsort -- sort block in a batch*/ /*{{{*/ static void do_batchsort(Sheet *sheet, Dimensions dm, char* arg) { Sortkey sk[MAX_SORTKEYS]; unsigned int key = 0; char* next; while( *arg != '\0' ) { while (isspace((int)*arg)) arg++; OLOCATION(sk[key].soff); sk[key].sortkey = 0; switch (*arg) { case 'a': sk[key].sortkey |= ASCENDING; arg++; break; case 'd': sk[key].sortkey &= ~ASCENDING; arg++; break; } if ( *arg != '\0' && dm != X ) { sk[key].soff[X] = (CoordT)strtol(arg, &next, 10); arg = next; } if ( *arg != '\0' && dm != Y ) { sk[key].soff[Y] = (CoordT)strtol(arg, &next, 10); arg = next; } if ( *arg != '\0' && dm != Z ) { sk[key].soff[Z] = (CoordT)strtol(arg, &next, 10); arg = next; } ++key; } do_mark(sheet, GET_MARK_ALL); sortblock(sheet, sheet->mark1, sheet->mark2, dm, sk, key); } /*}}}*/ /* do_mirror -- mirror block */ /*{{{*/ static int do_mirror(Sheet *sheet) { do_mark(sheet, GET_MARK_ALL); /* ask for direction of mirroring */ /*{{{*/ const char *menu[] = { [X] = _("lL)eft-right"), [Y] = _("uU)pside-down"), [Z] = _("aA)bove-below"), NULL}; int reply = line_menu(_("Mirror block:"), menu, 0); if (reply < 0) return reply; assert(reply < HYPER); /*}}}*/ mirrorblock(sheet, sheet->mark1, sheet->mark2, (Dimensions)reply); return 0; } /*}}}*/ /* do_goto -- go to a specific cell */ /*{{{*/ static int do_goto(Sheet *sheet, const char *expr) { assert(sheet != (Sheet*)0); size_t x = 0; size_t offx = 0; char buf[1024]; buf[0]='\0'; if (expr) strcpy(buf,expr); else { int c = line_edit(sheet, buf, sizeof(buf), _("Go to location:"), &x, &offx); if (c < 0) return c; } char *s = buf; Token **t = scan(&s); if (t != EMPTY_TVEC) { Token value; LOCATION_GETS(upd_l, sheet->cur); upd_sheet = sheet; value = eval_safe(t, FULL); tvecfree(t); if (value.type == LOCATION && IN_OCTANT(value.u.location)) movetoloc(sheet, value.u.location); else line_msg(_("Go to location:"), _("Not a valid location")); tfree(&value); } return -1; } /*}}}*/ /* do_sheetcmd -- process one key press */ /*{{{*/ int do_sheetcmd(Sheet *cursheet, Key c, bool moveonly) { switch ((int)c) { case K_GOTO: do_goto(cursheet, (const char *)0); break; case K_COLWIDTH: do_columnwidth(cursheet); break; case BLOCK_CLEAR: do_clear(cursheet); update(cursheet); break; case BLOCK_INSERT: do_insert(cursheet); update(cursheet); break; case BLOCK_DELETE: do_delete(cursheet); update(cursheet); break; case BLOCK_MOVE: do_move(cursheet,0,0); update(cursheet); break; case BLOCK_COPY: do_move(cursheet,1,0); update(cursheet); break; case BLOCK_FILL: do_fill(cursheet); update(cursheet); break; case FILL_BLOCK: fillwith(cursheet); update(cursheet); break; case BLOCK_SORT: do_sort(cursheet); update(cursheet); break; case BLOCK_MIRROR: do_mirror(cursheet); update(cursheet); break; case ADJUST_LEFT: case ADJUST_RIGHT: case ADJUST_CENTER: case ADJUST_DECIMAL: case ADJUST_SCIENTIFIC: case ADJUST_COMPACT: case ADJUST_HEXACT: case ADJUST_PRECISION: case ADJUST_SHADOW: case ADJUST_DIM: case ADJUST_BOLD: case ADJUST_ITALIC: case ADJUST_UNDERLINE: case ADJUST_FOREGROUND: case ADJUST_BACKGROUND: case ADJUST_TRANSPARENT: case ADJUST_LABEL: case ADJUST_LOCK: case ADJUST_IGNORE: do_attribute(cursheet, c); break; /* UP -- move up */ /*{{{*/ case K_UP: { relmoveto(cursheet, 0, -1, 0); break; } /*}}}*/ /* DOWN -- move down */ /*{{{*/ case K_DOWN: { relmoveto(cursheet, 0, 1, 0); break; } /*}}}*/ /* LEFT -- move left */ /*{{{*/ case K_LEFT: { relmoveto(cursheet, -1, 0, 0); break; } /*}}}*/ /* RIGHT -- move right */ /*{{{*/ case K_RIGHT: { relmoveto(cursheet, 1, 0, 0); break; } /*}}}*/ /* FIRSTL -- move to first line */ /*{{{*/ case K_FIRSTL: case '<': { moveto(cursheet, -1, 0, -1); break; } /*}}}*/ /* LASTL -- move to last line */ /*{{{*/ case K_LASTL: case '>': { moveto(cursheet, -1, ((cursheet->dim[Y] > 0) ? (CoordT)(cursheet->dim[Y]-1) : 0), -1); break; } /*}}}*/ /* HOME -- move to beginning of line */ /*{{{*/ case K_HOME: { moveto(cursheet, 0, -1, -1); break; } /*}}}*/ /* END -- move to end of line */ /*{{{*/ case K_END: { moveto(cursheet, ((cursheet->dim[X] > 0) ? (CoordT)(cursheet->dim[X]-1) : 0), -1, -1); break; } /*}}}*/ /* + -- move one layer down */ /*{{{*/ case K_NSHEET: case '+': { relmoveto(cursheet, 0, 0, 1); break; } /*}}}*/ /* - -- move one layer up */ /*{{{*/ case K_PSHEET: case '-': { relmoveto(cursheet, 0, 0, -1); break; } /*}}}*/ /* * -- move to bottom layer */ /*{{{*/ case K_LSHEET: case '*': { moveto(cursheet, -1, -1, ((cursheet->dim[Z] > 0) ? (CoordT)(cursheet->dim[Z]-1) : 0)); break; } /*}}}*/ /* _ -- move to top layer */ /*{{{*/ case K_FSHEET: case '_': { moveto(cursheet, -1, -1, 0); break; } /*}}}*/ /* ENTER -- edit current cell */ /*{{{*/ case K_ENTER: if (moveonly) break; do_edit(cursheet, '\0', NULL, BASE_CONT); break; /*}}}*/ /* MENTER -- edit current clocked cell */ /*{{{*/ case K_MENTER: if (moveonly) break; do_edit(cursheet, '\0', NULL, ITER_CONT); break; /*}}}*/ case K_EDIT_STYLE_EXPR: /* edit style expression */ /*{{{*/ if (moveonly) break; do_edit(cursheet, '\0', NULL, STYLE_CONT); break; /*}}}*/ /* ", @, digit -- edit current cell with character already in buffer */ /*{{{*/ case K_BACKSPACE: case K_DC: case '"': case '@': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (moveonly) break; do_edit(cursheet, c, NULL, BASE_CONT); break; /*}}}*/ /* MARK -- toggle block marking */ /*{{{*/ case '.': case K_MARK: if (moveonly) break; do_mark(cursheet, 0); break; /*}}}*/ /* _("Save sheet file format:") -- save menu */ /*{{{*/ case K_SAVEMENU: if (moveonly) break; do_save(cursheet); break; /*}}}*/ /* _("Load sheet file format:") -- load menu */ /*{{{*/ case K_LOAD: case K_LOADMENU: if (moveonly) break; do_load(cursheet); break; /*}}}*/ /* _("nN)ame") -- set name */ /*{{{*/ case K_NAME: if (moveonly) break; do_name(cursheet); break; /*}}}*/ #ifdef ENABLE_HELP case K_HELP: show_text(helpfile); break; #else case K_HELP: show_text(_("Sorry, manual is not installed.")); break; #endif case K_DUMPCELL: dump_current_cell(cursheet); break; case K_ABOUT: show_text(_("About teapot
\n\n"
        "               ` ',`    '  '                   \n"
        "                `   '  ` ' '                   \n"
        "                 `' '   '`'                    \n"
        "                 ' `   ' '`                    \n"
        "    '           '` ' ` '`` `                   \n"
        "    `.   Table Editor And Planner, or:         \n"
        "      ,         . ,   ,  . .                   \n"
        "                ` '   `  ' '                   \n"
        "     `::\\    /:::::::::::::::::\\   ___         \n"
        "      `::\\  /:::::::::::::::::::\\,'::::\\       \n"
        "       :::\\/:::::::::::::::::::::\\/   \\:\\      \n"
        "       :::::::::::::::::::::::::::\\    :::     \n"
        "       ::::::::::::::::::::::::::::;  /:;'     \n"
        "       `::::::::::::::::::::::::::::_/:;'      \n"
        "         `::::::::::::::::::::::::::::'        \n"
        "          `////////////////////////'           \n"
        "           `:::::::::::::::::::::'             \n"
        "
\n" "

Teapot " VERSION "

\n" "\n" "

Original Version: Michael Haardt
\n" "Current Maintainer: Joerg Walter
\n" "Contibutions by: Glen Whitney
\b" "Home Page: http://www.syntax-k.de/projekte/teapot/

\n" "This distribution: https://code.studioinfinity.org/glen/teapot-spreadsheet/

\n" "\n" "

Copyright 1995-2006 Michael Haardt,
\n" "Copyright 2009-2010 Joerg Walter (info@syntax-k.de)
" "Copyright 2019 Glen Whitney

\n" "\f" "

This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation, either version 3 of the License, or\n" "(at your option) any later version.

\n" "\n" "

This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.

\n" "\n" "

You should have received a copy of the GNU General Public License\n" "along with this program. If not, see http://www.gnu.org/licenses/.

" "")); break; /* MENU, / -- main menu */ /*{{{*/ case '/': if (!moveonly && do_sheetcmd(cursheet, show_menu(cursheet), 0)) return 1; break; /*}}}*/ /* _("sS)ave") -- save in current native format */ /*{{{*/ case K_SAVE: do_save(cursheet); break; /*}}}*/ /* _("cC)opy") -- copy block */ /*{{{*/ case K_COPY: if (moveonly) break; do_move(cursheet,1,1); break; /*}}}*/ /* RECALC -- recalculate */ /*{{{*/ case K_RECALC: if (moveonly) break; forceupdate(cursheet); break; /*}}}*/ /* _("Usage: clock(condition,location[,location])") -- clock */ /*{{{*/ case K_CLOCK: { Location w; for (ALL_LOCS_IN_SHEET(cursheet, w)) clk(cursheet, w); update(cursheet); break; } /*}}}*/ /* NPAGE -- page down */ /*{{{*/ case K_NPAGE: { cursheet->offy += (cursheet->maxy-3); relmoveto(cursheet, 0, cursheet->maxy-3, 0); break; } /*}}}*/ /* PPAGE -- page up */ /*{{{*/ case K_PPAGE: { cursheet->offy = cursheet->offy >= cursheet->maxy - 3 ? cursheet->offy - cursheet->maxy + 3 : 0; relmoveto(cursheet, 0, cursheet->cur[Y] >= (cursheet->maxy - 3) ? -(cursheet->maxy - 3) : -cursheet->cur[Y], 0); break; } /*}}}*/ /* FPAGE -- page right */ /*{{{*/ case K_FPAGE: { cursheet->offx += (CoordT)cursheet->width; relmoveto(cursheet, (CoordT)(cursheet->width), 0, 0); break; } /*}}}*/ /* BPAGE -- page left */ /*{{{*/ case K_BPAGE: cursheet->offx = (size_t)(cursheet->offx) >= cursheet->width ? cursheet->offx - (CoordT)(cursheet->width) : 0; relmoveto(cursheet, ((size_t)(cursheet->cur[X]) >= cursheet->width ? -((CoordT)(cursheet->width)) : -cursheet->cur[X]), 0, 0); break; /*}}}*/ /* SAVEQUIT -- save and quit */ /*{{{*/ case K_SAVEQUIT: { if (moveonly) break; if (do_save(cursheet)!=-2) return 1; break; } /*}}}*/ /* _("qQ)uit") -- quit */ /*{{{*/ case K_QUIT: if (moveonly) break; return 1; /*}}}*/ default: if (isalpha(c) && !moveonly) do_edit(cursheet, c, NULL, BASE_CONT); break; } return 0; } /*}}}*/ /* main */ /*{{{*/ int main(int argc, char *argv[]) { /* variables */ /*{{{*/ Sheet sheet,*cursheet; int o; const char *loadfile; char ln[1024]; /*}}}*/ setlocale(LC_ALL, ""); find_helpfile(helpfile, sizeof(helpfile), argv[0]); /* parse options */ /*{{{*/ while ((o=getopt(argc,argv,"bdhnrqHp:?"))!=EOF) switch (o) { /* b -- run batch */ /*{{{*/ case 'b': batch = true; break; /*}}}*/ /* d -- increase debug level */ /*{{{*/ case 'd': ++debug_level; break; /*}}}*/ /* n -- no quoted strings */ /*{{{*/ case 'n': quote = DIRECT_STRING; break; /*}}}*/ /* q -- force quoted strings */ /*{{{*/ case 'q': quote = QUOTE_STRING; break; /*}}}*/ /* H -- no row/column headers */ /*{{{*/ case 'H': header = false; break; /*}}}*/ /* r -- always redraw */ /*{{{*/ case 'r': { always_redraw = true; break; } /*}}}*/ /* p -- precision */ /*{{{*/ case 'p': { long n; char *end; n = strtol(optarg,&end,0); if (*end || n < 0 || n > FLT_T_DIG) { fprintf(stderr, _("teapot: default precision must be between 0 and %d.\n"), FLT_T_DIG); exit(1); } def_precision = (PrecisionLevel)n; break; } /*}}}*/ /* default -- includes ? and h */ /*{{{*/ default: { fprintf(stderr,_( "Usage: %s [-a] [-b] [-d]* [-h] [-n|-q] [-H] [-r] [-p digits] [file]\n" " -a: use ASCII file format as default\n" " -b: batch mode\n" " -d: increase debug level, once for each occurrence\n" " -h: print this message and exit\n" " -n|-q: DO NOT or DO display strings in quotes, respectively\n" " -H: hide row/column headers\n" " -r: redraw more often\n" " -p: set decimal precision\n" ), argv[0]); exit(1); } /*}}}*/ } loadfile = (optindname=strdup(loadfile); if (usexdr) { if ((msg=loadxdr(cursheet, cursheet->name)) != NULL) line_msg(_("Load sheet from XDR file:"), msg); } else if ((msg=loadport(cursheet, cursheet->name)) != NULL) line_msg(_("Load sheet from ASCII file:"),msg); } /*}}}*/ if (batch) /* process batch */ /*{{{*/ while (fgets(ln,sizeof(ln),stdin)!=(char*)0) { /* variables */ /*{{{*/ size_t len; char *cmd,*arg; /*}}}*/ /* set cmd and arg */ /*{{{*/ ++batchln; len=strlen(ln); if (len && ln[len-1]=='\n') ln[len-1]='\0'; cmd=ln; while (isspace((int)*cmd)) ++cmd; arg=cmd; while (*arg && !isspace((int)*arg)) ++arg; while (isspace((int)*arg)) *arg++='\0'; /*}}}*/ /* goto location */ /*{{{*/ if (strcmp(cmd,"goto")==0) do_goto(cursheet,arg); /*}}}*/ /* from location */ /*{{{*/ else if (strcmp(cmd,"from")==0) { do_goto(cursheet,arg); do_mark(cursheet,1); } /*}}}*/ /* to location */ /*{{{*/ else if (strcmp(cmd,"to")==0) { do_goto(cursheet,arg); do_mark(cursheet,2); } /*}}}*/ /* save-tbl file */ /*{{{*/ else if (strcmp(cmd,"save-tbl")==0) do_savetbl(cursheet,arg); /*}}}*/ /* save-latex file */ /*{{{*/ else if (strcmp(cmd,"save-latex")==0) do_savelatex(cursheet,arg); /*}}}*/ /* save-context file */ /*{{{*/ else if (strcmp(cmd,"save-context")==0) do_savecontext(cursheet,arg); /*}}}*/ /* save-csv file */ /*{{{*/ else if (strcmp(cmd,"save-csv")==0) do_savecsv(cursheet,arg); /*}}}*/ /* save-html file */ /*{{{*/ else if (strcmp(cmd,"save-html")==0) do_savehtml(cursheet,arg); /*}}}*/ /* load-csv file */ /*{{{*/ else if (strcmp(cmd,"load-csv")==0) { loadcsv(cursheet,arg); forceupdate(cursheet); } /*}}}*/ /* sort in x direction */ /*{{{*/ else if (strcmp(cmd,"sort-x")==0) do_batchsort(cursheet, X, arg); /*}}}*/ /* sort in y direction */ /*{{{*/ else if (strcmp(cmd,"sort-y")==0) do_batchsort(cursheet, Y, arg); /*}}}*/ /* sort in z direction */ /*{{{*/ else if (strcmp(cmd,"sort-z")==0) do_batchsort(cursheet, Z, arg); /*}}}*/ /* this is an unknown command */ /*{{{*/ else line_msg(_("Unknown batch command:"),cmd); /*}}}*/ } /*}}}*/ else /* process interactive input */ /*{{{*/ display_main(cursheet); /*}}}*/ freesheet(cursheet,1); fclose(stdin); return 0; } /*}}}*/