home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / sc5.1 / part02 < prev    next >
Encoding:
Internet Message Format  |  1988-01-30  |  61.0 KB

  1. Subject:  v13i017:  SC spreadsheet program, version 5.1, Part02/03
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: nscpdc.nsc.com!rgb
  7. Posting-number: Volume 13, Issue 17
  8. Archive-name: sc5.1/part02
  9.  
  10. # This is a shell archive.  Remove anything before this line
  11. # then unpack it by saving it in a file and typing "sh file"
  12. # (Files unpacked will be owned by you and have default permissions).
  13. # This archive contains the following files:
  14. #    ./psc.doc
  15. #    ./tutorial.sc
  16. #    ./sc.h
  17. #    ./sc.c
  18. #    ./lex.c
  19. #    ./gram.y
  20. #
  21. if `test ! -s ./psc.doc`
  22. then
  23. echo "Extracting ./psc.doc"
  24. cat > ./psc.doc << '\SHAR\EOF\'
  25. .TH PPNAME 1
  26. .SH NAME
  27. ppname \- prepare pname files
  28. .SH SYNOPSIS
  29. .B ppname
  30. [
  31. .I -Lkr
  32. ]
  33. [
  34. .I -s cell
  35. ]
  36. [
  37. .I -R n
  38. ]
  39. [
  40. .I -C n
  41. ]
  42. [
  43. .I -n n
  44. ]
  45. [
  46. .I -d c
  47. ]
  48.  
  49. .SH DESCRIPTION
  50. .I Ppname
  51. is used to prepare data for input to the spread sheet calculator
  52. .I pname(1).
  53. It accepts normal ascii data on standard input.  Standard output
  54. is a
  55. .I pname
  56. file.
  57. With no options, 
  58. .I ppname
  59. starts the spread sheet in cell A0.  Strings are right justified.
  60. All data on a line is entered on the same row; new input lines
  61. cause the output row number to increment by one.  The default delimiters
  62. are tab and space.  The column formats are set to one larger
  63. than the number of columns required to hold the largest value
  64. in the column.
  65.  
  66. Options:
  67.  
  68. .IP "\-L"
  69. Left justify strings.
  70.  
  71. .IP "\-k"
  72. Keep all delimiters.  This option causes the output cell to change on
  73. each new delimiter encountered in the input stream.   The default
  74. action is to condense multiple delimters to one, so that the cell only
  75. changes once per input data item.
  76.  
  77. .IP "\-r"
  78. Output the data by row first then column.  For input consisting of a single
  79. column, this
  80. option will result in output of one row with multiple columns
  81. instead of a single
  82. column spread sheet.
  83.  
  84. .IP "\-s cell"
  85. Start the top left corner of the spread sheet in 
  86. .I cell.
  87. For example, 
  88. .I "-s B33"
  89. will arrange the output data so that the
  90. spread sheet starts in column B, row 33.
  91.  
  92. .IP "\-R n"
  93. Increment by
  94. .I n 
  95. on each new output row.
  96.  
  97. .IP "\-C n"
  98. Increment by
  99. .I n 
  100. on each new output column.
  101.  
  102. .IP "\-n n"
  103. Output 
  104. .I n
  105. rows before advancing to the next column.  This option is used when
  106. the input is arranged in a single column and the spread sheet is to
  107. have multiple columns, each of which is to be length
  108. .I n.
  109.  
  110. .IP "\-d c"
  111. Use the single character
  112. .I c
  113. as the delimiter between input fields.
  114.  
  115. .SH SEE ALSO
  116. pname(1)
  117.  
  118. .SH AUTHOR
  119.  
  120. Robert Bond
  121. \SHAR\EOF\
  122. else
  123.   echo "will not over write ./psc.doc"
  124. fi
  125. if [ `wc -c ./psc.doc | awk '{printf $1}'` -ne 1855 ]
  126. then
  127. echo `wc -c ./psc.doc | awk '{print "Got " $1 ", Expected " 1855}'`
  128. fi
  129. if `test ! -s ./tutorial.sc`
  130. then
  131. echo "Extracting ./tutorial.sc"
  132. cat > ./tutorial.sc << '\SHAR\EOF\'
  133. # This data file was generated by the Spreadsheet Calculator.
  134. # You almost certainly shouldn't edit it.
  135.  
  136. define "page4" A70
  137. define "page3" A49
  138. define "page2" A29
  139. define "page1" A9
  140. define "page5" A89
  141. leftstring A1 = "This is a brief sc tutorial."
  142. leftstring A3 = "Cells are named by their column and row number.  For example,"
  143. leftstring A4 = "Cell A4"
  144. leftstring B4 = "Cell B4"
  145. leftstring C4 = "Cell C4"
  146. leftstring A5 = "Cell A5"
  147. leftstring A6 = "Cell A6"
  148. leftstring C6 = "Cell C6"
  149. leftstring A7 = "Cells range from A0 to AN199."
  150. leftstring A8 = "Cells can also be named by the user.  See 'range names' in the manual."
  151. leftstring page1 = "You can move the cursor a couple of different ways:"
  152. leftstring A11 = "^n, j and the <DOWN> arrow key go down"
  153. leftstring A12 = "^p, k and the <UP> arrow key go up"
  154. leftstring A13 = "^b, h and the <LEFT> arrow key go left"
  155. leftstring A14 = "^f, l and the <RIGHT> arrow key go right"
  156. leftstring A15 = "You can go directly to a cell by typing 'g' and the cell name. "
  157. leftstring A16 = "'g c6' will take you to cell c6."
  158. leftstring A18 = "Cells can contain numbers, formulas, or text."
  159. leftstring A19 = "Most of the cells on this page contain text."
  160. leftstring C20 = "<Type 'g page2' to continue>"
  161. leftstring A22 = "Cell d22 contains text"
  162. leftstring D22 = "Text "
  163. leftstring A23 = "Cell d23 contains a number"
  164. let D23 = 123.34
  165. leftstring A24 = "Cell d24 contains a formula"
  166. let D24 = D23+88
  167. leftstring A26 = "To see what the cell contains, just move the cursor"
  168. leftstring A27 = "onto the cell.  The contents will show up on line 1 in the brackets."
  169. leftstring page2 = "You can enter data into cells like this:"
  170. leftstring B30 = "'<text' enters left justified text."
  171. leftstring B31 = "'>text' enters right justified text."
  172. leftstring B32 = "'=number' enters a number"
  173. leftstring B33 = "'=formula' enters a formula."
  174. leftstring A35 = "Try duplicating d22 through d24 in e22 though e24."
  175. leftstring A37 = "You erase a cell by typing 'x' with the cursor on the cell."
  176. leftstring C40 = "<Type 'g page3' to continue>"
  177. leftstring A42 = "Here is a typical use for numbers and formulas:"
  178. let A44 = 10.3
  179. let B44 = 1877.5
  180. let C44 = 234.7
  181. let E44 = @sum(A44:C44)
  182. let A45 = 44.56
  183. let B45 = 44.3
  184. let C45 = -3
  185. let E45 = @sum(A45:C45)
  186. let A46 = 88.74
  187. let B46 = 8000
  188. let C46 = -9
  189. let E46 = @sum(A46:C46)
  190. let A47 = 99.2
  191. let B47 = -88
  192. let C47 = -44.6
  193. let E47 = @sum(A47:C47)
  194. let page3 = @sum(A44:A47)
  195. let B49 = @sum(B44:B47)
  196. let C49 = @sum(C44:C47)
  197. let E49 = @sum(A44:C47)
  198. leftstring A51 = "The data is entered in a44 through c47."
  199. leftstring A52 = "Cells a49, b49 and c49 sum their respective columns."
  200. leftstring A53 = "Cells e44, e45, e46, and e47 sum their respective rows."
  201. leftstring A54 = "Cell E49 is a grand total."
  202. leftstring A55 = "Try changing some of the data cells and watch the sums change."
  203. leftstring A57 = "You can also edit cells by putting the cursor on the cell and typing:"
  204. leftstring B58 = "'e' to edit the numeric portion."
  205. leftstring B59 = "'E' to edit the string portion."
  206. leftstring C60 = "<Type 'g page4' to continue>"
  207. leftstring A62 = "Since you are reading this, you know that you can load "
  208. leftstring A63 = "a data base from a file by typing the file name as an"
  209. leftstring A64 = "argument to the program.  You can also load or save a "
  210. leftstring A65 = "data base using the file commands:"
  211. leftstring B67 = "'G file'"
  212. leftstring C67 = "Gets the data from an sc file."
  213. leftstring B68 = "'P file'"
  214. leftstring C68 = "Puts the data from the spreadsheet into a file."
  215. leftstring page4 = "Try 'P foo.sc' to write this to the file foo.sc"
  216. leftstring A71 = "The Get command erases the current spreadsheet.  "
  217. leftstring A72 = "To merge a spreadsheet with the one currently in"
  218. leftstring A73 = "the machine, use:"
  219. leftstring B75 = "'M file'"
  220. leftstring C75 = "Merge the data from a saved sc file."
  221. leftstring A77 = "You can also get human readable versions of the data"
  222. leftstring A78 = "by using the Write command:"
  223. leftstring C80 = "<Type 'g page5' to continue>"
  224. leftstring A82 = "Try 'W tut.txt' for a clear text version of the tutorial."
  225. leftstring A85 = "This is the end of the tutorial.  We have explored"
  226. leftstring A86 = "The basic commands.  Much more detail is available"
  227. leftstring A87 = "in the man page."
  228. leftstring D91 = "GOOD LUCK!"
  229. \SHAR\EOF\
  230. else
  231.   echo "will not over write ./tutorial.sc"
  232. fi
  233. if [ `wc -c ./tutorial.sc | awk '{printf $1}'` -ne 4292 ]
  234. then
  235. echo `wc -c ./tutorial.sc | awk '{print "Got " $1 ", Expected " 4292}'`
  236. fi
  237. if `test ! -s ./sc.h`
  238. then
  239. echo "Extracting ./sc.h"
  240. cat > ./sc.h << '\SHAR\EOF\'
  241. /*    SC    A Table Calculator
  242.  *        Common definitions
  243.  *
  244.  *        original by James Gosling, September 1982
  245.  *        modified by Mark Weiser and Bruce Israel,
  246.  *            University of Maryland
  247.  *        R. Bond  12/86
  248.  *
  249.  */
  250.  
  251.  
  252.  
  253. #define MAXROWS 200
  254. #define MAXCOLS 40
  255. #define RESCOL 4  /* columns reserved for row numbers */
  256. #define RESROW 3  /* rows reserved for prompt, error, and column numbers */
  257. #define error move(1,0), clrtoeol(), (void) printw
  258.  
  259. struct ent_ptr {
  260.     int vf;
  261.     struct ent *vp;
  262. };
  263.  
  264. struct range_s {
  265.     struct ent_ptr left, right;
  266. };
  267.  
  268. /*
  269.  * If you want to save room, make row and col below into unsigned
  270.  * chars and make sure MAXROWS and MAXCOLS above are both less
  271.  * than 256.  (128 if your compiler doesn't support unsigned char).
  272.  *
  273.  * Some not too obvious things about the flags:
  274.  *    is_valid means there is a valid number in v.
  275.  *    label set means it points to a valid constant string.
  276.  *    is_strexpr set means expr yields a string expression.
  277.  *    If is_strexpr is not set, and expr points to an expression tree, the
  278.  *        expression yields a numeric expression.
  279.  *    So, either v or label can be set to a constant. 
  280.  *        Either (but not both at the same time) can be set from an expression.
  281.  */
  282.  
  283. #define VALID_CELL(p, r, c) ((p = tbl[r][c])&&((p->flags&is_valid)||p->label))
  284.  
  285. struct ent {
  286.     double v;
  287.     char *label;
  288.     struct enode *expr;
  289.     short flags;
  290.     short row, col;
  291.     struct ent *next;
  292. };
  293.  
  294. struct range {
  295.     struct ent_ptr r_left, r_right;
  296.     char *r_name;
  297.     struct range *r_next, *r_prev;
  298.     int r_is_range;
  299. };
  300.  
  301. #define FIX_ROW 1
  302. #define FIX_COL 2
  303.  
  304. struct enode {
  305.     int op;
  306.     union {
  307.     double k;
  308.     struct ent_ptr v;
  309.     struct range_s r;
  310.     char *s;
  311.     struct {
  312.         struct enode *left, *right;
  313.     } o;
  314.     } e;
  315. };
  316.  
  317. /* op values */
  318. #define O_VAR 'v'
  319. #define O_CONST 'k'
  320. #define O_SCONST '$'
  321. #define O_REDUCE(c) (c+0200)
  322.  
  323. #define ACOS 0
  324. #define ASIN 1
  325. #define ATAN 2
  326. #define CEIL 3
  327. #define COS 4
  328. #define EXP 5 
  329. #define FABS 6 
  330. #define FLOOR 7
  331. #define HYPOT 8
  332. #define LOG 9
  333. #define LOG10 10
  334. #define POW 11
  335. #define SIN 12
  336. #define SQRT 13
  337. #define TAN 14
  338. #define DTR 15
  339. #define RTD 16
  340. #define MIN 17
  341. #define MAX 18
  342. #define RND 19
  343. #define HOUR 20
  344. #define MINUTE 21
  345. #define SECOND 22
  346. #define MONTH 23
  347. #define DAY 24
  348. #define YEAR 25
  349. #define NOW 26
  350. #define DATE 27
  351. #define FMT 28
  352. #define SUBSTR 29
  353. #define STON 30
  354. #define EQS 31
  355.  
  356. /* flag values */
  357. #define is_valid     0001
  358. #define is_changed   0002
  359. #define is_strexpr   0004
  360. #define is_leftflush 0010
  361. #define is_deleted   0020
  362.  
  363. #define ctl(c) ('c'&037)
  364.  
  365. extern struct ent *tbl[MAXROWS][MAXCOLS];
  366.  
  367. extern int strow, stcol;
  368. extern int currow, curcol;
  369. extern int savedrow, savedcol;
  370. extern int FullUpdate;
  371. extern int maxrow, maxcol;
  372. extern int fwidth[MAXCOLS];
  373. extern int precision[MAXCOLS];
  374. extern char col_hidden[MAXCOLS];
  375. extern char row_hidden[MAXROWS];
  376. extern char line[1000];
  377. extern int linelim;
  378. extern int changed;
  379. extern struct ent *to_fix;
  380. extern int showsc, showsr;
  381. extern struct enode *new();
  382. extern struct enode *new_const();
  383. extern struct enode *new_var();
  384. extern struct enode *new_str();
  385. extern struct enode *new_range();
  386. extern struct ent *lookat();
  387. extern struct enode *copye();
  388. extern char *coltoa();
  389. extern FILE *openout();
  390. extern struct range *find_range();
  391. extern char *v_name();
  392. extern char *r_name();
  393. extern double eval();
  394. extern char *seval();
  395. extern int modflg;
  396. extern int Crypt;
  397. extern char *mdir;
  398. extern char *xmalloc();
  399. extern int xfree();
  400.  
  401. #if BSD42 || SYSIII
  402.  
  403. #ifndef cbreak
  404. #define    cbreak        crmode
  405. #define    nocbreak    nocrmode
  406. #endif
  407.  
  408. #endif
  409.  
  410. \SHAR\EOF\
  411. else
  412.   echo "will not over write ./sc.h"
  413. fi
  414. if [ `wc -c ./sc.h | awk '{printf $1}'` -ne 3542 ]
  415. then
  416. echo `wc -c ./sc.h | awk '{print "Got " $1 ", Expected " 3542}'`
  417. fi
  418. if `test ! -s ./sc.c`
  419. then
  420. echo "Extracting ./sc.c"
  421. cat > ./sc.c << '\SHAR\EOF\'
  422. /*    SC    A Spreadsheet Calculator
  423.  *        Main driver
  424.  *
  425.  *        original by James Gosling, September 1982
  426.  *        modifications by Mark Weiser and Bruce Israel,
  427.  *            University of Maryland
  428.  *
  429.  *              More mods Robert Bond, 12/86
  430.  *
  431.  */
  432.  
  433.  
  434. #include <signal.h>
  435. #include <curses.h>
  436.  
  437. #ifdef BSD42
  438. #include <strings.h>
  439. #else
  440. #ifndef SYSIII
  441. #include <string.h>
  442. #endif
  443. #endif
  444.  
  445. #include <stdio.h>
  446. #include "sc.h"
  447.  
  448. char *getenv();
  449.  
  450. #ifdef SYSV3
  451. void exit();
  452. #endif
  453.  
  454. /* default column width */
  455.  
  456. #define DEFWIDTH 10
  457. #define DEFPREC   2
  458.  
  459. #define MAXCMD 160    /* for ! command below */
  460.  
  461. /* Globals defined in sc.h */
  462.  
  463. struct ent *tbl[MAXROWS][MAXCOLS];
  464. int strow, stcol;
  465. int currow, curcol;
  466. int savedrow, savedcol;
  467. int FullUpdate;
  468. int maxrow, maxcol;
  469. int fwidth[MAXCOLS];
  470. int precision[MAXCOLS];
  471. char col_hidden[MAXCOLS];
  472. char row_hidden[MAXROWS];
  473. char line[1000];
  474. int changed;
  475. struct ent *to_fix;
  476. int modflg;
  477. int numeric;
  478. char *mdir;
  479. int showsc, showsr;    /* Starting cell for highlighted range */
  480.  
  481. char curfile[1024];
  482. char    revmsg[80];
  483.  
  484. int  linelim = -1;
  485. int  showme = 1;    /* 1 to display the current cell in the top line */
  486. int  showrange;        /* Causes ranges to be highlighted */
  487. int  lastmx, lastmy;    /* Screen address of the cursor */
  488. int  lastcol;        /* Spreadsheet Column the cursor was in last */
  489. char *under_cursor = " "; /* Data under the < cursor */
  490. char *rev = "$Revision: 5.1 $";
  491.  
  492. int seenerr;
  493.  
  494. yyerror (err)
  495. char *err; {
  496.     if (seenerr) return;
  497.     seenerr++;
  498.     (void) move (1,0);
  499.     (void) clrtoeol ();
  500.     (void) printw ("%s: %.*s<=%s",err,linelim,line,line+linelim);
  501. }
  502.  
  503. struct ent *
  504. lookat(row,col){
  505.     register struct ent **p;
  506.     if (row < 0)
  507.     row = 0;
  508.     else if (row > MAXROWS-1) 
  509.     row = MAXROWS-1;
  510.     if (col < 0) 
  511.     col = 0;
  512.     else if (col > MAXCOLS-1)
  513.     col = MAXCOLS-1;
  514.     p = &tbl[row][col];
  515.     if (*p==0) {
  516.     *p = (struct ent *) xmalloc ((unsigned)sizeof (struct ent));
  517.     if (row>maxrow) maxrow = row;
  518.     if (col>maxcol) maxcol = col;
  519.     (*p)->label = 0;
  520.     (*p)->flags = 0;
  521.     (*p)->row = row;
  522.     (*p)->col = col;
  523.     (*p)->expr = 0;
  524.     (*p)->v = (double) 0.0;
  525.     }
  526.     return *p;
  527. }
  528.  
  529. /*
  530.  * This structure is used to keep ent structs around before they
  531.  * are deleted to allow the sync_refs routine a chance to fix the
  532.  * variable references.
  533.  * We also use it as a last-deleted buffer for the 'p' command.
  534.  */
  535.  
  536. free_ent(p)
  537. register struct ent *p;
  538. {
  539.     p->next = to_fix;
  540.     to_fix = p;
  541.     p->flags |= is_deleted;
  542. }
  543.  
  544. flush_saved()
  545. {
  546.     register struct ent *p;
  547.     register struct ent *q;
  548.  
  549.     if (!(p = to_fix))
  550.     return;
  551.     while (p) {
  552.     (void) clearent(p);
  553.     q = p->next;
  554.     xfree((char *)p);
  555.     p = q;
  556.     }
  557.     to_fix = 0;
  558. }
  559.  
  560. update () {
  561.     register    row,
  562.                 col;
  563.     register struct ent **p;
  564.     int     mxcol;
  565.     int     mxrow;
  566.     int     rows;
  567.     int     cols;
  568.     int     minsr, minsc, maxsr, maxsc;
  569.     register r;
  570.     register i;
  571.  
  572.     while (row_hidden[currow])   /* You can't hide the last row or col */
  573.     currow++;
  574.     while (col_hidden[curcol])
  575.     curcol++;
  576.     /* First see if the last display still covers curcol */
  577.     if (stcol <= curcol) { 
  578.     for (i = stcol, cols = 0, col = RESCOL;
  579.             (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
  580.         cols++;
  581.         if (col_hidden[i])
  582.         continue;
  583.         col += fwidth[i];
  584.     }
  585.     }
  586.     while (stcol + cols - 1 < curcol || curcol < stcol) {
  587.     FullUpdate++;
  588.     if (stcol - 1 == curcol) {    /* How about back one? */
  589.         stcol--;
  590.     } else if (stcol + cols == curcol) {   /* Forward one? */
  591.         stcol++;
  592.     } else {
  593.         /* Try to put the cursor in the center of the screen */
  594.         col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL; 
  595.         stcol = curcol;
  596.         for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--) {
  597.         stcol--;
  598.         if (col_hidden[i])
  599.             continue;
  600.         col -= fwidth[i];
  601.         }
  602.     }
  603.     /* Now pick up the counts again */
  604.     for (i = stcol, cols = 0, col = RESCOL;
  605.             (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
  606.         cols++;
  607.         if (col_hidden[i])
  608.         continue;
  609.         col += fwidth[i];
  610.     }
  611.     }
  612.     /* Now - same process on the rows */
  613.     if (strow <= currow) { 
  614.     for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
  615.         rows++;
  616.         if (row_hidden[i])
  617.         continue;
  618.         row++;
  619.     }
  620.     }
  621.     while (strow + rows - 1 < currow || currow < strow) {
  622.     FullUpdate++;
  623.     if (strow - 1 == currow) {    /* How about up one? */
  624.         strow--;
  625.     } else if (strow + rows == currow) {   /* Down one? */
  626.         strow++;
  627.     } else {
  628.         /* Try to put the cursor in the center of the screen */
  629.         row = (LINES - RESROW) / 2 + RESROW; 
  630.         strow = currow;
  631.         for (i=currow-1; i >= 0 && row-1 > RESROW; i--) {
  632.         strow--;
  633.         if (row_hidden[i])
  634.             continue;
  635.         row--;
  636.         }
  637.     }
  638.     /* Now pick up the counts again */
  639.     for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
  640.         rows++;
  641.         if (row_hidden[i])
  642.         continue;
  643.         row++;
  644.     }
  645.     }
  646.     mxcol = stcol + cols - 1;
  647.     mxrow = strow + rows - 1;
  648.     if (FullUpdate) {
  649.     (void) move (2, 0);
  650.     (void) clrtobot ();
  651.     (void) standout();
  652.     for (row=RESROW, i=strow; i <= mxrow; i++) {
  653.         if (row_hidden[i]) 
  654.         continue;
  655.         (void) move(row,0);
  656. #if MAXROW < 1000
  657.         (void) printw("%-*d", RESCOL-1, i);
  658. #else
  659.         (void) printw("%-*d", RESCOL, i);
  660. #endif
  661.         row++;
  662.     }
  663.     (void) move (2,0);
  664.     (void) printw("%*s", RESCOL, " ");
  665.     for (col=RESCOL, i = stcol; i <= mxcol; i++) {
  666.         register int k;
  667.         if (col_hidden[i])
  668.         continue;
  669.         (void) move(2, col);
  670.         k = fwidth[i]/2;
  671.         if (k == 0)
  672.         (void) printw("%1s", coltoa(i));
  673.         else
  674.             (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i));
  675.         col += fwidth[i];
  676.     }
  677.     (void) standend();
  678.     }
  679.  
  680.     /* Get rid of the cursor standout */
  681.     (void) move(lastmx, lastmy);
  682.     if (showme)
  683.         repaint(lastmx, lastmy, fwidth[lastcol]);
  684.  
  685.     if (showrange && showme) {
  686.     minsr = showsr < currow ? showsr : currow;
  687.     minsc = showsc < curcol ? showsc : curcol;
  688.     maxsr = showsr > currow ? showsr : currow;
  689.     maxsc = showsc > curcol ? showsc : curcol;
  690.     (void) move(1,0);
  691.     (void) clrtoeol();
  692.         (void) printw("Default range - %s", r_name(minsr, minsc, maxsr, maxsc));
  693.     }
  694.  
  695.     /* Repaint the visible screen */
  696.     for (row = strow, r = RESROW; row <= mxrow; row++) {
  697.     register c = RESCOL;
  698.     int do_stand = 0;
  699.     int fieldlen;
  700.     int nextcol;
  701.  
  702.     if (row_hidden[row])
  703.         continue;
  704.     for (p = &tbl[row][col = stcol]; col <= mxcol;
  705.              p += nextcol - col,  col = nextcol, c += fieldlen) {
  706.  
  707.         nextcol = col+1;
  708.         if (col_hidden[col]) {
  709.         fieldlen = 0;
  710.         continue;
  711.         }
  712.  
  713.         fieldlen = fwidth[col];
  714.         if (showrange && showme && (row >= minsr) && (row <= maxsr) &&
  715.                    (col >= minsc) && (col <= maxsc)) {
  716.         do_stand = 1;
  717.         }
  718.         if (*p && ((*p) -> flags & is_changed || FullUpdate) || do_stand) {
  719.         char   *s;
  720.         (void) move (r, c);
  721.         if (!*p)
  722.             *p = lookat(row, col);
  723.         if (do_stand) {
  724.             (void) standout();
  725.             (*p) -> flags |= is_changed; 
  726.         } else {
  727.             (*p) -> flags &= ~is_changed;
  728.         }
  729.         if ((*p) -> flags & is_valid) {
  730.             char field[1024];
  731.             (void)sprintf(field,"%*.*f", fwidth[col],
  732.                              precision[col], (*p)->v);
  733.             if(strlen(field) > fwidth[col]) {
  734.             for(i = 0; i<fwidth[col]; i++)
  735.                 (void)addch('*');
  736.             } else {
  737.             (void)addstr(field);
  738.             }
  739.         }
  740.         if (s = (*p) -> label) {
  741.             char field[1024];
  742.             int  slen;
  743.             char *start, *last;
  744.             register char *fp;
  745.             struct ent *nc;
  746.  
  747.             /* This figures out if the label is allowed to
  748.                slop over into the next blank field */
  749.             slen = strlen(s);
  750.             while(slen>fieldlen && nextcol<=mxcol &&
  751.                !((nc = lookat(row,nextcol))->flags & is_valid) &&
  752.                !(nc->label)) {
  753.  
  754.             if (!col_hidden[nextcol])
  755.                 fieldlen += fwidth[nextcol];
  756.  
  757.                 nextcol++;
  758.             }
  759.             if (slen > fieldlen)
  760.             slen = fieldlen;
  761.  
  762.             /* Now justify and print */
  763.             start = (*p)->flags & is_leftflush ? field 
  764.                         : field + fieldlen - slen;
  765.             last = field+fieldlen;
  766.             fp = field;
  767.             while (fp < start)
  768.             *fp++ = ' ';
  769.             while (slen--)
  770.             *fp++ = *s++;
  771.             if (!((*p)->flags & is_valid) || fieldlen != fwidth[col]) 
  772.                 while (fp < last)
  773.                 *fp++ = ' ';
  774.             *fp = 0;
  775.             (void) mvaddstr(r, c, field);
  776.         }
  777.         if (!((*p)->flags & is_valid) && !(*p)->label) {
  778.             /* Need to repaint a blank cell */
  779.             (void) printw ("%*s", fwidth[col], " ");
  780.         }
  781.         if (do_stand) {
  782.             (void) standend();
  783.             do_stand = 0;
  784.         }
  785.         }
  786.     }
  787.     r++;
  788.     }
  789.         
  790.     (void) move(lastmy, lastmx+fwidth[lastcol]);
  791.     if((inch() & 0x7f) == '<')
  792.         (void) addstr(under_cursor);
  793.     lastmy =  RESROW;
  794.     for (row = strow; row < currow; row++)
  795.     if (!row_hidden[row])
  796.         lastmy += 1;
  797.     lastmx = RESCOL;
  798.     for (col = stcol; col < curcol; col++)
  799.     if (!col_hidden[col])
  800.         lastmx += fwidth[col];
  801.     lastcol = curcol;
  802.     (void) move(lastmx, lastmy);
  803.     if (showme) {
  804.         (void) standout();
  805.         repaint(lastmx, lastmy, fwidth[lastcol]);
  806.         (void) standend();
  807.     }
  808.     (void) move(lastmy, lastmx+fwidth[lastcol]);
  809.     *under_cursor = (inch() & 0x7f);
  810.     (void) addstr("<");
  811.  
  812.     (void) move (0, 0);
  813.     (void) clrtoeol ();
  814.     if (linelim >= 0) {
  815.     (void) addstr (">> ");
  816.     (void) addstr (line);
  817.     } else {
  818.     if (showme) {
  819.         register struct ent *p1;
  820.  
  821.             (void) printw("%s%d", coltoa(curcol), currow);
  822.         p1 = tbl[currow][curcol];
  823.         if (p1 && ((p1->flags & is_valid) || p1->label)) {
  824.         if (p1->expr) {
  825.             linelim = 0;
  826.             editexp(currow, curcol);
  827.         } else if (p1->label) {
  828.             (void) sprintf(line, "%s", p1->label);
  829.         } else {
  830.             (void) sprintf(line, "%.15g", p1->v);
  831.         }
  832.         (void) addstr("[");
  833.         (void) addstr (line);
  834.         (void) addstr("]");
  835.         linelim = -1;
  836.         } else {
  837.         (void) addstr("[]");
  838.         }
  839.     }
  840.     (void) move (lastmy, lastmx + fwidth[lastcol]);
  841.     }
  842.     if (revmsg[0]) {
  843.     (void) move(0, 0);
  844.     (void) printw(revmsg);
  845.     revmsg[0] = 0;
  846.     (void) move (lastmy, lastmx + fwidth[lastcol]);
  847.     }
  848.     FullUpdate = 0;
  849. }
  850.  
  851. repaint(x, y, len)
  852. {
  853.     char *buf;
  854.  
  855.     buf = " ";
  856.  
  857.     while(len-- > 0) {
  858.     (void) move(y,x);
  859.     *buf = inch() & 0x7f;
  860.     (void) addstr(buf);
  861.     x++;
  862.     }
  863. }
  864.  
  865. main (argc, argv)
  866. char  **argv; {
  867.     int     inloop = 1;
  868.     register int   c;
  869.     int     edistate = -1;
  870.     int     arg = 1;
  871.     int     narg;
  872.     int     nedistate;
  873.     int        running;
  874.     char    *revi;
  875.     char    *pname;
  876.  
  877.     pname = argv[0];
  878.     while (argc > 1 && argv[1][0] == '-') {
  879.     argv++;
  880.     argc--;
  881.         switch (argv[0][1]) {
  882.         case 'x':
  883.             Crypt = 1;
  884.             break;
  885.         case 'n':
  886.             numeric = 1;
  887.             break;
  888.         default:
  889.             (void) fprintf(stderr,"%s: unrecognized flag: %c\n",
  890.             pname,argv[0][1]);
  891.             exit(1);
  892.     }
  893.     }
  894.  
  895.     {
  896.     register    i;
  897.     for (i = 0; i < MAXCOLS; i++) {
  898.         fwidth[i] = DEFWIDTH;
  899.         precision[i] = DEFPREC;
  900.     }
  901.     }
  902.     curfile[0]=0;
  903.  
  904.     signals();
  905.     (void) initscr();
  906.     (void) clear();
  907.     nonl();
  908.     noecho ();
  909.     cbreak();
  910.     initkbd();
  911.     (void) strcpy(revmsg, pname);
  912.     for (revi=rev; *revi++ != ':';);
  913.     (void) strcat(revmsg, revi);
  914.     revi = revmsg+strlen(revmsg);
  915.     *--revi = 0;
  916.     (void) strcat(revmsg,"Type '?' for help.");
  917.     if (argc > 1) {
  918.     (void) strcpy(curfile,argv[1]);
  919.     readfile (argv[1], 0);
  920.     }
  921.     modflg = 0;
  922. #ifdef VENIX
  923.     setbuf (stdin, NULL);
  924. #endif
  925.     FullUpdate++;
  926.     while (inloop) { running = 1;
  927.     while (running) {
  928.     nedistate = -1;
  929.     narg = 1;
  930.     if (edistate < 0 && linelim < 0 && (changed || FullUpdate))
  931.         EvalAll (), changed = 0;
  932.     update();
  933. #ifndef SYSV3
  934.     (void) refresh(); /* 5.3 does a refresh in getch */ 
  935. #endif
  936.     c = nmgetch();
  937.     (void) move (1, 0);
  938.     (void) clrtoeol ();
  939.     (void) fflush (stdout);
  940.     seenerr = 0;
  941.     if ((c < ' ') || ( c == 0177 ))
  942.         switch (c) {
  943. #if defined(BSD42) || defined (BSD43)
  944.         case ctl (z):
  945.             deraw();
  946. #ifndef V7
  947.             (void) kill(getpid(),SIGTSTP);
  948. #endif
  949.  
  950.             /* the pc stops here */
  951.  
  952.             goraw();
  953.             break;
  954. #endif
  955.         case ctl (r):
  956.         case ctl (l):
  957.             FullUpdate++;
  958.             (void) clearok(stdscr,1);
  959.             break;
  960.         default:
  961.             error ("No such command  (^%c)", c + 0100);
  962.             break;
  963.         case ctl (b):
  964.             while (--arg>=0) {
  965.             if (curcol)
  966.                 curcol--;
  967.             else
  968.                 error ("At column A");
  969.             while(col_hidden[curcol] && curcol)
  970.                 curcol--;
  971.             }
  972.             break;
  973.         case ctl (c):
  974.             running = 0;
  975.             break;
  976.         case ctl (e):
  977.             switch (nmgetch()) {
  978.             case 'j':
  979.             case ctl(n):
  980.             doend(1,0);
  981.             break;
  982.             case 'k':
  983.             case ctl(p):
  984.             doend(-1,0);
  985.             break;
  986.             case 'h':
  987.             case ctl(b):
  988.             doend(0,-1);
  989.             break;
  990.             case 'l':
  991.             case ctl(f):
  992.             doend(0,1);
  993.             break;
  994.             default:
  995.             error("Invalid end command");
  996.             break;
  997.             }
  998.             break;
  999.         case ctl (f):
  1000.             while (--arg>=0) {
  1001.             if (curcol < MAXCOLS - 1)
  1002.                 curcol++;
  1003.             else
  1004.                 error ("The table can't be any wider");
  1005.             while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
  1006.                 curcol++;
  1007.             }
  1008.             break;
  1009.         case ctl (g):
  1010.         case ctl ([):
  1011.             showrange = 0;
  1012.             linelim = -1;
  1013.             (void) move (1, 0);
  1014.             (void) clrtoeol ();
  1015.             break;
  1016.         case 0177:
  1017.         case ctl (h):
  1018.             while (--arg>=0) if (linelim > 0)
  1019.             line[--linelim] = 0;
  1020.             break;
  1021.         case ctl (i):         /* tab */
  1022.             if (linelim > 0) {
  1023.             if (!showrange) {
  1024.                 startshow();
  1025.             } else {
  1026.                 showdr();
  1027.                 linelim = strlen(line);
  1028.                 line[linelim++] = ' ';
  1029.                 line[linelim] = 0;
  1030.                 showrange = 0;
  1031.             }
  1032.             linelim = strlen (line);
  1033.             }
  1034.             break;
  1035.         case ctl (m):
  1036.         case ctl (j):
  1037.             showrange = 0;
  1038.             if (linelim < 0)
  1039.             line[linelim = 0] = 0;
  1040.             else {
  1041.             linelim = 0;
  1042.             (void) yyparse ();
  1043.             linelim = -1;
  1044.             }
  1045.             break;
  1046.         case ctl (n):
  1047.             while (--arg>=0) {
  1048.             if (currow < MAXROWS - 1)
  1049.                 currow++;
  1050.             else
  1051.                 error ("The table can't be any longer");
  1052.             while (row_hidden[currow] && (currow < MAXROWS - 1))
  1053.                 currow++;
  1054.             }
  1055.             break;
  1056.         case ctl (p):
  1057.             while (--arg>=0) {
  1058.             if (currow)
  1059.                 currow--;
  1060.             else
  1061.                 error ("At row zero");
  1062.             while (row_hidden[currow] && currow)
  1063.                 currow--;
  1064.             }
  1065.             break;
  1066.         case ctl (q):
  1067.             break;    /* ignore flow control */
  1068.         case ctl (s):
  1069.             break;    /* ignore flow control */
  1070.         case ctl (t):
  1071.             error("Toggle - n:numeric  t:top row  x:encryption");
  1072.             (void) refresh();
  1073.             switch (nmgetch()) {
  1074.             case 't': case 'T':
  1075.                 showme ^= 1;
  1076.                 repaint(lastmx, lastmy, fwidth[lastcol]);
  1077.                 break;
  1078.             case 'n': case 'N':
  1079.                 numeric ^= 1;
  1080.                 error("Numeric input %sabled.",numeric? "en":"dis");
  1081.                 break;
  1082.             case 'x': case 'X':
  1083.                 Crypt ^= 1;
  1084.                 error("Encryption %sabled.",Crypt? "en":"dis");
  1085.                 break;
  1086.             default:
  1087.                 error("Bad toggle switch");
  1088.             }
  1089.             break;
  1090.         case ctl (u):
  1091.             narg = arg * 4;
  1092.             nedistate = 1;
  1093.             break;
  1094.         case ctl (v):    /* insert variable name */
  1095.             if (linelim > 0) {
  1096.             (void) sprintf (line+linelim,"%s", v_name(currow, curcol));
  1097.             linelim = strlen (line);
  1098.             }
  1099.             break;
  1100.         case ctl (w):    /* insert variable expression */
  1101.             if (linelim > 0) editexp(currow,curcol);
  1102.             break;
  1103.         case ctl (a):    /* insert variable value */
  1104.             if (linelim > 0) {
  1105.             struct ent *p = tbl[currow][curcol];
  1106.  
  1107.             if (p && p -> flags & is_valid) {
  1108.                 (void) sprintf (line + linelim, "%.*f",
  1109.                     precision[curcol],p -> v);
  1110.                 linelim = strlen (line);
  1111.             }
  1112.             }
  1113.             break;
  1114.         }
  1115.     else
  1116.         if ('0' <= c && c <= '9' && ( (numeric && edistate >= 0) ||
  1117.             (!numeric && (linelim < 0 || edistate >= 0))))
  1118.         {
  1119.         if (edistate != 0) {
  1120.             if (c == '0')      /* just a '0' goes to left col */
  1121.             curcol = 0;
  1122.             else {
  1123.                 nedistate = 0;
  1124.                 narg = c - '0';
  1125.             }
  1126.         } else {
  1127.             nedistate = 0;
  1128.             narg = arg * 10 + (c - '0');
  1129.         }
  1130.         }
  1131.         else
  1132.         if (linelim >= 0) {     /* Editing line */
  1133.             switch(c) {
  1134.             case ')':
  1135.                 if (showrange) {
  1136.                 showdr();
  1137.                     showrange = 0;
  1138.                     linelim = strlen (line);
  1139.                 }
  1140.                 break;
  1141.                default:
  1142.                 break;
  1143.             }
  1144.             line[linelim++] = c;
  1145.             line[linelim] = 0;
  1146.         }
  1147.         else
  1148.             switch (c) {
  1149.             case ':':
  1150.                 break;    /* Be nice to vi users */
  1151.  
  1152.             case '0': case '1': case '2': case '3': case '4':
  1153.             case '5': case '6': case '7': case '8': case '9':
  1154.             case '-': case '.': case '+':
  1155.                 (void) sprintf(line,"let %s = %c",
  1156.                     v_name(currow, curcol), c);
  1157.                 linelim = strlen (line);
  1158.                 break;
  1159.  
  1160.             case '=':
  1161.                 (void) sprintf(line,"let %s = ",
  1162.                         v_name(currow, curcol));
  1163.                 linelim = strlen (line);
  1164.                 break;
  1165.  
  1166.             case '!':
  1167.                 {
  1168.                 /*
  1169.                  *  "! command"  executes command
  1170.                  *  "!"    forks a shell
  1171.                  *  "!!" repeats last command
  1172.                  */
  1173.                 char *shl;
  1174.                 int pid, temp;
  1175.                 char cmd[MAXCMD];
  1176.                 static char lastcmd[MAXCMD];
  1177.  
  1178.                 if (!(shl = getenv("SHELL")))
  1179.                 shl = "/bin/sh";
  1180.  
  1181.                 deraw();
  1182.                 (void) fputs("! ", stdout);
  1183.                 (void) fflush(stdout);
  1184.                 (void) fgets(cmd, MAXCMD, stdin);
  1185.                 cmd[strlen(cmd) - 1] = '\0';    /* clobber \n */
  1186.                 if(strcmp(cmd,"!") == 0)        /* repeat? */
  1187.                     (void) strcpy(cmd, lastcmd);
  1188.                 else
  1189.                     (void) strcpy(lastcmd, cmd);
  1190.  
  1191.                 if (!(pid = fork()))
  1192.                 {
  1193.                     if(strlen(cmd))
  1194.                     (void)execl(shl,shl,"-c",cmd,(char *)0);
  1195.                 else
  1196.                     (void) execl(shl, shl, (char *)0);
  1197.                 exit(-127);
  1198.                 }
  1199.  
  1200.                 while (pid != wait(&temp));
  1201.  
  1202.                 (void) printf("Press <return> to continue\n");
  1203.                 (void)nmgetch();
  1204.                 goraw();
  1205.                 break;
  1206.                 }
  1207.  
  1208.             case '/':
  1209.                 error("c:copy x:erase v:value f:fill d:define u:undefine s:show");
  1210.                 (void) refresh();
  1211.                 switch (nmgetch()) {
  1212.                 case 'c':
  1213.                 (void) sprintf(line,"copy [dest_range src_range] ");
  1214.                 linelim = strlen(line);
  1215.                 startshow();
  1216.                 break;
  1217.                 case 'x':
  1218.                 (void) sprintf(line,"erase [range] ");
  1219.                 linelim = strlen(line);
  1220.                 startshow();
  1221.                 break;
  1222.                 case 'v':
  1223.                 (void) sprintf(line, "value [range] ");
  1224.                 linelim = strlen(line);
  1225.                 startshow();
  1226.                 break;
  1227.                 case 'f':
  1228.                 (void) sprintf(line,"fill [range start inc] ");
  1229.                 linelim = strlen(line);
  1230.                 startshow();
  1231.                 break;
  1232.                 case 'd':
  1233.                 (void) sprintf(line,"define [string range] \"");
  1234.                 linelim = strlen(line);
  1235.                 startshow();
  1236.                 modflg++;
  1237.                 break;
  1238.                 case 'u':
  1239.                 (void) sprintf(line,"undefine [range] ");
  1240.                 linelim = strlen(line);
  1241.                 modflg++;
  1242.                 break;
  1243.                 case 's':
  1244.                 {
  1245.                 FILE *f;
  1246.                 int pid;
  1247.                 f = openout("| sort | less", &pid);
  1248.                 if (!f) {
  1249.                     error("Cant open pipe to sort");
  1250.                     break;
  1251.                 }
  1252.                 list_range(f);
  1253.                 closeout(f, pid);
  1254.                 break;
  1255.                 }
  1256.                default:
  1257.                 error("Invalid region operation");
  1258.                 }
  1259.                 break;
  1260.             case '$':
  1261.                 {
  1262.                 register struct ent *p;
  1263.  
  1264.                 curcol = MAXCOLS - 1;
  1265.                 while (!VALID_CELL(p, currow, curcol) && curcol > 0)
  1266.                 curcol--;
  1267.                 break;
  1268.                 }
  1269.             case '#':
  1270.                 {
  1271.                 register struct ent *p;
  1272.  
  1273.                 currow = MAXROWS - 1;
  1274.                 while (!VALID_CELL(p, currow, curcol) && currow > 0)
  1275.                 currow--;
  1276.                 break;
  1277.                 }
  1278.             case 'w':
  1279.                 {
  1280.                 register struct ent *p;
  1281.  
  1282.                 while (--arg>=0) {
  1283.                 do {
  1284.                     if (curcol < MAXCOLS - 1)
  1285.                     curcol++;
  1286.                     else {
  1287.                     if (currow < MAXROWS - 1) {
  1288.                         while(++currow < MAXROWS - 1 &&
  1289.                                 row_hidden[currow]) /* */;
  1290.                         curcol = 0;
  1291.                     } else {
  1292.                         error("End of the table");
  1293.                         break;
  1294.                     }
  1295.                     }
  1296.                 } while(col_hidden[curcol] ||
  1297.                     !VALID_CELL(p, currow, curcol));
  1298.                 }
  1299.                 break;
  1300.                 }
  1301.             case 'b':
  1302.                 {
  1303.                 register struct ent *p;
  1304.  
  1305.                 while (--arg>=0) {
  1306.                 do {
  1307.                     if (curcol) 
  1308.                     curcol--;
  1309.                     else {
  1310.                     if (currow) {
  1311.                         while(--currow &&
  1312.                         row_hidden[currow]) /* */;
  1313.                         curcol = MAXCOLS - 1;
  1314.                     } else {
  1315.                         error ("At start of table");
  1316.                         break;
  1317.                     }
  1318.                     }
  1319.                 } while(col_hidden[curcol] ||
  1320.                     !VALID_CELL(p, currow, curcol));
  1321.                 }
  1322.                 break;
  1323.                 }
  1324.             case '^':
  1325.                 currow = 0;
  1326.                 break;
  1327.             case '?':
  1328.                 help ();
  1329.                 break;
  1330.             case '"':
  1331.                 (void) sprintf (line, "label %s = \"",
  1332.                         v_name(currow, curcol));
  1333.                 linelim = strlen (line);
  1334.                 break;
  1335.             case '<':
  1336.                 (void) sprintf (line, "leftstring %s = \"",
  1337.                     v_name(currow, curcol));
  1338.                 linelim = strlen (line);
  1339.                 break;
  1340.             case '>':
  1341.                 (void) sprintf (line, "rightstring %s = \"",
  1342.                    v_name(currow, curcol));
  1343.                 linelim = strlen (line);
  1344.                 break;
  1345.             case 'e':
  1346.                 editv (currow, curcol);
  1347.                 break;
  1348.             case 'E':
  1349.                 edits (currow, curcol);
  1350.                 break;
  1351.             case 'f':
  1352.                 if (arg == 1)
  1353.                     (void) sprintf (line, "format [for column] %s ",
  1354.                     coltoa(curcol));
  1355.                 else {
  1356.                 (void) sprintf(line, "format [for columns] %s:",
  1357.                     coltoa(curcol));
  1358.                 (void) sprintf(line+strlen(line), "%s ",
  1359.                     coltoa(curcol+arg-1));
  1360.                 }
  1361.                 error("Current format is %d %d",
  1362.                     fwidth[curcol],precision[curcol]);
  1363.                 linelim = strlen (line);
  1364.                 break;
  1365.             case 'g':
  1366.                 (void) sprintf (line, "goto [v] ");
  1367.                 linelim = strlen (line);
  1368.                 break;
  1369.             case 'P':
  1370.                 (void) sprintf (line, "put [\"dest\" range] \"");
  1371.                 if (*curfile)
  1372.                     error("Default path is '%s'",curfile);
  1373.                 linelim = strlen (line);
  1374.                 break;
  1375.             case 'M':
  1376.                 (void) sprintf (line, "merge [\"source\"] \"");
  1377.                 linelim = strlen (line);
  1378.                 break;
  1379.             case 'R':
  1380.                 (void) sprintf (line,"merge [\"macro_file\"] \"%s/", mdir);
  1381.                 linelim = strlen (line);
  1382.                 break;
  1383.             case 'D':
  1384.                 (void) sprintf (line, "mdir [\"macro_directory\"] \"");
  1385.                 linelim = strlen (line);
  1386.                 break;
  1387.             case 'G':
  1388.                 (void) sprintf (line, "get [\"source\"] \"");
  1389.                 if (*curfile)
  1390.                     error("Default file is '%s'",curfile);
  1391.                 linelim = strlen (line);
  1392.                 break;
  1393.             case 'W':
  1394.                 (void) sprintf (line, "write [\"dest\" range] \"");
  1395.                 linelim = strlen (line);
  1396.                 break;
  1397.             case 'T':    /* tbl output */
  1398.                 (void) sprintf (line, "tbl [\"dest\" range] \"");
  1399.                 linelim = strlen (line);
  1400.                 break;
  1401.             case 'i':
  1402.                 switch (get_qual()) {
  1403.                 case 'r':
  1404.                 insertrow(arg);
  1405.                 break;
  1406.                 case 'c':
  1407.                 insertcol(arg);
  1408.                 break;
  1409.                 default:
  1410.                 error("Invalid insert command");
  1411.                 break;
  1412.                 }
  1413.                 break;
  1414.             case 'd':
  1415.                 switch (get_qual()) {
  1416.                 case 'r':
  1417.                 deleterow(arg);
  1418.                 break;
  1419.                 case 'c':
  1420.                 deletecol(arg);
  1421.                 break;
  1422.                 default:
  1423.                 error("Invalid delete command");
  1424.                 break;
  1425.                 }
  1426.                 break;
  1427.             case 'v':
  1428.                 switch (get_qual()) {
  1429.                 case 'r':
  1430.                 rowvalueize(arg);
  1431.                 modflg++;
  1432.                 break;
  1433.                 case 'c':
  1434.                 colvalueize(arg);
  1435.                 modflg++;
  1436.                 break;
  1437.                 default:
  1438.                 error("Invalid value command");
  1439.                 break;
  1440.                 }
  1441.                 break;
  1442.             case 'p':
  1443.                 {
  1444.                 register qual;
  1445.                 qual = get_qual();
  1446.                 while (arg--)
  1447.                     pullcells(qual);
  1448.                 break;
  1449.                 }
  1450.             case 'x':
  1451.                 {
  1452.                 register struct ent **p;
  1453.                 register int c1;
  1454.  
  1455.                 flush_saved();
  1456.                 for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
  1457.                 p = &tbl[currow][c1];
  1458.                 if (*p) {
  1459.                         free_ent(*p);
  1460.                         *p = 0;
  1461.                 }
  1462.                 }
  1463.                 sync_refs();
  1464.                 FullUpdate++;
  1465.                 }
  1466.                 break;
  1467.             case 'Q':
  1468.             case 'q':
  1469.                 running = 0;
  1470.                 break;
  1471.             case 'h':
  1472.                 while (--arg>=0) {
  1473.                 if (curcol)
  1474.                     curcol--;
  1475.                 else
  1476.                     error ("At column A");
  1477.                 while(col_hidden[curcol] && curcol)
  1478.                     curcol--;
  1479.                 }
  1480.                 break;
  1481.             case 'j':
  1482.                 while (--arg>=0) {
  1483.                 if (currow < MAXROWS - 1)
  1484.                     currow++;
  1485.                 else
  1486.                     error ("The table can't be any longer");
  1487.                 while (row_hidden[currow]&&(currow<MAXROWS-1))
  1488.                     currow++;
  1489.                 }
  1490.                 break;
  1491.             case 'k':
  1492.                 while (--arg>=0) {
  1493.                 if (currow)
  1494.                     currow--;
  1495.                 else
  1496.                     error ("At row zero");
  1497.                 while (row_hidden[currow] && currow)
  1498.                     currow--;
  1499.                 }
  1500.                 break;
  1501.             case ' ':
  1502.             case 'l':
  1503.                 while (--arg>=0) {
  1504.                 if (curcol < MAXCOLS - 1)
  1505.                     curcol++;
  1506.                 else
  1507.                     error ("The table can't be any wider");
  1508.                 while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
  1509.                     curcol++;
  1510.                 }
  1511.                 break;
  1512.             case 'm':
  1513.                 savedrow = currow;
  1514.                 savedcol = curcol;
  1515.                 break;
  1516.             case 'c': {
  1517.                 register struct ent *p = tbl[savedrow][savedcol];
  1518.                 register c1;
  1519.                 register struct ent *n;
  1520.                 if (!p)
  1521.                 break;
  1522.                 FullUpdate++;
  1523.                 modflg++;
  1524.                 for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
  1525.                 n = lookat (currow, c1);
  1526.                 (void) clearent(n);
  1527.                 n -> flags = p -> flags;
  1528.                 n -> v = p -> v;
  1529.                 n -> expr = copye(p->expr,
  1530.                         currow - savedrow,
  1531.                         c1 - savedcol);
  1532.                 n -> label = 0;
  1533.                 if (p -> label) {
  1534.                     n -> label = (char *)
  1535.                          xmalloc((unsigned)strlen(p->label)+1);
  1536.                 (void) strcpy (n -> label, p -> label);
  1537.                 }
  1538.                 }
  1539.                 break;
  1540.             }
  1541.             case 'z':
  1542.                 switch (get_qual()) {
  1543.                 case 'r':
  1544.                 hiderow(arg);
  1545.                 break;
  1546.                 case 'c':
  1547.                 hidecol(arg);
  1548.                 break;
  1549.                 default:
  1550.                 error("Invalid zap command");
  1551.                 break;
  1552.                 }
  1553.                 break;
  1554.             case 's':
  1555.                 switch (get_qual()) {
  1556.                 case 'r':
  1557.                 rowshow_op();
  1558.                 break;
  1559.                 case 'c':
  1560.                 colshow_op();
  1561.                 break;
  1562.                 default:
  1563.                 error("Invalid show command");
  1564.                 break;
  1565.                 }
  1566.                 break;
  1567.             case 'a':
  1568.                 switch (get_qual()) {
  1569.                 case 'r':
  1570.                 while (arg--)
  1571.                     duprow();
  1572.                 break;
  1573.                 case 'c':
  1574.                 while (arg--)
  1575.                     dupcol();
  1576.                 break;
  1577.                 default:
  1578.                 error("Invalid add row/col command");
  1579.                 break;
  1580.                 }
  1581.                 break;
  1582.             default:
  1583.                 if ((c & 0177) != c)
  1584.                 error("Weird character, decimal '%d'.\n",
  1585.                     (int) c);
  1586.                 else
  1587.                     error ("No such command  (%c)", c);
  1588.                 break;
  1589.             }
  1590.     edistate = nedistate;
  1591.     arg = narg;
  1592.     }                /* while (running) */
  1593.     inloop = modcheck(" before exiting");
  1594.     }                /*  while (inloop) */
  1595.     deraw();
  1596.     endwin();
  1597.     exit(0);
  1598.     /*NOTREACHED*/
  1599. }
  1600.  
  1601. startshow()
  1602. {
  1603.     showrange = 1;
  1604.     showsr = currow;
  1605.     showsc = curcol;
  1606. }
  1607.  
  1608. showdr()
  1609. {
  1610.     int     minsr, minsc, maxsr, maxsc;
  1611.  
  1612.     minsr = showsr < currow ? showsr : currow;
  1613.     minsc = showsc < curcol ? showsc : curcol;
  1614.     maxsr = showsr > currow ? showsr : currow;
  1615.     maxsc = showsc > curcol ? showsc : curcol;
  1616.     (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc));
  1617. }
  1618.  
  1619.  
  1620. goraw()
  1621. {
  1622. #if SYSV2 || SYSV3
  1623.     fixterm();
  1624. #else
  1625.     cbreak();
  1626.     nonl();
  1627.     noecho ();
  1628. #endif
  1629.     kbd_again();
  1630.     (void) clear();
  1631.     FullUpdate++;
  1632. }
  1633.  
  1634. deraw()
  1635. {
  1636.     (void) move (LINES - 1, 0);
  1637.     (void) clrtoeol();
  1638.     (void) refresh();
  1639. #if SYSV2 || SYSV3
  1640.     resetterm();
  1641. #else
  1642.     nocbreak();
  1643.     nl();
  1644.     echo();
  1645. #endif
  1646.     resetkbd();
  1647. }
  1648.  
  1649. signals()
  1650. {
  1651. #ifdef SYSV3
  1652.     void quit();
  1653.     void timeout();
  1654. #else
  1655.     int quit();
  1656.     int timeout();
  1657. #endif
  1658.  
  1659.     (void) signal(SIGINT, SIG_IGN);
  1660.     (void) signal(SIGQUIT, quit);
  1661.     (void) signal(SIGPIPE, quit);
  1662.     (void) signal(SIGTERM, quit);
  1663.     (void) signal(SIGALRM, timeout);
  1664.     (void) signal(SIGFPE, quit);
  1665.     (void) signal(SIGBUS, quit);
  1666. }
  1667.  
  1668. #ifdef SYSV3
  1669. void
  1670. #endif
  1671. quit()
  1672. {
  1673.     deraw();
  1674.     resetkbd();
  1675.     endwin();
  1676.     exit(1);
  1677. }
  1678.  
  1679. modcheck(endstr)
  1680. char *endstr;
  1681. {
  1682.     if (modflg && curfile[0]) {
  1683.     char ch, lin[100];
  1684.  
  1685.     (void) move (0, 0);
  1686.     (void) clrtoeol ();
  1687.     (void) sprintf (lin,"File '%s' is modified, save%s? ",curfile,endstr);
  1688.     (void) addstr (lin);
  1689.     (void) refresh();
  1690.     ch = nmgetch();
  1691.      if (ch != 'n' && ch != 'N')
  1692.          if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
  1693.          return (1);
  1694.     else if (ch == ctl (g) || ch == ctl([)) return(1);
  1695.     } else if (modflg) {
  1696.     char ch, lin[100];
  1697.  
  1698.     (void) move (0, 0);
  1699.     (void) clrtoeol ();
  1700.     (void) sprintf (lin,"Do you want a chance to save the data? ");
  1701.     (void) addstr (lin);
  1702.     (void) refresh();
  1703.     ch = nmgetch();
  1704.     if (ch == 'n' || ch == 'N') return(0);
  1705.     else return(1);
  1706.       }
  1707.     return(0);
  1708. }
  1709.  
  1710.     
  1711. writefile (fname, r0, c0, rn, cn)
  1712. char *fname;
  1713. {
  1714.     register FILE *f;
  1715.     register struct ent **p;
  1716.     register r, c;
  1717.     char save[1024];
  1718.     int pid;
  1719.  
  1720.     if (Crypt) {
  1721.     return (cwritefile(fname, r0, c0, rn, cn));
  1722.     }
  1723.  
  1724.     if (*fname == 0) fname = &curfile[0];
  1725.  
  1726.     (void) strcpy(save,fname);
  1727.  
  1728.     f = openout(fname, &pid);
  1729.     if (f == 0) {
  1730.     error ("Can't create %s", fname);
  1731.     return (-1);
  1732.     }
  1733.  
  1734.     (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
  1735.     (void) fprintf (f, "Calculator.\n");
  1736.     (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
  1737.     for (c=0; c<MAXCOLS; c++)
  1738.     if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
  1739.         (void) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
  1740.     write_range(f);
  1741.     if (mdir) 
  1742.         (void) fprintf(f, "mdir \"%s\"\n", mdir);
  1743.     for (r=r0; r<=rn; r++) {
  1744.     p = &tbl[r][0];
  1745.     for (c=c0; c<=cn; c++, p++)
  1746.         if (*p) {
  1747.         if ((*p)->label) {
  1748.             edits(r,c);
  1749.             (void) fprintf(f, "%s\n",line);
  1750.         }
  1751.         if ((*p)->flags&is_valid) {
  1752.             editv (r, c);
  1753.             (void) fprintf (f, "%s\n",line);
  1754.         }
  1755.         }
  1756.     }
  1757.  
  1758.     closeout(f, pid);
  1759.  
  1760.     if (!pid) {
  1761.         (void) strcpy(curfile, save);
  1762.         modflg = 0;
  1763.         error("File '%s' written.",curfile);
  1764.     }
  1765.  
  1766.     return (0);
  1767. }
  1768.  
  1769. readfile (fname,eraseflg)
  1770. char *fname;
  1771. int eraseflg;
  1772. {
  1773.     register FILE *f;
  1774.     char save[1024];
  1775.  
  1776.     if (*fname == '*' && mdir) { 
  1777.        (void) strcpy(save, mdir);
  1778.        *fname = '/';
  1779.        (void) strcat(save, fname);
  1780.     } else {
  1781.         if (*fname == 0)
  1782.         fname = &curfile[0];
  1783.         (void) strcpy(save,fname);
  1784.     }
  1785.  
  1786.     if (Crypt)  {
  1787.     creadfile(save, eraseflg);
  1788.     return;
  1789.     }
  1790.  
  1791.     if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
  1792.  
  1793.     f = fopen (save, "r");
  1794.     if (f==0) {
  1795.     error ("Can't read %s", save);
  1796.     return;
  1797.     }
  1798.  
  1799.     if (eraseflg) erasedb ();
  1800.  
  1801.     while (fgets(line,sizeof line,f)) {
  1802.     linelim = 0;
  1803.     if (line[0] != '#') (void) yyparse ();
  1804.     }
  1805.     (void) fclose (f);
  1806.     linelim = -1;
  1807.     modflg++;
  1808.     if (eraseflg) {
  1809.     (void) strcpy(curfile,save);
  1810.     modflg = 0;
  1811.     }
  1812.     EvalAll();
  1813. }
  1814.  
  1815. erasedb () {
  1816.     register r, c;
  1817.     for (c = 0; c<=maxcol; c++) {
  1818.     fwidth[c] = DEFWIDTH;
  1819.     precision[c] = DEFPREC;
  1820.     }
  1821.  
  1822.     for (r = 0; r<=maxrow; r++) {
  1823.     register struct ent **p = &tbl[r][0];
  1824.     for (c=0; c++<=maxcol; p++)
  1825.         if (*p) {
  1826.         if ((*p)->expr) efree ((*p) -> expr);
  1827.         if ((*p)->label) xfree ((char *)((*p) -> label));
  1828.         xfree ((char *)(*p));
  1829.         *p = 0;
  1830.         }
  1831.     }
  1832.     maxrow = 0;
  1833.     maxcol = 0;
  1834.     clean_range();
  1835.     FullUpdate++;
  1836. }
  1837.  
  1838. #if DEBUG
  1839. debugout(g,fmt,args) FILE *g; char *fmt; {
  1840.     int op;
  1841.  
  1842.     if (g == 0) g = fopen("debug","a"),op = 1;
  1843.     if (g == 0) return;
  1844.  
  1845.     _doprnt(fmt, &args, g);
  1846.  
  1847.     (void) fflush(g);
  1848.     if (op) (void) fclose(g);
  1849. }
  1850. #endif
  1851. \SHAR\EOF\
  1852. else
  1853.   echo "will not over write ./sc.c"
  1854. fi
  1855. if [ `wc -c ./sc.c | awk '{printf $1}'` -ne 30534 ]
  1856. then
  1857. echo `wc -c ./sc.c | awk '{print "Got " $1 ", Expected " 30534}'`
  1858. fi
  1859. if `test ! -s ./lex.c`
  1860. then
  1861. echo "Extracting ./lex.c"
  1862. cat > ./lex.c << '\SHAR\EOF\'
  1863. /*    SC    A Spreadsheet Calculator
  1864.  *        Lexical analyser
  1865.  *
  1866.  *        original by James Gosling, September 1982
  1867.  *        modifications by Mark Weiser and Bruce Israel,
  1868.  *            University of Maryland
  1869.  *
  1870.  *              More mods Robert Bond, 12/86
  1871.  *
  1872.  */
  1873.  
  1874.  
  1875.  
  1876. #if defined(BSD42) || defined(BSD43)
  1877. #include <sys/ioctl.h>
  1878. #endif 
  1879.  
  1880. #include <curses.h>
  1881. #include <signal.h>
  1882. #include <setjmp.h>
  1883. #include "sc.h"
  1884. #include <ctype.h>
  1885.  
  1886. #ifdef BSD42
  1887. #include <strings.h>
  1888. #else
  1889. #ifndef SYSIII
  1890. #include <string.h>
  1891. #endif
  1892. #endif
  1893.  
  1894. #include "y.tab.h"
  1895.  
  1896. char *strtof();
  1897.  
  1898. jmp_buf wakeup;
  1899. jmp_buf fpe_buf;
  1900.  
  1901. struct key {
  1902.     char *key;
  1903.     int val;
  1904. };
  1905.  
  1906. struct key experres[] = {
  1907. #include "experres.h"
  1908.     0, 0};
  1909.  
  1910. struct key statres[] = {
  1911. #include "statres.h"
  1912.     0, 0};
  1913.  
  1914. #define ctl(x) ('x'&037)
  1915.  
  1916. yylex () {
  1917.     register char *p = line+linelim;
  1918.     int ret;
  1919.     while (isspace(*p)) p++;
  1920.     if (*p==0) ret = -1;
  1921.     else if (isalpha(*p)) {
  1922.     char *tokenst = p;
  1923.     register tokenl;
  1924.     register struct key *tblp;
  1925.     tokenl = 0;
  1926.     /*
  1927.      * This picks up either 1 or 2 alpha characters (a column) or
  1928.      * tokens with at least three leading alphas and '_' or digits
  1929.      * (a function or token or command or a range name)
  1930.     */
  1931.     while (isalpha(*p) || ((*p == '_') || isdigit(*p)) && (tokenl > 2)) {
  1932.         p++;
  1933.         tokenl++;
  1934.     }
  1935.     if (tokenl <= 2) {
  1936.         register  col;  /* a COL is 1 or 2 char alpha (and not pi or ln!) */
  1937.         if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'i') {
  1938.         ret = K_PI;
  1939.         } else if (tokenl == 2 && tokenst[0] == 'l' && tokenst[1] == 'n') {
  1940.         ret = K_LN;
  1941.         } else {
  1942.         ret = COL;
  1943.         col = ((tokenst[0] & 0137) - 'A');
  1944.         if (p == tokenst+2)
  1945.             col = (col + 1)*26 + ((tokenst[1] & 0137) - 'A');
  1946.         yylval.ival =  col;
  1947.         }
  1948.     } else {
  1949.         ret = WORD;
  1950.         for (tblp = linelim ? experres : statres; tblp->key; tblp++)
  1951.             if (((tblp->key[0]^tokenst[0])&0137)==0
  1952.              && tblp->key[tokenl]==0) {
  1953.             register i = 1;
  1954.             while (i<tokenl && ((tokenst[i]^tblp->key[i])&0137)==0)
  1955.                 i++;
  1956.             if (i>=tokenl) {
  1957.                 ret = tblp->val;
  1958.                 break;
  1959.             }
  1960.             }
  1961.         if (ret==WORD) { 
  1962.         struct range *r;
  1963.         if (r = find_range(tokenst, tokenl,
  1964.                    (struct ent *)0, (struct ent *)0)) {
  1965.             yylval.rval.left = r->r_left;
  1966.             yylval.rval.right = r->r_right;
  1967.             if (r->r_is_range)
  1968.                 ret = RANGE;
  1969.             else
  1970.             ret = VAR;
  1971.         } else {
  1972.             linelim = p-line;
  1973.             yyerror ("Unintelligible word");
  1974.         }
  1975.         }
  1976.     }
  1977.     } else if ((*p == '.') || isdigit(*p)) {
  1978.     double v = 0;
  1979.     int temp;
  1980.     char *nstart = p;
  1981.     if (*p != '.') {
  1982.         do v = v*10 + (double)(*p-'0');
  1983.         while (isdigit(*++p));
  1984.     }
  1985.     if (*p=='.' || *p == 'e' || *p == 'E') {
  1986.         ret = FNUMBER;
  1987.         p = strtof(nstart, &yylval.fval);
  1988.     } else {
  1989.         /* A NUMBER must hold at least MAXROW and MAXCOL */
  1990.         /* This is consistent with a short row and col in struct ent */
  1991.         if (v > (double)32767 || v < (double)-32768) {
  1992.         ret = FNUMBER;
  1993.         yylval.fval = v;
  1994.         } else {
  1995.         temp = (int)v;
  1996.         if((double)temp != v) {
  1997.             ret = FNUMBER;
  1998.             yylval.fval = v;
  1999.         } else {
  2000.             ret = NUMBER;
  2001.             yylval.ival = temp;
  2002.         }
  2003.         }
  2004.     }
  2005.     } else if (*p=='"') {
  2006.     char *ptr;
  2007.         ptr = p+1;
  2008.         while(*ptr && *ptr++ != '"');
  2009.         ptr = xmalloc((unsigned)(ptr-p));
  2010.     yylval.sval = ptr;
  2011.     p += 1;
  2012.     while (*p && *p!='"') *ptr++ = *p++;
  2013.     *ptr = 0;
  2014.     if (*p) p += 1;
  2015.     ret = STRING;
  2016.     } else if (*p=='[') {
  2017.     while (*p && *p!=']') p++;
  2018.     if (*p) p++;
  2019.     linelim = p-line;
  2020.     return yylex();
  2021.     } else ret = *p++;
  2022.     linelim = p-line;
  2023.     return ret;
  2024. }
  2025.  
  2026. #ifdef SIMPLE
  2027.  
  2028. initkbd()
  2029. {}
  2030.  
  2031. kbd_again()
  2032. {}
  2033.  
  2034. resetkbd()
  2035. {}
  2036.  
  2037. nmgetch()
  2038. {
  2039.     return (getchar() & 0x7f);
  2040. }
  2041.  
  2042. #else /*SIMPLE*/
  2043.  
  2044. #if defined(BSD42) || defined (SYSIII) || defined(BSD43)
  2045.  
  2046. #define N_KEY 4
  2047.  
  2048. struct key_map {
  2049.     char *k_str;
  2050.     char k_val;
  2051.     char k_index;
  2052. }; 
  2053.  
  2054. struct key_map km[N_KEY];
  2055.  
  2056. char keyarea[N_KEY*10];
  2057.  
  2058. char *tgetstr();
  2059. char *getenv();
  2060. char *ks;
  2061. char ks_buf[20];
  2062. char *ke;
  2063. char ke_buf[20];
  2064.  
  2065. #ifdef TIOCSLTC
  2066. struct ltchars old_chars, new_chars;
  2067. #endif
  2068.  
  2069. char dont_use[] = {
  2070.     ctl(z), ctl(r), ctl(l), ctl(b), ctl(c), ctl(f), ctl(g), ctl([),
  2071.     ctl(h), ctl(m), ctl(j), ctl(n), ctl(p), ctl(q), ctl(s), ctl(t),
  2072.     ctl(u), ctl(v), ctl(e), ctl(a), ctl(i), ctl(w), 0,
  2073. };
  2074.  
  2075. charout(c)
  2076. int c;
  2077. {
  2078.     (void)putchar(c);
  2079. }
  2080.  
  2081. initkbd()
  2082. {
  2083.     register struct key_map *kp;
  2084.     register i,j;
  2085.     char *p = keyarea;
  2086.     char *ktmp;
  2087.     static char buf[1024]; /* Why do I have to do this again? */
  2088.  
  2089.     if (tgetent(buf, getenv("TERM")) <= 0)
  2090.     return;
  2091.  
  2092.     km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl(b);
  2093.     km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl(f);
  2094.     km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl(p);
  2095.     km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl(n);
  2096.     ktmp = tgetstr("ks",&p);
  2097.     if (ktmp)  {
  2098.     (void) strcpy(ks_buf, ktmp);
  2099.     ks = ks_buf;
  2100.     tputs(ks, 1, charout);
  2101.     }
  2102.     ktmp = tgetstr("ke",&p);
  2103.     if (ktmp)  {
  2104.     (void) strcpy(ke_buf, ktmp);
  2105.     ke = ke_buf;
  2106.     }
  2107.  
  2108.     /* Unmap arrow keys which conflict with our ctl keys   */
  2109.     /* Ignore unset, longer than length 1, and 1-1 mapped keys */
  2110.  
  2111.     for (i = 0; i < N_KEY; i++) {
  2112.     kp = &km[i];
  2113.     if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val))
  2114.         for (j = 0; dont_use[j] != 0; j++)
  2115.             if (kp->k_str[0] == dont_use[j]) {
  2116.              kp->k_str = (char *)0;
  2117.              break;
  2118.         }
  2119.     }
  2120.  
  2121.  
  2122. #ifdef TIOCSLTC
  2123.     (void)ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars);
  2124.     new_chars = old_chars;
  2125.     if (old_chars.t_lnextc == ctl(v))
  2126.     new_chars.t_lnextc = -1;
  2127.     if (old_chars.t_rprntc == ctl(r))
  2128.     new_chars.t_rprntc = -1;
  2129.     (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
  2130. #endif
  2131. }
  2132.  
  2133. kbd_again()
  2134. {
  2135.     if (ks) 
  2136.     tputs(ks, 1, charout);
  2137.  
  2138. #ifdef TIOCSLTC
  2139.     (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
  2140. #endif
  2141. }
  2142.  
  2143. resetkbd()
  2144. {
  2145.     if (ke) 
  2146.     tputs(ke, 1, charout);
  2147.  
  2148. #ifdef TIOCSLTC
  2149.     (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars);
  2150. #endif
  2151. }
  2152.  
  2153. nmgetch() 
  2154. {
  2155.     register int c;
  2156.     register struct key_map *kp;
  2157.     register struct key_map *biggest;
  2158.     register int i;
  2159.     int almost;
  2160.     int maybe;
  2161.  
  2162.     static char dumpbuf[10];
  2163.     static char *dumpindex;
  2164.  
  2165. #ifdef SYSV3
  2166.     void timeout();
  2167. #else
  2168.     int timeout();
  2169. #endif
  2170.  
  2171.     if (dumpindex && *dumpindex)
  2172.         return (*dumpindex++);
  2173.  
  2174.     c = getchar() & 0x7f;
  2175.     biggest = 0;
  2176.     almost = 0;
  2177.  
  2178.     for (kp = &km[0]; kp < &km[N_KEY]; kp++) {
  2179.     if (!kp->k_str)
  2180.         continue;
  2181.     if (c == kp->k_str[kp->k_index]) {
  2182.         almost = 1;
  2183.         kp->k_index++;
  2184.         if (kp->k_str[kp->k_index] == 0) {
  2185.         c = kp->k_val;
  2186.                    for (kp = &km[0]; kp < &km[N_KEY]; kp++)
  2187.                 kp->k_index = 0;
  2188.             return(c);
  2189.         }
  2190.     }
  2191.     if (!biggest && kp->k_index)
  2192.         biggest = kp;
  2193.         else if (kp->k_index && biggest->k_index < kp->k_index)
  2194.         biggest = kp;
  2195.     }
  2196.  
  2197.     if (almost) { 
  2198.  
  2199.         (void) signal(SIGALRM, timeout);
  2200.         (void) alarm(1);
  2201.  
  2202.     if (setjmp(wakeup) == 0) { 
  2203.         maybe = nmgetch();
  2204.         (void) alarm(0);
  2205.         return(maybe);
  2206.     }
  2207.  
  2208.     }
  2209.     
  2210.     if (biggest) {
  2211.     for (i = 0; i<biggest->k_index; i++) 
  2212.         dumpbuf[i] = biggest->k_str[i];
  2213.     dumpbuf[i++] = c;
  2214.     dumpbuf[i] = 0;
  2215.     dumpindex = &dumpbuf[1];
  2216.            for (kp = &km[0]; kp < &km[N_KEY]; kp++)
  2217.         kp->k_index = 0;
  2218.     return (dumpbuf[0]);
  2219.     }
  2220.  
  2221.     return(c);
  2222. }
  2223.  
  2224. #endif
  2225.  
  2226. #if defined(SYSV2) || defined(SYSV3)
  2227.  
  2228. initkbd()
  2229. {
  2230.     keypad(stdscr, TRUE);
  2231. }
  2232.  
  2233. kbd_again()
  2234. {
  2235.     keypad(stdscr, TRUE);
  2236. }
  2237.  
  2238. resetkbd()
  2239. {
  2240.     keypad(stdscr, FALSE);
  2241. }
  2242.  
  2243. nmgetch()
  2244. {
  2245.     register int c;
  2246.  
  2247.     c = getch();
  2248.     switch (c) {
  2249.     case KEY_LEFT:  c = ctl(b); break;
  2250.     case KEY_RIGHT: c = ctl(f); break;
  2251.     case KEY_UP:    c = ctl(p); break;
  2252.     case KEY_DOWN:  c = ctl(n); break;
  2253.     default:   c = c & 0x7f; 
  2254.     }
  2255.     return (c);
  2256. }
  2257.  
  2258. #endif /* SYSV2 || SYSV3 */
  2259.  
  2260. #endif /* SIMPLE */
  2261.  
  2262. #ifdef SYSV3
  2263. void
  2264. #endif
  2265. timeout()
  2266. {
  2267.     longjmp(wakeup, -1);
  2268. }
  2269.  
  2270. int dbline;
  2271.  
  2272. /*VARARGS*/
  2273. void
  2274. debug (str)
  2275. char *str;
  2276. {
  2277.     (void) mvprintw (2+(dbline++%22),80-70,str);
  2278.     (void) clrtoeol();
  2279. }
  2280.  
  2281. #ifdef SYSV3
  2282. void
  2283. #endif
  2284. fpe_trap()
  2285. {
  2286.     longjmp(fpe_buf, 1);
  2287. }
  2288.  
  2289. /*
  2290.  * This converts a floating point number of the form
  2291.  * [s]ddd[.d*][esd*]  where s can be a + or - and e is E or e.
  2292.  * to floating point. 
  2293.  * p is advanced.
  2294.  */
  2295.  
  2296. char *
  2297. strtof(p, res)
  2298. register char *p;
  2299. double *res;
  2300. {
  2301.     double acc;
  2302.     int sign;
  2303.     double fpos;
  2304.     int exp;
  2305.     int exps;
  2306. #ifdef SYSV3
  2307.     void quit();
  2308. #else
  2309.     int quit();
  2310. #endif
  2311.  
  2312.     (void) signal(SIGFPE, fpe_trap);
  2313.     if (setjmp(fpe_buf)) {
  2314.     error("Floating point exception\n");
  2315.     *res = 0.0; 
  2316.         (void) signal(SIGFPE, quit);
  2317.     return(p);
  2318.     }
  2319.     acc = 0.0;
  2320.     sign = 1;
  2321.     exp = 0;
  2322.     exps = 1;
  2323.     if (*p == '+')
  2324.         p++;
  2325.     else if (*p == '-') {
  2326.         p++;
  2327.         sign = -1;
  2328.     }
  2329.     while (isdigit(*p)) {
  2330.         acc = acc * 10.0 + (double)(*p - '0');
  2331.         p++;
  2332.     }
  2333.     if (*p == 'e' || *p == 'E') {
  2334.         p++;
  2335.         if (*p == '+')
  2336.         p++;
  2337.         else if (*p == '-') {
  2338.         p++;
  2339.         exps = -1;
  2340.         }
  2341.         while(isdigit(*p)) {
  2342.         exp = exp * 10 + (*p - '0');
  2343.         p++;
  2344.         }
  2345.     }
  2346.     if (*p == '.') {
  2347.     fpos = 1.0/10.0;
  2348.     p++;
  2349.     while(isdigit(*p)) {
  2350.         acc += (*p - '0') * fpos;
  2351.         fpos *= 1.0/10.0;
  2352.         p++;
  2353.     }
  2354.     }
  2355.     if (*p == 'e' || *p == 'E') {
  2356.     exp = 0;
  2357.     exps = 1;
  2358.         p++;
  2359.     if (*p == '+')
  2360.         p++;
  2361.     else if (*p == '-') {
  2362.         p++;
  2363.         exps = -1;
  2364.     }
  2365.     while(isdigit(*p)) {
  2366.         exp = exp * 10 + (*p - '0');
  2367.         p++;
  2368.     }
  2369.     }
  2370.     if (exp) {
  2371.     if (exps > 0)
  2372.         while (exp--)
  2373.         acc *= 10.0;
  2374.     else
  2375.         while (exp--)
  2376.         acc *= 1.0/10.0;
  2377.     }
  2378.     if (sign > 0)
  2379.         *res = acc;
  2380.     else
  2381.     *res = -acc;
  2382.  
  2383.     (void) signal(SIGFPE, quit);
  2384.     return(p);
  2385. }
  2386.  
  2387. help () {
  2388.     (void) move(1,0);
  2389.     (void) clrtobot();
  2390.     dbline = 0;
  2391.     debug ("Cursor:     ^n j next row       ^p k prev. row  ESC ^g erase cmd");
  2392.     debug ("            ^f l fwd col        ^b h back col    ^l ^r redraw screen");
  2393.     debug ("               w fwd to next       b back to next   ^e <dir> end");
  2394.     debug ("               0 col A             $ last col        g goto ");
  2395.     debug ("               ^ row 0             # last row");
  2396.     debug ("Cell:      \" < > enter label       = enter value     x clear cell");
  2397.     debug ("               c copy cell         m mark cell      ^t line 1 on/off");  
  2398.     debug ("              ^a type value       ^w type expr.     ^v type vbl name");
  2399.     debug ("Row, Col:  ar ac dup           ir ic insert      sr sc show");
  2400.     debug ("           dr dc delete        zr zc hide        pr pc pull");
  2401.     debug ("           vr vc value only        f format");
  2402.     debug ("Ranges:       /u undefine range   /s show ranges    /d define range");
  2403.     debug ("              /c copy range       /x clear range    /f fill range");
  2404.     debug ("              /v values only");
  2405.     debug ("File:          G get database      M merge database  T write tbl fmt");
  2406.     debug ("               P put database      W write listing   R run macros");
  2407.     debug ("               D define directory");
  2408.     debug ("Misc:        Q q quit             pm pull (merge)");
  2409.     debug ("Expr:      +-*/^ arithmetic     ?e:e conditional   & | booleans");
  2410.     debug ("           < = > relations     <= >= relations      != relations");
  2411.     debug ("                 @sum(range)         @avg(range)       @prod(range)");
  2412.     debug ("                 @func(e) - lots of other math functions");
  2413.     error("Hit any key to continue ");
  2414.     (void) refresh();
  2415.     (void) nmgetch();
  2416.     FullUpdate++;
  2417.     (void) move(1,0);
  2418.     (void) clrtobot();
  2419. }
  2420. \SHAR\EOF\
  2421. else
  2422.   echo "will not over write ./lex.c"
  2423. fi
  2424. if [ `wc -c ./lex.c | awk '{printf $1}'` -ne 11396 ]
  2425. then
  2426. echo `wc -c ./lex.c | awk '{print "Got " $1 ", Expected " 11396}'`
  2427. fi
  2428. if `test ! -s ./gram.y`
  2429. then
  2430. echo "Extracting ./gram.y"
  2431. cat > ./gram.y << '\SHAR\EOF\'
  2432. /*    SC    A Spreadsheet Calculator
  2433.  *        Command and expression parser
  2434.  *
  2435.  *        original by James Gosling, September 1982
  2436.  *        modified by Mark Weiser and Bruce Israel,
  2437.  *            University of Maryland
  2438.  *
  2439.  *         more mods Robert Bond 12/86
  2440.  *
  2441.  */
  2442.  
  2443.  
  2444.  
  2445. %{
  2446. #include <curses.h>
  2447. #include "sc.h"
  2448.  
  2449. #define ENULL (struct enode *)0
  2450.  
  2451. char *strcpy();
  2452. %}
  2453.  
  2454. %union {
  2455.     int ival;
  2456.     double fval;
  2457.     struct ent_ptr ent;
  2458.     struct enode *enode;
  2459.     char *sval;
  2460.     struct range_s rval;
  2461. }
  2462.  
  2463. %type <ent> var
  2464. %type <fval> num
  2465. %type <rval> range
  2466. %type <rval> var_or_range
  2467. %type <sval> strarg
  2468. %type <enode> e term
  2469. %token <sval> STRING
  2470. %token <ival> NUMBER
  2471. %token <fval> FNUMBER
  2472. %token <rval> RANGE
  2473. %token <rval> VAR
  2474. %token <sval> WORD
  2475. %token <ival> COL
  2476. %token S_FORMAT
  2477. %token S_LABEL
  2478. %token S_LEFTSTRING
  2479. %token S_RIGHTSTRING
  2480. %token S_GET
  2481. %token S_PUT
  2482. %token S_MERGE
  2483. %token S_LET
  2484. %token S_WRITE
  2485. %token S_TBL
  2486. %token S_COPY
  2487. %token S_SHOW
  2488. %token S_ERASE
  2489. %token S_FILL
  2490. %token S_GOTO
  2491. %token S_DEFINE
  2492. %token S_UNDEFINE
  2493. %token S_VALUE
  2494. %token S_MDIR
  2495.  
  2496. %token K_FIXED
  2497. %token K_SUM
  2498. %token K_PROD
  2499. %token K_AVG
  2500. %token K_STDDEV
  2501. %token K_ACOS
  2502. %token K_ASIN
  2503. %token K_ATAN
  2504. %token K_CEIL
  2505. %token K_COS
  2506. %token K_EXP
  2507. %token K_FABS
  2508. %token K_FLOOR
  2509. %token K_HYPOT
  2510. %token K_LN
  2511. %token K_LOG
  2512. %token K_PI
  2513. %token K_POW
  2514. %token K_SIN
  2515. %token K_SQRT
  2516. %token K_TAN
  2517. %token K_DTR
  2518. %token K_RTD
  2519. %token K_MAX
  2520. %token K_MIN
  2521. %token K_RND
  2522. %token K_HOUR
  2523. %token K_MINUTE
  2524. %token K_SECOND
  2525. %token K_MONTH
  2526. %token K_DAY
  2527. %token K_YEAR
  2528. %token K_NOW
  2529. %token K_DATE
  2530. %token K_FMT
  2531. %token K_LBL
  2532. %token K_SUBSTR
  2533. %token K_STON
  2534. %token K_EQS
  2535.  
  2536. %left '?' ':'
  2537. %left '|'
  2538. %left '&'
  2539. %nonassoc '<' '=' '>' '!'
  2540. %left '+' '-' '#'
  2541. %left '*' '/'
  2542. %left '^'
  2543.  
  2544. %%
  2545. command:    S_LET var_or_range '=' e
  2546.                 { let($2.left.vp, $4); }
  2547.     |    S_LABEL var_or_range '=' e
  2548.                 { slet($2.left.vp, $4, 0); }
  2549.     |    S_LEFTSTRING var_or_range '=' e
  2550.                 { slet($2.left.vp, $4, -1); }
  2551.     |    S_RIGHTSTRING var_or_range '=' e
  2552.                 { slet($2.left.vp, $4, 1); }
  2553.     |    S_FORMAT COL ':' COL NUMBER NUMBER
  2554.                 { doformat($2,$4,$5,$6); }
  2555.     |    S_FORMAT COL NUMBER NUMBER
  2556.                 { doformat($2,$2,$3,$4); }
  2557.     |    S_GET strarg    {  /* This tmp hack is because readfile
  2558.                     * recurses back through yyparse. */
  2559.                   char *tmp;
  2560.                   tmp = $2;
  2561.                   readfile (tmp, 1);
  2562.                   xfree(tmp);
  2563.                 }
  2564.     |    S_MERGE strarg    {
  2565.                   char *tmp;
  2566.                   tmp = $2;
  2567.                   readfile (tmp, 0);
  2568.                   xfree(tmp);
  2569.                 }
  2570.     |    S_MDIR strarg    
  2571.                 { if (mdir) xfree(mdir); mdir = $2; }
  2572.     |       S_PUT strarg range
  2573.                 { (void) writefile($2, ($3.left.vp)->row, 
  2574.                  ($3.left.vp)->col, ($3.right.vp)->row,
  2575.                  ($3.right.vp)->col);
  2576.                  xfree($2); }
  2577.     |    S_PUT strarg    
  2578.                 { (void) writefile ($2, 0, 0, maxrow, maxcol);
  2579.                  xfree($2); }
  2580.     |       S_WRITE strarg range { (void) printfile($2, ($3.left.vp)->row, 
  2581.              ($3.left.vp)->col, ($3.right.vp)->row,
  2582.              ($3.right.vp)->col);
  2583.              xfree($2); }
  2584.     |    S_WRITE strarg    { (void) printfile ($2, 0, 0, maxrow, maxcol);
  2585.              xfree($2); }
  2586.     |       S_TBL strarg range { (void) tblprintfile($2, ($3.left.vp)->row, 
  2587.              ($3.left.vp)->col, ($3.right.vp)->row,
  2588.              ($3.right.vp)->col);
  2589.              xfree($2); }
  2590.     |    S_TBL strarg    { (void)tblprintfile ($2, 0, 0, maxrow, maxcol);
  2591.              xfree($2); }
  2592.     |       S_SHOW COL ':' COL
  2593.                     { showcol( $2, $4); }
  2594.     |       S_SHOW NUMBER ':' NUMBER
  2595.                     { showrow( $2, $4); }
  2596.     |    S_COPY range var_or_range 
  2597.                     { copy($2.left.vp,$2.right.vp,
  2598.                     $3.left.vp,$3.right.vp); }
  2599.     |    S_ERASE       
  2600.                     { eraser(lookat(showsr, showsc),
  2601.                         lookat(currow, curcol)); }
  2602.     |    S_ERASE var_or_range 
  2603.                     { eraser($2.left.vp, $2.right.vp); }
  2604.     |    S_VALUE       { valueize_area(showsr, showsc, currow, curcol);
  2605.                  modflg++; }
  2606.     |    S_VALUE var_or_range { valueize_area(($2.left.vp)->row,
  2607.                 ($2.left.vp)->col,
  2608.                 ($2.right.vp)->row,
  2609.                 ($2.right.vp)->col); modflg++; }
  2610.     |    S_FILL num num  { fill(lookat(showsr, showsc),
  2611.                       lookat(currow, curcol), $2, $3); }
  2612.     |    S_FILL var_or_range num num
  2613.                  { fill($2.left.vp, $2.right.vp, $3, $4); }
  2614.     |    S_GOTO var_or_range {(void) moveto($2.left.vp); }
  2615.     |    S_DEFINE strarg       { struct ent_ptr arg1, arg2;
  2616.                     arg1.vp = lookat(showsr, showsc);
  2617.                     arg1.vf = 0;
  2618.                     arg2.vp = lookat(currow, curcol);
  2619.                     arg2.vf = 0;
  2620.                     add_range($2, arg1, arg2, 1); }
  2621.  
  2622.     |    S_DEFINE strarg range { add_range($2, $3.left, $3.right, 1); }
  2623.     |    S_DEFINE strarg var   { add_range($2, $3, $3, 0); }
  2624.     |    S_UNDEFINE var_or_range { del_range($2.left.vp, $2.right.vp); }
  2625.     |    /* nothing */
  2626.     |    error;
  2627.  
  2628. term:         var        { $$ = new_var('v', $1); }
  2629.     |    K_FIXED term    { $$ = new ('f', ENULL, $2); }
  2630.     |       '@' K_SUM '(' var_or_range ')' 
  2631.                 { $$ = new_range(O_REDUCE('+'), $4); }
  2632.     |       '@' K_PROD '(' var_or_range ')' 
  2633.                 { $$ = new_range (O_REDUCE('*'), $4); }
  2634.     |       '@' K_AVG '(' var_or_range ')' 
  2635.                 { $$ = new_range (O_REDUCE('a'), $4); }
  2636.     |       '@' K_STDDEV '(' var_or_range ')' 
  2637.                 { $$ = new_range (O_REDUCE('s'), $4); }
  2638.     |       '@' K_MAX '(' var_or_range ')' 
  2639.                 { $$ = new_range (O_REDUCE(MAX), $4); }
  2640.     |       '@' K_MIN '(' var_or_range ')' 
  2641.                 { $$ = new_range (O_REDUCE(MIN), $4); }
  2642.     | '@' K_ACOS '(' e ')'
  2643.             { $$ = new(ACOS, ENULL, $4); }
  2644.     | '@' K_ASIN '(' e ')'     { $$ = new(ASIN, ENULL, $4); }
  2645.     | '@' K_ATAN '(' e ')'     { $$ = new(ATAN, ENULL, $4); }
  2646.     | '@' K_CEIL '(' e ')'     { $$ = new(CEIL, ENULL, $4); }
  2647.     | '@' K_COS '(' e ')'     { $$ = new(COS, ENULL, $4); }
  2648.     | '@' K_EXP '(' e ')'     { $$ = new(EXP, ENULL, $4); }
  2649.     | '@' K_FABS '(' e ')'     { $$ = new(FABS, ENULL, $4); }
  2650.     | '@' K_FLOOR '(' e ')'     { $$ = new(FLOOR, ENULL, $4); }
  2651.     | '@' K_HYPOT '(' e ',' e ')'    { $$ = new(HYPOT, $4, $6); }
  2652.     | '@' K_LN '(' e ')'     { $$ = new(LOG, ENULL, $4); }
  2653.     | '@' K_LOG '(' e ')'     { $$ = new(LOG10, ENULL, $4); }
  2654.     | '@' K_POW '(' e ',' e ')'    { $$ = new(POW, $4, $6); }
  2655.     | '@' K_SIN '(' e ')'     { $$ = new(SIN, ENULL, $4); }
  2656.     | '@' K_SQRT '(' e ')'     { $$ = new(SQRT, ENULL, $4); }
  2657.     | '@' K_TAN '(' e ')'     { $$ = new(TAN, ENULL, $4); }
  2658.     | '@' K_DTR '(' e ')'     { $$ = new(DTR, ENULL, $4); }
  2659.     | '@' K_RTD '(' e ')'     { $$ = new(RTD, ENULL, $4); }
  2660.     | '@' K_RND '(' e ')'     { $$ = new(RND, ENULL, $4); }
  2661.     | '@' K_HOUR '(' e ')'      { $$ = new(HOUR,ENULL, $4); }
  2662.     | '@' K_MINUTE '(' e ')' { $$ = new(MINUTE,ENULL, $4); }
  2663.     | '@' K_SECOND '(' e ')' { $$ = new(SECOND,ENULL, $4); }
  2664.     | '@' K_MONTH '(' e ')'     { $$ = new(MONTH,ENULL,$4); }
  2665.     | '@' K_DAY '(' e ')'    { $$ = new(DAY, ENULL, $4); }
  2666.     | '@' K_YEAR '(' e ')'   { $$ = new(YEAR, ENULL, $4); }
  2667.     | '@' K_NOW              { $$ = new(NOW, ENULL, ENULL);}
  2668.     | '@' K_STON '(' e ')'   { $$ = new(STON, ENULL, $4); }
  2669.     | '@' K_EQS '(' e ',' e ')' { $$ = new (EQS, $4, $6); }
  2670.     | '@' K_DATE '(' e ')'     { $$ = new(DATE, ENULL, $4); }
  2671.     | '@' K_FMT  '(' e ',' e ')' { $$ = new(FMT, $4, $6); }
  2672.     | '@' K_SUBSTR '(' e ',' e ',' e ')'
  2673.                  { $$ = new(SUBSTR, $4, new(',', $6, $8)); }
  2674.     |    '(' e ')'     { $$ = $2; }
  2675.     |    '+' term     { $$ = $2; }
  2676.     |    '-' term     { $$ = new ('m', ENULL, $2); }
  2677.     |    NUMBER         { $$ = new_const('k', (double) $1); }
  2678.     |    FNUMBER         { $$ = new_const('k', $1); }
  2679.     |    K_PI    { $$ = new_const('k', (double)3.14159265358979323846); }
  2680.     |    STRING             { $$ = new_str($1); }
  2681.     |    '~' term     { $$ = new ('~', ENULL, $2); }
  2682.     |    '!' term     { $$ = new ('~', ENULL, $2); }
  2683.     ;
  2684.  
  2685. e:        e '+' e        { $$ = new ('+', $1, $3); }
  2686.     |    e '-' e        { $$ = new ('-', $1, $3); }
  2687.     |    e '*' e        { $$ = new ('*', $1, $3); }
  2688.     |    e '/' e        { $$ = new ('/', $1, $3); }
  2689.     |    e '^' e        { $$ = new ('^', $1, $3); }
  2690.     |    term
  2691.     |    e '?' e ':' e    { $$ = new ('?', $1, new(':', $3, $5)); }
  2692.     |    e '<' e        { $$ = new ('<', $1, $3); }
  2693.     |    e '=' e        { $$ = new ('=', $1, $3); }
  2694.     |    e '>' e        { $$ = new ('>', $1, $3); }
  2695.     |    e '&' e        { $$ = new ('&', $1, $3); }
  2696.     |    e '|' e        { $$ = new ('|', $1, $3); }
  2697.     |    e '<' '=' e    { $$ = new ('~', ENULL, new ('>', $1, $4)); }
  2698.     |    e '!' '=' e    { $$ = new ('~', ENULL, new ('=', $1, $4)); }
  2699.     |    e '>' '=' e    { $$ = new ('~', ENULL, new ('<', $1, $4)); }
  2700.     |    e '#' e        { $$ = new ('#', $1, $3); }
  2701.     ;
  2702.  
  2703. range:        var ':' var    { $$.left = $1; $$.right = $3; }
  2704.     |     RANGE        { $$ = $1; }
  2705.     ;
  2706.  
  2707. var:        COL NUMBER    { $$.vp = lookat($2 , $1); $$.vf = 0;}
  2708.     |    '$' COL NUMBER    { $$.vp = lookat($3 , $2);
  2709.                     $$.vf = FIX_COL;}
  2710.     |    COL '$' NUMBER    { $$.vp = lookat($3 , $1);
  2711.                     $$.vf = FIX_ROW;}
  2712.     |    '$' COL '$' NUMBER { $$.vp = lookat($4 , $2);
  2713.                     $$.vf = FIX_ROW | FIX_COL;}
  2714.     |    VAR        { $$ = $1.left; }
  2715.     ;
  2716.  
  2717. var_or_range:    range        { $$ = $1; }
  2718.     |    var        { $$.left = $1; $$.right = $1; }
  2719.     ;
  2720.  
  2721. num:        NUMBER        { $$ = (double) $1; }
  2722.     |    FNUMBER        { $$ = $1; }
  2723.     |    '-' num        { $$ = -$2; }
  2724.     |    '+' num        { $$ = $2; }
  2725.     ;
  2726.  
  2727. strarg:        STRING        { $$ = $1; }
  2728.     |    var        {
  2729.                     char *s, *s1;
  2730.                     s1 = $1.vp->label;
  2731.                     if (!s1)
  2732.                     s1 = "NULL_STRING";
  2733.                     s = xmalloc((unsigned)strlen(s1)+1);
  2734.                     (void) strcpy(s, s1);
  2735.                     $$ = s;
  2736.                 }
  2737. \SHAR\EOF\
  2738. else
  2739.   echo "will not over write ./gram.y"
  2740. fi
  2741. if [ `wc -c ./gram.y | awk '{printf $1}'` -ne 8571 ]
  2742. then
  2743. echo `wc -c ./gram.y | awk '{print "Got " $1 ", Expected " 8571}'`
  2744. fi
  2745. echo "Finished archive 2 of 3"
  2746. # if you want to concatenate archives, remove anything after this line
  2747. exit
  2748.