home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Science / Science.zip / OS2SCALC.ZIP / SC.C < prev    next >
C/C++ Source or Header  |  1990-07-20  |  23KB  |  1,063 lines

  1. /*    SC    A Spreadsheet Calculator
  2.  *        Main driver
  3.  *
  4.  *        original by James Gosling, September 1982
  5.  *        modifications by Mark Weiser and Bruce Israel,
  6.  *            University of Maryland
  7.  *
  8.  *              More mods Robert Bond, 12/86
  9.  *        Major mods to run on VMS and AMIGA, 1/17/87
  10.  *   OS/2 Modifications by Brady Flowers, 7/19/90
  11.  *
  12.  */
  13.  
  14. #include "sc.h"
  15.  
  16. #ifdef OS2
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <stdarg.h>
  20. #include <ctype.h>
  21. #include <process.h>
  22. #include "curs.h"
  23. #else
  24. extern char *malloc();
  25. #endif
  26.  
  27. /* default column width */
  28.  
  29. #define DEFWIDTH 10
  30. #define DEFPREC   2
  31.  
  32. #define RESCOL 4  /* columns reserved for row numbers */
  33. #define RESROW 3  /* rows reserved for prompt, error, and column numbers */
  34.  
  35. char curfile[1024];
  36.  
  37. int showme = 1;  /* 1 to display the current cell in the top line */
  38. int batch = 0;
  39.  
  40.  
  41. #ifdef OS2
  42.  
  43. VOID error(char *fmt, ...)
  44. {
  45.   va_list args;
  46.  
  47.   va_start(args, fmt);
  48.   if (batch)
  49.     vfprintf(stderr, fmt, args);
  50.   else
  51.   {
  52.       move (1,0);
  53.       clrtoeol ();
  54.       vprintw(fmt, args);
  55.   }
  56. }
  57.  
  58. static int shell(void);
  59.  
  60. static int shell()
  61. {
  62.   char *comspec;
  63.  
  64.   if (comspec = getenv("COMSPEC"))
  65.   {
  66.     if (spawnl(P_WAIT, comspec, comspec, "/k (cls & echo Type EXIT to return to spreadsheet)", NULL) == -1)
  67.       error("Error executing command processor");
  68.     else
  69.       return 0;
  70.   }
  71.   else
  72.     error("Cannot locate command processor");
  73.  
  74.   return -1;
  75. }
  76.  
  77. #else
  78.  
  79. VOID error(fmt,a,b,c,d,e)
  80. {
  81.  
  82.   if (batch)
  83.     fprintf(stderr,fmt,a,b,c,d,e);
  84.   else
  85.   {
  86.       move (1,0);
  87.       clrtoeol ();
  88.       printw (fmt,a,b,c,d,e);
  89.   }
  90. }
  91.  
  92. #endif
  93.  
  94.  
  95. int seenerr;
  96.  
  97. VOID yyerror (err)
  98. char *err;
  99. {
  100.   if (seenerr) return;
  101.   seenerr++;
  102.   move (1,0);
  103.   clrtoeol ();
  104.   printw ("%s: %.*s <= %s",err,linelim,line,line+linelim);
  105. }
  106.  
  107.  
  108.  
  109.  
  110. struct ent *lookat(row,col)
  111. {
  112.   register struct ent **p;
  113.  
  114.   if (row < 0)
  115.       row = 0;
  116.   else if (row > MAXROWS-1)
  117.       row = MAXROWS-1;
  118.  
  119.   if (col < 0)
  120.       col = 0;
  121.   else if (col > MAXCOLS-1)
  122.       col = MAXCOLS-1;
  123.  
  124.   p = &tbl[row][col];
  125.   if (*p==0)
  126.   {
  127.       *p = (struct ent *) malloc (sizeof (struct ent));
  128.       if (row>maxrow) maxrow = row;
  129.       if (col>maxcol) maxcol = col;
  130.       (*p)->label = 0;
  131.       (*p)->flags = 0;
  132.       (*p)->row = row;
  133.       (*p)->col = col;
  134.       (*p)->expr = 0;
  135.       (*p)->v = (double) 0.0;
  136.   }
  137.   else if ((*p)->flags & is_deleted)
  138.       debug("But %s%d has been deleted!", coltoa(col), row);
  139.  
  140.   return *p;
  141. }
  142.  
  143.  
  144. /*
  145.  * This structure is used to keep ent structs around before they
  146.  * are deleted to allow the sync_refs routine a chance to fix the
  147.  * variable references.
  148.  * We also use it as a last-deleted buffer for the 'p' command.
  149.  */
  150.  
  151. VOID free_ent(p)
  152. register struct ent *p;
  153. {
  154.   p->next = to_fix;
  155.   to_fix = p;
  156.   p->flags |= is_deleted;
  157. }
  158.  
  159.  
  160.  
  161. VOID flush_saved()
  162. {
  163.   register struct ent *p;
  164.   register struct ent *q;
  165.  
  166.   if (!(p = to_fix))
  167.       return;
  168.   while (p)
  169.   {
  170.       clearent(p);
  171.       q = p->next;
  172.       free(p);
  173.       p = q;
  174.   }
  175.   to_fix = 0;
  176. }
  177.  
  178.  
  179.  
  180. VOID update()
  181. {
  182.   register    row,
  183.               col;
  184.   register struct ent **p;
  185.   static  lastmx,
  186.           lastmy;
  187.   static  char *under_cursor = " ";
  188.   int     maxcol;
  189.   int     maxrow;
  190.   int     rows;
  191.   int     cols;
  192.   register r;
  193.  
  194.   while (hidden_row[currow])   /* You can't hide the last row or col */
  195.       currow++;
  196.   while (hidden_col[curcol])
  197.       curcol++;
  198.   if (curcol < stcol)
  199.       stcol = curcol, FullUpdate++;
  200.   if (currow < strow)
  201.       strow = currow, FullUpdate++;
  202.  
  203.   while (1)
  204.   {
  205.       register    i;
  206.       for (i = stcol, cols = 0, col = RESCOL;
  207.          (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++)
  208.     {
  209.         cols++;
  210.         if (hidden_col[i])
  211.             continue;
  212.         col += fwidth[i];
  213.       }
  214.       if (curcol >= stcol + cols)
  215.         stcol++, FullUpdate++;
  216.       else
  217.         break;
  218.   }
  219.  
  220.   while (1)
  221.   {
  222.       register    i;
  223.       for (i = strow, rows = 0, row = RESROW;
  224.          row < ROWS && i < MAXROWS; i++)
  225.     {
  226.         rows++;
  227.         if (hidden_row[i])
  228.             continue;
  229.         row++;
  230.       }
  231.       if (currow >= strow + rows)
  232.         strow++, FullUpdate++;
  233.       else
  234.         break;
  235.   }
  236.  
  237.   maxcol = stcol + cols - 1;
  238.   maxrow = strow + rows - 1;
  239.   if (FullUpdate)
  240.   {
  241.       register int i;
  242.  
  243.       move (2, 0);
  244.       clrtobot ();
  245.       standout();
  246.       for (row=RESROW, i=strow; i <= maxrow; i++)
  247.     {
  248.         if (hidden_row[i])
  249.             continue;
  250.         move(row,0);
  251.         printw("%-*d", RESCOL, i);
  252.         row++;
  253.       }
  254.       move (2,0);
  255.       printw("%*s", RESCOL, " ");
  256.       for (col=RESCOL, i = stcol; i <= maxcol; i++)
  257.     {
  258.         if (hidden_col[i])
  259.             continue;
  260.         move(2, col);
  261.         printw("%*s", fwidth[i], coltoa(i));
  262.         col += fwidth[i];
  263.       }
  264.       standend();
  265.   }
  266.   for (row = strow, r = RESROW; row <= maxrow; row++)
  267.   {
  268.       register    c = RESCOL;
  269.       if (hidden_row[row])
  270.         continue;
  271.       for (p = &tbl[row][col = stcol]; col <= maxcol; col++, p++)
  272.     {
  273.         if (hidden_col[col])
  274.             continue;
  275.         if (*p && ((*p) -> flags & is_changed || FullUpdate))
  276.       {
  277.             char   *s;
  278.  
  279.             move (r, c);
  280.             (*p) -> flags &= ~is_changed;
  281.             if ((*p) -> flags & is_valid)
  282.               printw ("%*.*f", fwidth[col], precision[col], (*p) -> v);
  283.             if (s = (*p) -> label)
  284.         {
  285.               char field[1024];
  286.  
  287.               strncpy(field,s,fwidth[col]);
  288.               field[fwidth[col]] = 0;
  289.               move (r,(*p) -> flags & is_leftflush
  290.                   ? c : c - strlen (field) + fwidth[col]);
  291.               addstr(field);
  292.             }
  293.         }
  294.         c += fwidth[col];
  295.       }
  296.  
  297.       r++;
  298.   }
  299.  
  300.   move(lastmy, lastmx);
  301.   if (inch() == '<')
  302.     addstr (under_cursor);
  303.  
  304.   lastmy =  RESROW;
  305.   for (row = strow; row < currow; row++)
  306.       if (!hidden_row[row])
  307.           lastmy += 1;
  308.  
  309.   lastmx = RESCOL;
  310.   for (col = stcol; col <= curcol; col++)
  311.       if (!hidden_col[col])
  312.           lastmx += fwidth[col];
  313.  
  314.   move(lastmy, lastmx);
  315.   *under_cursor = inch();
  316.   addstr ("<");
  317.   move (0, 0);
  318.   clrtoeol ();
  319.   if (linelim >= 0)
  320.   {
  321.       addstr (">> ");
  322.       addstr (line);
  323.   }
  324.   else
  325.   {
  326.       if (showme)
  327.     {
  328.         register struct ent *p;
  329.  
  330.         p = tbl[currow][curcol];
  331.         if (p && ((p->flags & is_valid) || p->label))
  332.       {
  333.             if (p->expr || !p->label)
  334.         {
  335.               linelim = 0;
  336.               editexp(currow, curcol);
  337.             }
  338.         else
  339.         {
  340.               sprintf(line, "%s", p->label);
  341.             }
  342.             addstr("[");
  343.             addstr (line);
  344.             addstr("]");
  345.             linelim = -1;
  346.         }
  347.       else
  348.       {
  349.             addstr("[]");
  350.         }
  351.       }
  352.       move (lastmy, lastmx);
  353.   }
  354.  
  355.   FullUpdate = 0;
  356. }
  357.  
  358.  
  359.  
  360. void quit()
  361. {
  362.   endwin ();
  363.  
  364. #ifdef OS2
  365.   exit(0);
  366. #else
  367.   exit();
  368. #endif
  369. }
  370.  
  371.  
  372.  
  373. int main (argc, argv)
  374. char  **argv;
  375. {
  376.   int      inloop = 1;
  377.   register int   c;
  378.   int      edistate = -1;
  379.   int      arg = 1;
  380.   int      narg;
  381.   int      nedistate = -1;
  382.   int         running = 1;
  383.  
  384.   {
  385.       register  i;
  386.  
  387.       for (i = 0; i < MAXCOLS; i++)
  388.     {
  389.         fwidth[i] = DEFWIDTH;
  390.         precision[i] = DEFPREC;
  391.       }
  392.   }
  393.  
  394.   linelim = -1;
  395.   curfile[0]=0;
  396.   running = 1;
  397.  
  398.  
  399. #ifdef OS2
  400.  
  401.   // Parse the extended OS/2 command line.
  402.   {
  403.     register char *cp;
  404.  
  405.     for (c = 1; c < argc;)
  406.     {
  407.       if ((argv[c][0] == '-') || (argv[c][0] == '/'))
  408.       {
  409.         for (cp = argv[c]+1; *cp; cp++)
  410.         {
  411.           switch (*cp)
  412.           {
  413.             case 'b':
  414.               batch = 1;
  415.               break;
  416.             case 'r':
  417.               fRemote = 1;
  418.               if (isdigit(*(cp+1)))
  419.               {
  420.                 PCrows = atoi(cp+1);
  421.                 while (isdigit(*++cp));
  422.                 --cp;
  423.               }
  424.               break;
  425.           }
  426.         }
  427.         if (c == 1)
  428.         {
  429.           --argc;
  430.           ++argv;
  431.         }
  432.         else
  433.           ++c;
  434.       }
  435.       else
  436.         ++c;
  437.     }
  438.   }
  439.  
  440. #else
  441.  
  442.   if (argc > 1 && (! strcmp(argv[1],"-b")))
  443.   {
  444.       argc--, argv++;
  445.       batch = 1;
  446.   }
  447.  
  448. #endif
  449.  
  450.   if (! batch)
  451.   {
  452.       initscr ();
  453.   }
  454.  
  455.   initkbd();
  456.   if (argc > 1)
  457.   {
  458.       strcpy(curfile,argv[1]);
  459.       readfile (argv[1],0);
  460.   }
  461.   modflg = 0;
  462.   if (batch) exit(0);
  463.   error ("SC 2.1  Type '?' for help.");
  464.   FullUpdate++;
  465.   while (inloop)
  466.   {
  467.     running = 1;
  468.     while (running)
  469.     {
  470.         nedistate = -1;
  471.         narg = 1;
  472.         if (edistate < 0 && linelim < 0 && (changed || FullUpdate))
  473.           EvalAll (), changed = 0;
  474.         update ();
  475.         refresh ();
  476.         move (1, 0);
  477.         clrtoeol ();
  478.         fflush (stdout);
  479.         seenerr = 0;
  480.         if (((c = nmgetch ()) < ' ') || ( c == 0177 ))
  481.           switch (c)
  482.         {
  483.               case ctl ('z'):
  484.                 quit();
  485.                 break;
  486.               case ctl ('r'):
  487.                 FullUpdate++;
  488.                 touchwin();
  489.                 clear();
  490.                 break;
  491.               default:
  492.                 error ("No such command  (^%c)", c + 0100);
  493.                 break;
  494.               case ctl ('b'):
  495.             while (--arg >= 0)
  496.             {
  497.                     if (curcol)
  498.                       curcol--;
  499.                     else
  500.                       error ("At column A");
  501.                     while(hidden_col[curcol] && curcol)
  502.                       curcol--;
  503.                 }
  504.                 break;
  505.               case ctl ('c'):
  506.                 running = 0;
  507.                 break;
  508.               case ctl ('f'):
  509.               while (--arg >= 0)
  510.             {
  511.                     if (curcol < MAXCOLS - 1)
  512.                       curcol++;
  513.                     else
  514.                       error ("The table can't be any wider");
  515.                     while(hidden_col[curcol]&&(curcol<MAXCOLS-1))
  516.                       curcol++;
  517.                 }
  518.                 break;
  519.               case ctl ('g'):
  520.               case ctl ('['):
  521.                 linelim = -1;
  522.                 move (1, 0);
  523.                 clrtoeol ();
  524.                 break;
  525.               case 0177:
  526.               case ctl ('h'):
  527.                 while (--arg>=0) if (linelim > 0)
  528.                     line[--linelim] = 0;
  529.                 break;
  530.               case ctl ('l'):
  531.                 FullUpdate++;
  532.                 break;
  533.               case ctl ('m'):
  534.             if (linelim < 0)
  535.                     line[linelim = 0] = 0;
  536.                 else
  537.             {
  538.                     linelim = 0;
  539.                     yyparse ();
  540.                     linelim = -1;
  541.               }
  542.               break;
  543.               case ctl ('n'):
  544.               while (--arg >= 0)
  545.             {
  546.                     if (currow < MAXROWS - 1)
  547.                       currow++;
  548.                     else
  549.                       error ("The table can't be any longer");
  550.                     while (hidden_row[currow] && (currow < MAXROWS - 1))
  551.                       currow++;
  552.                 }
  553.                 break;
  554.               case ctl ('p'):
  555.               while (--arg >= 0)
  556.             {
  557.                     if (currow)
  558.                       currow--;
  559.                     else
  560.                       error ("At row zero");
  561.                     while (hidden_row[currow] && currow)
  562.                       currow--;
  563.                 }
  564.                 break;
  565.               case ctl ('q'):
  566.                 break;    /* ignore flow control */
  567.               case ctl ('s'):
  568.                 break;    /* ignore flow control */
  569.               case ctl ('t'):
  570.                 showme ^= 1;
  571.                 break;
  572.               case ctl ('u'):
  573.                 narg = arg * 4;
  574.                 nedistate = 1;
  575.                 break;
  576.               case ctl ('v'):    /* insert variable name */
  577.               if (linelim > 0)
  578.             {
  579.                     sprintf (line+linelim,"%s%d", coltoa(curcol), currow);
  580.                     linelim = strlen (line);
  581.                 }
  582.                 break;
  583.               case ctl ('e'):    /* insert variable expression */
  584.               if (linelim > 0) editexp(currow,curcol);
  585.               break;
  586.               case ctl ('a'):    /* insert variable value */
  587.               if (linelim > 0)
  588.             {
  589.                     struct ent *p = tbl[currow][curcol];
  590.  
  591.                     if (p && p -> flags & is_valid)
  592.               {
  593.                       sprintf (line + linelim, "%.*f",
  594.                           precision[curcol],p -> v);
  595.                       linelim = strlen (line);
  596.                     }
  597.               }
  598.               break;
  599.             }
  600.         else
  601.           if ('0' <= c && c <= '9' && (linelim < 0 || edistate >= 0))
  602.         {
  603.               if (edistate != 0)
  604.           {
  605.                 if (c == '0')      /* just a '0' goes to left col */
  606.                     curcol = 0;
  607.                 else
  608.             {
  609.                   nedistate = 0;
  610.                   narg = c - '0';
  611.                 }
  612.               }
  613.           else
  614.           {
  615.                 nedistate = 0;
  616.                 narg = arg * 10 + (c - '0');
  617.               }
  618.           }
  619.           else
  620.               if (linelim >= 0)
  621.           {
  622.                 line[linelim++] = (char)c;
  623.                 line[linelim] = 0;
  624.               }
  625.               else
  626.                 switch (c)
  627.             {
  628.                     case '.':
  629.                       nedistate = 1;
  630.                       break;
  631.                     case ':':
  632.                       break;    /* Be nice to vi users */
  633.                     case '=':
  634.                       sprintf(line,"let %s%d = ",coltoa(curcol),currow);
  635.                       linelim = strlen (line);
  636.                       break;
  637.                     case '/':
  638.                       sprintf(line,"copy [to] %s%d [from] ",
  639.                                       coltoa(curcol), currow);
  640.                       linelim = strlen (line);
  641.                       break;
  642.                     case '$':
  643.                       curcol = MAXCOLS - 1;
  644.                       while (!tbl[currow][curcol] && curcol > 0)
  645.                           curcol--;
  646.                   break;
  647. #ifdef OS2
  648.               case '!':
  649.                 if (shell() == 0)
  650.                 {
  651.                       FullUpdate++;
  652.                       touchwin();
  653.                       clear();
  654.                 }
  655.                     break;
  656. #endif
  657.                     case '?':
  658.                       help ();
  659.                       break;
  660.                     case '"':
  661.                       sprintf (line, "label %s%d = \"",
  662.                                             coltoa(curcol), currow);
  663.                       linelim = strlen (line);
  664.                       break;
  665.                     case '<':
  666.                       sprintf (line, "leftstring %s%d = \"",
  667.                                         coltoa(curcol), currow);
  668.                       linelim = strlen (line);
  669.                       break;
  670.                     case '>':
  671.                       sprintf (line, "rightstring %s%d = \"",
  672.                                         coltoa(curcol), currow);
  673.                       linelim = strlen (line);
  674.                       break;
  675.                     case 'e':
  676.                       editv (currow, curcol);
  677.                       break;
  678.                     case 'E':
  679.                       edits (currow, curcol);
  680.                       break;
  681.                     case 'f':
  682.                       sprintf (line, "format [for column] %s [is] ",
  683.                                           coltoa(curcol));
  684.                       error("Current format is %d %d",
  685.                           fwidth[curcol],precision[curcol]);
  686.                       linelim = strlen (line);
  687.                       break;
  688.                     case 'P':
  689.                       sprintf (line, "put [database into] \"");
  690.                       if (*curfile)
  691.                         error("default file is '%s'",curfile);
  692.                       linelim = strlen (line);
  693.                       break;
  694.                     case 'M':
  695.                       sprintf (line, "merge [database from] \"");
  696.                       linelim = strlen (line);
  697.                       break;
  698.                     case 'G':
  699.                       sprintf (line, "get [database from] \"");
  700.                       if (*curfile)
  701.                         error("default file is '%s'",curfile);
  702.                       linelim = strlen (line);
  703.                       break;
  704.                     case 'W':
  705.                       sprintf (line, "write [listing to] \"");
  706.                       linelim = strlen (line);
  707.                       break;
  708.                     case 'T':    /* tbl output */
  709.                       sprintf (line, "tbl [listing to] \"");
  710.                       linelim = strlen (line);
  711.                       break;
  712.                     case 'i':
  713.                     switch (get_qual())
  714.                 {
  715.                         case 'r':
  716.                             insertrow(arg);
  717.                             break;
  718.                         case 'c':
  719.                             insertcol(arg);
  720.                             break;
  721.                         default:
  722.                             break;
  723.                       }
  724.                       break;
  725.                     case 'd':
  726.                       switch (get_qual())
  727.                 {
  728.                         case 'r':
  729.                             deleterow(arg);
  730.                             break;
  731.                         case 'c':
  732.                             deletecol(arg);
  733.                             break;
  734.                         default:
  735.                             break;
  736.                     }
  737.                       break;
  738.                     case 'v':
  739.                       switch (get_qual())
  740.                 {
  741.                         case 'r':
  742.                             valueizerow(arg);
  743.                             break;
  744.                         case 'c':
  745.                             valueizecol(arg);
  746.                             break;
  747.                         default:
  748.                             break;
  749.                     }
  750.                     break;
  751.                     case 'p':
  752.                     {
  753.                         register qual;
  754.  
  755.                         qual = get_qual();
  756.                         while (arg--)
  757.                           pullcells(qual);
  758.                         break;
  759.                       }
  760.                     case 'x':
  761.                       {
  762.                         register struct ent **p;
  763.                         register int c;
  764.  
  765.                         flush_saved();
  766.                         for (c = curcol; arg-- && c < MAXCOLS; c++)
  767.                   {
  768.                             p = &tbl[currow][c];
  769.                             if (*p)
  770.                     {
  771.                             free_ent(*p);
  772.                             *p = 0;
  773.                             }
  774.                         }
  775.                         sync_refs();
  776.                         FullUpdate++;
  777.                       }
  778.                       break;
  779.                     case 'Q':
  780.                     case 'q':
  781.                       running = 0;
  782.                       break;
  783.                     case 'h':
  784.                       while (--arg >= 0)
  785.                 {
  786.                           if (curcol)
  787.                           curcol--;
  788.                           else
  789.                           error ("At column A");
  790.                           while(hidden_col[curcol] && curcol)
  791.                           curcol--;
  792.                       }
  793.                     break;
  794.                     case 'j':
  795.                       while (--arg >= 0)
  796.                 {
  797.                           if (currow < MAXROWS - 1)
  798.                             currow++;
  799.                           else
  800.                             error ("The table can't be any longer");
  801.                           while (hidden_row[currow]&&(currow<MAXROWS-1))
  802.                             currow++;
  803.                       }
  804.                       break;
  805.                     case 'k':
  806.                       while (--arg >= 0)
  807.                 {
  808.                           if (currow)
  809.                           currow--;
  810.                           else
  811.                           error ("At row zero");
  812.                           while (hidden_row[currow] && currow)
  813.                           currow--;
  814.                   }
  815.                       break;
  816.                     case 'l':
  817.                       while (--arg >= 0)
  818.                 {
  819.                           if (curcol < MAXCOLS - 1)
  820.                           curcol++;
  821.                           else
  822.                           error ("The table can't be any wider");
  823.                           while(hidden_col[curcol]&&(curcol<MAXCOLS-1))
  824.                           curcol++;
  825.                     }
  826.                       break;
  827.                     case 'm':
  828.                       savedrow = currow;
  829.                       savedcol = curcol;
  830.                       break;
  831.                     case 'c':
  832.                 {
  833.                         register struct ent *p = tbl[savedrow][savedcol];
  834.                         register c;
  835.                         register struct ent *n;
  836.  
  837.                         if (!p)
  838.                             break;
  839.                         FullUpdate++;
  840.                         modflg++;
  841.                         for (c = curcol; arg-- && c < MAXCOLS; c++)
  842.                   {
  843.                             n = lookat (currow, c);
  844.                             clearent(n);
  845.                              n -> flags = p -> flags;
  846.                             n -> v = p -> v;
  847.                             n -> expr = copye(p->expr,
  848.                                                 currow - savedrow,
  849.                                                 c - savedcol);
  850.                             n -> label = 0;
  851.                             if (p -> label)
  852.                     {
  853.                               n -> label = (char *)malloc(strlen(p->label)+1);
  854.                               strcpy (n -> label, p -> label);
  855.                           }
  856.                         }
  857.                         break;
  858.                       }
  859.                     case 'z':
  860.                       switch (get_qual())
  861.                 {
  862.                         case 'r':
  863.                             hiderow(arg);
  864.                             break;
  865.                         case 'c':
  866.                             hidecol(arg);
  867.                             break;
  868.                         default:
  869.                             break;
  870.                       }
  871.                       break;
  872.                     case 's':
  873.                       switch (get_qual())
  874.                 {
  875.                         case 'r':
  876.                             showrow_op();
  877.                             break;
  878.                         case 'c':
  879.                             showcol_op();
  880.                             break;
  881.                         default:
  882.                             break;
  883.                       }
  884.                       break;
  885.                     case 'a':
  886.                       switch (get_qual())
  887.                 {
  888.                         case 'r':
  889.                             while (arg--)
  890.                             duprow();
  891.                             break;
  892.                         case 'c':
  893.                             while (arg--)
  894.                             dupcol();
  895.                             break;
  896.                         default:
  897.                             break;
  898.                       }
  899.                       break;
  900.                     default:
  901.                       if ((c & 0177) != c)
  902.                           error("Weird character, decimal '%d'.\n", (int) c);
  903.                       else
  904.                   error ("No such command  (%c)", c);
  905.                       break;
  906.                 }
  907.  
  908.       edistate = nedistate;
  909.         arg = narg;
  910.     }                /* while (running) */
  911.  
  912.     inloop = modcheck(" before exiting");
  913.   }                /*  while (inloop) */
  914.  
  915.   endwin ();
  916.   return 0;
  917. }
  918.  
  919.  
  920.  
  921.  
  922. int modcheck(endstr)
  923. char *endstr;
  924. {
  925.   if (modflg && curfile[0])
  926.   {
  927.       char ch, lin[100];
  928.  
  929.       move (0, 0);
  930.       clrtoeol ();
  931.       sprintf (lin,"File '%s' is modified, save%s? ",curfile,endstr);
  932.       addstr (lin);
  933.       refresh();
  934.       ch = (char)nmgetch();
  935.       if (ch == 'y' || ch == 'Y')
  936.       writefile(curfile);
  937.       else if (ch == ctl ('g'))
  938.       return(1);
  939.   }
  940.   return(0);
  941. }
  942.  
  943.  
  944.  
  945. VOID writefile(fname)
  946. char *fname;
  947. {
  948.   register FILE *f;
  949.   register struct ent **p;
  950.   register r, c;
  951.   char save[1024];
  952.  
  953.   if (*fname == 0) fname = &curfile[0];
  954.  
  955.   strcpy(save,fname);
  956.  
  957.   f = fopen (fname, "w");
  958.   if (f == 0)
  959.   {
  960.       error ("Can't create %s", fname);
  961.       return;
  962.   }
  963.  
  964.   fprintf (f, "# This data file was generated by the Spreadsheet ");
  965.   fprintf (f, "Calculator.\n");
  966.   fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
  967.  
  968.   for (c=0; c<MAXCOLS; c++)
  969.       if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
  970.         fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
  971.  
  972.   for (r=0; r<=maxrow; r++)
  973.   {
  974.       p = &tbl[r][0];
  975.       for (c=0; c<=maxcol; c++, p++)
  976.         if (*p)
  977.       {
  978.             if ((*p)->label)
  979.               fprintf (f, "%sstring %s%d = \"%s\"\n",
  980.                               (*p)->flags&is_leftflush ? "left" : "right",
  981.                               coltoa(c),r,(*p)->label);
  982.             if ((*p)->flags&is_valid)
  983.         {
  984.               editv (r, c);
  985.               fprintf (f, "%s\n",line);
  986.             }
  987.         }
  988.   }
  989.  
  990.   fclose (f);
  991.   strcpy(curfile,save);
  992.  
  993.   modflg = 0;
  994.   error("File '%s' written.",curfile);
  995. }
  996.  
  997.  
  998.  
  999. VOID readfile(fname,eraseflg)
  1000. char *fname; int eraseflg;
  1001. {
  1002.   register FILE *f;
  1003.   char save[1024];
  1004.  
  1005.   if (*fname == 0) fname = &curfile[0];
  1006.   strcpy(save,fname);
  1007.  
  1008.   if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
  1009.  
  1010.   f = fopen (save, "r");
  1011.   if (f == 0)
  1012.   {
  1013.       error ("Can't read %s", save);
  1014.       return;
  1015.   }
  1016.  
  1017.   if (eraseflg) erasedb();
  1018.  
  1019.   while (fgets(line,sizeof line,f))
  1020.   {
  1021.       linelim = 0;
  1022.       if (line[0] != '#') yyparse();
  1023.   }
  1024.   fclose (f);
  1025.   linelim = -1;
  1026.   modflg++;
  1027.   if (eraseflg)
  1028.   {
  1029.       strcpy(curfile,save);
  1030.       modflg = 0;
  1031.   }
  1032.   EvalAll();
  1033. }
  1034.  
  1035.  
  1036.  
  1037. VOID erasedb()
  1038. {
  1039.   register r, c;
  1040.  
  1041.   for (c = 0; c <= maxcol; c++)
  1042.   {
  1043.       fwidth[c] = DEFWIDTH;
  1044.       precision[c] = DEFPREC;
  1045.   }
  1046.  
  1047.   for (r = 0; r <= maxrow; r++)
  1048.   {
  1049.       register struct ent **p = &tbl[r][0];
  1050.       for (c = 0; c++ <= maxcol; p++)
  1051.         if (*p)
  1052.       {
  1053.             if ((*p)->expr) efree ((*p) -> expr);
  1054.             if ((*p)->label) free ((*p) -> label);
  1055.             free (*p);
  1056.             *p = 0;
  1057.         }
  1058.   }
  1059.   maxrow = 0;
  1060.   maxcol = 0;
  1061.   FullUpdate++;
  1062. }
  1063.