home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / apps / 123 / vcsrc / sc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-05-10  |  18.8 KB  |  854 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.  * 
  11.  */ 
  12.  
  13. #include "sc.h" 
  14.  
  15. extern char *malloc(); 
  16.  
  17. /* default column width */ 
  18.  
  19. #define DEFWIDTH 10 
  20. #define DEFPREC   2 
  21.  
  22. #define RESCOL 4  /* columns reserved for row numbers */ 
  23. #define RESROW 3  /* rows reserved for prompt, error, and column numbers */ 
  24.  
  25. char curfile[1024]; 
  26.  
  27. int showme = 1;  /* 1 to display the current cell in the top line */ 
  28. int batch = 0; 
  29.  
  30. error (fmt,a,b,c,d,e) { 
  31.     if (batch) fprintf(stderr,fmt,a,b,c,d,e); 
  32.     else { 
  33.     move (1,0); 
  34.     clrtoeol (); 
  35.     printw (fmt,a,b,c,d,e); 
  36.     } 
  37.  
  38. int seenerr; 
  39.  
  40. yyerror (err) 
  41. char *err; { 
  42.     if (seenerr) return; 
  43.     seenerr++; 
  44.     move (1,0); 
  45.     clrtoeol (); 
  46. #ifdef TOS 
  47.     { 
  48.         char format[20]; 
  49.         sprintf(format,"%%s: %%.%ds <= %%s",linelim); 
  50.         printw(format,err,line,line+linelim); 
  51.     } 
  52. #else 
  53.     printw ("%s: %.*s <= %s",err,linelim,line,line+linelim); 
  54. #endif 
  55.  
  56. struct ent * 
  57. lookat(row,col){ 
  58.     register struct ent **p; 
  59.     if (row < 0) 
  60.     row = 0; 
  61.     else if (row > MAXROWS-1) 
  62.     row = MAXROWS-1; 
  63.     if (col < 0) 
  64.     col = 0; 
  65.     else if (col > MAXCOLS-1) 
  66.     col = MAXCOLS-1; 
  67.     p = &tbl[row][col]; 
  68.     if (*p==0) { 
  69.     *p = (struct ent *) malloc (sizeof (struct ent)); 
  70.     if (row>maxrow) maxrow = row; 
  71.     if (col>maxcol) maxcol = col; 
  72.     (*p)->label = 0; 
  73.     (*p)->flags = 0; 
  74.     (*p)->row = row; 
  75.     (*p)->col = col; 
  76.     (*p)->expr = 0; 
  77.     (*p)->v = (double) 0.0; 
  78.     } else if ((*p)->flags & is_deleted) 
  79.     debug("But %s%d has been deleted!", coltoa(col), row); 
  80.     return *p; 
  81.  
  82. /* 
  83.  * This structure is used to keep ent structs around before they 
  84.  * are deleted to allow the sync_refs routine a chance to fix the 
  85.  * variable references. 
  86.  * We also use it as a last-deleted buffer for the 'p' command. 
  87.  */ 
  88.  
  89. free_ent(p) 
  90. register struct ent *p; 
  91.     p->next = to_fix; 
  92.     to_fix = p; 
  93.     p->flags |= is_deleted; 
  94.  
  95. flush_saved() 
  96.     register struct ent *p; 
  97.     register struct ent *q; 
  98.  
  99.     if (!(p = to_fix)) 
  100.     return; 
  101.     while (p) { 
  102.     clearent(p); 
  103.     q = p->next; 
  104.     free(p); 
  105.     p = q; 
  106.     } 
  107.     to_fix = 0; 
  108.  
  109. update () { 
  110.     register    row, 
  111.                 col; 
  112.     register struct ent **p; 
  113.     static  lastmx, 
  114.             lastmy; 
  115.     static  char *under_cursor = " "; 
  116.     int     maxcol; 
  117.     int     maxrow; 
  118.     int     rows; 
  119.     int     cols; 
  120.     register r; 
  121.  
  122.     while (hidden_row[currow])   /* You can't hide the last row or col */ 
  123.     currow++; 
  124.     while (hidden_col[curcol]) 
  125.     curcol++; 
  126.     if (curcol < stcol) 
  127.     stcol = curcol, FullUpdate++; 
  128.     if (currow < strow) 
  129.     strow = currow, FullUpdate++; 
  130.     while (1) { 
  131.     register    i; 
  132.     for (i = stcol, cols = 0, col = RESCOL; 
  133.          (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) { 
  134.         cols++; 
  135.         if (hidden_col[i]) 
  136.         continue; 
  137.         col += fwidth[i]; 
  138.     } 
  139.     if (curcol >= stcol + cols) 
  140.         stcol++, FullUpdate++; 
  141.     else 
  142.         break; 
  143.     } 
  144.     while (1) { 
  145.     register    i; 
  146.     for (i = strow, rows = 0, row = RESROW; 
  147.          row < ROWS && i < MAXROWS; i++) { 
  148.         rows++; 
  149.         if (hidden_row[i]) 
  150.         continue; 
  151.         row++; 
  152.     } 
  153.     if (currow >= strow + rows) 
  154.         strow++, FullUpdate++; 
  155.     else 
  156.         break; 
  157.     } 
  158.     maxcol = stcol + cols - 1; 
  159.     maxrow = strow + rows - 1; 
  160.     if (FullUpdate) { 
  161.     register int i; 
  162.     move (2, 0); 
  163.     clrtobot (); 
  164.     standout(); 
  165.     for (row=RESROW, i=strow; i <= maxrow; i++) { 
  166.         if (hidden_row[i]) 
  167.         continue; 
  168.         move(row,0); 
  169. #ifdef TOS 
  170.         { 
  171.             char format[10]; 
  172.             sprintf(format,"%%-%dd",RESCOL); 
  173.             printw(format,i); 
  174.         } 
  175. #else 
  176.         printw("%-*d", RESCOL, i); 
  177. #endif 
  178.         row++; 
  179.     } 
  180.     move (2,0); 
  181. #ifdef TOS 
  182.     { 
  183.         char format[10]; 
  184.         sprintf(format,"%%%ds",RESCOL); 
  185.         printw(format," "); 
  186.     } 
  187. #else 
  188.     printw("%*s", RESCOL, " "); 
  189. #endif 
  190.     for (col=RESCOL, i = stcol; i <= maxcol; i++) { 
  191.         if (hidden_col[i]) 
  192.         continue; 
  193.         move(2, col); 
  194. #ifdef TOS 
  195.     { 
  196.         char format[10]; 
  197.         sprintf(format,"%%%ds",fwidth[i]); 
  198.         printw(format,coltoa(i)); 
  199.     } 
  200. #else 
  201.         printw("%*s", fwidth[i], coltoa(i)); 
  202. #endif 
  203.         col += fwidth[i]; 
  204.     } 
  205.     standend(); 
  206.     } 
  207.     for (row = strow, r = RESROW; row <= maxrow; row++) { 
  208.     register    c = RESCOL; 
  209.     if (hidden_row[row]) 
  210.         continue; 
  211.     for (p = &tbl[row][col = stcol]; col <= maxcol; col++, p++) { 
  212.         if (hidden_col[col]) 
  213.         continue; 
  214.         if (*p && ((*p) -> flags & is_changed || FullUpdate)) { 
  215.         char   *s; 
  216.         move (r, c); 
  217.         (*p) -> flags &= ~is_changed; 
  218.         if ((*p) -> flags & is_valid) 
  219. #ifdef TOS 
  220.             { 
  221.                 char format[16]; 
  222.                 sprintf(format,"%%%d.%df",fwidth[col],precision[col]); 
  223.                 printw(format,(*p)->v); 
  224.             } 
  225. #else 
  226.             printw ("%*.*f", fwidth[col], precision[col], (*p) -> v); 
  227. #endif 
  228.         if (s = (*p) -> label) { 
  229.             char field[1024]; 
  230.  
  231.             strncpy(field,s,fwidth[col]); 
  232.             field[fwidth[col]] = 0; 
  233.             move (r,(*p) -> flags & is_leftflush 
  234.                 ? c : c - strlen (field) + fwidth[col]); 
  235.             addstr(field); 
  236.         } 
  237.         } 
  238.         c += fwidth[col]; 
  239.     } 
  240.     r++; 
  241.     } 
  242.     
  243.     move(lastmy, lastmx); 
  244.     if (inch() == '<') 
  245.         addstr (under_cursor); 
  246.     lastmy =  RESROW; 
  247.     for (row = strow; row < currow; row++) 
  248.     if (!hidden_row[row]) 
  249.         lastmy += 1; 
  250.     lastmx = RESCOL; 
  251.     for (col = stcol; col <= curcol; col++) 
  252.     if (!hidden_col[col]) 
  253.         lastmx += fwidth[col]; 
  254.     move(lastmy, lastmx); 
  255.     *under_cursor = inch(); 
  256.     addstr ("<"); 
  257.     move (0, 0); 
  258.     clrtoeol (); 
  259.     if (linelim >= 0) { 
  260.     addstr (">> "); 
  261.     addstr (line); 
  262.     } else { 
  263.     if (showme) { 
  264.         register struct ent *p; 
  265.         p = tbl[currow][curcol]; 
  266.         if (p && ((p->flags & is_valid) || p->label)) { 
  267.         if (p->expr || !p->label) { 
  268.             linelim = 0; 
  269.             editexp(currow, curcol); 
  270.         } else { 
  271.             sprintf(line, "%s", p->label); 
  272.         } 
  273.         addstr("["); 
  274.         addstr (line); 
  275.         addstr("]"); 
  276.         linelim = -1; 
  277.         } else { 
  278.         addstr("[]"); 
  279.         } 
  280.     } 
  281.     move (lastmy, lastmx); 
  282.     } 
  283.     FullUpdate = 0; 
  284.  
  285. void 
  286. quit() 
  287.     endwin (); 
  288.     exit(); 
  289.  
  290. main (argc, argv) 
  291. char  **argv; { 
  292.     int     inloop = 1; 
  293.     register int   c; 
  294.     int     edistate = -1; 
  295.     int     arg = 1; 
  296.     int     narg; 
  297.     int     nedistate = -1; 
  298.     int        running = 1; 
  299.     { 
  300.     register    i; 
  301.     for (i = 0; i < MAXCOLS; i++) { 
  302.         fwidth[i] = DEFWIDTH; 
  303.         precision[i] = DEFPREC; 
  304.     } 
  305.     } 
  306.     linelim = -1; 
  307.     curfile[0]=0; 
  308.     running = 1; 
  309.  
  310.     if (argc > 1 && (! strcmp(argv[1],"-b"))) { 
  311.     argc--, argv++; 
  312.     batch = 1; 
  313.     } 
  314.  
  315.     if (! batch) { 
  316.     initscr (); 
  317.     } 
  318.     initkbd(); 
  319.     if (argc > 1) { 
  320.     strcpy(curfile,argv[1]); 
  321.     readfile (argv[1],0); 
  322.     } 
  323.     modflg = 0; 
  324.     if (batch) exit(0); 
  325.     error ("VC 2.1  Type '?' for help."); 
  326.     FullUpdate++; 
  327.     while (inloop) { running = 1; 
  328.     while (running) { 
  329.     nedistate = -1; 
  330.     narg = 1; 
  331.     if (edistate < 0 && linelim < 0 && (changed || FullUpdate)) 
  332.         EvalAll (), changed = 0; 
  333.     update (); 
  334.     refresh (); 
  335.     move (1, 0); 
  336.     clrtoeol (); 
  337.     fflush (stdout); 
  338.     seenerr = 0; 
  339.     if (((c = nmgetch ()) < ' ') || ( c == 0177 )) 
  340.         switch (c) { 
  341.         case ctl (z): 
  342.             quit(); 
  343.             break; 
  344.         case ctl (r): 
  345.             FullUpdate++; 
  346.             touchwin(); 
  347.             clear(); 
  348.             break; 
  349.         default: 
  350.             error ("No such command  (^%c)", c + 0100); 
  351.             break; 
  352.         case ctl (b): 
  353.             while (--arg>=0) { 
  354.             if (curcol) 
  355.                 curcol--; 
  356.             else 
  357.                 error ("At column A"); 
  358.             while(hidden_col[curcol] && curcol) 
  359.                 curcol--; 
  360.             } 
  361.             break; 
  362.         case ctl (c): 
  363.             running = 0; 
  364.             break; 
  365.         case ctl (f): 
  366.             while (--arg>=0) { 
  367.             if (curcol < MAXCOLS - 1) 
  368.                 curcol++; 
  369.             else 
  370.                 error ("The table can't be any wider"); 
  371.             while(hidden_col[curcol]&&(curcol<MAXCOLS-1)) 
  372.                 curcol++; 
  373.             } 
  374.             break; 
  375.         case ctl (g): 
  376.         case ctl ([): 
  377.             linelim = -1; 
  378.             move (1, 0); 
  379.             clrtoeol (); 
  380.             break; 
  381.         case 0177: 
  382.         case ctl (h): 
  383.             while (--arg>=0) if (linelim > 0) 
  384.             line[--linelim] = 0; 
  385.             break; 
  386.         case ctl (l): 
  387.             FullUpdate++; 
  388.             break; 
  389.         case ctl (m): 
  390.             if (linelim < 0) 
  391.             line[linelim = 0] = 0; 
  392.             else { 
  393.             linelim = 0; 
  394.             yyparse (); 
  395.             linelim = -1; 
  396.             } 
  397.             break; 
  398.         case ctl (n): 
  399.             while (--arg>=0) { 
  400.             if (currow < MAXROWS - 1) 
  401.                 currow++; 
  402.             else 
  403.                 error ("The table can't be any longer"); 
  404.             while (hidden_row[currow] && (currow < MAXROWS - 1)) 
  405.                 currow++; 
  406.             } 
  407.             break; 
  408.         case ctl (p): 
  409.             while (--arg>=0) { 
  410.             if (currow) 
  411.                 currow--; 
  412.             else 
  413.                 error ("At row zero"); 
  414.             while (hidden_row[currow] && currow) 
  415.                 currow--; 
  416.             } 
  417.             break; 
  418.         case ctl (q): 
  419.             break;    /* ignore flow control */ 
  420.         case ctl (s): 
  421.             break;    /* ignore flow control */ 
  422.         case ctl (t): 
  423.             showme ^= 1; 
  424.             break; 
  425.         case ctl (u): 
  426.             narg = arg * 4; 
  427.             nedistate = 1; 
  428.             break; 
  429.         case ctl (v):    /* insert variable name */ 
  430.             if (linelim > 0) { 
  431.             sprintf (line+linelim,"%s%d", coltoa(curcol), currow); 
  432.             linelim = strlen (line); 
  433.             } 
  434.             break; 
  435.         case ctl (e):    /* insert variable expression */ 
  436.             if (linelim > 0) editexp(currow,curcol); 
  437.             break; 
  438.         case ctl (a):    /* insert variable value */ 
  439.             if (linelim > 0) { 
  440.             struct ent *p = tbl[currow][curcol]; 
  441.  
  442.             if (p && p -> flags & is_valid) { 
  443.                 sprintf (line + linelim, "%.*f", 
  444.                     precision[curcol],p -> v); 
  445.                 linelim = strlen (line); 
  446.             } 
  447.             } 
  448.             break; 
  449.         } 
  450.     else 
  451.         if ('0' <= c && c <= '9' && (linelim < 0 || edistate >= 0)) { 
  452.         if (edistate != 0) { 
  453.             if (c == '0')      /* just a '0' goes to left col */ 
  454.             curcol = 0; 
  455.             else { 
  456.                 nedistate = 0; 
  457.                 narg = c - '0'; 
  458.             } 
  459.         } else { 
  460.             nedistate = 0; 
  461.             narg = arg * 10 + (c - '0'); 
  462.         } 
  463.         } 
  464.         else 
  465.         if (linelim >= 0) { 
  466.             line[linelim++] = c; 
  467.             line[linelim] = 0; 
  468.         } 
  469.         else 
  470.             switch (c) { 
  471.             case '.': 
  472.                 nedistate = 1; 
  473.                 break; 
  474.             case ':': 
  475.                 break;    /* Be nice to vi users */ 
  476.             case '=': 
  477.                 sprintf(line,"let %s%d = ",coltoa(curcol),currow); 
  478.                 linelim = strlen (line); 
  479.                 break; 
  480.             case '/': 
  481.                 sprintf(line,"copy [to] %s%d [from] ", 
  482.                       coltoa(curcol), currow); 
  483.                 linelim = strlen (line); 
  484.                 break; 
  485.             case '$': 
  486.                 curcol = MAXCOLS - 1; 
  487.                 while (!tbl[currow][curcol] && curcol > 0) 
  488.                 curcol--; 
  489.                 break; 
  490.             case '?': 
  491.                 help (); 
  492.                 break; 
  493.             case '"': 
  494.                 sprintf (line, "label %s%d = \"", 
  495.                         coltoa(curcol), currow); 
  496.                 linelim = strlen (line); 
  497.                 break; 
  498.             case '<': 
  499.                 sprintf (line, "leftstring %s%d = \"", 
  500.                     coltoa(curcol), currow); 
  501.                 linelim = strlen (line); 
  502.                 break; 
  503.             case '>': 
  504.                 sprintf (line, "rightstring %s%d = \"", 
  505.                     coltoa(curcol), currow); 
  506.                 linelim = strlen (line); 
  507.                 break; 
  508.             case 'e': 
  509.                 editv (currow, curcol); 
  510.                 break; 
  511.             case 'E': 
  512.                 edits (currow, curcol); 
  513.                 break; 
  514.             case 'f': 
  515.                 sprintf (line, "format [for column] %s [is] ", 
  516.                     coltoa(curcol)); 
  517.                 error("Current format is %d %d", 
  518.                     fwidth[curcol],precision[curcol]); 
  519.                 linelim = strlen (line); 
  520.                 break; 
  521.             case 'P': 
  522.                 sprintf (line, "put [database into] \""); 
  523.                 if (*curfile) 
  524.                 error("default file is '%s'",curfile); 
  525.                 linelim = strlen (line); 
  526.                 break; 
  527.             case 'M': 
  528.                 sprintf (line, "merge [database from] \""); 
  529.                 linelim = strlen (line); 
  530.                 break; 
  531.             case 'G': 
  532.                 sprintf (line, "get [database from] \""); 
  533.                 if (*curfile) 
  534.                 error("default file is '%s'",curfile); 
  535.                 linelim = strlen (line); 
  536.                 break; 
  537.             case 'W': 
  538.                 sprintf (line, "write [listing to] \""); 
  539.                 linelim = strlen (line); 
  540.                 break; 
  541.             case 'T':    /* tbl output */ 
  542.                 sprintf (line, "tbl [listing to] \""); 
  543.                 linelim = strlen (line); 
  544.                 break; 
  545.             case 'i': 
  546.                 switch (get_qual()) { 
  547.                 case 'r': 
  548.                 insertrow(arg); 
  549.                 break; 
  550.                 case 'c': 
  551.                 insertcol(arg); 
  552.                 break; 
  553.                 default: 
  554.                 break; 
  555.                 } 
  556.                 break; 
  557.             case 'd': 
  558.                 switch (get_qual()) { 
  559.                 case 'r': 
  560.                 deleterow(arg); 
  561.                 break; 
  562.                 case 'c': 
  563.                 deletecol(arg); 
  564.                 break; 
  565.                 default: 
  566.                 break; 
  567.                 } 
  568.                 break; 
  569.             case 'v': 
  570.                 switch (get_qual()) { 
  571.                 case 'r': 
  572.                 valueizerow(arg); 
  573.                 break; 
  574.                 case 'c': 
  575.                 valueizecol(arg); 
  576.                 break; 
  577.                 default: 
  578.                 break; 
  579.                 } 
  580.                 break; 
  581.             case 'p': 
  582.                 { 
  583.                 register qual; 
  584.                 qual = get_qual(); 
  585.                 while (arg--) 
  586.                     pullcells(qual); 
  587.                 break; 
  588.                 } 
  589.             case 'x': 
  590.                 { 
  591.                 register struct ent **p; 
  592.                 register int c; 
  593.                 flush_saved(); 
  594.                 for (c = curcol; arg-- && c < MAXCOLS; c++) { 
  595.                 p = &tbl[currow][c]; 
  596.                 if (*p) { 
  597.                         free_ent(*p); 
  598.                         *p = 0; 
  599.                 } 
  600.                 } 
  601.                 sync_refs(); 
  602.                 FullUpdate++; 
  603.                 } 
  604.                 break; 
  605.             case 'Q': 
  606.             case 'q': 
  607.                 running = 0; 
  608.                 break; 
  609.             case 'h': 
  610.                 while (--arg>=0) { 
  611.                 if (curcol) 
  612.                     curcol--; 
  613.                 else 
  614.                     error ("At column A"); 
  615.                 while(hidden_col[curcol] && curcol) 
  616.                     curcol--; 
  617.                 } 
  618.                 break; 
  619.             case 'j': 
  620.                 while (--arg>=0) { 
  621.                 if (currow < MAXROWS - 1) 
  622.                     currow++; 
  623.                 else 
  624.                     error ("The table can't be any longer"); 
  625.                 while (hidden_row[currow]&&(currow<MAXROWS-1)) 
  626.                     currow++; 
  627.                 } 
  628.                 break; 
  629.             case 'k': 
  630.                 while (--arg>=0) { 
  631.                 if (currow) 
  632.                     currow--; 
  633.                 else 
  634.                     error ("At row zero"); 
  635.                 while (hidden_row[currow] && currow) 
  636.                     currow--; 
  637.                 } 
  638.                 break; 
  639.             case 'l': 
  640.                 while (--arg>=0) { 
  641.                 if (curcol < MAXCOLS - 1) 
  642.                     curcol++; 
  643.                 else 
  644.                     error ("The table can't be any wider"); 
  645.                 while(hidden_col[curcol]&&(curcol<MAXCOLS-1)) 
  646.                     curcol++; 
  647.                 } 
  648.                 break; 
  649.             case 'm': 
  650.                 savedrow = currow; 
  651.                 savedcol = curcol; 
  652.                 break; 
  653.             case 'c': { 
  654.                 register struct ent *p = tbl[savedrow][savedcol]; 
  655.                 register c; 
  656.                 register struct ent *n; 
  657.                 if (!p) 
  658.                 break; 
  659.                 FullUpdate++; 
  660.                 modflg++; 
  661.                 for (c = curcol; arg-- && c < MAXCOLS; c++) { 
  662.                 n = lookat (currow, c); 
  663.                 clearent(n); 
  664.                 n -> flags = p -> flags; 
  665.                 n -> v = p -> v; 
  666.                 n -> expr = copye(p->expr, 
  667.                         currow - savedrow, 
  668.                         c - savedcol); 
  669.                 n -> label = 0; 
  670.                 if (p -> label) { 
  671.                     n -> label = (char *) 
  672.                          malloc(strlen(p->label)+1); 
  673.                 strcpy (n -> label, p -> label); 
  674.                 } 
  675.                 } 
  676.                 break; 
  677.             } 
  678.             case 'z': 
  679.                 switch (get_qual()) { 
  680.                 case 'r': 
  681.                 hiderow(arg); 
  682.                 break; 
  683.                 case 'c': 
  684.                 hidecol(arg); 
  685.                 break; 
  686.                 default: 
  687.                 break; 
  688.                 } 
  689.                 break; 
  690.             case 's': 
  691.                 switch (get_qual()) { 
  692.                 case 'r': 
  693.                 showrow_op(); 
  694.                 break; 
  695.                 case 'c': 
  696.                 showcol_op(); 
  697.                 break; 
  698.                 default: 
  699.                 break; 
  700.                 } 
  701.                 break; 
  702.             case 'a': 
  703.                 switch (get_qual()) { 
  704.                 case 'r': 
  705.                 while (arg--) 
  706.                     duprow(); 
  707.                 break; 
  708.                 case 'c': 
  709.                 while (arg--) 
  710.                     dupcol(); 
  711.                 break; 
  712.                 default: 
  713.                 break; 
  714.                 } 
  715.                 break; 
  716.             default: 
  717.                 if ((c & 0177) != c) 
  718.                 error("Weird character, decimal '%d'.\n", 
  719.                     (int) c); 
  720.                 else error ("No such command  (%c)", c); 
  721.                 break; 
  722.             } 
  723.     edistate = nedistate; 
  724.     arg = narg; 
  725.     }                /* while (running) */ 
  726.     inloop = modcheck(" before exiting"); 
  727.     }                /*  while (inloop) */ 
  728.     endwin (); 
  729.  
  730. modcheck(endstr) char *endstr; { 
  731.     if (modflg && curfile[0]) { 
  732.     char ch, lin[100]; 
  733.  
  734.     move (0, 0); 
  735.     clrtoeol (); 
  736.     sprintf (lin,"File '%s' is modified, save%s? ",curfile,endstr); 
  737.     addstr (lin); 
  738.     refresh(); 
  739.     ch = nmgetch(); 
  740.     if (ch == 'y' || ch == 'Y') writefile(curfile); 
  741.     else if (ch == ctl (g)) return(1); 
  742.     } 
  743.     return(0); 
  744.     
  745. writefile (fname) 
  746. char *fname; { 
  747.     register FILE *f; 
  748.     register struct ent **p; 
  749.     register r, c; 
  750.     char save[1024]; 
  751.  
  752.     if (*fname == 0) fname = &curfile[0]; 
  753.  
  754.     strcpy(save,fname); 
  755.  
  756.     f = fopen (fname, "w"); 
  757.     if (f==0) { 
  758.     error ("Can't create %s", fname); 
  759.     return; 
  760.     } 
  761.  
  762.     fprintf (f, "# This data file was generated by the Spreadsheet "); 
  763.     fprintf (f, "Calculator.\n"); 
  764.     fprintf (f, "# You almost certainly shouldn't edit it.\n\n"); 
  765.     for (c=0; c<MAXCOLS; c++) 
  766.     if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC) 
  767.         fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]); 
  768.     for (r=0; r<=maxrow; r++) { 
  769.     p = &tbl[r][0]; 
  770.     for (c=0; c<=maxcol; c++, p++) 
  771.         if (*p) { 
  772.         if ((*p)->label) 
  773.             fprintf (f, "%sstring %s%d = \"%s\"\n", 
  774.                 (*p)->flags&is_leftflush ? "left" : "right", 
  775.                 coltoa(c),r,(*p)->label); 
  776.         if ((*p)->flags&is_valid) { 
  777.             editv (r, c); 
  778.             fprintf (f, "%s\n",line); 
  779.         } 
  780.         } 
  781.     } 
  782.     fclose (f); 
  783.     strcpy(curfile,save); 
  784.  
  785.     modflg = 0; 
  786.     error("File '%s' written.",curfile); 
  787.  
  788. readfile (fname,eraseflg) 
  789. char *fname; int eraseflg; { 
  790.     register FILE *f; 
  791.     char save[1024]; 
  792.  
  793.     if (*fname == 0) fname = &curfile[0]; 
  794.     strcpy(save,fname); 
  795.  
  796.     if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return; 
  797.  
  798.     f = fopen (save, "r"); 
  799.     if (f==0) { 
  800.     error ("Can't read %s", save); 
  801.     return; 
  802.     } 
  803.  
  804.     if (eraseflg) erasedb (); 
  805.  
  806.     while (fgets(line,sizeof line,f)) { 
  807.     linelim = 0; 
  808.     if (line[0] != '#') yyparse (); 
  809.     } 
  810.     fclose (f); 
  811.     linelim = -1; 
  812.     modflg++; 
  813.     if (eraseflg) { 
  814.     strcpy(curfile,save); 
  815.     modflg = 0; 
  816.     } 
  817.     EvalAll(); 
  818.  
  819. erasedb () { 
  820.     register r, c; 
  821.     for (c = 0; c<=maxcol; c++) { 
  822.     fwidth[c] = DEFWIDTH; 
  823.     precision[c] = DEFPREC; 
  824.     } 
  825.  
  826.     for (r = 0; r<=maxrow; r++) { 
  827.     register struct ent **p = &tbl[r][0]; 
  828.     for (c=0; c++<=maxcol; p++) 
  829.         if (*p) { 
  830.         if ((*p)->expr) efree ((*p) -> expr); 
  831.         if ((*p)->label) free ((*p) -> label); 
  832.         free (*p); 
  833.         *p = 0; 
  834.         } 
  835.     } 
  836.     maxrow = 0; 
  837.     maxcol = 0; 
  838.     FullUpdate++; 
  839.