"Fossies" - the Fresh Open Source Software Archive

Member "teapot-2.3.0/main.c" (6 Feb 2012, 55065 Bytes) of package /linux/privat/old/teapot-2.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation.

    1 /* #includes */ /*{{{C}}}*//*{{{*/
    2 #ifndef NO_POSIX_SOURCE
    3 #undef  _POSIX_SOURCE
    4 #define _POSIX_SOURCE   1
    5 #undef  _POSIX_C_SOURCE
    6 #define _POSIX_C_SOURCE 2
    7 #undef  _XOPEN_SOURCE
    8 #define _XOPEN_SOURCE 500
    9 #endif
   10 
   11 #ifdef DMALLOC
   12 #include "dmalloc.h"
   13 #endif
   14 
   15 #include <assert.h>
   16 #include <ctype.h>
   17 #include <float.h>
   18 #include <limits.h>
   19 #include <locale.h>
   20 #include <stdarg.h>
   21 #include <stdio.h>
   22 #include <stdlib.h>
   23 extern char *optarg;
   24 extern int optind,opterr,optopt;
   25 int getopt(int argc, char * const *argv, const char *optstring);
   26 #include <string.h>
   27 #include <unistd.h>
   28 
   29 
   30 #include "default.h"
   31 #include "display.h"
   32 #include "eval.h"
   33 #include "htmlio.h"
   34 #include "latex.h"
   35 #include "context.h"
   36 #include "main.h"
   37 #include "misc.h"
   38 #include "sc.h"
   39 #include "scanner.h"
   40 #include "utf8.h"
   41 #include "parser.h"
   42 #include "sheet.h"
   43 #include "wk1.h"
   44 /*}}}*/
   45 
   46 /* variables */ /*{{{*/
   47 char helpfile[PATH_MAX];
   48 int batch=0;
   49 unsigned int batchln=0;
   50 int def_precision=DEF_PRECISION;
   51 int quote=0;
   52 int header=1;
   53 static int usexdr=1;
   54 /*}}}*/
   55 
   56 static void get_mark(Sheet *sheet, int *x1, int *x2, int *y1, int *y2, int *z1, int *z2, int everything)
   57 {
   58     if (sheet->marking) {
   59         posorder(&sheet->mark1x, &sheet->mark2x);
   60         posorder(&sheet->mark1y, &sheet->mark2y);
   61         posorder(&sheet->mark1z, &sheet->mark2z);
   62         sheet->marking = 0;
   63     }
   64     if (x1) {
   65         if (sheet->mark1x >= 0) {
   66             *x1 = sheet->mark1x;
   67             *x2 = sheet->mark2x;
   68             *y1 = sheet->mark1y;
   69             *y2 = sheet->mark2y;
   70             *z1 = sheet->mark1z;
   71             *z2 = sheet->mark2z;
   72         } else if (everything) {
   73             *x1 = 0;
   74             *x2 = sheet->dimx-1;
   75             *y1 = 0;
   76             *y2 = sheet->dimy-1;
   77             *z1 = 0;
   78             *z2 = sheet->dimz-1;
   79         } else {
   80             *x1 = *x2 = sheet->curx;
   81             *y1 = *y2 = sheet->cury;
   82             *z1 = *z2 = sheet->curz;
   83         }
   84     }
   85 }
   86 
   87 void moveto(Sheet *sheet, int x, int y, int z)
   88 {
   89     int need_redraw = 0;
   90     int xdir = x > sheet->curx?1:-1;
   91 
   92     if (x >= 0) sheet->curx = x;
   93     if (y >= 0) sheet->cury = y;
   94     if (z >= 0) need_redraw++, sheet->curz = z;
   95     while (sheet->curx > 0 && shadowed(sheet, sheet->curx, sheet->cury, sheet->curz)) sheet->curx += xdir;
   96 
   97     if (sheet->marking) {
   98         sheet->mark2x = sheet->curx;
   99         sheet->mark2y = sheet->cury;
  100         sheet->mark2z = sheet->curz;
  101     }
  102 
  103     if (sheet->curx <= sheet->offx && sheet->offx) need_redraw++, sheet->offx = (sheet->curx?sheet->curx-1:0);
  104     if (sheet->cury <= sheet->offy && sheet->offy) need_redraw++, sheet->offy = (sheet->cury?sheet->cury-1:0);
  105     if (sheet->curx >= sheet->offx+sheet->maxx) need_redraw++, sheet->offx = sheet->curx-sheet->maxx+2;
  106     if (sheet->cury >= sheet->offy+sheet->maxy) need_redraw++, sheet->offy = sheet->cury-sheet->maxy+2;
  107 
  108     if (need_redraw) redraw_sheet(sheet);
  109     else if (x != sheet->curx || y != sheet->cury || z != sheet->curz) redraw_cell(sheet, sheet->curx, sheet->cury, sheet->curz);
  110 }
  111 
  112 void relmoveto(Sheet *sheet, int x, int y, int z)
  113 {
  114     moveto(sheet, sheet->curx+x, sheet->cury+y, (z?sheet->curz+z:-1));
  115 }
  116 
  117 /* line_numedit   -- number line editor function */ /*{{{*/
  118 static int line_numedit(int *n, const char *prompt, size_t *x, size_t *offx)
  119 {
  120   /* variables */ /*{{{*/
  121   char buf[20];
  122   const char *s;
  123   Token **t;
  124   int c;
  125   /*}}}*/
  126 
  127   /* asserts */ /*{{{*/
  128   assert(prompt!=(char*)0);
  129   assert(x!=(size_t*)0);
  130   assert(offx!=(size_t*)0);
  131   /*}}}*/
  132   t=(Token**)0;
  133   sprintf(buf,"%d",*n);
  134   s=buf+strlen(buf);
  135   do
  136   {
  137     tvecfree(t);
  138     *x=s-buf;
  139     if ((c=line_edit((Sheet*)0,buf,sizeof(buf),prompt,x,offx))<0) return c;
  140     s=buf;
  141     t=scan(&s);
  142   } while ((*s!='\0' && t==(Token**)0) || !(t!=(Token**)0 && ((*t)==(Token*)0 || ((*t)->type==INT && (*t)->u.integer>=0 && *(t+1)==(Token*)0))));
  143   if (t==(Token**)0 || *t==(Token*)0) *n=-1;
  144   else *n=(*t)->u.integer;
  145   tvecfree(t);
  146   return 0;
  147 }
  148 /*}}}*/
  149 /* line_lidedit   -- label identifier line editor function */ /*{{{*/
  150 static int line_idedit(char *ident, size_t size, const char *prompt, size_t *x, size_t *offx)
  151 {
  152   /* variables */ /*{{{*/
  153   const char *s;
  154   Token **t;
  155   int c;
  156   /*}}}*/
  157 
  158   t=(Token**)0;
  159   s=ident+strlen(ident);
  160   do
  161   {
  162     tvecfree(t);
  163     *x=s-ident;
  164     if ((c=line_edit((Sheet*)0,ident,size,prompt,x,offx))<0) return c;
  165     s=ident;
  166     t=scan(&s);
  167   } while ((*s!='\0' && t==(Token**)0) || !(t!=(Token**)0 && ((*t)==(Token*)0 || ((*t)->type==LIDENT && *(t+1)==(Token*)0))));
  168   tvecfree(t);
  169   return 0;
  170 }
  171 /*}}}*/
  172 /* doanyway       -- ask if action should be done despite unsaved changes */ /*{{{*/
  173 int doanyway(Sheet *sheet, const char *msg)
  174 {
  175   int result;
  176 
  177   if (sheet->changed) {
  178     result=line_ok(msg,0);
  179     if (result < 0) return 0;
  180     return result;
  181   }
  182   return 1;
  183 }
  184 /*}}}*/
  185 
  186 /* do_edit        -- set or modify cell contents */ /*{{{*/
  187 static int do_edit(Sheet *cursheet, Key c, const char *expr, int clocked)
  188 {
  189   /* variables */ /*{{{*/
  190   char buf[1024];
  191   const char *s;
  192   size_t x,offx;
  193   int curx,cury,curz;
  194   Token **t;
  195   /*}}}*/
  196 
  197   if (locked(cursheet,cursheet->curx,cursheet->cury,cursheet->curz)) line_msg(_("Edit cell:"),_("Cell is locked"));
  198   else
  199   {
  200     curx=cursheet->curx;
  201     cury=cursheet->cury;
  202     curz=cursheet->curz;
  203     if (expr)
  204     {
  205       s=expr;
  206       t=scan(&s);
  207       if (*s!='\0' && t==(Token**)0) line_msg(clocked ? _("Clocked cell contents:") : _("Cell contents:"),"XXX invalid expression");
  208     }
  209     else
  210     {
  211       offx=0;
  212       if (c==K_NONE)
  213       {
  214         print(buf,sizeof(buf),0,1,getscientific(cursheet,cursheet->curx,cursheet->cury,cursheet->curz),-1,getcont(cursheet,cursheet->curx,cursheet->cury,cursheet->curz,clocked));
  215         s=buf+strlen(buf);
  216       }
  217       else if (c==K_BACKSPACE)
  218       {
  219         print(buf,sizeof(buf),0,1,getscientific(cursheet,cursheet->curx,cursheet->cury,cursheet->curz),-1,getcont(cursheet,cursheet->curx,cursheet->cury,cursheet->curz,clocked));
  220         if (strlen(buf)) *mbspos(buf+strlen(buf),-1)='\0';
  221         s=buf+strlen(buf);
  222       }
  223       else if (c==K_DC)
  224       {
  225         print(buf,sizeof(buf),0,1,getscientific(cursheet,cursheet->curx,cursheet->cury,cursheet->curz),-1,getcont(cursheet,cursheet->curx,cursheet->cury,cursheet->curz,clocked));
  226         memmove(buf,mbspos(buf,1),strlen(mbspos(buf,1))+1);
  227         s=buf;
  228       }
  229       else if (isalpha(c))
  230       {
  231         buf[0] = '"';
  232         buf[1] = c;
  233         buf[2] = 0;
  234         s=buf+2;
  235       }
  236       else
  237       {
  238         if (c < 256) buf[0]=c;
  239         else buf[0] = 0;
  240         buf[1]='\0';
  241         s=buf+1;
  242       }
  243       do
  244       {
  245         int r;
  246 
  247         x=mbslen(buf)-mbslen(s);
  248         if ((r=line_edit(cursheet,buf,sizeof(buf),clocked ? _("Clocked cell contents:") : _("Cell contents:"),&x,&offx))<0) return r;
  249         s=buf;
  250         if (buf[0] == '"' && buf[strlen(buf)-1] != '"' && strlen(buf)+1 < sizeof(buf)) {
  251             buf[strlen(buf)+1] = 0;
  252             buf[strlen(buf)] = '"';
  253         }
  254         t=scan(&s);
  255       } while (*s!='\0' && t==(Token**)0);
  256     }
  257     if (t!=(Token**)0 && *t==(Token*)0) { free(t); t=(Token**)0; }
  258     moveto(cursheet,curx,cury,curz);
  259     putcont(cursheet,cursheet->curx,cursheet->cury,cursheet->curz,t,clocked);
  260     forceupdate(cursheet);
  261   }
  262   return 0;
  263 }
  264 /*}}}*/
  265 /* do_label       -- modify cell label */ /*{{{*/
  266 static int do_label(Sheet *sheet)
  267 {
  268   /* variables */ /*{{{*/
  269   char buf[1024],oldlabel[1024];
  270   size_t edx,offx,ok;
  271   Token t;
  272   int x,y,z,x1,y1,z1,x2,y2,z2;
  273   int c;
  274   /*}}}*/
  275 
  276   assert(sheet!=(Sheet*)0);
  277   if (sheet->mark1x==-1 && locked(sheet,sheet->curx,sheet->cury,sheet->curz)) line_msg(_("Cell label:"),_("Cell is locked"));
  278   else
  279   {
  280     get_mark(sheet, &x1, &x2, &y1, &y2, &z1, &z2, 0);
  281     ok=edx=offx=0;
  282     (void)strcpy(buf,getlabel(sheet,sheet->curx,sheet->cury,sheet->curz));
  283     (void)strcpy(oldlabel,buf);
  284     do
  285     {
  286       if ((c=line_idedit(buf,sizeof(buf),_("Cell label:"),&edx,&offx))<0) return c;
  287       if (buf[0]=='\0') ok=1;
  288       else
  289       {
  290         ok=((t=findlabel(sheet,buf)).type==EEK || (t.type==LOCATION && t.u.location[0]==sheet->curx && t.u.location[1]==sheet->cury && t.u.location[2]==sheet->curz));
  291         tfree(&t);
  292       }
  293     } while (!ok);
  294     setlabel(sheet,sheet->curx,sheet->cury,sheet->curz,buf,1);
  295     if (buf[0]!='\0') for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) relabel(sheet,oldlabel,buf,x,y,z);
  296   }
  297   return -1;
  298 }
  299 /*}}}*/
  300 /* do_columnwidth -- set the column width */ /*{{{*/
  301 static int do_columnwidth(Sheet *cursheet)
  302 {
  303   /* variables */ /*{{{*/
  304   size_t edx,offx;
  305   int n;
  306   int x,x1,x2,z,z1,z2;
  307   int c;
  308   /*}}}*/
  309 
  310   offx=0;
  311   edx=0;
  312   n=columnwidth(cursheet,cursheet->curx,cursheet->curz);
  313   do if ((c=line_numedit(&n,_("Column width:"),&edx,&offx))<0) return c; while (n<=0);
  314   if (cursheet->mark1x==-1)
  315   /* range is the current cell */ /*{{{*/
  316   {
  317     x1=x2=cursheet->curx;
  318     z1=z2=cursheet->curz;
  319   }
  320   /*}}}*/
  321   else
  322   /* range is the marked cube */ /*{{{*/
  323   {
  324     x1=cursheet->mark1x; x2=cursheet->mark2x;
  325     z1=cursheet->mark1z; z2=cursheet->mark2z;
  326   }
  327   /*}}}*/
  328   for (x=x1; x<=x2; ++x) for (z=z1; z<=z2; ++z) setwidth(cursheet,x,z,n);
  329   return -1;
  330 }
  331 /*}}}*/
  332 /* do_attribute   -- set cell attributes */ /*{{{*/
  333 static void do_attribute(Sheet *cursheet, Key action)
  334 {
  335   /* variables */ /*{{{*/
  336   int x,y,z;
  337   int x1,y1,z1;
  338   int x2,y2,z2;
  339   int c = 0;
  340   /*}}}*/
  341 
  342   get_mark(cursheet, &x1, &x2, &y1, &y2, &z1, &z2, 0);
  343 
  344   if (action != ADJUST_LOCK && cursheet->mark1x==-1 &&  action != ADJUST_LOCK && locked(cursheet,cursheet->curx,cursheet->cury,cursheet->curz))
  345   {
  346     line_msg(_("Cell attribute:"),_("Cell is locked"));
  347     return;
  348   }
  349   switch ((int)action)
  350   {
  351     /* 0       -- adjust left */ /*{{{*/
  352     case ADJUST_LEFT:
  353     {
  354       if (cursheet->mark1x != -1 && line_ok(_("Make block left-adjusted:"), 0) <= 0) break;
  355       for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) setadjust(cursheet,x,y,z,LEFT);
  356       break;
  357     }
  358     /*}}}*/
  359     /* 1       -- adjust right */ /*{{{*/
  360     case ADJUST_RIGHT:
  361     {
  362       if (cursheet->mark1x != -1 && line_ok(_("Make block right-adjusted:"), 0) <= 0) break;
  363       for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) setadjust(cursheet,x,y,z,RIGHT);
  364       break;
  365     }
  366     /*}}}*/
  367     /* 2       -- adjust centered */ /*{{{*/
  368     case ADJUST_CENTER:
  369     {
  370       if (cursheet->mark1x != -1 && line_ok(_("Make block centered:"), 0) <= 0) break;
  371       for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) setadjust(cursheet,x,y,z,CENTER);
  372       break;
  373     }
  374     /*}}}*/
  375     /* 3       -- set scientific notation flag */ /*{{{*/
  376     case ADJUST_SCIENTIFIC:
  377     {
  378       int n;
  379 
  380       if (cursheet->mark1x==-1) n = !getscientific(cursheet,x1,y1,z1);
  381       else n = line_ok(_("Make block notation scientific:"), getscientific(cursheet,x1,y1,z1));
  382       if (n >= 0) for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) setscientific(cursheet,x,y,z,n);
  383       break;
  384     }
  385     /*}}}*/
  386     /* 5       -- set precision */ /*{{{*/
  387     case ADJUST_PRECISION:
  388     {
  389       size_t ex,offx;
  390       int n;
  391 
  392       offx=0;
  393       ex=0;
  394       n=getprecision(cursheet,x1,y1,z1);
  395       do if (line_numedit(&n,cursheet->mark1x==-1 ? _("Precision for cell:") : _("Precision for block:"),&ex,&offx)==-1) return; while (n!=-1 && (n==0 || n>20));
  396       for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) setprecision(cursheet,x,y,z,n);
  397       break;
  398     }
  399     /*}}}*/
  400     /* 6       -- shadow */ /*{{{*/
  401     case ADJUST_SHADOW:
  402     {
  403       int n;
  404 
  405       if (cursheet->mark1x==-1) n = !shadowed(cursheet,x1,y1,z1);
  406       else n = line_ok(_("Shadow block:"), shadowed(cursheet,x1,y1,z1));
  407       if (x1 == 0 && n == 1) {
  408         line_msg(_("Shadow cell:"),_("You can not shadow cells in column 0"));
  409         break;
  410       }
  411 
  412       if (n >= 0) {
  413         for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z)
  414         {
  415           int rx;
  416 
  417           if (n==0) for (rx=x+1; shadowed(cursheet,rx,y,z); ++rx) shadow(cursheet,rx,y,z,0);
  418           else if (x>0) shadow(cursheet,x,y,z,1);
  419         }
  420       }
  421       break;
  422     }
  423     /*}}}*/
  424     /* 7       -- transparent */ /*{{{*/
  425     case ADJUST_TRANSPARENT:
  426     {
  427       int n;
  428 
  429       if (cursheet->mark1x==-1) n = !transparent(cursheet,x1,y1,z1);
  430       else n = line_ok(_("Make block transparent:"), transparent(cursheet,x1,y1,z1));
  431       if (n >= 0) for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) maketrans(cursheet,x,y,z,n);
  432       break;
  433     }
  434     /*}}}*/
  435     /* 8       -- bold */ /*{{{*/
  436     case ADJUST_BOLD:
  437     {
  438       int n;
  439 
  440       if (cursheet->mark1x==-1) n = !isbold(cursheet,x1,y1,z1);
  441       else n = line_ok(_("Make block bold:"), isbold(cursheet,x1,y1,z1));
  442       if (n >= 0) for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) bold(cursheet,x,y,z,n);
  443       break;
  444     }
  445     /*}}}*/
  446     /* 9       -- underline */ /*{{{*/
  447     case ADJUST_UNDERLINE:
  448     {
  449       int n;
  450 
  451       if (cursheet->mark1x==-1) n = !underlined(cursheet,x1,y1,z1);
  452       else n = line_ok(_("Make block underlined:"), underlined(cursheet,x1,y1,z1));
  453       if (n >= 0) for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) underline(cursheet,x,y,z,n);
  454       break;
  455     }
  456     /*}}}*/
  457     /* 1       -- edit label and goto end */ /*{{{*/
  458     case ADJUST_LABEL:
  459     {
  460       do_label(cursheet);
  461       return;
  462     }
  463     /*}}}*/
  464     /* 2       -- lock */ /*{{{*/
  465     case ADJUST_LOCK:
  466     {
  467       int n;
  468 
  469       if (cursheet->mark1x==-1) n = !locked(cursheet,x1,y1,z1);
  470       else n = line_ok(_("Lock block:"), locked(cursheet,x1,y1,z1));
  471       if (n >= 0) for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) lockcell(cursheet,x,y,z,n);
  472 
  473       break;
  474     }
  475     /*}}}*/
  476     /* 3       -- ignore */ /*{{{*/
  477     case ADJUST_IGNORE:
  478     {
  479       int n;
  480 
  481       if (cursheet->mark1x==-1) n = !ignored(cursheet,x1,y1,z1);
  482       else n = line_ok(_("Ignore values of all cells in this block:"), ignored(cursheet,x1,y1,z1));
  483       if (n >= 0) for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) igncell(cursheet,x,y,z,n);
  484       break;
  485     }
  486     /*}}}*/
  487     /* default -- should not happen */ /*{{{*/
  488       default: assert(0);
  489     /*}}}*/
  490   }
  491   if (c>=0)
  492   {
  493     if (cursheet->mark1x==-1) redraw_cell(cursheet, cursheet->curx, cursheet->cury, cursheet->curz);
  494     else redraw_sheet(cursheet);
  495   }
  496   forceupdate(cursheet);
  497   return;
  498 }
  499 /*}}}*/
  500 /* do_savexdr     -- save sheet as XDR file */ /*{{{*/
  501 static int do_savexdr(Sheet *cursheet, const char *name)
  502 {
  503   char buf[PATH_MAX];
  504   const char *msg;
  505   unsigned int count;
  506 
  507   if (!name) {
  508       name = cursheet->name;
  509 
  510       if (strcmp(name+strlen(name)-3,".tp")) {
  511         snprintf(buf, sizeof(buf), "%s.tp", name);
  512         name = buf;
  513       }
  514   }
  515 
  516   if ((msg = savexdr(cursheet, name, &count))) {
  517     line_msg(_("Save sheet to XDR file:"), msg);
  518     return -2;
  519   }
  520 
  521   snprintf(buf, sizeof(buf), _("%u cells written"), count);
  522   if (!batch) line_msg(_("Save sheet to XDR file:"),buf);
  523   return -1;
  524 }
  525 /*}}}*/
  526 /* do_saveport    -- save sheet as portable ASCII file */ /*{{{*/
  527 static int do_saveport(Sheet *cursheet, const char *name)
  528 {
  529   char buf[PATH_MAX];
  530   const char *msg;
  531   unsigned int count;
  532 
  533   if (!name) name = cursheet->name;
  534 
  535   if ((msg = saveport(cursheet, name, &count))) {
  536     line_msg(_("Save sheet to ASCII file:"),msg);
  537     return -2;
  538   }
  539 
  540   snprintf(buf, sizeof(buf), _("%u cells written"), count);
  541   if (!batch) line_msg(_("Save sheet to ASCII file:"),buf);
  542   return -1;
  543 }
  544 /*}}}*/
  545 /* do_savetbl     -- save sheet as tbl file */ /*{{{*/
  546 static int do_savetbl(Sheet *cursheet, const char *name)
  547 {
  548   char buf[PATH_MAX];
  549   const char *msg;
  550   int standalone=0;
  551   int x1,y1,z1,x2,y2,z2;
  552   unsigned int count;
  553 
  554   get_mark(cursheet, &x1, &x2, &y1, &y2, &z1, &z2, 1);
  555   if (!name) {
  556     name = cursheet->name;
  557     if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone;
  558   }
  559 
  560   if ((msg = savetbl(cursheet, name, !standalone, x1, y1, z1, x2, y2, z2, &count))) {
  561     line_msg(_("Save in tbl format to file:"),msg);
  562     return -2;
  563   }
  564 
  565   snprintf(buf, sizeof(buf), _("%u cells written"), count);
  566   if (!batch) line_msg(_("Save in tbl format to file:"), buf);
  567   return -1;
  568 }
  569 /*}}}*/
  570 /* do_savelatex   -- save sheet as LaTeX file */ /*{{{*/
  571 static int do_savelatex(Sheet *cursheet, const char *name)
  572 {
  573   char buf[PATH_MAX];
  574   const char *msg;
  575   int standalone=0;
  576   int x1,y1,z1,x2,y2,z2;
  577   unsigned int count;
  578 
  579   get_mark(cursheet, &x1, &x2, &y1, &y2, &z1, &z2, 1);
  580   if (!name) {
  581     name = cursheet->name;
  582     if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone;
  583   }
  584 
  585   if ((msg = savelatex(cursheet, name, !standalone, x1, y1, z1, x2, y2, z2, &count))) {
  586     line_msg(_("Save in LaTeX format to file:"),msg);
  587     return -2;
  588   }
  589 
  590   snprintf(buf, sizeof(buf), _("%u cells written"), count);
  591   if (!batch) line_msg(_("Save in LaTeX format to file:"), buf);
  592   return -1;
  593 }
  594 /*}}}*/
  595 /* do_savecontext   -- save sheet as ConTeXt file */ /*{{{*/
  596 static int do_savecontext(Sheet *cursheet, const char *name)
  597 {
  598   char buf[PATH_MAX];
  599   const char *msg;
  600   int standalone=0;
  601   int x1,y1,z1,x2,y2,z2;
  602   unsigned int count;
  603 
  604   get_mark(cursheet, &x1, &x2, &y1, &y2, &z1, &z2, 1);
  605   if (!name) {
  606     name = cursheet->name;
  607     if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone;
  608   }
  609 
  610   if ((msg = savecontext(cursheet, name, !standalone, x1, y1, z1, x2, y2, z2, &count))) {
  611     line_msg(_("Save in ConTeXt format to file:"),msg);
  612     return -2;
  613   }
  614 
  615   snprintf(buf, sizeof(buf), _("%u cells written"), count);
  616   if (!batch) line_msg(_("Save in ConTeXt format to file:"), buf);
  617   return -1;
  618 }
  619 /*}}}*/
  620 /* do_savehtml    -- save sheet as HTML file */ /*{{{*/
  621 static int do_savehtml(Sheet *cursheet, const char *name)
  622 {
  623   char buf[PATH_MAX];
  624   const char *msg;
  625   int standalone=0;
  626   int x1,y1,z1,x2,y2,z2;
  627   unsigned int count;
  628 
  629   get_mark(cursheet, &x1, &x2, &y1, &y2, &z1, &z2, 1);
  630   if (!name) {
  631     name = cursheet->name;
  632     if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone;
  633   }
  634 
  635   if ((msg = savehtml(cursheet, name, !standalone, x1, y1, z1, x2, y2, z2, &count))) {
  636     line_msg(_("Save in HTML format to file:"),msg);
  637     return -2;
  638   }
  639 
  640   snprintf(buf, sizeof(buf), _("%u cells written"), count);
  641   if (!batch) line_msg(_("Save in HTML format to file:"), buf);
  642   return -1;
  643 }
  644 /*}}}*/
  645 /* do_savetext    -- save sheet as formatted text file */ /*{{{*/
  646 static int do_savetext(Sheet *cursheet, const char *name)
  647 {
  648   char buf[PATH_MAX];
  649   const char *msg;
  650   int x1,y1,z1,x2,y2,z2;
  651   unsigned int count;
  652 
  653   get_mark(cursheet, &x1, &x2, &y1, &y2, &z1, &z2, 1);
  654   if (!name) name = cursheet->name;
  655 
  656   if ((msg = savetext(cursheet, name, x1, y1, z1, x2, y2, z2, &count))) {
  657     line_msg(_("Save in plain text format to file:"),msg);
  658     return -2;
  659   }
  660 
  661   snprintf(buf, sizeof(buf), _("%u cells written"), count);
  662   if (!batch) line_msg(_("Save in plain text format to file:"), buf);
  663   return -1;
  664 }
  665 /*}}}*/
  666 /* do_savecsv     -- save sheet as CSV file */ /*{{{*/
  667 static int do_savecsv(Sheet *cursheet, const char *name)
  668 {
  669   char buf[PATH_MAX];
  670   const char *msg;
  671   int x1,y1,z1,x2,y2,z2;
  672   unsigned int count;
  673   int sep = 0;
  674   const char seps[4] = ",;\t";
  675 
  676   get_mark(cursheet, &x1, &x2, &y1, &y2, &z1, &z2, 1);
  677   if (!name) {
  678     MenuChoice menu[4];
  679     name = cursheet->name;
  680 
  681     menu[0].str=mystrmalloc(_("cC)omma (,)")); menu[0].c='\0';
  682     menu[1].str=mystrmalloc(_("sS)emicolon (;)")); menu[1].c='\0';
  683     menu[2].str=mystrmalloc(_("tT)ab (\\t)")); menu[2].c='\0';
  684     menu[3].str=(char*)0;
  685     sep=line_menu(_("Choose separator:"),menu,0);
  686     if (sep < 0) return sep;
  687   }
  688 
  689   if ((msg = savecsv(cursheet, name, seps[sep], x1, y1, z1, x2, y2, z2, &count))) {
  690     line_msg(_("Save in CSV format to file:"),msg);
  691     return -2;
  692   }
  693 
  694   snprintf(buf, sizeof(buf), _("%u cells written"), count);
  695   if (!batch) line_msg(_("Save in CSV format to file:"), buf);
  696   return -1;
  697 }
  698 /*}}}*/
  699 /* do_loadxdr     -- load sheet from XDR file */ /*{{{*/
  700 static int do_loadxdr(Sheet *cursheet)
  701 {
  702   const char *msg;
  703 
  704   if ((msg=loadxdr(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from XDR file:"),msg);
  705   return -1;
  706 }
  707 /*}}}*/
  708 /* do_loadport    -- load sheet from portable ASCII file */ /*{{{*/
  709 static int do_loadport(Sheet *cursheet)
  710 {
  711   const char *msg;
  712   /*}}}*/
  713 
  714   if ((msg=loadport(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from ASCII file:"),msg);
  715   return -1;
  716 }
  717 /*}}}*/
  718 /* do_loadsc      -- load sheet from SC file */ /*{{{*/
  719 static int do_loadsc(Sheet *cursheet)
  720 {
  721   const char *msg;
  722 
  723   if ((msg=loadsc(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from SC file:"),msg);
  724   return -1;
  725 }
  726 /*}}}*/
  727 /* do_loadwk1     -- load sheet from WK1 file */ /*{{{*/
  728 static int do_loadwk1(Sheet *cursheet)
  729 {
  730   const char *msg;
  731 
  732   if ((msg=loadwk1(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from WK1 file:"),msg);
  733   return -1;
  734 }
  735 /*}}}*/
  736 /* do_loadcsv     -- load/merge sheet from CSV file */ /*{{{*/
  737 static int do_loadcsv(Sheet *cursheet)
  738 {
  739   const char *msg;
  740 
  741   if ((msg=loadcsv(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from CSV file:"),msg);
  742   return -1;
  743 }
  744 /*}}}*/
  745 /* do_mark        -- set mark */ /*{{{*/
  746 void do_mark(Sheet *cursheet, int force)
  747 {
  748   if (force==0)
  749   {
  750     if (!cursheet->marking && cursheet->mark1x==-1) force=1;
  751     else if (cursheet->marking) force=2;
  752     else force=3;
  753   }
  754   switch (force)
  755   {
  756     case 1:
  757     {
  758       cursheet->mark1x=cursheet->mark2x=cursheet->curx;
  759       cursheet->mark1y=cursheet->mark2y=cursheet->cury;
  760       cursheet->mark1z=cursheet->mark2z=cursheet->curz;
  761       cursheet->marking=1;
  762       break;
  763     }
  764     case 2:
  765     {
  766       cursheet->marking=0;
  767       break;
  768     }
  769     case 3:
  770     {
  771       cursheet->mark1x=-1;
  772       break;
  773     }
  774     default: assert(0);
  775   }
  776 }
  777 /*}}}*/
  778 static int do_name(Sheet *cursheet);
  779 /* do_save        -- save sheet */ /*{{{*/
  780 static int do_save(Sheet *cursheet)
  781 {
  782     const char *ext = cursheet->name;
  783     if (ext==(char*)0) return do_name(cursheet);
  784 
  785     ext += strlen(ext)-1;
  786 
  787     if (!strcmp(ext-3, ".tpa")) return do_saveport(cursheet, NULL);
  788     if (!strcmp(ext-3, ".tbl")) return do_savetbl(cursheet, NULL);
  789     if (!strcmp(ext-5, ".latex")) return do_savelatex(cursheet, NULL);
  790     if (!strcmp(ext-4, ".html")) return do_savehtml(cursheet, NULL);
  791     if (!strcmp(ext-3, ".csv")) return do_savecsv(cursheet, NULL);
  792     if (!strcmp(ext-3, ".txt")) return do_savetext(cursheet, NULL);
  793     if (!strcmp(ext-3, ".tex")) return do_savecontext(cursheet, NULL);
  794     return do_savexdr(cursheet, NULL);
  795 }
  796 /*}}}*/
  797 /* do_name        -- (re)name sheet */ /*{{{*/
  798 static int do_name(Sheet *cursheet)
  799 {
  800     const char *name;
  801 
  802     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);
  803     if (!name) return -1;
  804 
  805     if (cursheet->name!=(char*)0) free(cursheet->name);
  806     cursheet->name=strdup(name);
  807     return do_save(cursheet);
  808 }
  809 /*}}}*/
  810 /* do_load        -- load sheet */ /*{{{*/
  811 static int do_load(Sheet *cursheet)
  812 {
  813     const char *name, *ext;
  814 
  815     if (doanyway(cursheet, _("Sheet modified, load new file anyway?")) != 1) return -1;
  816 
  817     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);
  818     if (!name) return -1;
  819     if (cursheet->name!=(char*)0) free(cursheet->name);
  820     cursheet->name=strdup(name);
  821 
  822     ext = name+strlen(name)-1;
  823     if (!strcmp(ext-3, ".tpa")) return do_loadport(cursheet);
  824     if (!strcmp(ext-2, ".sc")) return do_loadsc(cursheet);
  825     if (!strcmp(ext-3, ".wk1")) return do_loadwk1(cursheet);
  826     if (!strcmp(ext-3, ".csv")) return do_loadcsv(cursheet);
  827     return do_loadxdr(cursheet);
  828 }
  829 /*}}}*/
  830 
  831 /* do_clear       -- clear block */ /*{{{*/
  832 static int do_clear(Sheet *sheet)
  833 {
  834   /* variables */ /*{{{*/
  835   int x,y,z;
  836   int x1,y1,z1;
  837   int x2,y2,z2;
  838   int c;
  839   /*}}}*/
  840 
  841   if (sheet->mark1x==-1 && locked(sheet,sheet->curx,sheet->cury,sheet->curz)) line_msg(_("Clear cell:"),_("Cell is locked"));
  842   else
  843   {
  844     if (sheet->mark1x!=-1)
  845     {
  846       if ((c=line_ok(_("Clear block:"),0))<0) return c;
  847       else if (c!=1) return -1;
  848     }
  849     get_mark(sheet, &x1, &x2, &y1, &y2, &z1, &z2, 0);
  850     for (x=x1; x<=x2; ++x) for (y=y1; y<=y2; ++y) for (z=z1; z<=z2; ++z) freecell(sheet,x,y,z);
  851     cachelabels(sheet);
  852     forceupdate(sheet);
  853   }
  854   return -1;
  855 }
  856 /*}}}*/
  857 /* do_insert      -- insert block */ /*{{{*/
  858 static int do_insert(Sheet *sheet)
  859 {
  860   /* variables */ /*{{{*/
  861   int x1,y1,z1,x2,y2,z2,reply;
  862   /*}}}*/
  863 
  864   /* ask for direction of insertation */ /*{{{*/
  865   {
  866     MenuChoice menu[4];
  867 
  868     menu[0].str=mystrmalloc(_("cC)olumn")); menu[0].c='\0';
  869     menu[1].str=mystrmalloc(_("rR)ow")); menu[1].c='\0';
  870     menu[2].str=mystrmalloc(_("dD)epth")); menu[2].c='\0';
  871     menu[3].str=(char*)0;
  872     reply=line_menu(_("Insert:"),menu,0);
  873     free(menu[0].str);
  874     free(menu[1].str);
  875     free(menu[2].str);
  876     if (reply<0) return reply;
  877   }
  878   /*}}}*/
  879   if (sheet->mark1x==-1)
  880   /* ask if current cell or whole dimension should be used */ /*{{{*/
  881   {
  882     /* variables */ /*{{{*/
  883     MenuChoice menu[3];
  884     int r;
  885     /*}}}*/
  886 
  887     /* show menu */ /*{{{*/
  888     switch (reply)
  889     {
  890       case 0: menu[0].str=mystrmalloc(_("wW)hole column")); break;
  891       case 1: menu[0].str=mystrmalloc(_("wW)hole line")); break;
  892       case 2: menu[0].str=mystrmalloc(_("wW)hole sheet")); break;
  893       default: assert(0);
  894     }
  895     menu[1].str=mystrmalloc(_("sS)ingle cell")); menu[1].c='\0';
  896     menu[2].str=(char*)0;
  897     r=line_menu(_("Insert:"),menu,0);
  898     free(menu[0].str);
  899     free(menu[1].str);
  900     /*}}}*/
  901     switch (r)
  902     {
  903       /*  0 -- use whole dimension */ /*{{{*/
  904       case 0:
  905       {
  906         switch (reply)
  907         {
  908           /*  0 -- use whole column */ /*{{{*/
  909           case 0:
  910           {
  911             x1=x2=sheet->curx;
  912             y1=0; y2=sheet->dimy;
  913             z1=z2=sheet->curz;
  914             break;
  915           }
  916           /*}}}*/
  917           /*  1 -- use whole line */ /*{{{*/
  918           case 1:
  919           {
  920             x1=0; x2=sheet->dimx;
  921             y1=y2=sheet->cury;
  922             z1=z2=sheet->curz;
  923             break;
  924           }
  925           /*}}}*/
  926           /*  2 -- use whole layer */ /*{{{*/
  927           case 2:
  928           {
  929             x1=0; x2=sheet->dimx;
  930             y1=0; y2=sheet->dimy;
  931             z1=z2=sheet->curz;
  932             break;
  933           }
  934           /*}}}*/
  935           /*  default -- should not happen */ /*{{{*/
  936           default: assert(0);
  937           /*}}}*/
  938         }
  939         break;
  940       }
  941       /*}}}*/
  942       /*  1 -- use current cell */ /*{{{*/
  943       case 1:
  944       {
  945         x1=x2=sheet->curx;
  946         y1=y2=sheet->cury;
  947         z1=z2=sheet->curz;
  948         break;
  949       }
  950       /*}}}*/
  951       /* -2,-1 -- go up or abort */ /*{{{*/
  952       case -2:
  953       case -1: return r;
  954       /*}}}*/
  955       /* default -- should not happen */ /*{{{*/
  956       default: assert(0);
  957       /*}}}*/
  958     }
  959   }
  960   /*}}}*/
  961   else
  962   /* range is the marked cube */ /*{{{*/
  963   {
  964       get_mark(sheet, &x1, &x2, &y1, &y2, &z1, &z2, 0);
  965   }
  966   /*}}}*/
  967   switch (reply)
  968   {
  969     /*  0      -- columns */ /*{{{*/
  970     case 0: insertcube(sheet,x1,y1,z1,x2,y2,z2,IN_X); break;
  971     /*}}}*/
  972     /*  1      -- rows */ /*{{{*/
  973     case 1: insertcube(sheet,x1,y1,z1,x2,y2,z2,IN_Y); break;
  974     /*}}}*/
  975     /*  2      -- depth */ /*{{{*/
  976     case 2: insertcube(sheet,x1,y1,z1,x2,y2,z2,IN_Z); break;
  977     /*}}}*/
  978   }
  979   return 0;
  980 }
  981 /*}}}*/
  982 /* do_delete      -- delete block */ /*{{{*/
  983 static int do_delete(Sheet *sheet)
  984 {
  985   /* variables */ /*{{{*/
  986   int x1,y1,z1,x2,y2,z2,reply;
  987   /*}}}*/
  988 
  989   firstmenu:
  990   /* ask for direction of deletion */ /*{{{*/
  991   {
  992     MenuChoice menu[4];
  993 
  994     menu[0].str=mystrmalloc(_("cC)olumn")); menu[0].c='\0';
  995     menu[1].str=mystrmalloc(_("rR)ow")); menu[1].c='\0';
  996     menu[2].str=mystrmalloc(_("dD)epth")); menu[2].c='\0';
  997     menu[3].str=(char*)0;
  998     reply=line_menu(_("Delete:"),menu,0);
  999     free(menu[0].str);
 1000     free(menu[1].str);
 1001     free(menu[2].str);
 1002     if (reply<0) return reply;
 1003   }
 1004   /*}}}*/
 1005   if (sheet->mark1x==-1)
 1006   /* ask if range is the current cell or whole dimension should be used */ /*{{{*/
 1007   {
 1008     /* variables */ /*{{{*/
 1009     MenuChoice menu[3];
 1010     int r;
 1011     /*}}}*/
 1012 
 1013     /* show menu */ /*{{{*/
 1014     switch (reply)
 1015     {
 1016       case 0: menu[0].str=mystrmalloc(_("wW)hole column")); break;
 1017       case 1: menu[0].str=mystrmalloc(_("wW)hole line")); break;
 1018       case 2: menu[0].str=mystrmalloc(_("wW)hole sheet")); break;
 1019       default: assert(0);
 1020     }
 1021     menu[1].str=mystrmalloc(_("sS)ingle cell")); menu[1].c='\0';
 1022     menu[2].str=(char*)0;
 1023     r=line_menu(_("Delete:"),menu,0);
 1024     free(menu[0].str);
 1025     free(menu[1].str);
 1026     /*}}}*/
 1027     switch (r)
 1028     {
 1029       /*  0 -- use whole dimension */ /*{{{*/
 1030       case 0:
 1031       {
 1032         switch (reply)
 1033         {
 1034           /*  0 -- use whole column */ /*{{{*/
 1035           case 0:
 1036           {
 1037             x1=x2=sheet->curx;
 1038             y1=0; y2=sheet->dimy;
 1039             z1=z2=sheet->curz;
 1040             break;
 1041           }
 1042           /*}}}*/
 1043           /*  1 -- use whole line */ /*{{{*/
 1044           case 1:
 1045           {
 1046             x1=0; x2=sheet->dimx;
 1047             y1=y2=sheet->cury;
 1048             z1=z2=sheet->curz;
 1049             break;
 1050           }
 1051           /*}}}*/
 1052           /*  2 -- use whole layer */ /*{{{*/
 1053           case 2:
 1054           {
 1055             x1=0; x2=sheet->dimx;
 1056             y1=0; y2=sheet->dimy;
 1057             z1=z2=sheet->curz;
 1058             break;
 1059           }
 1060           /*}}}*/
 1061           /*  default -- should not happen */ /*{{{*/
 1062           default: assert(0);
 1063           /*}}}*/
 1064         }
 1065         break;
 1066       }
 1067       /*}}}*/
 1068       /*  1 -- use current cell */ /*{{{*/
 1069       case 1:
 1070       {
 1071         x1=x2=sheet->curx;
 1072         y1=y2=sheet->cury;
 1073         z1=z2=sheet->curz;
 1074         break;
 1075       }
 1076       /*}}}*/
 1077       /* -1 -- abort */ /*{{{*/
 1078       case -1: return -1;
 1079       /*}}}*/
 1080       /* -2 -- go back to previous menu */ /*{{{*/
 1081       case -2: goto firstmenu;
 1082       /*}}}*/
 1083       /* default -- should not happen */ /*{{{*/
 1084       default: assert(0);
 1085       /*}}}*/
 1086     }
 1087   }
 1088   /*}}}*/
 1089   else
 1090   /* range is the marked cube */ /*{{{*/
 1091   {
 1092       get_mark(sheet, &x1, &x2, &y1, &y2, &z1, &z2, 0);
 1093   }
 1094   /*}}}*/
 1095   switch(reply)
 1096   {
 1097     /*  0      -- columns */ /*{{{*/
 1098     case 0: deletecube(sheet,x1,y1,z1,x2,y2,z2,IN_X); break;
 1099     /*}}}*/
 1100     /*  1      -- rows */ /*{{{*/
 1101     case 1: deletecube(sheet,x1,y1,z1,x2,y2,z2,IN_Y); break;
 1102     /*}}}*/
 1103     /*  2      -- depth */ /*{{{*/
 1104     case 2: deletecube(sheet,x1,y1,z1,x2,y2,z2,IN_Z); break;
 1105     /*}}}*/
 1106   }
 1107   return -1;
 1108 }
 1109 /*}}}*/
 1110 /* do_move        -- copy or move a block */ /*{{{*/
 1111 static int do_move(Sheet *sheet, int copy, int force)
 1112 {
 1113   int c;
 1114 
 1115   c=-1;
 1116   if (sheet->mark1x==-1) line_msg(copy ? _("Copy block:") : _("Move block:"),_("No block marked"));
 1117   else if (force || (c=line_ok(copy ? _("Copy block:") : _("Move block:"),0))==1)
 1118   {
 1119     int x1,y1,z1;
 1120     int x2,y2,z2;
 1121 
 1122     get_mark(sheet, &x1, &x2, &y1, &y2, &z1, &z2, 0);
 1123     moveblock(sheet,x1,y1,z1,x2,y2,z2,sheet->curx,sheet->cury,sheet->curz,copy);
 1124     if (!copy) sheet->mark1x=-1;
 1125   }
 1126   if (c<0) return c; else return -1;
 1127 }
 1128 /*}}}*/
 1129 /* do_fill        -- fill a block */ /*{{{*/
 1130 static int do_fill(Sheet *sheet)
 1131 {
 1132   /* variables */ /*{{{*/
 1133   size_t offx,edx;
 1134   int cols,rows,layers;
 1135   int x,y,z;
 1136   int x1,y1,z1;
 1137   int x2,y2,z2;
 1138   int c;
 1139   /*}}}*/
 1140 
 1141   if (sheet->mark1x==-1) line_msg(_("Fill block:"),_("No block marked"));
 1142   else
 1143   {
 1144     get_mark(sheet, &x1, &x2, &y1, &y2, &z1, &z2, 0);
 1145     cols=rows=layers=1;
 1146     firstmenu:
 1147     offx=0;
 1148     edx=0;
 1149     do if ((c=line_numedit(&cols,_("Number of column-wise repetitions:"),&edx,&offx))<0) return c; while (cols<=0);
 1150     secondmenu:
 1151     offx=0;
 1152     edx=0;
 1153     do
 1154     {
 1155       c=line_numedit(&rows,_("Number of row-wise repetitions:"),&edx,&offx);
 1156       if (c==-1) return -1;
 1157       else if (c==-2) goto firstmenu;
 1158     } while (rows<=0);
 1159     offx=0;
 1160     edx=0;
 1161     do
 1162     {
 1163       c=line_numedit(&layers,_("Number of depth-wise repetitions:"),&edx,&offx);
 1164       if (c==-1) return -1;
 1165       else if (c==-2) goto secondmenu;
 1166     } while (layers<=0);
 1167     for (x=0; x<cols; ++x) for (y=0; y<rows; ++y) for (z=0; z<layers; ++z) moveblock(sheet,x1,y1,z1,x2,y2,z2,sheet->curx+x*(x2-x1+1),sheet->cury+y*(y2-y1+1),sheet->curz+z*(z2-z1+1),1);
 1168   }
 1169   return -1;
 1170 }
 1171 /*}}}*/
 1172 /* do_sort        -- sort block */ /*{{{*/
 1173 static int do_sort(Sheet *sheet)
 1174 {
 1175   /* variables */ /*{{{*/
 1176   MenuChoice menu1[4],menu2[3],menu3[3];
 1177   Sortkey sk[MAX_SORTKEYS];
 1178   unsigned int key;
 1179   size_t x,offx;
 1180   const char *msg;
 1181   Direction in_dir=(Direction)-2; /* cause run time error */
 1182   int x1,y1,z1,x2,y2,z2;
 1183   int doit=-1;
 1184   int c;
 1185   int last;
 1186   /*}}}*/
 1187 
 1188   /* note and order block coordinates */ /*{{{*/
 1189   get_mark(sheet, &x1, &x2, &y1, &y2, &z1, &z2, 1);
 1190   /*}}}*/
 1191   /* build menues */ /*{{{*/
 1192   menu1[0].str=mystrmalloc(_("cC)olumn"));     menu1[0].c='\0';
 1193   menu1[1].str=mystrmalloc(_("rR)ow"));     menu1[1].c='\0';
 1194   menu1[2].str=mystrmalloc(_("dD)epth"));     menu1[2].c='\0';
 1195   menu1[3].str=(char*)0;
 1196   menu2[0].str=mystrmalloc(_("sS)ort region"));  menu2[0].c='\0';
 1197   menu2[1].str=mystrmalloc(_("aA)dd key"));  menu2[1].c='\0';
 1198   menu2[2].str=(char*)0;
 1199   menu3[0].str=mystrmalloc(_("aA)scending"));  menu3[0].c='\0';
 1200   menu3[1].str=mystrmalloc(_("dD)escending")); menu3[0].c='\0';
 1201   menu3[2].str=(char*)0;
 1202   /*}}}*/
 1203 
 1204   last=-1;
 1205   /* ask for sort direction */ /*{{{*/
 1206   zero: switch (c=line_menu(_("Sort block:"),menu1,0))
 1207   {
 1208     /*  0      -- in X */ /*{{{*/
 1209     case 0: in_dir=IN_X; break;
 1210     /*}}}*/
 1211     /*  1      -- in Y */ /*{{{*/
 1212     case 1: in_dir=IN_Y; break;
 1213     /*}}}*/
 1214     /*  2      -- in Z */ /*{{{*/
 1215     case 2: in_dir=IN_Z; break;
 1216     /*}}}*/
 1217     /* -2,-1   -- abort */ /*{{{*/
 1218     case -2:
 1219     case -1: goto greak;
 1220     /*}}}*/
 1221     /* default -- should not happen */ /*{{{*/
 1222     default: assert(0);
 1223     /*}}}*/
 1224   }
 1225   last=0;
 1226   /*}}}*/
 1227   key=0;
 1228   do
 1229   {
 1230     /* ask for positions */ /*{{{*/
 1231     one: if (in_dir==IN_X) sk[key].x=0; else /* ask for x position */ /*{{{*/
 1232     {
 1233       x=0;
 1234       offx=0;
 1235       sk[key].x=0;
 1236       do
 1237       {
 1238         c=line_numedit(&(sk[key].x),_("X position of key vector:"),&x,&offx);
 1239         if (c==-1) goto greak;
 1240         else if (c==-2) switch (last)
 1241         {
 1242           case -1: goto greak;
 1243           case 0: goto zero;
 1244           case 2: goto two;
 1245           case 3: goto three;
 1246           case 5: goto five;
 1247         }
 1248       } while (sk[key].x<0);
 1249       last=1;
 1250     }
 1251     /*}}}*/
 1252     two: if (in_dir==IN_Y) sk[key].y=0; else /* ask for y position */ /*{{{*/
 1253     {
 1254       x=0;
 1255       offx=0;
 1256       sk[key].y=0;
 1257       do
 1258       {
 1259         c=line_numedit(&(sk[key].y),_("Y position of key vector:"),&x,&offx);
 1260         if (c==-1) goto greak;
 1261         else if (c==-2) switch (last)
 1262         {
 1263           case -1: goto greak;
 1264           case 0: goto zero;
 1265           case 1: goto one;
 1266           case 3: goto three;
 1267           case 5: goto five;
 1268           default: assert(0);
 1269         }
 1270       } while (sk[key].y<0);
 1271       last=2;
 1272     }
 1273     /*}}}*/
 1274     three: if (in_dir==IN_Z) sk[key].z=0; else /* ask for z position */ /*{{{*/
 1275     {
 1276       x=0;
 1277       offx=0;
 1278       sk[key].z=0;
 1279       do
 1280       {
 1281         c=line_numedit(&(sk[key].z),_("Z position of key vector:"),&x,&offx);
 1282         if (c==-1) goto greak;
 1283         else if (c==-2) switch (last)
 1284         {
 1285           case -1: goto greak;
 1286           case 0: goto zero;
 1287           case 1: goto one;
 1288           case 2: goto two;
 1289           case 5: goto five;
 1290           default: assert(0);
 1291         }
 1292       } while (sk[key].z<0);
 1293       last=3;
 1294     }
 1295     /*}}}*/
 1296     /*}}}*/
 1297     /* ask for sort key */ /*{{{*/
 1298     four: sk[key].sortkey=0;
 1299     switch (c=line_menu(_("Sort block:"),menu3,0))
 1300     {
 1301       /*  0      -- ascending */ /*{{{*/
 1302       case 0: sk[key].sortkey|=ASCENDING; break;
 1303       /*}}}*/
 1304       /*  1      -- descending */ /*{{{*/
 1305       case 1: sk[key].sortkey&=~ASCENDING; break;
 1306       /*}}}*/
 1307       /* -1      -- abort */ /*{{{*/
 1308       case -1: goto greak;
 1309       /*}}}*/
 1310       /* -2      -- go to first menu */ /*{{{*/
 1311       case -2: switch (last)
 1312       {
 1313         case -1: goto greak;
 1314         case 1: goto one;
 1315         case 2: goto two;
 1316         case 3: goto three;
 1317         default: assert(0);
 1318       }
 1319       /*}}}*/
 1320       /* default -- should not happen */ /*{{{*/
 1321       default: assert(0);
 1322       /*}}}*/
 1323     }
 1324     last=4;
 1325     /*}}}*/
 1326     ++key;
 1327     five:
 1328     if (key==MAX_SORTKEYS) /* ask for sort comfirmation */ /*{{{*/
 1329     {
 1330       c=line_ok(_("Sort block:"),0);
 1331       if (c==-1) goto greak;
 1332       else if (c==-2) goto four;
 1333       else if (c==0) doit=1;
 1334     }
 1335     /*}}}*/
 1336     else /* ask for sort or adding another key */ /*{{{*/
 1337     switch (line_menu(_("Sort block:"),menu2,0))
 1338     {
 1339       /*       0 -- sort it */ /*{{{*/
 1340       case 0: doit=1; break;
 1341       /*}}}*/
 1342       /*       1 -- add another key */ /*{{{*/
 1343       case 1: doit=0; break;
 1344       /*}}}*/
 1345       /*      -1 -- abort */ /*{{{*/
 1346       case -1: goto greak;
 1347       /*}}}*/
 1348       case -2: goto four;
 1349       /* default -- should not happen */ /*{{{*/
 1350       default: assert(0);
 1351       /*}}}*/
 1352     }
 1353     /*}}}*/
 1354     last=5;
 1355   } while (!doit);
 1356   c=-1;
 1357   if ((msg=sortblock(sheet,x1,y1,z1,x2,y2,z2,in_dir,sk,key))!=(const char*)0) line_msg(_("Sort block:"),msg);
 1358   greak:
 1359   /* free menues */ /*{{{*/
 1360   free((char*)menu1[0].str);
 1361   free((char*)menu1[1].str);
 1362   free((char*)menu1[2].str);
 1363   free((char*)menu2[0].str);
 1364   free((char*)menu2[1].str);
 1365   free((char*)menu2[2].str);
 1366   free((char*)menu3[0].str);
 1367   free((char*)menu3[1].str);
 1368   free((char*)menu3[2].str);
 1369   /*}}}*/
 1370   return c;
 1371 }
 1372 /*}}}*/
 1373 /* do_batchsort -- sort block in a batch*/ /*{{{*/
 1374 static void do_batchsort(Sheet *sheet, Direction dir, char* arg)
 1375 {
 1376   Sortkey sk[MAX_SORTKEYS];
 1377   int x1,y1,z1,x2,y2,z2;
 1378   unsigned int key = 0;
 1379   char* next;
 1380   while( *arg != '\0' )
 1381   {
 1382     while (isspace((int)*arg)) arg++;
 1383     sk[key].x=sk[key].y=sk[key].z=sk[key].sortkey=0;
 1384     switch (*arg)
 1385     {
 1386       case 'a': sk[key].sortkey|=ASCENDING; arg++; break;
 1387       case 'd': sk[key].sortkey&=~ASCENDING; arg++; break;
 1388     }
 1389     if ( *arg != '\0' && dir != IN_X ) { sk[key].x=strtol(arg, &next, 10); arg = next; }
 1390     if ( *arg != '\0' && dir != IN_Y ) { sk[key].y=strtol(arg, &next, 10); arg = next; }
 1391     if ( *arg != '\0' && dir != IN_Z ) { sk[key].z=strtol(arg, &next, 10); arg = next; }
 1392     key++;
 1393   }
 1394   get_mark(sheet, &x1, &x2, &y1, &y2, &z1, &z2, 1);
 1395   sortblock(sheet, x1, y1, z1, x2, y2, z2, dir, sk, key);
 1396 }
 1397 /*}}}*/
 1398 /* do_mirror      -- mirror block */ /*{{{*/
 1399 static int do_mirror(Sheet *sheet)
 1400 {
 1401   /* variables */ /*{{{*/
 1402   int x1,y1,z1,x2,y2,z2,reply;
 1403   /*}}}*/
 1404 
 1405   /* note and order block coordinates */ /*{{{*/
 1406   get_mark(sheet, &x1, &x2, &y1, &y2, &z1, &z2, 1);
 1407   /*}}}*/
 1408   /* ask for direction of mirroring */ /*{{{*/
 1409   {
 1410     MenuChoice menu[4];
 1411 
 1412     menu[0].str=mystrmalloc(_("lL)eft-right")); menu[0].c='\0';
 1413     menu[1].str=mystrmalloc(_("uU)pside-down")); menu[1].c='\0';
 1414     menu[2].str=mystrmalloc(_("fF)ront-back")); menu[2].c='\0';
 1415     menu[3].str=(char*)0;
 1416     reply=line_menu(_("Mirror block:"),menu,0);
 1417     free(menu[0].str);
 1418     free(menu[1].str);
 1419     free(menu[2].str);
 1420     if (reply<0) return reply;
 1421   }
 1422   /*}}}*/
 1423   switch (reply)
 1424   {
 1425     /*  0      -- left-right */ /*{{{*/
 1426     case 0: mirrorblock(sheet,x1,y1,z1,x2,y2,z2,IN_X); break;
 1427     /*}}}*/
 1428     /*  1      -- upside-down */ /*{{{*/
 1429     case 1: mirrorblock(sheet,x1,y1,z1,x2,y2,z2,IN_Y); break;
 1430     /*}}}*/
 1431     /*  2      -- front-back */ /*{{{*/
 1432     case 2: mirrorblock(sheet,x1,y1,z1,x2,y2,z2,IN_Z); break;
 1433     /*}}}*/
 1434     default: assert(0);
 1435   }
 1436   return 0;
 1437 }
 1438 /*}}}*/
 1439 /* do_goto        -- go to a specific cell */ /*{{{*/
 1440 static int do_goto(Sheet *sheet, const char *expr)
 1441 {
 1442   /* variables */ /*{{{*/
 1443   char buf[1024];
 1444   const char *s;
 1445   size_t x,offx;
 1446   Token **t;
 1447   int c;
 1448   /*}}}*/
 1449 
 1450   assert(sheet!=(Sheet*)0);
 1451   buf[0]='\0';
 1452   x=offx=0;
 1453   if (expr) strcpy(buf,expr);
 1454   else if ((c=line_edit(sheet,buf,sizeof(buf),_("Go to location:"),&x,&offx))<0) return c;
 1455   s=buf;
 1456   t=scan(&s);
 1457   if (t!=(Token**)0)
 1458   {
 1459     Token value;
 1460 
 1461     upd_x=sheet->curx;
 1462     upd_y=sheet->cury;
 1463     upd_z=sheet->curz;
 1464     upd_sheet=sheet;
 1465     value=eval(t);
 1466     tvecfree(t);
 1467     if (value.type==LOCATION && value.u.location[0]>=0 && value.u.location[1]>=0 && value.u.location[2]>=0)
 1468         moveto(sheet,value.u.location[0],value.u.location[1],value.u.location[2]);
 1469     else
 1470         line_msg(_("Go to location:"),_("Not a valid location"));
 1471     tfree(&value);
 1472   }
 1473   return -1;
 1474 }
 1475 /*}}}*/
 1476 
 1477 /* do_sheetcmd    -- process one key press */ /*{{{*/
 1478 int do_sheetcmd(Sheet *cursheet, Key c, int moveonly)
 1479 {
 1480   switch ((int)c)
 1481   {
 1482     case K_GOTO: do_goto(cursheet, (const char *)0); break;
 1483     case K_COLWIDTH: do_columnwidth(cursheet); break;
 1484     case BLOCK_CLEAR: do_clear(cursheet); redraw_sheet(cursheet); break;
 1485     case BLOCK_INSERT: do_insert(cursheet); redraw_sheet(cursheet); break;
 1486     case BLOCK_DELETE: do_delete(cursheet); redraw_sheet(cursheet); break;
 1487     case BLOCK_MOVE: do_move(cursheet,0,0); redraw_sheet(cursheet); break;
 1488     case BLOCK_COPY: do_move(cursheet,1,0); redraw_sheet(cursheet); break;
 1489     case BLOCK_FILL: do_fill(cursheet); redraw_sheet(cursheet); break;
 1490     case BLOCK_SORT: do_sort(cursheet); redraw_sheet(cursheet); break;
 1491     case BLOCK_MIRROR: do_mirror(cursheet); redraw_sheet(cursheet); break;
 1492     case ADJUST_LEFT:
 1493     case ADJUST_RIGHT:
 1494     case ADJUST_CENTER:
 1495     case ADJUST_SCIENTIFIC:
 1496     case ADJUST_PRECISION:
 1497     case ADJUST_SHADOW:
 1498     case ADJUST_BOLD:
 1499     case ADJUST_UNDERLINE:
 1500     case ADJUST_TRANSPARENT:
 1501     case ADJUST_LABEL:
 1502     case ADJUST_LOCK:
 1503     case ADJUST_IGNORE: do_attribute(cursheet, c); break;
 1504     /* UP         -- move up */ /*{{{*/
 1505     case K_UP:
 1506     {
 1507       relmoveto(cursheet, 0, -1, 0);
 1508       break;
 1509     }
 1510     /*}}}*/
 1511     /* DOWN       -- move down */ /*{{{*/
 1512     case K_DOWN:
 1513     {
 1514       relmoveto(cursheet, 0, 1, 0);
 1515       break;
 1516     }
 1517     /*}}}*/
 1518     /* LEFT       -- move left */ /*{{{*/
 1519     case K_LEFT:
 1520     {
 1521       relmoveto(cursheet, -1, 0, 0);
 1522       break;
 1523     }
 1524     /*}}}*/
 1525     /* RIGHT      -- move right */ /*{{{*/
 1526     case K_RIGHT:
 1527     {
 1528       relmoveto(cursheet, 1, 0, 0);
 1529       break;
 1530     }
 1531     /*}}}*/
 1532     /* FIRSTL     -- move to first line */ /*{{{*/
 1533     case K_FIRSTL:
 1534     case '<':
 1535     {
 1536       moveto(cursheet, -1, 0, -1);
 1537       break;
 1538     }
 1539     /*}}}*/
 1540     /* LASTL      -- move to last line */ /*{{{*/
 1541     case K_LASTL:
 1542     case '>':
 1543     {
 1544       moveto(cursheet, -1, (cursheet->dimy ? cursheet->dimy-1 : 0), -1);
 1545       break;
 1546     }
 1547     /*}}}*/
 1548     /* HOME       -- move to beginning of line */ /*{{{*/
 1549     case K_HOME:
 1550     {
 1551       moveto(cursheet, 0, -1, -1);
 1552       break;
 1553     }
 1554     /*}}}*/
 1555     /* END        -- move to end of line */ /*{{{*/
 1556     case K_END:
 1557     {
 1558       moveto(cursheet, (cursheet->dimx ? cursheet->dimx-1 : 0), -1, -1);
 1559       break;
 1560     }
 1561     /*}}}*/
 1562     /* +          -- move one sheet down */ /*{{{*/
 1563     case K_NSHEET:
 1564     case '+':
 1565     {
 1566       relmoveto(cursheet, 0, 0, 1);
 1567       break;
 1568     }
 1569     /*}}}*/
 1570     /* -          -- move one sheet up */ /*{{{*/
 1571     case K_PSHEET:
 1572     case '-':
 1573     {
 1574       relmoveto(cursheet, 0, 0, -1);
 1575       break;
 1576     }
 1577     /*}}}*/
 1578     /* *          -- move to bottom sheet */ /*{{{*/
 1579     case K_LSHEET:
 1580     case '*':
 1581     {
 1582       moveto(cursheet, -1, -1, (cursheet->dimz ? cursheet->dimz-1 : 0));
 1583       break;
 1584     }
 1585     /*}}}*/
 1586     /* _          -- move to top sheet */ /*{{{*/
 1587     case K_FSHEET:
 1588     case '_':
 1589     {
 1590       moveto(cursheet, -1, -1, 0);
 1591       break;
 1592     }
 1593     /*}}}*/
 1594     /* ENTER      -- edit current cell */ /*{{{*/
 1595     case K_ENTER: if (moveonly) break; do_edit(cursheet,'\0',(const char*)0,0); break;
 1596     /*}}}*/
 1597     /* MENTER     -- edit current clocked cell */ /*{{{*/
 1598     case K_MENTER: if (moveonly) break; do_edit(cursheet,'\0',(const char*)0,1); break;
 1599     /*}}}*/
 1600     /* ", @, digit -- edit current cell with character already in buffer */ /*{{{*/
 1601     case K_BACKSPACE:
 1602     case K_DC:
 1603     case '"':
 1604     case '@':
 1605     case '0':
 1606     case '1':
 1607     case '2':
 1608     case '3':
 1609     case '4':
 1610     case '5':
 1611     case '6':
 1612     case '7':
 1613     case '8':
 1614     case '9': if (moveonly) break; do_edit(cursheet,c,(const char*)0,0); break;
 1615     /*}}}*/
 1616     /* MARK       -- toggle block marking */ /*{{{*/
 1617     case '.':
 1618     case K_MARK: if (moveonly) break; do_mark(cursheet,0); break;
 1619     /*}}}*/
 1620     /* _("Save sheet file format:")   -- save menu */ /*{{{*/
 1621     case K_SAVEMENU: if (moveonly) break; do_save(cursheet); break;
 1622     /*}}}*/
 1623     /* _("Load sheet file format:")   -- load menu */ /*{{{*/
 1624     case K_LOAD:
 1625     case K_LOADMENU: if (moveonly) break; do_load(cursheet); break;
 1626     /*}}}*/
 1627     /* _("nN)ame")       -- set name */ /*{{{*/
 1628     case K_NAME: if (moveonly) break; do_name(cursheet); break;
 1629     /*}}}*/
 1630 #ifdef ENABLE_HELP
 1631     case K_HELP: show_text(helpfile); break;
 1632 #else
 1633     case K_HELP: show_text(_("Sorry, manual is not installed.")); break;
 1634 #endif
 1635     case K_ABOUT: show_text(_("<html><head><title>About teapot</title></head><body><center><pre>\n\n"
 1636         "               ` ',`    '  '                   \n"
 1637         "                `   '  ` ' '                   \n"
 1638         "                 `' '   '`'                    \n"
 1639         "                 ' `   ' '`                    \n"
 1640         "    '           '` ' ` '`` `                   \n"
 1641         "    `.   Table Editor And Planner, or:         \n"
 1642         "      ,         . ,   ,  . .                   \n"
 1643         "                ` '   `  ' '                   \n"
 1644         "     `::\\    /:::::::::::::::::\\   ___         \n"
 1645         "      `::\\  /:::::::::::::::::::\\,'::::\\       \n"
 1646         "       :::\\/:::::::::::::::::::::\\/   \\:\\      \n"
 1647         "       :::::::::::::::::::::::::::\\    :::     \n"
 1648         "       ::::::::::::::::::::::::::::;  /:;'     \n"
 1649         "       `::::::::::::::::::::::::::::_/:;'      \n"
 1650         "         `::::::::::::::::::::::::::::'        \n"
 1651         "          `////////////////////////'           \n"
 1652         "           `:::::::::::::::::::::'             \n"
 1653         "</pre>\n"
 1654         "<p>Teapot " VERSION "</p>\n"
 1655         "\n"
 1656         "<p>Original Version: Michael Haardt<br>\n"
 1657         "Current Maintainer: Joerg Walter<br>\n"
 1658         "Home Page: <a href='http://www.syntax-k.de/projekte/teapot/'>http://www.syntax-k.de/projekte/teapot/</a></p>\n"
 1659         "\n"
 1660         "<p>Copyright 1995-2006 Michael Haardt,<br>\n"
 1661         "Copyright 2009-2010 Joerg Walter (<a href='mailto:info@syntax-k.de'>info@syntax-k.de</a>)</p></center>\n"
 1662         "\f"
 1663         "<p>This program is free software: you can redistribute it and/or modify\n"
 1664         "it under the terms of the GNU General Public License as published by\n"
 1665         "the Free Software Foundation, either version 3 of the License, or\n"
 1666         "(at your option) any later version.</p>\n"
 1667         "\n"
 1668         "<p>This program is distributed in the hope that it will be useful,\n"
 1669         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
 1670         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
 1671         "GNU General Public License for more details.</p>\n"
 1672         "\n"
 1673         "<p>You should have received a copy of the GNU General Public License\n"
 1674         "along with this program.  If not, see <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.</p>"
 1675         "</body></html>"));
 1676         break;
 1677     /* MENU, / -- main menu */ /*{{{*/
 1678     case '/': if (!moveonly && do_sheetcmd(cursheet, show_menu(cursheet), 0)) return 1; break;
 1679     /*}}}*/
 1680     /* _("sS)ave")       -- save in current native format */ /*{{{*/
 1681     case K_SAVE: do_save(cursheet); break;
 1682     /*}}}*/
 1683     /* _("cC)opy")       -- copy block */ /*{{{*/
 1684     case K_COPY: if (moveonly) break; do_move(cursheet,1,1); break;
 1685     /*}}}*/
 1686     /* RECALC     -- recalculate */ /*{{{*/
 1687     case K_RECALC: if (moveonly) break; forceupdate(cursheet); break;
 1688     /*}}}*/
 1689     /* _("Usage: clock(condition,location[,location])")      -- clock */ /*{{{*/
 1690     case K_CLOCK:
 1691     {
 1692       int x,y,z;
 1693 
 1694       for (x=0; x<cursheet->dimx; ++x)
 1695       for (y=0; y<cursheet->dimy; ++y)
 1696       for (z=0; z<cursheet->dimz; ++z)
 1697       clk(cursheet,x,y,z);
 1698       update(cursheet);
 1699       break;
 1700     }
 1701     /*}}}*/
 1702     /* NPAGE      -- page down    */ /*{{{*/
 1703     case K_NPAGE:
 1704     {
 1705       cursheet->offy+=(cursheet->maxy-3);
 1706       relmoveto(cursheet, 0, cursheet->maxy-3, 0);
 1707       break;
 1708     }
 1709     /*}}}*/
 1710     /* PPAGE      -- page up    */ /*{{{*/
 1711     case K_PPAGE:
 1712     {
 1713       cursheet->offy = (cursheet->offy>=(cursheet->maxy-3) ? cursheet->offy-(cursheet->maxy-3) : 0);
 1714       relmoveto(cursheet, 0, (cursheet->cury>=(cursheet->maxy-3) ? -(cursheet->maxy-3) : -cursheet->cury), 0);
 1715       break;
 1716     }
 1717     /*}}}*/
 1718     /* FPAGE      -- page right    */ /*{{{*/
 1719     case K_FPAGE:
 1720     {
 1721       cursheet->offx+=cursheet->width;
 1722       relmoveto(cursheet, cursheet->width, 0, 0);
 1723       break;
 1724     }
 1725     /*}}}*/
 1726     /* BPAGE      -- page left */ /*{{{*/
 1727     case K_BPAGE:
 1728     {
 1729       cursheet->offx=(cursheet->offx>=cursheet->width ? cursheet->offx-cursheet->width : 0);
 1730       relmoveto(cursheet, (cursheet->curx>=cursheet->width ? -cursheet->width : -cursheet->curx), 0, 0);
 1731       break;
 1732     }
 1733     /*}}}*/
 1734     /* SAVEQUIT   -- save and quit */ /*{{{*/
 1735     case K_SAVEQUIT:
 1736     {
 1737       if (moveonly) break;
 1738       if (do_save(cursheet)!=-2) return 1;
 1739       break;
 1740     }
 1741     /*}}}*/
 1742     /* _("qQ)uit")       -- quit */ /*{{{*/
 1743     case K_QUIT: if (moveonly) break; return 1;
 1744     /*}}}*/
 1745     default:
 1746         if (isalpha(c) && !moveonly) do_edit(cursheet,c,(const char*)0,0);
 1747         break;
 1748   }
 1749   return 0;
 1750 }
 1751 /*}}}*/
 1752 
 1753 /* main */ /*{{{*/
 1754 int main(int argc, char *argv[])
 1755 {
 1756   /* variables */ /*{{{*/
 1757   Sheet sheet,*cursheet;
 1758   int o;
 1759   const char *loadfile;
 1760   int always_redraw=0;
 1761   char ln[1024];
 1762   /*}}}*/
 1763 
 1764   setlocale(LC_ALL, "");
 1765   find_helpfile(helpfile, sizeof(helpfile), argv[0]);
 1766 
 1767   /* parse options */ /*{{{*/
 1768   while ((o=getopt(argc,argv,"abhnrqHp:?"))!=EOF) switch (o)
 1769   {
 1770     /* a       -- use ascii as default */ /*{{{*/
 1771     case 'a':
 1772     {
 1773       usexdr=0;
 1774       break;
 1775     }
 1776     /*}}}*/
 1777     /* b       -- run batch */ /*{{{*/
 1778     case 'b': batch=1; break;
 1779     /*}}}*/
 1780     /* n       -- no quoted strings */ /*{{{*/
 1781     case 'n': quote=0; break;
 1782     /*}}}*/
 1783     /* q       -- force quoted strings */ /*{{{*/
 1784     case 'q': quote=1; break;
 1785     /*}}}*/
 1786     /* H       -- no row/column headers */ /*{{{*/
 1787     case 'H': header=0; break;
 1788     /*}}}*/
 1789     /* r       -- always redraw */ /*{{{*/
 1790     case 'r':
 1791     {
 1792       always_redraw=1;
 1793       break;
 1794     }
 1795     /*}}}*/
 1796     /* p       -- precision */ /*{{{*/
 1797     case 'p':
 1798     {
 1799       long n;
 1800       char *end;
 1801 
 1802       n=strtol(optarg,&end,0);
 1803       if (*end || n<0 || n>DBL_DIG)
 1804       {
 1805         fprintf(stderr,_("teapot: precision must be between 0 and %d.\n"),DBL_DIG);
 1806         exit(1);
 1807       }
 1808       def_precision=n;
 1809       break;
 1810     }
 1811     /*}}}*/
 1812     /* default -- includes ? and h */ /*{{{*/
 1813     default:
 1814     {
 1815       fprintf(stderr,_(
 1816           "Usage: %s [-a] [-b] [-n] [-H] [-r] [-p digits] [file]\n"
 1817           "       -a: use ASCII file format as default\n"
 1818           "       -b: batch mode\n"
 1819           "       -q: display strings in quotes\n"
 1820           "       -H: hide row/column headers\n"
 1821           "       -r: redraw more often\n"
 1822           "       -p: set decimal precision\n"
 1823           ), argv[0]);
 1824       exit(1);
 1825     }
 1826     /*}}}*/
 1827   }
 1828   loadfile=(optind<argc ? argv[optind] : (const char*)0);
 1829   /*}}}*/
 1830   /* create empty sheet */ /*{{{*/
 1831   cursheet=&sheet;
 1832   cursheet->curx=cursheet->cury=cursheet->curz=0;
 1833   cursheet->offx=cursheet->offy=0;
 1834   cursheet->dimx=cursheet->dimy=cursheet->dimz=0;
 1835   cursheet->sheet=(Cell**)0;
 1836   cursheet->column=(int*)0;
 1837   cursheet->orix=0;
 1838   cursheet->oriy=0;
 1839   cursheet->maxx=0;
 1840   cursheet->maxy=0;
 1841   cursheet->name=(char*)0;
 1842   cursheet->mark1x=-1;
 1843   cursheet->marking=0;
 1844   cursheet->changed=0;
 1845   cursheet->moveonly=0;
 1846   cursheet->clk=0;
 1847   (void)memset(cursheet->labelcache,0,sizeof(cursheet->labelcache));
 1848   /*}}}*/
 1849   /* start display */ /*{{{*/
 1850   if (!batch) {
 1851     display_init(&sheet, always_redraw);
 1852     line_msg((const char*)0,"");
 1853   }
 1854   /*}}}*/
 1855   if (loadfile) /* load given sheet */ /*{{{*/
 1856   {
 1857     const char *msg;
 1858 
 1859     cursheet->name=mystrmalloc(loadfile);
 1860     if (usexdr)
 1861     {
 1862       if ((msg=loadxdr(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from XDR file:"),msg);
 1863     }
 1864     else
 1865     {
 1866       if ((msg=loadport(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from ASCII file:"),msg);
 1867     }
 1868   }
 1869   /*}}}*/
 1870   if (batch) /* process batch */ /*{{{*/
 1871   while (fgets(ln,sizeof(ln),stdin)!=(char*)0)
 1872   {
 1873     /* variables */ /*{{{*/
 1874     size_t len;
 1875     char *cmd,*arg;
 1876     /*}}}*/
 1877 
 1878     /* set cmd and arg */ /*{{{*/
 1879     ++batchln;
 1880     len=strlen(ln);
 1881     if (len && ln[len-1]=='\n') ln[len-1]='\0';
 1882     cmd=ln; while (isspace((int)*cmd)) ++cmd;
 1883     arg=cmd;
 1884     while (*arg && !isspace((int)*arg)) ++arg;
 1885     while (isspace((int)*arg)) *arg++='\0';
 1886     /*}}}*/
 1887 
 1888     /* goto location */ /*{{{*/
 1889     if (strcmp(cmd,"goto")==0) do_goto(cursheet,arg);
 1890     /*}}}*/
 1891     /* from location */ /*{{{*/
 1892     else if (strcmp(cmd,"from")==0)
 1893     {
 1894       do_goto(cursheet,arg);
 1895       do_mark(cursheet,1);
 1896     }
 1897     /*}}}*/
 1898     /* to location */ /*{{{*/
 1899     else if (strcmp(cmd,"to")==0)
 1900     {
 1901       do_goto(cursheet,arg);
 1902       do_mark(cursheet,2);
 1903     }
 1904     /*}}}*/
 1905     /* save-tbl file  */ /*{{{*/
 1906     else if (strcmp(cmd,"save-tbl")==0) do_savetbl(cursheet,arg);
 1907     /*}}}*/
 1908     /* save-latex file  */ /*{{{*/
 1909     else if (strcmp(cmd,"save-latex")==0) do_savelatex(cursheet,arg);
 1910     /*}}}*/
 1911     /* save-context file  */ /*{{{*/
 1912     else if (strcmp(cmd,"save-context")==0) do_savecontext(cursheet,arg);
 1913     /*}}}*/
 1914     /* save-csv file  */ /*{{{*/
 1915     else if (strcmp(cmd,"save-csv")==0) do_savecsv(cursheet,arg);
 1916     /*}}}*/
 1917     /* save-html file  */ /*{{{*/
 1918     else if (strcmp(cmd,"save-html")==0) do_savehtml(cursheet,arg);
 1919     /*}}}*/
 1920     /* load-csv file  */ /*{{{*/
 1921     else if (strcmp(cmd,"load-csv")==0) { loadcsv(cursheet,arg); forceupdate(cursheet); }
 1922     /*}}}*/
 1923     /* sort in x direction */ /*{{{*/
 1924     else if (strcmp(cmd,"sort-x")==0) do_batchsort(cursheet, IN_X, arg);
 1925     /*}}}*/
 1926     /* sort in y direction */ /*{{{*/
 1927     else if (strcmp(cmd,"sort-y")==0) do_batchsort(cursheet, IN_Y, arg);
 1928     /*}}}*/
 1929     /* sort in z direction */ /*{{{*/
 1930     else if (strcmp(cmd,"sort-z")==0) do_batchsort(cursheet, IN_Z, arg);
 1931     /*}}}*/
 1932     /* this is an unknown command */ /*{{{*/
 1933     else line_msg(_("Unknown batch command:"),cmd);
 1934     /*}}}*/
 1935   }
 1936   /*}}}*/
 1937   else /* process interactive input */ /*{{{*/
 1938   {
 1939     display_main(cursheet);
 1940     display_end();
 1941   }
 1942   /*}}}*/
 1943   freesheet(cursheet,1);
 1944   fclose(stdin);
 1945   return 0;
 1946 }
 1947 /*}}}*/