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