/* #includes */ /*{{{C}}}*//*{{{*/ #ifndef NO_POSIX_SOURCE #undef _POSIX_SOURCE #define _POSIX_SOURCE 1 #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 2 #undef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif #ifdef DMALLOC #include "dmalloc.h" #endif #include #include #include #include #include #include #include #include #include extern char *optarg; extern int optind,opterr,optopt; int getopt(int argc, char * const *argv, const char *optstring); extern char *strdup(const char* s); #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; int 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, int x, int y, int z) { int need_redraw = 0; int xdir = x > sheet->cur[X]?1:-1; if (x >= 0) sheet->cur[X] = x; if (y >= 0) sheet->cur[Y] = y; if (z >= 0) need_redraw++, 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) need_redraw++, sheet->offx = (sheet->cur[X]?sheet->cur[X]-1:0); if (sheet->cur[Y] <= sheet->offy && sheet->offy) need_redraw++, sheet->offy = (sheet->cur[Y]?sheet->cur[Y]-1:0); if (sheet->cur[X] >= sheet->offx+sheet->maxx) need_redraw++, sheet->offx = sheet->cur[X]-sheet->maxx+2; if (sheet->cur[Y] >= sheet->offy+sheet->maxy) need_redraw++, sheet->offy = sheet->cur[Y]-sheet->maxy+2; if (need_redraw) redraw_sheet(sheet); else if (x != sheet->cur[X] || y != sheet->cur[Y] || z != sheet->cur[Z]) redraw_cell(sheet, sheet->cur); } void movetoloc(Sheet *sheet, const Location dest) { moveto(sheet, dest[X], dest[Y], dest[Z]); } void relmoveto(Sheet *sheet, int x, int y, int 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 = 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 = 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 = 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 */ /*{{{*/ int doanyway(Sheet *sheet, const char *msg) { int result; if (sheet->changed) { result = line_ok(msg,0); if (result < 0) return 0; return result; } return 1; } /*}}}*/ /* do_edit -- set or modify cell contents */ /*{{{*/ static int do_edit(Sheet *cursheet, Key c, char *expr, TokVariety tv) { /* variables */ /*{{{*/ char buf[1024]; const char *prompt; char *s; size_t x,offx; Location scur; Token **t; Token newcont; Cell *cell; /*}}}*/ cell = curcell(cursheet); if (locked(cell)) line_msg(_("Edit cell:"),_("Cell is locked")); else { newcont.type = EMPTY; LOCATION_GETS(scur, cursheet->cur); if (expr) { s = expr; t = scan(&s); prompt = _("Cell contents:"); if (tv == ITER_CONT) prompt = _("Clocked cell contents"); if (*s != '\0') if (t == EMPTY_TVEC) line_msg(prompt, "XXX invalid expression"); else { newcont = eval_safe(t, LITERAL); if (newcont.type = EEK) line_msg(prompt, "XXX unparseable expression"); } tvecfree(t); } else { Token cntt; offx=0; if (c == K_NONE) { cntt = gettok(cell, tv); printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, 0, 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, 0, 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, 0, TRUNCATED_ERROR, &cntt); memmove(buf,mbspos(buf,1),strlen(mbspos(buf,1))+1); s = buf; } else if (isalpha(c)) { buf[0] = '"'; buf[1] = c; buf[2] = 0; s=buf+2; } else { if (c < 256) buf[0]=c; else buf[0] = 0; buf[1]='\0'; s=buf+1; } do { int r; tfree(&newcont); newcont.type = EEK; newcont.u.err = (char *)0; x = mbslen(buf)-mbslen(s); prompt = _("Cell contents:"); if (tv == ITER_CONT) prompt = _("Clocked cell contents:"); if ((r = line_edit(cursheet, buf, sizeof(buf), prompt, &x, &offx)) < 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)] = '"'; } 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 = 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,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); bool changed = false; if (action != ADJUST_LOCK && onecell && locked(fcell)) { line_msg(_("Cell attribute:"),_("Cell is locked")); return; } switch ((int)action) { case ADJUST_CENTER: ++adj; /* drop through */ case ADJUST_RIGHT: ++adj; /* drop 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; /* drop through */ case ADJUST_COMPACT: ++ff; /* drop through */ case ADJUST_SCIENTIFIC: ++ff; /* drop 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: { size_t ex,offx; int n; offx=0; ex=0; n = getprecision(fcell); 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, n) || changed; break; } /*}}}*/ /* 6 -- shadow */ /*{{{*/ case ADJUST_SHADOW: { int n; Location r; LOCATION_GETS(r, cursheet->mark1); ++r[X]; if (onecell) n = !SHADOWED(cursheet, r); else n = line_binary(_("Set block to:"), _("uU)nshadowed"), _("sS)hadowed"), !SHADOWED(cursheet, r)); 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 r; if (n == 0) { LOCATION_GETS(r, w); if (!SHADOWED(cursheet, r)) ++(r[X]); for (; SHADOWED(cursheet, r); ++(r[X])) changed = shadow(cursheet, r, 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 = !transparent(fcell); else n = line_binary(_("Set block to:"), _("pP)rotected"), _("tT)ransparent:"), !transparent(fcell)); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) changed = maketrans(cursheet, w, n) || changed; break; } /*}}}*/ /* 8 -- bold */ /*{{{*/ case ADJUST_BOLD: { int n; if (onecell) n = !isbold(fcell); else n = line_binary(_("Set block weight to:"), _("rR)egular"), _("bB)old"), !isbold(fcell)); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) changed = bold(cursheet, w, n) || changed; break; } /*}}}*/ /* 9 -- underline */ /*{{{*/ case ADJUST_UNDERLINE: { int n; if (onecell) n = !underlined(fcell); else n = line_binary(_("Set block to:"), _("nN)ot underline"), _("uU)nderline"), !underlined(fcell)); 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) { if (onecell) redraw_cell(cursheet, cursheet->mark1); else redraw_sheet(cursheet); 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; int x1,y1,z1,x2,y2,z2; 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; int x1,y1,z1,x2,y2,z2; 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; int x1,y1,z1,x2,y2,z2; 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; Dimensions dim; 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: { for (dim = X; dim < HYPER; ++dim) posorder(&(cursheet->mark1[dim]), &(cursheet->mark2[dim])); 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); cursheet->mark2[X] = cursheet->dimx - 1; cursheet->mark2[Y] = cursheet->dimy - 1; cursheet->mark2[Z] = cursheet->dimz - 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) { int reply; /* ask for direction of insertion */ /*{{{*/ { const char* menu[] = { _("cC)olumn"), _("rR)ow"), _("dD)epth"), NULL }; reply = line_menu(_("Insert:"), menu, 0); if (reply<0) return reply; } /*}}}*/ 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 *menu[3]; /* show menu */ /*{{{*/ switch (reply) { case 0: menu[0] = _("wW)hole column"); break; case 1: menu[0] = _("wW)hole line"); break; case 2: menu[0] = _("wW)hole sheet"); break; default: assert(0); } menu[1] = _("sS)ingle cell"); menu[2] = NULL; int r = line_menu(_("Insert:"), menu, 0); /*}}}*/ switch (r) { /* 0 -- use whole dimension */ /*{{{*/ case 0: { switch (reply) { /* 0 -- use whole column */ /*{{{*/ case 0: { beg[Y] = 0; end[Y] = sheet->dimy; break; } /*}}}*/ /* 1 -- use whole line */ /*{{{*/ case 1: { beg[X] = 0; end[X] = sheet->dimx; break; } /*}}}*/ /* 2 -- use whole layer */ /*{{{*/ case 2: { beg[X] = 0; end[X] = sheet->dimx; beg[Y] = 0; end[Y] = sheet->dimy; break; } /*}}}*/ /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } break; } /*}}}*/ /* 1 -- use current cell */ /*{{{*/ case 1: break; /*}}}*/ /* -2,-1 -- go up or abort */ /*{{{*/ case -2: case -1: return r; /*}}}*/ /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } } /*}}}*/ /*}}}*/ switch (reply) { /* 0 -- columns */ /*{{{*/ case 0: insertcube(sheet, beg, end, IN_X); break; /*}}}*/ /* 1 -- rows */ /*{{{*/ case 1: insertcube(sheet, beg, end, IN_Y); break; /*}}}*/ /* 2 -- depth */ /*{{{*/ case 2: insertcube(sheet, beg, end, IN_Z); break; /*}}}*/ } return 0; } /*}}}*/ /* do_delete -- delete block */ /*{{{*/ static int do_delete(Sheet *sheet) { int reply; firstmenu: /* ask for direction of deletion */ /*{{{*/ { const char* menu[] = { _("cC)olumn"), _("rR)ow"), _("dD)epth"), NULL }; reply = line_menu(_("Delete:"), menu, 0); if (reply < 0) return reply; } /*}}}*/ 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 *menu[3]; /* show menu */ /*{{{*/ switch (reply) { case 0: menu[0] = _("wW)hole column"); break; case 1: menu[0] = _("wW)hole line"); break; case 2: menu[0] = _("wW)hole sheet"); break; default: assert(0); } menu[1] = _("sS)ingle cell"); menu[2] = NULL; int r = line_menu(_("Delete:"), menu, 0); /*}}}*/ switch (r) { /* 0 -- use whole dimension */ /*{{{*/ case 0: { switch (reply) { /* 0 -- use whole column */ /*{{{*/ case 0: { beg[Y] = 0; end[Y] = sheet->dimy; break; } /*}}}*/ /* 1 -- use whole line */ /*{{{*/ case 1: { beg[X] = 0; end[X] = sheet->dimx; break; } /*}}}*/ /* 2 -- use whole layer */ /*{{{*/ case 2: { beg[X] = 0; end[X] = sheet->dimx; beg[Y] = 0; end[Y] = sheet->dimy; break; } /*}}}*/ /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } break; } /*}}}*/ /* 1 -- use current cell */ /*{{{*/ case 1: break; /*}}}*/ /* -1 -- abort */ /*{{{*/ case -1: return -1; /*}}}*/ /* -2 -- go back to previous menu */ /*{{{*/ case -2: goto firstmenu; /*}}}*/ /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } } /*}}}*/ /*}}}*/ switch(reply) { /* 0 -- columns */ /*{{{*/ case 0: deletecube(sheet, beg, end, IN_X); break; /*}}}*/ /* 1 -- rows */ /*{{{*/ case 1: deletecube(sheet, beg, end, IN_Y); break; /*}}}*/ /* 2 -- depth */ /*{{{*/ case 2: deletecube(sheet, beg, end, IN_Z); break; /*}}}*/ } return -1; } /*}}}*/ /* 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 -1; } /*}}}*/ /* do_fill -- fill a block */ /*{{{*/ static int do_fill(Sheet *sheet) { /* variables */ /*{{{*/ int cols,rows,layers; int x,y,z; Location wid, go; int c; /*}}}*/ if (getmarkstate(sheet) == UNMARKED) line_msg(_("Fill block:"),_("No block marked")); else { do_mark(sheet, MARKED); cols=rows=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_GETS(wid, sheet->mark2); LOCATION_SUB(wid, sheet->mark1); wid[X]++; wid[Y]++; wid[Z]++; LOCATION_GETS(go, sheet->cur); for (z=0; zcur[Y]; ycur[X]; xmark1, 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[] = { _("cC)olumn"), _("rR)ow"), _("dD)epth"), NULL }; const char* menu2[] = { _("sS)ort region"), _("aA)dd key"), NULL }; const char* menu3[] = { _("aA)scending"), _("dD)escending"), NULL }; /*}}}*/ int last = -1; Direction in_dir = (Direction)-2; /* cause run time error */ int dir; /* ask for sort direction */ /*{{{*/ zero: dir = line_menu(_("Sort block:"), menu1, 0); switch (dir) { case 0: in_dir = IN_X; break; case 1: in_dir = IN_Y; break; case 2: in_dir = IN_Z; break; case -2: case -1: return dir; default: assert(0); } last=0; /*}}}*/ Sortkey sk[MAX_SORTKEYS]; unsigned int key = 0; bool doit = false; do { /* ask for positions */ /*{{{*/ one: if (in_dir==IN_X) sk[key].x=0; else /* ask for x position */ /*{{{*/ { sk[key].x = 0; do { int c = line_numedit(&(sk[key].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].x < 0); last = 1; } /*}}}*/ two: if (in_dir==IN_Y) sk[key].y=0; else /* ask for y position */ /*{{{*/ { sk[key].y = 0; do { int c = line_numedit(&(sk[key].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].y < 0); last = 2; } /*}}}*/ three: if (in_dir==IN_Z) sk[key].z=0; else /* ask for z position */ /*{{{*/ { sk[key].z = 0; do { int c = line_numedit(&(sk[key].z), _("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].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 0; } /*}}}*/ /* do_batchsort -- sort block in a batch*/ /*{{{*/ static void do_batchsort(Sheet *sheet, Direction dir, char* arg) { Sortkey sk[MAX_SORTKEYS]; int x1,y1,z1,x2,y2,z2; unsigned int key = 0; char* next; while( *arg != '\0' ) { while (isspace((int)*arg)) arg++; sk[key].x=sk[key].y=sk[key].z=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' && dir != IN_X ) { sk[key].x=strtol(arg, &next, 10); arg = next; } if ( *arg != '\0' && dir != IN_Y ) { sk[key].y=strtol(arg, &next, 10); arg = next; } if ( *arg != '\0' && dir != IN_Z ) { sk[key].z=strtol(arg, &next, 10); arg = next; } key++; } do_mark(sheet, GET_MARK_ALL); sortblock(sheet, sheet->mark1, sheet->mark2, dir, sk, key); } /*}}}*/ /* do_mirror -- mirror block */ /*{{{*/ static int do_mirror(Sheet *sheet) { /* variables */ /*{{{*/ int x1,y1,z1,x2,y2,z2,reply; /*}}}*/ do_mark(sheet, GET_MARK_ALL); /* ask for direction of mirroring */ /*{{{*/ { const char *menu[] = { _("lL)eft-right"), _("uU)pside-down"), _("fF)ront-back"), NULL}; reply = line_menu(_("Mirror block:"), menu, 0); if (reply < 0) return reply; } /*}}}*/ switch (reply) { /* 0 -- left-right */ /*{{{*/ case 0: mirrorblock(sheet, sheet->mark1, sheet->mark2, IN_X); break; /*}}}*/ /* 1 -- upside-down */ /*{{{*/ case 1: mirrorblock(sheet, sheet->mark1, sheet->mark2, IN_Y); break; /*}}}*/ /* 2 -- front-back */ /*{{{*/ case 2: mirrorblock(sheet, sheet->mark1, sheet->mark2, IN_Z); break; /*}}}*/ default: assert(0); } 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, int 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); redraw_sheet(cursheet); break; case BLOCK_INSERT: do_insert(cursheet); redraw_sheet(cursheet); break; case BLOCK_DELETE: do_delete(cursheet); redraw_sheet(cursheet); break; case BLOCK_MOVE: do_move(cursheet,0,0); redraw_sheet(cursheet); break; case BLOCK_COPY: do_move(cursheet,1,0); redraw_sheet(cursheet); break; case BLOCK_FILL: do_fill(cursheet); redraw_sheet(cursheet); break; case FILL_BLOCK: fillwith(cursheet); redraw_sheet(cursheet); break; case BLOCK_SORT: do_sort(cursheet); redraw_sheet(cursheet); break; case BLOCK_MIRROR: do_mirror(cursheet); redraw_sheet(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_BOLD: case ADJUST_UNDERLINE: 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->dimy ? cursheet->dimy-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->dimx ? cursheet->dimx-1 : 0), -1, -1); break; } /*}}}*/ /* + -- move one sheet down */ /*{{{*/ case K_NSHEET: case '+': { relmoveto(cursheet, 0, 0, 1); break; } /*}}}*/ /* - -- move one sheet up */ /*{{{*/ case K_PSHEET: case '-': { relmoveto(cursheet, 0, 0, -1); break; } /*}}}*/ /* * -- move to bottom sheet */ /*{{{*/ case K_LSHEET: case '*': { moveto(cursheet, -1, -1, (cursheet->dimz ? cursheet->dimz-1 : 0)); break; } /*}}}*/ /* _ -- move to top sheet */ /*{{{*/ 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, 0); break; /*}}}*/ /* MENTER -- edit current clocked cell */ /*{{{*/ case K_MENTER: if (moveonly) break; do_edit(cursheet, '\0', NULL, 1); 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, 0); 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+=cursheet->width; relmoveto(cursheet, cursheet->width, 0, 0); break; } /*}}}*/ /* BPAGE -- page left */ /*{{{*/ case K_BPAGE: { cursheet->offx=(cursheet->offx>=cursheet->width ? cursheet->offx-cursheet->width : 0); relmoveto(cursheet, (cursheet->cur[X]>=cursheet->width ? -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, 0); 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 > LDBL_DIG) { fprintf(stderr, _("teapot: precision must be between 0 and %d.\n"), LDBL_DIG); exit(1); } def_precision=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, IN_X, arg); /*}}}*/ /* sort in y direction */ /*{{{*/ else if (strcmp(cmd,"sort-y")==0) do_batchsort(cursheet, IN_Y, arg); /*}}}*/ /* sort in z direction */ /*{{{*/ else if (strcmp(cmd,"sort-z")==0) do_batchsort(cursheet, IN_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; } /*}}}*/