/* #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" /*}}}*/ /* variables */ /*{{{*/ char helpfile[PATH_MAX]; bool batch = false; unsigned int batchln=0; int def_precision = DEF_PRECISION; bool quote = false; bool header = true; bool always_redraw = false; int debug_level = 0; static bool usexdr = true; /*}}}*/ 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, size_t *x, size_t *offx) { /* variables */ /*{{{*/ char buf[20]; const char *s; Token **t; int c; /*}}}*/ /* asserts */ /*{{{*/ assert(prompt!=(char*)0); assert(x!=(size_t*)0); assert(offx!=(size_t*)0); /*}}}*/ t=(Token**)0; sprintf(buf,"%d",*n); s=buf+strlen(buf); do { tvecfree(t); *x=s-buf; if ((c=line_edit((Sheet*)0,buf,sizeof(buf),prompt,x,offx))<0) return c; s=buf; t=scan(&s); } while ((*s!='\0' && t==(Token**)0) || !(t!=(Token**)0 && ((*t)==(Token*)0 || ((*t)->type==INT && (*t)->u.integer>=0 && *(t+1)==(Token*)0)))); if (t==(Token**)0 || *t==(Token*)0) *n=-1; else *n=(*t)->u.integer; tvecfree(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) { /* variables */ /*{{{*/ const char *s; Token **t; int c; /*}}}*/ t=(Token**)0; s=ident+strlen(ident); do { tvecfree(t); *x=s-ident; if ((c=line_edit((Sheet*)0,ident,size,prompt,x,offx))<0) return c; s=ident; t=scan(&s); } while ((*s!='\0' && t==(Token**)0) || !(t!=(Token**)0 && ((*t)==(Token*)0 || ((*t)->type==LIDENT && *(t+1)==(Token*)0)))); tvecfree(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, const char *expr, ContentVariety cv) { /* variables */ /*{{{*/ char buf[1024]; const char *s, *prompt; size_t x,offx; Location scur; Token **t; Cell *cell; /*}}}*/ cell = curcell(cursheet); if (locked(cell)) line_msg(_("Edit cell:"),_("Cell is locked")); else { LOCATION_GETS(scur, cursheet->cur); if (expr) { s=expr; t=scan(&s); prompt = _("Cell contents:"); if (cv == ITERATIVE) prompt = _("Clocked cell contents"); if (*s!='\0' && t==(Token**)0) line_msg(prompt, "XXX invalid expression"); } else { offx=0; if (c==K_NONE) { print(buf, sizeof(buf), 0, 1, getscientific(cell), -1, getcont(cell, cv)); s=buf+strlen(buf); } else if (c==K_BACKSPACE) { print(buf, sizeof(buf), 0, 1, getscientific(cell), -1, getcont(cell, cv)); if (strlen(buf)) *mbspos(buf+strlen(buf),-1)='\0'; s=buf+strlen(buf); } else if (c==K_DC) { print(buf, sizeof(buf), 0, 1, getscientific(cell), -1, getcont(cell, cv)); 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; x=mbslen(buf)-mbslen(s); prompt = _("Cell contents:"); if (cv == ITERATIVE) 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); } while (*s!='\0' && t==(Token**)0); } if (t!=(Token**)0 && *t==(Token*)0) { free(t); t=(Token**)0; } movetoloc(cursheet, scur); putcont(cursheet, cursheet->cur, t, cv); 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') for (ALL_LOCS_IN_REGION(sheet,w)) relabel(sheet, w, oldlabel, buf); } return -1; } /*}}}*/ /* do_columnwidth -- set the column width */ /*{{{*/ static int do_columnwidth(Sheet *cursheet) { /* variables */ /*{{{*/ size_t edx,offx; int n; int x, z; int c; /*}}}*/ offx=0; edx=0; do_mark(cursheet, GET_MARK_CUR); n = columnwidth(cursheet, cursheet->mark1[X], cursheet->mark1[Z]); do { if ((c=line_numedit(&n,_("Column width:"),&edx,&offx))<0) return c; } while (n<=0); /*}}}*/ for (x = cursheet->mark1[X]; x <= cursheet->mark2[X]; ++x) for (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) { /* variables */ /*{{{*/ Location w; Adjust adj; bool onecell; Cell *fcell; int c = 0; /*}}}*/ adj = LEFT; do_mark(cursheet, GET_MARK_CUR); onecell = SAME_LOC(cursheet->mark1, cursheet->mark2); fcell = safe_cell_at(cursheet, cursheet->mark1); 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; case ADJUST_LEFT: { const char *templ = _("Change adjustment of block to "); char *prompt = malloc(strlen(templ) + 64); const char *way = _("center?"); if (action == ADJUST_RIGHT) way = _("right?"); else if (action == ADJUST_LEFT) way = _("left?"); strcpy(prompt, templ); strcat(prompt, way); if (!onecell && line_ok(prompt, 0) <= 0) break; for (ALL_LOCS_IN_REGION(cursheet,w)) setadjust(cursheet, w, adj); break; } /* 3 -- set scientific notation flag */ /*{{{*/ case ADJUST_SCIENTIFIC: { int n; if (onecell) n = !getscientific(fcell); else n = line_binary(_("Make block notation:"), _("dD)ecimal"), _("sS)cientific"), !getscientific(fcell)); if (n >= 0) for (ALL_LOCS_IN_REGION(cursheet,w)) setscientific(cursheet, w, n); break; } /*}}}*/ /* 5 -- set precision */ /*{{{*/ case ADJUST_PRECISION: { size_t ex,offx; int n; offx=0; ex=0; n = getprecision(fcell); do if (line_numedit(&n, onecell ? _("Precision for cell:") : _("Precision for block:"),&ex,&offx)==-1) return; while (n!=-1 && (n==0 || n>20)); for (ALL_LOCS_IN_REGION(cursheet,w)) setprecision(cursheet, w, n); 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])) shadow(cursheet, r, 0); } else if (w[X]>0) shadow(cursheet, w, 1); } } 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)) maketrans(cursheet, w, n); 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)) bold(cursheet, w, n); 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)) underline(cursheet, w, n); 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)) lockcell(cursheet, w, n); 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)) igncell(cursheet, w, n); break; } /*}}}*/ /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } if (c>=0) { if (onecell) redraw_cell(cursheet, cursheet->mark1); else redraw_sheet(cursheet); } forceupdate(cursheet); return; } /*}}}*/ /* do_savexdr -- save sheet as XDR file */ /*{{{*/ static int do_savexdr(Sheet *cursheet, const char *name) { char buf[PATH_MAX]; const char *msg; unsigned int count; if (!name) { name = cursheet->name; if (strcmp(name+strlen(name)-3,".tp")) { snprintf(buf, sizeof(buf), "%s.tp", name); name = buf; } } if ((msg = savexdr(cursheet, name, &count))) { line_msg(_("Save sheet to XDR file:"), msg); return -2; } snprintf(buf, sizeof(buf), _("%u cells written"), count); if (!batch) line_msg(_("Save sheet to XDR file:"),buf); return -1; } /*}}}*/ /* 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) { char buf[PATH_MAX]; const char *msg; int x1,y1,z1,x2,y2,z2; unsigned int count; int sep = 0; const char seps[4] = ",;\t"; do_mark(cursheet, GET_MARK_ALL); if (!name) { MenuChoice menu[4]; name = cursheet->name; menu[0].str=strdup(_("cC)omma (,)")); menu[0].c='\0'; menu[1].str=strdup(_("sS)emicolon (;)")); menu[1].c='\0'; menu[2].str=strdup(_("tT)ab (\\t)")); menu[2].c='\0'; menu[3].str=(char*)0; sep=line_menu(_("Choose separator:"),menu,0); if (sep < 0) return sep; } if ((msg = savecsv(cursheet, name, seps[sep], cursheet->mark1, cursheet->mark2, &count))) { line_msg(_("Save in CSV format to file:"),msg); return -2; } 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, ".tpa")) return do_saveport(cursheet, NULL); 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_savexdr(cursheet, NULL); } /*}}}*/ /* do_name -- (re)name sheet */ /*{{{*/ static int do_name(Sheet *cursheet) { const char *name; name = line_file(cursheet->name, _("Teapot \t*.tp\nTeapot 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 \t*.tp\nTeapot ASCII \t*.tpa\nSC Spreadsheet Calculator \t*.sc\nLotus 1-2-3 \t*.wk1\nCSV \t*.csv"), _("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-3, ".tpa")) return do_loadport(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_loadxdr(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) { /* variables */ /*{{{*/ int reply; bool onecell; Location beg, end; /*}}}*/ /* ask for direction of insertion */ /*{{{*/ { MenuChoice menu[4]; menu[0].str = _("cC)olumn"); menu[0].c='\0'; menu[1].str = _("rR)ow"); menu[1].c='\0'; menu[2].str = _("dD)epth"); menu[2].c='\0'; menu[3].str=(char*)0; reply=line_menu(_("Insert:"),menu,0); if (reply<0) return reply; } /*}}}*/ do_mark(sheet, GET_MARK_CUR); LOCATION_GETS(beg, sheet->mark1); LOCATION_GETS(end, sheet->mark2); onecell = SAME_LOC(beg, end); if (onecell) /* ask if current cell or whole dimension should be used */ /*{{{*/ { /* variables */ /*{{{*/ MenuChoice menu[3]; int r; /*}}}*/ /* show menu */ /*{{{*/ switch (reply) { case 0: menu[0].str = _("wW)hole column"); break; case 1: menu[0].str = _("wW)hole line"); break; case 2: menu[0].str = _("wW)hole sheet"); break; default: assert(0); } menu[1].str = _("sS)ingle cell"); menu[1].c='\0'; menu[2].str = (char*)0; 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) { /* variables */ /*{{{*/ int reply; bool onecell; Location beg, end; /*}}}*/ firstmenu: /* ask for direction of deletion */ /*{{{*/ { MenuChoice menu[4]; menu[0].str = _("cC)olumn"); menu[0].c='\0'; menu[1].str = _("rR)ow"); menu[1].c='\0'; menu[2].str = _("dD)epth"); menu[2].c='\0'; menu[3].str = (char*)0; reply=line_menu(_("Delete:"),menu,0); if (reply<0) return reply; } /*}}}*/ do_mark(sheet, GET_MARK_CUR); LOCATION_GETS(beg, sheet->mark1); LOCATION_GETS(end, sheet->mark2); onecell = SAME_LOC(beg, end); if (onecell) /* ask if range is the current cell or whole dimension should be used */ /*{{{*/ { /* variables */ /*{{{*/ MenuChoice menu[3]; int r; /*}}}*/ /* show menu */ /*{{{*/ switch (reply) { case 0: menu[0].str = _("wW)hole column"); break; case 1: menu[0].str = _("wW)hole line"); break; case 2: menu[0].str = _("wW)hole sheet"); break; default: assert(0); } menu[1].str = _("sS)ingle cell"); menu[1].c='\0'; menu[2].str=(char*)0; 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 */ /*{{{*/ size_t offx,edx; 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: offx=0; edx=0; do if ((c=line_numedit(&cols,_("Number of column-wise repetitions:"),&edx,&offx))<0) return c; while (cols<=0); secondmenu: offx=0; edx=0; do { c=line_numedit(&rows,_("Number of row-wise repetitions:"),&edx,&offx); if (c==-1) return -1; else if (c==-2) goto firstmenu; } while (rows<=0); offx=0; edx=0; do { c=line_numedit(&layers,_("Number of depth-wise repetitions:"),&edx,&offx); 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); if (scan_labels) cachelabels(she); forceupdate(she); } /* do_sort -- sort block */ /*{{{*/ static int do_sort(Sheet *sheet) { /* variables */ /*{{{*/ MenuChoice menu1[4],menu2[3],menu3[3]; Sortkey sk[MAX_SORTKEYS]; unsigned int key; size_t x,offx; const char *msg; Direction in_dir=(Direction)-2; /* cause run time error */ int x1,y1,z1,x2,y2,z2; int doit=-1; int c; int last; /*}}}*/ do_mark(sheet, GET_MARK_ALL); /* build menues */ /*{{{*/ menu1[0].str=strdup(_("cC)olumn")); menu1[0].c='\0'; menu1[1].str=strdup(_("rR)ow")); menu1[1].c='\0'; menu1[2].str=strdup(_("dD)epth")); menu1[2].c='\0'; menu1[3].str=(char*)0; menu2[0].str=strdup(_("sS)ort region")); menu2[0].c='\0'; menu2[1].str=strdup(_("aA)dd key")); menu2[1].c='\0'; menu2[2].str=(char*)0; menu3[0].str=strdup(_("aA)scending")); menu3[0].c='\0'; menu3[1].str=strdup(_("dD)escending")); menu3[0].c='\0'; menu3[2].str=(char*)0; /*}}}*/ last=-1; /* ask for sort direction */ /*{{{*/ zero: switch (c=line_menu(_("Sort block:"),menu1,0)) { /* 0 -- in X */ /*{{{*/ case 0: in_dir=IN_X; break; /*}}}*/ /* 1 -- in Y */ /*{{{*/ case 1: in_dir=IN_Y; break; /*}}}*/ /* 2 -- in Z */ /*{{{*/ case 2: in_dir=IN_Z; break; /*}}}*/ /* -2,-1 -- abort */ /*{{{*/ case -2: case -1: goto greak; /*}}}*/ /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } last=0; /*}}}*/ key=0; do { /* ask for positions */ /*{{{*/ one: if (in_dir==IN_X) sk[key].x=0; else /* ask for x position */ /*{{{*/ { x=0; offx=0; sk[key].x=0; do { c=line_numedit(&(sk[key].x),_("X position of key vector:"),&x,&offx); if (c==-1) goto greak; else if (c==-2) switch (last) { case -1: goto greak; 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 */ /*{{{*/ { x=0; offx=0; sk[key].y=0; do { c=line_numedit(&(sk[key].y),_("Y position of key vector:"),&x,&offx); if (c==-1) goto greak; else if (c==-2) switch (last) { case -1: goto greak; 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 */ /*{{{*/ { x=0; offx=0; sk[key].z=0; do { c=line_numedit(&(sk[key].z),_("Z position of key vector:"),&x,&offx); if (c==-1) goto greak; else if (c==-2) switch (last) { case -1: goto greak; 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; switch (c=line_menu(_("Sort block:"),menu3,0)) { /* 0 -- ascending */ /*{{{*/ case 0: sk[key].sortkey|=ASCENDING; break; /*}}}*/ /* 1 -- descending */ /*{{{*/ case 1: sk[key].sortkey&=~ASCENDING; break; /*}}}*/ /* -1 -- abort */ /*{{{*/ case -1: goto greak; /*}}}*/ /* -2 -- go to first menu */ /*{{{*/ case -2: switch (last) { case -1: goto greak; case 1: goto one; case 2: goto two; case 3: goto three; default: assert(0); } /*}}}*/ /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } last=4; /*}}}*/ ++key; five: if (key==MAX_SORTKEYS) /* ask for sort comfirmation */ /*{{{*/ { c=line_ok(_("Sort block:"),0); if (c==-1) goto greak; else if (c==-2) goto four; else if (c==0) doit=1; } /*}}}*/ else /* ask for sort or adding another key */ /*{{{*/ switch (line_menu(_("Sort block:"),menu2,0)) { /* 0 -- sort it */ /*{{{*/ case 0: doit=1; break; /*}}}*/ /* 1 -- add another key */ /*{{{*/ case 1: doit=0; break; /*}}}*/ /* -1 -- abort */ /*{{{*/ case -1: goto greak; /*}}}*/ case -2: goto four; /* default -- should not happen */ /*{{{*/ default: assert(0); /*}}}*/ } /*}}}*/ last=5; } while (!doit); c=-1; if ((msg=sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key))!=(const char*)0) line_msg(_("Sort block:"),msg); greak: /* free menues */ /*{{{*/ free((char*)menu1[0].str); free((char*)menu1[1].str); free((char*)menu1[2].str); free((char*)menu2[0].str); free((char*)menu2[1].str); free((char*)menu2[2].str); free((char*)menu3[0].str); free((char*)menu3[1].str); free((char*)menu3[2].str); /*}}}*/ return c; } /*}}}*/ /* 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 */ /*{{{*/ { MenuChoice menu[4]; menu[0].str = _("lL)eft-right"); menu[0].c='\0'; menu[1].str = _("uU)pside-down"); menu[1].c='\0'; menu[2].str = _("fF)ront-back"); menu[2].c='\0'; menu[3].str = (char*)0; 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) { /* variables */ /*{{{*/ char buf[1024]; const char *s; size_t x,offx; Token **t; int c; /*}}}*/ assert(sheet!=(Sheet*)0); buf[0]='\0'; x=offx=0; if (expr) strcpy(buf,expr); else if ((c=line_edit(sheet,buf,sizeof(buf),_("Go to location:"),&x,&offx))<0) return c; s=buf; t=scan(&s); if (t!=(Token**)0) { Token value; LOCATION_GETS(upd_l, sheet->cur); upd_sheet=sheet; value=eval(t); 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_SCIENTIFIC: 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',(const char*)0,0); break; /*}}}*/ /* MENTER -- edit current clocked cell */ /*{{{*/ case K_MENTER: if (moveonly) break; do_edit(cursheet,'\0',(const char*)0,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,(const char*)0,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,(const char*)0,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,"abdhnrqHp:?"))!=EOF) switch (o) { /* a -- use ascii as default */ /*{{{*/ case 'a': { usexdr = false; break; } /*}}}*/ /* b -- run batch */ /*{{{*/ case 'b': batch = true; break; /*}}}*/ /* d -- increase debug level */ /*{{{*/ case 'd': ++debug_level; break; /*}}}*/ /* n -- no quoted strings */ /*{{{*/ case 'n': quote = false; break; /*}}}*/ /* q -- force quoted strings */ /*{{{*/ case 'q': quote = true; 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>DBL_DIG) { fprintf(stderr,_("teapot: precision must be between 0 and %d.\n"),DBL_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))!=(const char*)0) line_msg(_("Load sheet from XDR file:"),msg); } else { if ((msg=loadport(cursheet,cursheet->name))!=(const char*)0) 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; } /*}}}*/