home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume11 / sc4.1 / part02 < prev    next >
Internet Message Format  |  1987-08-17  |  48KB

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v11i018:  Spread sheet program, sc 4.1, Part02/03
  5. Message-ID: <998@uunet.UU.NET>
  6. Date: 18 Aug 87 22:52:43 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 2178
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: Robert Bond <rgb@nscpdc.nsc.com>
  12. Posting-number: Volume 11, Issue 18
  13. Archive-name: sc4.1/Part02
  14.  
  15. # This is a shell archive.  Remove anything before this line
  16. # then unpack it by saving it in a file and typing "sh file"
  17. # (Files unpacked will be owned by you and have default permissions).
  18. # This archive contains the following files:
  19. #    ./sc.doc
  20. #    ./sc.h
  21. #    ./sc.c
  22. #    ./lex.c
  23. #
  24. if `test ! -s ./sc.doc`
  25. then
  26. echo "writing ./sc.doc"
  27. cat > ./sc.doc << '\SHAR\EOF\'
  28. .TH PNAME 1
  29. .SH NAME
  30. pname \- spread sheet calculator
  31. .SH SYNOPSIS
  32. .B pname
  33. [
  34. .I -x
  35. ]
  36. [
  37. .I file
  38. ]
  39.  
  40. .SH DESCRIPTION
  41. The spread sheet calculator
  42. .I pname
  43. is based on rectangular tables much like a financial spread sheet.
  44. When it is invoked it presents you with an empty
  45. table organized as rows and columns of cells.  Each cell may have a label
  46. string associated with it and an expression.  The expression may be a
  47. constant or it may compute something based on other entries.
  48.  
  49. The single option 
  50. .I -x
  51. causes the 
  52. .I put
  53. and
  54. .I get
  55. commands to encrypt and decrypt the data files.  
  56.  
  57. When \fIpname\fR is running, the screen is divided into four regions. The top
  58. line is for entering commands. The second line is for messages from
  59. \fIpname\fR.
  60. The third line and the first four columns show the row and column numbers.
  61. The rest of the screen forms a window looking at the table.
  62. The screen has two
  63. cursors: a cell cursor (indicated by a '<' on the screen) and a character
  64. cursor (indicated by the terminal's hardware cursor).  The cell and
  65. character cursors are often the same.  They will differ when a command
  66. is being typed on the top line.
  67.  
  68. Commands which use the terminal's control key
  69. such as ^N will work both when a
  70. command is being typed and when in normal mode.
  71.  
  72. The cursor control commands and the row, column commands can be 
  73. prefixed by a numeric argument indicating how many times the command
  74. is to be executed.  "^U" can be used before the number if
  75. the number is to be entered while a command is being typed
  76. into the command line.
  77.  
  78. Cursor control commands:
  79.  
  80. .IP ^N
  81. Move the cell cursor to the next row.
  82.  
  83. .IP ^P
  84. Move the cell cursor to the previous row.
  85.  
  86. .IP ^F
  87. Move the cell cursor forward one column.
  88.  
  89. .IP ^B
  90. Move the cell cursor backward one column.
  91.  
  92. .IP ^H
  93. Backspace one character.
  94.  
  95. .IP "h, j, k, l"
  96. Alternate cursor controls (left, down, up, right).
  97.  
  98. .IP "Arrow Keys"
  99. The terminal's arrow keys provide another alternate set of cell
  100. cursor controls if they exist and are supported in the
  101. .I termcap
  102. entry.
  103. Some terminals have arrow keys which conflict
  104. with other control key codes.  For example, a terminal could send ^H when the
  105. back arrow key is depressed.  In these cases, the conflicting arrow key
  106. performs the same function as the key combination it mimics.
  107.  
  108. .IP 0
  109. Move the cell cursor to column 0 of the current row. 
  110.  
  111. .IP $
  112. Move the cell cursor to the last valid column in the current row.
  113.  
  114. .IP ^
  115. Move the cell cursor to row 0 of the current column.
  116.  
  117. .IP #
  118. Move the cell cursor to the last valid row in the current column.
  119.  
  120. .IP g
  121. Go to a cell.  The program will prompt for the name of a cell.
  122. Enter a cell number such as "a0" or "ae122".
  123.  
  124. .PP
  125. Cell entry and editing commands:
  126.  
  127. .IP =
  128. Prompts for an expression which will be evaluated dynamically to produce a
  129. value for the cell pointed at by the cell cursor.  This may be used in
  130. conjunction with ^V to make one entries value be dependent on anothers.
  131.  
  132. .IP """
  133. Enter a label for the current cell.
  134.  
  135. .IP <
  136. Enter a label that will be flushed left against the
  137. left edge of the cell.
  138.  
  139. .IP >
  140. Enter a label that will be flushed right against the
  141. right edge of the cell.
  142.  
  143. .IP x
  144. Clears the current cell.  You may prefix this command with a count of
  145. the number of cells on the current row to clear.  Cells cleared with
  146. this command may be recalled with any of the variations of the pull
  147. command.
  148.  
  149. .IP e
  150. Edit the value associated with the current cell.  This is identical to '='
  151. except that the command line starts out containing the old value or
  152. expression associated with the cell.
  153.  
  154. .IP E
  155. Edit the string associated with the current cell.  This is the same as
  156. either "leftstring", "rightstring", or "label", with the additional
  157. fact that the command line starts out with the old string.
  158.  
  159. .IP m 
  160. Mark a cell to be used as the source for the copy command.
  161.  
  162. .IP c
  163. Copy the last marked cell to the current cell, updating the row and
  164. column references.
  165.  
  166. .IP ^T
  167. Toggle cell display.  The current cell's contents are displayed in line
  168. one when no command being entered or edited.  ^T turns the
  169. display on or off.
  170.  
  171. .PP
  172. File operations
  173.  
  174. .IP G
  175. Get a new database from a file.  If the encryption option
  176. .I -x
  177. was specified, the file is decrypted before it is loaded into the
  178. spread sheet.
  179.  
  180. .IP P
  181. Put the current database into a file.  If the encryption option
  182. .I -x
  183. was specified, the file is encrypted before it is saved.
  184.  
  185. .IP W
  186. Write a listing of the current database in a form that matches its
  187. appearance on the screen.  This differs from the "put" command in that
  188. "put"s files are intended to be reloaded with "get", while "write" produces
  189. a file for people to look at.
  190.  
  191. .IP T
  192. Write a listing of the current database to a file, but put ":"s between
  193. each field.  This  is useful for tables that will be further formatted
  194. by the
  195. .I tbl
  196. preprocessor of
  197. .I nroff.
  198.  
  199. .IP M
  200. Merges the database from the named file into the current database.  Values,
  201. expressions and names defined in the named file are written into the current
  202. file, overwriting the existing entries at those locations.
  203.  
  204. .PP 
  205. The three output operators, 
  206. .I put, write
  207. and
  208. .I tbl
  209. can pipe their output to a program.  To use this option, enter "| program" to
  210. the prompt asking for a file name.  For example, to redirect the output
  211. of the write command to the printer, you could enter "| lpr -p".
  212.  
  213. .PP
  214. Row and Column operations.  Members of this class of commands can be used
  215. on either rows or columns.  The second letter of the command is either
  216. a column designator (one of the characters c, j, k, ^N, ^p) or a 
  217. row designator (one of r, l, h, ^B, ^F).
  218. Commands which move or copy cells also modify the variable references 
  219. in affected cell expressions.
  220. Variable references may be frozen by using the "fixed" operator.
  221.  
  222. .IP "ar, ac"
  223. Creates a new row (column) immediately following the current row (column).
  224. It is initialized
  225. to be a copy of the current one.
  226.  
  227. .IP "dr, dc"
  228. Delete this row (column).
  229.  
  230. .IP "pr, pc, pm"
  231. Pull deleted rows (columns) back into the spread sheet.  The last deleted
  232. set of cells is put back into the spread sheet at the current location.
  233. .I Pr
  234. inserts enough rows to hold the data.
  235. .I Pc
  236. inserts enough columns to hold the data.
  237. .I Pm
  238. (merge) does not insert rows or columns. It overwrites the cells
  239. beginning at the current cursor location.
  240.  
  241. .IP "ir, ic"
  242. Insert a new row (column) by moving the row (column) containing the cell
  243. cursor, and all
  244. following, down (right) one.  The new position will be empty.
  245.  
  246. .IP "zr, zc"
  247. Hide ("zap") the current row (column).  This keeps a row or column from being
  248. displayed but keeps it in the data base.
  249.  
  250. .IP "vr, vc"
  251. Removes expressions from the affected rows (columns), leaving only
  252. the values which were in the cells before the command
  253. was executed.
  254.  
  255. .IP "sr, sc"
  256. Show hidden rows (columns).  Type in a range of rows or columns
  257. to be revealed.  The command default is the first range of rows or
  258. columns currently hidden.
  259.  
  260. .IP f
  261. Sets the output format to be used for printing the numbers in each cell in
  262. the current column.  Type in two numbers which will be the width in
  263. characters of a column and the number of digits which will follow the
  264. decimal point.  Note that this command has only a column version and
  265. does not have a second letter.  A preceeding count can be used to
  266. specify that more than one column be formatted.
  267.  
  268. .PP
  269. Range Operations:
  270. Range operations
  271. affect a rectangular region on the screen.  
  272. All of the commands in this class start with a slash; the second
  273. letter of the command indicates which command.
  274. The program will prompt for needed parameters.  Phrases surrounded by
  275. square brackets in the prompt are informational only and may be erased with
  276. the backspace key.
  277.  
  278. Prompts requesting variable names
  279. may be satisfied with either an explicit variable name, such as "A10"
  280. or with a variable name previously defined in a 
  281. .I /d
  282. command.  Range name prompts require either an explicit range such
  283. as "A10:B20" or a range name previously defined with a 
  284. .I /d
  285. command.
  286.  
  287. .IP "/x"
  288. Clear a region.  Cells cleared with this command may be recalled
  289. via any of the pull row or column commands.
  290.  
  291. .IP "/c"
  292. Copy a region to the area starting at the current cell.
  293.  
  294. .IP "/f"
  295. Fill a region with constant values.  The start and increment numbers
  296. may be positive or negative.
  297.  
  298. .IP "/d"
  299. This command is used to assign a symbolic name to a single cell or 
  300. a rectangular range of cells on the screen.  The parameters are the
  301. name, surrounded by quotation marks, and either a single cell name
  302. such as "A10" or a range such as "A10:B20".  Names defined in this
  303. fashion will be used by the program in future prompts, may be
  304. entered in response to prompts requesting a cell or range name,
  305. and will be saved when the spread sheet is saved with a
  306. .I Put
  307. command.  Names defined must be more than two alpha
  308. characters long to differentiate them from a column names, and must not have
  309. embedded special characters.  Names may include the character "_" or numerals
  310. as long as they occur after the first three alpha characters.
  311.  
  312. .IP "/s"
  313. This command will list the defined range names.
  314.  
  315. .IP "/u"
  316. This command is used to undefine a range name.  The range must have
  317. been previously defined.
  318.  
  319. .PP
  320. Miscellaneous commands:
  321.  
  322. .IP q
  323. Exit from \fIpname\fR.  If you were editing a file, and you modified
  324. it, then
  325. \fIpname\fR will ask about saving before exiting. 
  326. If you aren't editing a file and haven't saved the data you
  327. entered, you will get a chance to save the data
  328. before you exit.
  329.  
  330. .IP ^C
  331. Alternate exit command.
  332.  
  333. .IP ?
  334. Types a brief helpful message.
  335.  
  336. .IP "^G or ESC"
  337. Abort entry of the current command.
  338.  
  339. .IP "^R or ^L"
  340. Redraw the screen.
  341.  
  342. .IP ^V
  343. Types, in the command line, the name of the cell referenced by
  344. the cell cursor.  This is used when typing in expressions which refer to
  345. entries in the table.
  346.  
  347. .IP ^E
  348. Types, in the command line, the expression of the cell referenced
  349. by the cell cursor.
  350.  
  351. .IP ^A
  352. Types, in the command line, the value of the cell referenced
  353. by the cell cursor.
  354.  
  355. .PP
  356. Expressions that are used with the '=' and 'e' commands have a fairly
  357. conventional syntax.  Terms may be variable names (from the ^V command),
  358. parenthesised expressions, negated terms, and constants. 
  359. Rectangular regions of the screen may be operated upon with '@' functions
  360. such as sum (@sum), average (@avg) and product (@prod).
  361. Terms may be combined using many binary
  362. operators.  Their precedences (from highest to lowest) are: ^; *,/; +,-;
  363. <,=,>,<=,>=; &; |; ?.
  364.  
  365. .TP 15
  366. e+e
  367. Addition.
  368.  
  369. .TP 15
  370. e-e
  371. Subtraction.
  372.  
  373. .TP 15
  374. e*e
  375. Multiplication.
  376.  
  377. .TP 15
  378. e/e
  379. Division.
  380.  
  381. .TP 15
  382. e^e
  383. Exponentiation.
  384.  
  385. .TP 15
  386. @sum(v:v)
  387. Sum all valid (nonblank) entries in the region whose two corners are defined
  388. by the two variable (cell) names given.
  389.  
  390. .TP 15
  391. @avg(v:v)
  392. Average all valid (nonblank) entries in the region whose two corners are defined
  393. by the two variable (cell) names given.
  394.  
  395. .TP 15
  396. @prod(v:v)
  397. Multiply together all valid (nonblank) entries in the region whose two
  398. corners are defined by the two variable (cell) names given.
  399.  
  400. .TP 15
  401. @max(v:v)
  402. Return the maximum value in specified region.
  403.  
  404. .TP 15
  405. @min(v:v)
  406. Return the minimum value in the specified region.
  407.  
  408. .TP 15
  409. @stddev(v:v)
  410. Return the sample standard deviation of the specified region.
  411.  
  412. .TP 15
  413. e?e:e
  414. Conditional: If the first expression is true then the value of the second is
  415. returned, otherwise the value of the third is.
  416.  
  417. .TP 15
  418. <,=,>,<=,>=
  419. Relationals: true iff the indicated relation holds.
  420.  
  421. .TP 15
  422. &,|
  423. Boolean connectives.
  424.  
  425. .TP 15
  426. fixed
  427. To make a variable not change automatically when a cell moves,
  428. put the word \*(lqfixed\*(rq in front of the reference.  I.e.
  429. B1*fixed C3
  430.  
  431. .PP
  432. Assorted math functions.  Most of these are standard system functions
  433. more fully described in
  434. .I math(3).
  435. All of them operate on floating point numbers (doubles);
  436. the trig functions operate with angles in radians.
  437.  
  438. .TP 15
  439. @exp(expr)
  440. Returns exponential function of <expr>.
  441.  
  442. .TP 15
  443. @ln(expr)
  444. Returns the natural logarithm of <expr>.
  445.  
  446. .TP 15
  447. @log(expr)
  448. Returns the base 10 logarithm of <expr>.
  449.  
  450. .TP 15
  451. @pow(expr1,expr2)
  452. Returns <expr1> raised to the power of <expr2>.
  453.  
  454. .TP 15
  455. @floor(expr)
  456. Returns returns the largest integer not greater than <expr>.
  457.  
  458. .TP 15
  459. @ceil(expr)
  460. Returns the smallest integer not less than <expr>.
  461.  
  462. .TP 15
  463. @rnd(expr)
  464. Rounds <expr> to the nearest integer.
  465.  
  466. .TP 15
  467. @hypot(x,y)
  468. Returns SQRT(x*x+y*y), taking precautions against unwarranted overflows.
  469.  
  470. .TP 15
  471. @fabs(expr)
  472. Returns the absolute value |expr|.
  473.  
  474. .TP 15
  475. @sin(expr), @cos(expr), @tan(expr)
  476. Return trigonometric functions of radian arguments. The magnitude of the
  477. arguments are not checked to assure meaningful results.
  478.  
  479. .TP 15
  480. @asin(expr)
  481. Returns the arc sin in the range -pi/2 to pi/2
  482.  
  483. .TP 15
  484. @acos(expr)
  485. Returns the arc cosine in the range 0 to pi.
  486. }i(<|J
  487. .TP 15
  488. @atan(expr)
  489. Returns the arc tangent of <expr> in the range -pi/2 to pi/2.
  490.  
  491. .TP 15
  492. @dtr(expr)
  493. Converts <expr> in degrees to radians.
  494.  
  495. .TP 15
  496. @rtd(expr)
  497. Converts <expr> in radians to degrees.
  498.  
  499. .TP 15
  500. pi
  501. A constant quite close to pi.
  502.  
  503. .TP 15
  504. @gamma(expr1)
  505. Returns the natural log of the gamma function.
  506.  
  507. .SH SEE ALSO
  508. bc(1), dc(1), crypt(1)
  509.  
  510. .SH BUGS
  511.  
  512. Expression reevaluation is done in the same top-to-bottom, left-to-right
  513. manner as is done in other spread sheet calculators.  This is silly.  A
  514. proper following of the dependency graph with (perhaps) recourse to
  515. relaxation should be implemented.
  516.  
  517. At most 200 rows and 40 columns.
  518. \SHAR\EOF\
  519. else
  520.   echo "will not over write ./sc.doc"
  521. fi
  522. if [ `wc -c ./sc.doc | awk '{printf $1}'` -ne 13353 ]
  523. then
  524. echo `wc -c ./sc.doc | awk '{print "Got " $1 ", Expected " 13353}'`
  525. fi
  526. if `test ! -s ./sc.h`
  527. then
  528. echo "writing ./sc.h"
  529. cat > ./sc.h << '\SHAR\EOF\'
  530. /*    VC    A Table Calculator
  531.  *        Common definitions
  532.  *
  533.  *        original by James Gosling, September 1982
  534.  *        modified by Mark Weiser and Bruce Israel,
  535.  *            University of Maryland
  536.  *
  537.  */
  538.  
  539.  
  540.  
  541. #define MAXROWS 200
  542. #define MAXCOLS 40
  543. #define error move(1,0), clrtoeol(), printw
  544.  
  545. typedef struct range_s {
  546.     struct ent *left, *right;
  547. } RANGE_S;
  548.  
  549. /*
  550.  * If you want to save room, make row and col below into unsigned
  551.  * chars and make sure MAXROWS and MAXCOLS above are both less
  552.  * than 256.  (128 if your compiler doesn't support unsigned char).
  553.  */
  554.  
  555. struct ent {
  556.     double v;
  557.     char *label;
  558.     struct enode *expr;
  559.     short flags;
  560.     short row, col;
  561.     struct ent *next;
  562. };
  563.  
  564. struct range {
  565.     struct ent *r_left, *r_right;
  566.     char *r_name;
  567.     struct range *r_next, *r_prev;
  568. };
  569.  
  570. struct enode {
  571.     int op;
  572.     union {
  573.     double k;
  574.     struct ent *v;
  575.     struct {
  576.         struct enode *left, *right;
  577.     } o;
  578.     } e;
  579. };
  580.  
  581. /* op values */
  582. #define O_VAR 'v'
  583. #define O_CONST 'k'
  584. #define O_REDUCE(c) (c+0200)
  585.  
  586. #define ACOS 0
  587. #define ASIN 1
  588. #define ATAN 2
  589. #define CEIL 3
  590. #define COS 4
  591. #define EXP 5 
  592. #define FABS 6 
  593. #define FLOOR 7
  594. #define HYPOT 8
  595. #define LOG 9
  596. #define LOG10 10
  597. #define POW 11
  598. #define SIN 12
  599. #define SQRT 13
  600. #define TAN 14
  601. #define DTR 15
  602. #define RTD 16
  603. #define MIN 17
  604. #define MAX 18
  605. #define RND 19
  606.  
  607. /* flag values */
  608. #define is_valid     0001
  609. #define is_changed   0002
  610. #define is_lchanged  0004
  611. #define is_leftflush 0010
  612. #define is_deleted   0020
  613.  
  614. #define ctl(c) ('c'&037)
  615.  
  616. extern struct ent *tbl[MAXROWS][MAXCOLS];
  617.  
  618. extern int strow, stcol;
  619. extern int currow, curcol;
  620. extern int savedrow, savedcol;
  621. extern int FullUpdate;
  622. extern int maxrow, maxcol;
  623. extern int fwidth[MAXCOLS];
  624. extern int precision[MAXCOLS];
  625. extern char col_hidden[MAXCOLS];
  626. extern char row_hidden[MAXROWS];
  627. extern char line[1000];
  628. extern int linelim;
  629. extern int changed;
  630. extern struct ent *to_fix;
  631. extern struct enode *new();
  632. extern struct enode *new_const();
  633. extern struct enode *new_var();
  634. extern struct ent *lookat();
  635. extern struct enode *copye();
  636. extern char *coltoa();
  637. extern FILE *openout();
  638. extern struct range *find_range();
  639. extern char *v_name();
  640. extern int modflg;
  641. extern int Crypt;
  642.  
  643. #if BSD42 || SYSIII
  644. #define    cbreak        crmode
  645. #define    nocbreak    nocrmode
  646. #endif
  647.  
  648. \SHAR\EOF\
  649. else
  650.   echo "will not over write ./sc.h"
  651. fi
  652. if [ `wc -c ./sc.h | awk '{printf $1}'` -ne 2228 ]
  653. then
  654. echo `wc -c ./sc.h | awk '{print "Got " $1 ", Expected " 2228}'`
  655. fi
  656. if `test ! -s ./sc.c`
  657. then
  658. echo "writing ./sc.c"
  659. cat > ./sc.c << '\SHAR\EOF\'
  660. /*    SC    A Spreadsheet Calculator
  661.  *        Main driver
  662.  *
  663.  *        original by James Gosling, September 1982
  664.  *        modifications by Mark Weiser and Bruce Israel,
  665.  *            University of Maryland
  666.  *
  667.  *              More mods Robert Bond, 12/86
  668.  *
  669.  */
  670.  
  671.  
  672. #include <signal.h>
  673. #include <curses.h>
  674.  
  675. #ifdef BSD42
  676. #include <strings.h>
  677. #else
  678. #ifndef SYSIII
  679. #include <string.h>
  680. #endif
  681. #endif
  682.  
  683. #include <stdio.h>
  684. #include "sc.h"
  685.  
  686. char *xmalloc();
  687.  
  688. /* default column width */
  689.  
  690. #define DEFWIDTH 10
  691. #define DEFPREC   2
  692.  
  693. #define RESCOL 4  /* columns reserved for row numbers */
  694. #define RESROW 3  /* rows reserved for prompt, error, and column numbers */
  695.  
  696. /* Globals defined in sc.h */
  697.  
  698. struct ent *tbl[MAXROWS][MAXCOLS];
  699. int strow, stcol;
  700. int currow, curcol;
  701. int savedrow, savedcol;
  702. int FullUpdate;
  703. int maxrow, maxcol;
  704. int fwidth[MAXCOLS];
  705. int precision[MAXCOLS];
  706. char col_hidden[MAXCOLS];
  707. char row_hidden[MAXROWS];
  708. char line[1000];
  709. int changed;
  710. struct ent *to_fix;
  711. int modflg;
  712.  
  713. char curfile[1024];
  714.  
  715. int linelim = -1;
  716. int showme = 1;  /* 1 to display the current cell in the top line */
  717. char *rev = "$Revision: 4.1 $";
  718.  
  719. int seenerr;
  720.  
  721. yyerror (err)
  722. char *err; {
  723.     if (seenerr) return;
  724.     seenerr++;
  725.     move (1,0);
  726.     clrtoeol ();
  727.     printw ("%s: %.*s<=%s",err,linelim,line,line+linelim);
  728. }
  729.  
  730. struct ent *
  731. lookat(row,col){
  732.     register struct ent **p;
  733.     if (row < 0)
  734.     row = 0;
  735.     else if (row > MAXROWS-1) 
  736.     row = MAXROWS-1;
  737.     if (col < 0) 
  738.     col = 0;
  739.     else if (col > MAXCOLS-1)
  740.     col = MAXCOLS-1;
  741.     p = &tbl[row][col];
  742.     if (*p==0) {
  743.     *p = (struct ent *) xmalloc ((unsigned)sizeof (struct ent));
  744.     if (row>maxrow) maxrow = row;
  745.     if (col>maxcol) maxcol = col;
  746.     (*p)->label = 0;
  747.     (*p)->flags = 0;
  748.     (*p)->row = row;
  749.     (*p)->col = col;
  750.     (*p)->expr = 0;
  751.     (*p)->v = (double) 0.0;
  752.     }
  753.     return *p;
  754. }
  755.  
  756. /*
  757.  * This structure is used to keep ent structs around before they
  758.  * are deleted to allow the sync_refs routine a chance to fix the
  759.  * variable references.
  760.  * We also use it as a last-deleted buffer for the 'p' command.
  761.  */
  762.  
  763. free_ent(p)
  764. register struct ent *p;
  765. {
  766.     p->next = to_fix;
  767.     to_fix = p;
  768.     p->flags |= is_deleted;
  769. }
  770.  
  771. flush_saved()
  772. {
  773.     register struct ent *p;
  774.     register struct ent *q;
  775.  
  776.     if (!(p = to_fix))
  777.     return;
  778.     while (p) {
  779.     clearent(p);
  780.     q = p->next;
  781.     xfree((char *)p);
  782.     p = q;
  783.     }
  784.     to_fix = 0;
  785. }
  786.  
  787. update () {
  788.     register    row,
  789.                 col;
  790.     register struct ent **p;
  791.     static  lastmx,
  792.             lastmy;
  793.     static  char *under_cursor = " ";
  794.     int     maxcol;
  795.     int     maxrow;
  796.     int     rows;
  797.     int     cols;
  798.     register r;
  799.  
  800.     while (row_hidden[currow])   /* You can't hide the last row or col */
  801.     currow++;
  802.     while (col_hidden[curcol])
  803.     curcol++;
  804.     if (curcol < stcol)
  805.     stcol = curcol, FullUpdate++;
  806.     if (currow < strow)
  807.     strow = currow, FullUpdate++;
  808.     while (1) {
  809.     register    i;
  810.     for (i = stcol, cols = 0, col = RESCOL;
  811.          (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
  812.         cols++;
  813.         if (col_hidden[i])
  814.         continue;
  815.         col += fwidth[i];
  816.     }
  817.     if (curcol >= stcol + cols)
  818.         stcol++, FullUpdate++;
  819.     else
  820.         break;
  821.     }
  822.     while (1) {
  823.     register    i;
  824.     for (i = strow, rows = 0, row = RESROW;
  825.          row < LINES && i < MAXROWS; i++) {
  826.         rows++;
  827.         if (row_hidden[i])
  828.         continue;
  829.         row++;
  830.     }
  831.     if (currow >= strow + rows)
  832.         strow++, FullUpdate++;
  833.     else
  834.         break;
  835.     }
  836.     maxcol = stcol + cols - 1;
  837.     maxrow = strow + rows - 1;
  838.     if (FullUpdate) {
  839.     register int i;
  840.     move (2, 0);
  841.     clrtobot ();
  842.     standout();
  843.     for (row=RESROW, i=strow; i <= maxrow; i++) {
  844.         if (row_hidden[i]) 
  845.         continue;
  846.         move(row,0);
  847.         printw("%-*d", RESCOL, i);
  848.         row++;
  849.     }
  850.     move (2,0);
  851.     printw("%*s", RESCOL, " ");
  852.     for (col=RESCOL, i = stcol; i <= maxcol; i++) {
  853.         if (col_hidden[i])
  854.         continue;
  855.         move(2, col);
  856.         printw("%*s", fwidth[i], coltoa(i));
  857.         col += fwidth[i];
  858.     }
  859.     standend();
  860.     }
  861.     for (row = strow, r = RESROW; row <= maxrow; row++) {
  862.     register    c = RESCOL;
  863.     if (row_hidden[row])
  864.         continue;
  865.     for (p = &tbl[row][col = stcol]; col <= maxcol; col++, p++) {
  866.         if (col_hidden[col])
  867.         continue;
  868.         if (*p && ((*p) -> flags & is_changed || FullUpdate)) {
  869.         char   *s;
  870.         move (r, c);
  871.         (*p) -> flags &= ~is_changed;
  872.         if ((*p) -> flags & is_valid)
  873.             printw ("%*.*f", fwidth[col], precision[col], (*p) -> v);
  874.         if (s = (*p) -> label) {
  875.             char field[1024];
  876.  
  877.             strncpy(field,s,fwidth[col]);
  878.             field[fwidth[col]] = 0;
  879.             mvaddstr (r,
  880.                 (*p) -> flags & is_leftflush
  881.                 ? c : c - strlen (field) + fwidth[col],
  882.                 field);
  883.         }
  884.         }
  885.         c += fwidth[col];
  886.     }
  887.     r++;
  888.     }
  889.     
  890.     move(lastmy, lastmx);
  891.     if (inch() == '<')
  892.         addstr (under_cursor);
  893.     lastmy =  RESROW;
  894.     for (row = strow; row < currow; row++)
  895.     if (!row_hidden[row])
  896.         lastmy += 1;
  897.     lastmx = RESCOL;
  898.     for (col = stcol; col <= curcol; col++)
  899.     if (!col_hidden[col])
  900.         lastmx += fwidth[col];
  901.     move(lastmy, lastmx);
  902.     *under_cursor = inch();
  903.     addstr ("<");
  904.     move (0, 0);
  905.     clrtoeol ();
  906.     if (linelim >= 0) {
  907.     addstr (">> ");
  908.     addstr (line);
  909.     } else {
  910.     if (showme) {
  911.         register struct ent *p;
  912.         p = tbl[currow][curcol];
  913.         if (p && ((p->flags & is_valid) || p->label)) {
  914.         if (p->expr || !p->label) {
  915.             linelim = 0;
  916.             editexp(currow, curcol);
  917.         } else {
  918.             sprintf(line, "%s", p->label);
  919.         }
  920.         addstr("[");
  921.         addstr (line);
  922.         addstr("]");
  923.         linelim = -1;
  924.         } else {
  925.         addstr("[]");
  926.         }
  927.     }
  928.     move (lastmy, lastmx);
  929.     }
  930.     FullUpdate = 0;
  931. }
  932.  
  933. main (argc, argv)
  934. char  **argv; {
  935.     int     inloop = 1;
  936.     register int   c;
  937.     int     edistate = -1;
  938.     int     arg = 1;
  939.     int     narg;
  940.     int     nedistate;
  941.     int        running;
  942.     char    revmsg[80];
  943.     char    *revi;
  944.     char    *pname;
  945.  
  946.     pname = argv[0];
  947.  
  948.     {
  949.     register    i;
  950.     for (i = 0; i < MAXCOLS; i++) {
  951.         fwidth[i] = DEFWIDTH;
  952.         precision[i] = DEFPREC;
  953.     }
  954.     }
  955.     curfile[0]=0;
  956.     running = 1;
  957.  
  958.     signals();
  959.     initscr ();
  960.     goraw();
  961.     initkbd();
  962.     if (argc > 1 && !strcmp(argv[1], "-x")) { 
  963.         Crypt++;
  964.         argv++;
  965.         argc--;
  966.     }
  967.     if (argc > 1) {
  968.     strcpy(curfile,argv[1]);
  969.     readfile (argv[1],0);
  970.     }
  971.     modflg = 0;
  972.     strcpy(revmsg, pname);
  973.     for (revi=rev; *revi++ != ':';);
  974.     strcat(revmsg, revi);
  975.     revi = revmsg+strlen(revmsg);
  976.     *--revi = 0;
  977.     strcat(revmsg,"Type '?' for help.");
  978.     error (revmsg);
  979. #ifdef VENIX
  980.     setbuf (stdin, NULL);
  981. #endif
  982.     FullUpdate++;
  983.     while (inloop) { running = 1;
  984.     while (running) {
  985.     nedistate = -1;
  986.     narg = 1;
  987.     if (edistate < 0 && linelim < 0 && (changed || FullUpdate))
  988.         EvalAll (), changed = 0;
  989.     update();
  990. #ifndef SYSV3
  991.     refresh(); /* 5.3 does a refresh in getch */ 
  992. #endif
  993.     c = nmgetch();
  994.     move (1, 0);
  995.     clrtoeol ();
  996.     fflush (stdout);
  997.     seenerr = 0;
  998.     if ((c < ' ') || ( c == 0177 ))
  999.         switch (c) {
  1000. #if defined(BSD42) || defined (BSD43)
  1001.         case ctl (z):
  1002.             deraw();
  1003. #ifndef V7
  1004.             kill(getpid(),SIGTSTP);
  1005. #endif
  1006.  
  1007.             /* the pc stops here */
  1008.  
  1009.             goraw();
  1010.             break;
  1011. #endif
  1012.         case ctl (r):
  1013.         case ctl (l):
  1014.             FullUpdate++;
  1015.             clearok(stdscr,1);
  1016.             break;
  1017.         default:
  1018.             error ("No such command  (^%c)", c + 0100);
  1019.             break;
  1020.         case ctl (b):
  1021.             while (--arg>=0) {
  1022.             if (curcol)
  1023.                 curcol--;
  1024.             else
  1025.                 error ("At column A");
  1026.             while(col_hidden[curcol] && curcol)
  1027.                 curcol--;
  1028.             }
  1029.             break;
  1030.         case ctl (c):
  1031.             running = 0;
  1032.             break;
  1033.         case ctl (f):
  1034.             while (--arg>=0) {
  1035.             if (curcol < MAXCOLS - 1)
  1036.                 curcol++;
  1037.             else
  1038.                 error ("The table can't be any wider");
  1039.             while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
  1040.                 curcol++;
  1041.             }
  1042.             break;
  1043.         case ctl (g):
  1044.         case ctl ([):
  1045.             linelim = -1;
  1046.             move (1, 0);
  1047.             clrtoeol ();
  1048.             break;
  1049.         case 0177:
  1050.         case ctl (h):
  1051.             while (--arg>=0) if (linelim > 0)
  1052.             line[--linelim] = 0;
  1053.             break;
  1054.         case ctl (m):
  1055.         case ctl (j):
  1056.             if (linelim < 0)
  1057.             line[linelim = 0] = 0;
  1058.             else {
  1059.             linelim = 0;
  1060.             yyparse ();
  1061.             linelim = -1;
  1062.             }
  1063.             break;
  1064.         case ctl (n):
  1065.             while (--arg>=0) {
  1066.             if (currow < MAXROWS - 1)
  1067.                 currow++;
  1068.             else
  1069.                 error ("The table can't be any longer");
  1070.             while (row_hidden[currow] && (currow < MAXROWS - 1))
  1071.                 currow++;
  1072.             }
  1073.             break;
  1074.         case ctl (p):
  1075.             while (--arg>=0) {
  1076.             if (currow)
  1077.                 currow--;
  1078.             else
  1079.                 error ("At row zero");
  1080.             while (row_hidden[currow] && currow)
  1081.                 currow--;
  1082.             }
  1083.             break;
  1084.         case ctl (q):
  1085.             break;    /* ignore flow control */
  1086.         case ctl (s):
  1087.             break;    /* ignore flow control */
  1088.         case ctl (t):
  1089.             showme ^= 1;
  1090.             break;
  1091.         case ctl (u):
  1092.             narg = arg * 4;
  1093.             nedistate = 1;
  1094.             break;
  1095.         case ctl (v):    /* insert variable name */
  1096.             if (linelim > 0) {
  1097.             sprintf (line+linelim,"%s", v_name(currow, curcol));
  1098.             linelim = strlen (line);
  1099.             }
  1100.             break;
  1101.         case ctl (e):    /* insert variable expression */
  1102.             if (linelim > 0) editexp(currow,curcol);
  1103.             break;
  1104.         case ctl (a):    /* insert variable value */
  1105.             if (linelim > 0) {
  1106.             struct ent *p = tbl[currow][curcol];
  1107.  
  1108.             if (p && p -> flags & is_valid) {
  1109.                 sprintf (line + linelim, "%.*f",
  1110.                     precision[curcol],p -> v);
  1111.                 linelim = strlen (line);
  1112.             }
  1113.             }
  1114.             break;
  1115.         }
  1116.     else
  1117. #ifdef QUICK
  1118.         if ('0' <= c && c <= '9' &&  edistate >= 0) {
  1119. #else
  1120.         if ('0' <= c && c <= '9' && (linelim < 0 || edistate >= 0)) {
  1121. #endif /* QUICK */
  1122.         if (edistate != 0) {
  1123.             if (c == '0')      /* just a '0' goes to left col */
  1124.             curcol = 0;
  1125.             else {
  1126.                 nedistate = 0;
  1127.                 narg = c - '0';
  1128.             }
  1129.         } else {
  1130.             nedistate = 0;
  1131.             narg = arg * 10 + (c - '0');
  1132.         }
  1133.         }
  1134.         else
  1135.         if (linelim >= 0) {
  1136.             line[linelim++] = c;
  1137.             line[linelim] = 0;
  1138.         }
  1139.         else
  1140.             switch (c) {
  1141.             case '.':
  1142.                 nedistate = 1;
  1143.                 break;
  1144.             case ':':
  1145.                 break;    /* Be nice to vi users */
  1146. #ifdef QUICK
  1147.             case '0':
  1148.             case '1':
  1149.             case '2':
  1150.             case '3':
  1151.             case '4':
  1152.             case '5':
  1153.             case '6':
  1154.             case '7':
  1155.             case '8':
  1156.             case '9':
  1157.             case '-':
  1158.                 sprintf(line,"let %s = %c",
  1159.                     v_name(currow, curcol), c);
  1160.                 linelim = strlen (line);
  1161.                 break;
  1162. #endif /* QUICK */
  1163.             case '=':
  1164.                 sprintf(line,"let %s = ",v_name(currow, curcol));
  1165.                 linelim = strlen (line);
  1166.                 break;
  1167.             case '/':
  1168.                 error("c:copy  x:erase  f:fill  d:define  u:undefine  s:show");
  1169.                 refresh();
  1170.                 switch (nmgetch()) {
  1171.                 case 'c':
  1172.                 sprintf(line,"copy [to] %s [from range] ",
  1173.                            v_name(currow, curcol));
  1174.                 linelim = strlen(line);
  1175.                 break;
  1176.                 case 'x':
  1177.                 sprintf(line,"erase [range] ");
  1178.                 linelim = strlen(line);
  1179.                 break;
  1180.                 case 'f':
  1181.                 sprintf(line,"fill [range start inc] ");
  1182.                 linelim = strlen(line);
  1183.                 break;
  1184.                 case 'd':
  1185.                 sprintf(line,"define [string range] \"");
  1186.                 linelim = strlen(line);
  1187.                 modflg++;
  1188.                 break;
  1189.                 case 'u':
  1190.                 sprintf(line,"undefine [range] ");
  1191.                 linelim = strlen(line);
  1192.                 modflg++;
  1193.                 break;
  1194.                 case 's':
  1195.                 {
  1196.                 FILE *f;
  1197.                 int pid;
  1198.                 f = openout("| sort | less", &pid);
  1199.                 if (!f) {
  1200.                     error("Cant open pipe to sort");
  1201.                     break;
  1202.                 }
  1203.                 list_range(f);
  1204.                 closeout(f, pid);
  1205.                 break;
  1206.                 }
  1207.                default:
  1208.                 error("Invalid region operation");
  1209.                 }
  1210.                 break;
  1211.             case '$':
  1212.                 curcol = MAXCOLS - 1;
  1213.                 while (!tbl[currow][curcol] && curcol > 0)
  1214.                 curcol--;
  1215.                 break;
  1216.             case '#':
  1217.                 currow = MAXROWS - 1;
  1218.                 while (!tbl[currow][curcol] && currow > 0)
  1219.                 currow--;
  1220.                 break;
  1221.             case '^':
  1222.                 currow = 0;
  1223.                 break;
  1224.             case '?':
  1225.                 help ();
  1226.                 break;
  1227.             case '"':
  1228.                 sprintf (line, "label %s = \"",
  1229.                         v_name(currow, curcol));
  1230.                 linelim = strlen (line);
  1231.                 break;
  1232.             case '<':
  1233.                 sprintf (line, "leftstring %s = \"",
  1234.                     v_name(currow, curcol));
  1235.                 linelim = strlen (line);
  1236.                 break;
  1237.             case '>':
  1238.                 sprintf (line, "rightstring %s = \"",
  1239.                    v_name(currow, curcol));
  1240.                 linelim = strlen (line);
  1241.                 break;
  1242.             case 'e':
  1243.                 editv (currow, curcol);
  1244.                 break;
  1245.             case 'E':
  1246.                 edits (currow, curcol);
  1247.                 break;
  1248.             case 'f':
  1249.                 if (arg == 1)
  1250.                     sprintf (line, "format [for column] %s ",
  1251.                     coltoa(curcol));
  1252.                 else {
  1253.                 sprintf(line, "format [for columns] %s:",
  1254.                     coltoa(curcol));
  1255.                 sprintf(line+strlen(line), "%s ",
  1256.                     coltoa(curcol+arg-1));
  1257.                 }
  1258.                 error("Current format is %d %d",
  1259.                     fwidth[curcol],precision[curcol]);
  1260.                 linelim = strlen (line);
  1261.                 break;
  1262.             case 'g':
  1263.                 sprintf (line, "goto [v] ");
  1264.                 linelim = strlen (line);
  1265.                 break;
  1266.             case 'P':
  1267.                 sprintf (line, "put [database into] \"");
  1268.                 if (*curfile)
  1269.                     error("Default path is '%s'",curfile);
  1270.                 linelim = strlen (line);
  1271.                 break;
  1272.             case 'M':
  1273.                 sprintf (line, "merge [database from] \"");
  1274.                 linelim = strlen (line);
  1275.                 break;
  1276.             case 'G':
  1277.                 sprintf (line, "get [database from] \"");
  1278.                 if (*curfile)
  1279.                     error("Default file is '%s'",curfile);
  1280.                 linelim = strlen (line);
  1281.                 break;
  1282.             case 'W':
  1283.                 sprintf (line, "write [listing to] \"");
  1284.                 linelim = strlen (line);
  1285.                 break;
  1286.             case 'T':    /* tbl output */
  1287.                 sprintf (line, "tbl [listing to] \"");
  1288.                 linelim = strlen (line);
  1289.                 break;
  1290.             case 'i':
  1291.                 switch (get_qual()) {
  1292.                 case 'r':
  1293.                 insertrow(arg);
  1294.                 break;
  1295.                 case 'c':
  1296.                 insertcol(arg);
  1297.                 break;
  1298.                 default:
  1299.                 error("Invalid insert command");
  1300.                 break;
  1301.                 }
  1302.                 break;
  1303.             case 'd':
  1304.                 switch (get_qual()) {
  1305.                 case 'r':
  1306.                 deleterow(arg);
  1307.                 break;
  1308.                 case 'c':
  1309.                 deletecol(arg);
  1310.                 break;
  1311.                 default:
  1312.                 error("Invalid delete command");
  1313.                 break;
  1314.                 }
  1315.                 break;
  1316.             case 'v':
  1317.                 switch (get_qual()) {
  1318.                 case 'r':
  1319.                 rowvalueize(arg);
  1320.                 modflg++;
  1321.                 break;
  1322.                 case 'c':
  1323.                 colvalueize(arg);
  1324.                 modflg++;
  1325.                 break;
  1326.                 default:
  1327.                 error("Invalid value command");
  1328.                 break;
  1329.                 }
  1330.                 break;
  1331.             case 'p':
  1332.                 {
  1333.                 register qual;
  1334.                 qual = get_qual();
  1335.                 while (arg--)
  1336.                     pullcells(qual);
  1337.                 break;
  1338.                 }
  1339.             case 'x':
  1340.                 {
  1341.                 register struct ent **p;
  1342.                 register int c;
  1343.                 flush_saved();
  1344.                 for (c = curcol; arg-- && c < MAXCOLS; c++) {
  1345.                 p = &tbl[currow][c];
  1346.                 if (*p) {
  1347.                         free_ent(*p);
  1348.                         *p = 0;
  1349.                 }
  1350.                 }
  1351.                 sync_refs();
  1352.                 FullUpdate++;
  1353.                 }
  1354.                 break;
  1355.             case 'Q':
  1356.             case 'q':
  1357.                 running = 0;
  1358.                 break;
  1359.             case 'h':
  1360.                 while (--arg>=0) {
  1361.                 if (curcol)
  1362.                     curcol--;
  1363.                 else
  1364.                     error ("At column A");
  1365.                 while(col_hidden[curcol] && curcol)
  1366.                     curcol--;
  1367.                 }
  1368.                 break;
  1369.             case 'j':
  1370.                 while (--arg>=0) {
  1371.                 if (currow < MAXROWS - 1)
  1372.                     currow++;
  1373.                 else
  1374.                     error ("The table can't be any longer");
  1375.                 while (row_hidden[currow]&&(currow<MAXROWS-1))
  1376.                     currow++;
  1377.                 }
  1378.                 break;
  1379.             case 'k':
  1380.                 while (--arg>=0) {
  1381.                 if (currow)
  1382.                     currow--;
  1383.                 else
  1384.                     error ("At row zero");
  1385.                 while (row_hidden[currow] && currow)
  1386.                     currow--;
  1387.                 }
  1388.                 break;
  1389.             case 'l':
  1390.                 while (--arg>=0) {
  1391.                 if (curcol < MAXCOLS - 1)
  1392.                     curcol++;
  1393.                 else
  1394.                     error ("The table can't be any wider");
  1395.                 while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
  1396.                     curcol++;
  1397.                 }
  1398.                 break;
  1399.             case 'm':
  1400.                 savedrow = currow;
  1401.                 savedcol = curcol;
  1402.                 break;
  1403.             case 'c': {
  1404.                 register struct ent *p = tbl[savedrow][savedcol];
  1405.                 register c;
  1406.                 register struct ent *n;
  1407.                 if (!p)
  1408.                 break;
  1409.                 FullUpdate++;
  1410.                 modflg++;
  1411.                 for (c = curcol; arg-- && c < MAXCOLS; c++) {
  1412.                 n = lookat (currow, c);
  1413.                 clearent(n);
  1414.                 n -> flags = p -> flags;
  1415.                 n -> v = p -> v;
  1416.                 n -> expr = copye(p->expr,
  1417.                         currow - savedrow,
  1418.                         c - savedcol);
  1419.                 n -> label = 0;
  1420.                 if (p -> label) {
  1421.                     n -> label = (char *)
  1422.                          xmalloc((unsigned)strlen(p->label)+1);
  1423.                 strcpy (n -> label, p -> label);
  1424.                 }
  1425.                 }
  1426.                 break;
  1427.             }
  1428.             case 'z':
  1429.                 switch (get_qual()) {
  1430.                 case 'r':
  1431.                 hiderow(arg);
  1432.                 break;
  1433.                 case 'c':
  1434.                 hidecol(arg);
  1435.                 break;
  1436.                 default:
  1437.                 error("Invalid zap command");
  1438.                 break;
  1439.                 }
  1440.                 break;
  1441.             case 's':
  1442.                 switch (get_qual()) {
  1443.                 case 'r':
  1444.                 rowshow_op();
  1445.                 break;
  1446.                 case 'c':
  1447.                 colshow_op();
  1448.                 break;
  1449.                 default:
  1450.                 error("Invalid show command");
  1451.                 break;
  1452.                 }
  1453.                 break;
  1454.             case 'a':
  1455.                 switch (get_qual()) {
  1456.                 case 'r':
  1457.                 while (arg--)
  1458.                     duprow();
  1459.                 break;
  1460.                 case 'c':
  1461.                 while (arg--)
  1462.                     dupcol();
  1463.                 break;
  1464.                 default:
  1465.                 error("Invalid add row/col command");
  1466.                 break;
  1467.                 }
  1468.                 break;
  1469.             default:
  1470.                 if ((c & 0177) != c)
  1471.                 error("Weird character, decimal '%d'.\n",
  1472.                     (int) c);
  1473.                 else error ("No such command  (%c)", c);
  1474.                 break;
  1475.             }
  1476.     edistate = nedistate;
  1477.     arg = narg;
  1478.     }                /* while (running) */
  1479.     inloop = modcheck(" before exiting");
  1480.     }                /*  while (inloop) */
  1481.     deraw();
  1482.     resetkbd();
  1483.     endwin ();
  1484. }
  1485.  
  1486. goraw()
  1487. {
  1488.     clear();
  1489.     cbreak();
  1490.     nonl();
  1491.     noecho ();
  1492.     FullUpdate++;
  1493. }
  1494.  
  1495. deraw()
  1496. {
  1497.     move (LINES - 1, 0);
  1498.     clrtoeol();
  1499.     refresh();
  1500.     nocbreak();
  1501.     nl();
  1502.     echo();
  1503. }
  1504.  
  1505. signals()
  1506. {
  1507.     int quit();
  1508.     int timeout();
  1509.  
  1510.     signal(SIGINT, SIG_IGN);
  1511.     signal(SIGQUIT, quit);
  1512.     signal(SIGPIPE, quit);
  1513.     signal(SIGTERM, quit);
  1514.     signal(SIGALRM, timeout);
  1515.     signal(SIGFPE, quit);
  1516.     signal(SIGBUS, quit);
  1517. }
  1518.  
  1519. quit()
  1520. {
  1521.     deraw();
  1522.     resetkbd();
  1523.     endwin();
  1524.     exit(1);
  1525. }
  1526.  
  1527. modcheck(endstr)
  1528. char *endstr;
  1529. {
  1530.     if (modflg && curfile[0]) {
  1531.     char ch, lin[100];
  1532.  
  1533.     move (0, 0);
  1534.     clrtoeol ();
  1535.     sprintf (lin,"File '%s' is modified, save%s? ",curfile,endstr);
  1536.     addstr (lin);
  1537.     refresh();
  1538.     ch = nmgetch();
  1539.      if (ch != 'n' && ch != 'N')
  1540.          if (writefile(curfile) < 0)
  1541.          return (1);
  1542.     else if (ch == ctl (g) || ch == ctl([)) return(1);
  1543.     } else if (modflg) {
  1544.     char ch, lin[100];
  1545.  
  1546.     move (0, 0);
  1547.     clrtoeol ();
  1548.     sprintf (lin,"Do you want a chance to save the data? ");
  1549.     addstr (lin);
  1550.     refresh();
  1551.     ch = nmgetch();
  1552.     if (ch == 'n' || ch == 'N') return(0);
  1553.     else return(1);
  1554.       }
  1555.     return(0);
  1556. }
  1557.  
  1558.     
  1559. writefile (fname)
  1560. char *fname; {
  1561.     register FILE *f;
  1562.     register struct ent **p;
  1563.     register r, c;
  1564.     char save[1024];
  1565.     int pid;
  1566.  
  1567.     if (Crypt) {
  1568.     return (cwritefile(fname));
  1569.     }
  1570.  
  1571.     if (*fname == 0) fname = &curfile[0];
  1572.  
  1573.     strcpy(save,fname);
  1574.  
  1575.     f = openout(fname, &pid);
  1576.     if (f==0) {
  1577.     error ("Can't create %s", fname);
  1578.     return (-1);
  1579.     }
  1580.  
  1581.     fprintf (f, "# This data file was generated by the Spreadsheet ");
  1582.     fprintf (f, "Calculator.\n");
  1583.     fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
  1584.     for (c=0; c<MAXCOLS; c++)
  1585.     if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
  1586.         fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
  1587.     write_range(f);
  1588.     for (r=0; r<=maxrow; r++) {
  1589.     p = &tbl[r][0];
  1590.     for (c=0; c<=maxcol; c++, p++)
  1591.         if (*p) {
  1592.         if ((*p)->label)
  1593.             fprintf (f, "%sstring %s%d = \"%s\"\n",
  1594.                 (*p)->flags&is_leftflush ? "left" : "right",
  1595.                 coltoa(c),r,(*p)->label);
  1596.         if ((*p)->flags&is_valid) {
  1597.             editv (r, c);
  1598.             fprintf (f, "%s\n",line);
  1599.         }
  1600.         }
  1601.     }
  1602.  
  1603.     closeout(f, pid);
  1604.  
  1605.     if (!pid) {
  1606.         strcpy(curfile, save);
  1607.         modflg = 0;
  1608.         error("File '%s' written.",curfile);
  1609.     }
  1610.  
  1611.     return (0);
  1612. }
  1613.  
  1614. readfile (fname,eraseflg)
  1615. char *fname; int eraseflg; {
  1616.     register FILE *f;
  1617.     char save[1024];
  1618.  
  1619.     if (Crypt)  {
  1620.     creadfile(fname, eraseflg);
  1621.     return;
  1622.     }
  1623.  
  1624.     if (*fname == 0) fname = &curfile[0];
  1625.     strcpy(save,fname);
  1626.  
  1627.     if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
  1628.  
  1629.     f = fopen (save, "r");
  1630.     if (f==0) {
  1631.     error ("Can't read %s", save);
  1632.     return;
  1633.     }
  1634.  
  1635.     if (eraseflg) erasedb ();
  1636.  
  1637.     while (fgets(line,sizeof line,f)) {
  1638.     linelim = 0;
  1639.     if (line[0] != '#') yyparse ();
  1640.     }
  1641.     fclose (f);
  1642.     linelim = -1;
  1643.     modflg++;
  1644.     if (eraseflg) {
  1645.     strcpy(curfile,save);
  1646.     modflg = 0;
  1647.     }
  1648.     EvalAll();
  1649. }
  1650.  
  1651. erasedb () {
  1652.     register r, c;
  1653.     for (c = 0; c<=maxcol; c++) {
  1654.     fwidth[c] = DEFWIDTH;
  1655.     precision[c] = DEFPREC;
  1656.     }
  1657.  
  1658.     for (r = 0; r<=maxrow; r++) {
  1659.     register struct ent **p = &tbl[r][0];
  1660.     for (c=0; c++<=maxcol; p++)
  1661.         if (*p) {
  1662.         if ((*p)->expr) efree ((*p) -> expr);
  1663.         if ((*p)->label) xfree ((char *)((*p) -> label));
  1664.         xfree ((char *)(*p));
  1665.         *p = 0;
  1666.         }
  1667.     }
  1668.     maxrow = 0;
  1669.     maxcol = 0;
  1670.     FullUpdate++;
  1671. }
  1672.  
  1673. #if DEBUG
  1674. debugout(g,fmt,args) FILE *g; char *fmt; {
  1675.     int op;
  1676.  
  1677.     if (g == 0) g = fopen("debug","a"),op = 1;
  1678.     if (g == 0) return;
  1679.  
  1680.     _doprnt(fmt, &args, g);
  1681.  
  1682.     fflush(g);
  1683.     if (op) fclose(g);
  1684. }
  1685. #endif
  1686. \SHAR\EOF\
  1687. else
  1688.   echo "will not over write ./sc.c"
  1689. fi
  1690. if [ `wc -c ./sc.c | awk '{printf $1}'` -ne 20711 ]
  1691. then
  1692. echo `wc -c ./sc.c | awk '{print "Got " $1 ", Expected " 20711}'`
  1693. fi
  1694. if `test ! -s ./lex.c`
  1695. then
  1696. echo "writing ./lex.c"
  1697. cat > ./lex.c << '\SHAR\EOF\'
  1698. /*    SC    A Spreadsheet Calculator
  1699.  *        Lexical analyser
  1700.  *
  1701.  *        original by James Gosling, September 1982
  1702.  *        modifications by Mark Weiser and Bruce Israel,
  1703.  *            University of Maryland
  1704.  *
  1705.  *              More mods Robert Bond, 12/86
  1706.  *
  1707.  */
  1708.  
  1709.  
  1710.  
  1711. #if defined(BSD42) || defined(BSD43)
  1712. #include <sys/ioctl.h>
  1713. #endif 
  1714.  
  1715. #include <curses.h>
  1716. #include <signal.h>
  1717. #include <setjmp.h>
  1718. #include "sc.h"
  1719. #include <ctype.h>
  1720.  
  1721. #ifdef BSD42
  1722. #include <strings.h>
  1723. #else
  1724. #ifndef SYSIII
  1725. #include <string.h>
  1726. #endif
  1727. #endif
  1728.  
  1729. #include "y.tab.h"
  1730.  
  1731. char *strtof();
  1732. char *xmalloc();
  1733.  
  1734. jmp_buf wakeup;
  1735.  
  1736. struct key {
  1737.     char *key;
  1738.     int val;
  1739. };
  1740.  
  1741. struct key experres[] = {
  1742. #include "experres.h"
  1743.     0, 0};
  1744.  
  1745. struct key statres[] = {
  1746. #include "statres.h"
  1747.     0, 0};
  1748.  
  1749. #define ctl(x) ('x'&037)
  1750.  
  1751. yylex () {
  1752.     register char *p = line+linelim;
  1753.     int ret;
  1754.     while (isspace(*p)) p++;
  1755.     if (*p==0) ret = -1;
  1756.     else if (isalpha(*p)) {
  1757.     char *tokenst = p;
  1758.     register tokenl;
  1759.     register struct key *tbl;
  1760.     tokenl = 0;
  1761.     /*
  1762.      * This picks up either 1 or 2 alpha characters (a column) or
  1763.      * tokens with at least three leading alphas and '_' or digits
  1764.      * (a function or token or command or a range name)
  1765.     */
  1766.     while (isalpha(*p) || ((*p == '_') || isdigit(*p)) && (tokenl > 2)) {
  1767.         p++;
  1768.         tokenl++;
  1769.     }
  1770.     if (tokenl <= 2) {
  1771.         register  col;  /* a COL is 1 or 2 char alpha (and not pi or ln!) */
  1772.         if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'i') {
  1773.         ret = K_PI;
  1774.         } else if (tokenl == 2 && tokenst[0] == 'l' && tokenst[1] == 'n') {
  1775.         ret = K_LN;
  1776.         } else {
  1777.         ret = COL;
  1778.         col = ((tokenst[0] & 0137) - 'A');
  1779.         if (p == tokenst+2)
  1780.             col = (col + 1)*26 + ((tokenst[1] & 0137) - 'A');
  1781.         yylval.ival =  col;
  1782.         }
  1783.     } else {
  1784.         ret = WORD;
  1785.         for (tbl = linelim ? experres : statres; tbl->key; tbl++)
  1786.             if (((tbl->key[0]^tokenst[0])&0137)==0
  1787.              && tbl->key[tokenl]==0) {
  1788.             register i = 1;
  1789.             while (i<tokenl && ((tokenst[i]^tbl->key[i])&0137)==0)
  1790.                 i++;
  1791.             if (i>=tokenl) {
  1792.                 ret = tbl->val;
  1793.                 break;
  1794.             }
  1795.             }
  1796.         if (ret==WORD) { 
  1797.         struct range *r;
  1798.         if (r = find_range(tokenst, tokenl,
  1799.                    (struct ent *)0, (struct ent *)0)) {
  1800.             yylval.rval.left = r->r_left;
  1801.             yylval.rval.right = r->r_right;
  1802.             ret = RANGE;
  1803.         } else {
  1804.             linelim = p-line;
  1805.             yyerror ("Unintelligible word");
  1806.         }
  1807.         }
  1808.     }
  1809.     } else if ((*p == '.') || isdigit(*p)) {
  1810.     double v = 0;
  1811.     long temp;
  1812.     char *nstart = p;
  1813.     if (*p != '.') {
  1814.         do v = v*10 + (double)(*p-'0');
  1815.         while (isdigit(*++p));
  1816.     }
  1817.     if (*p=='.' || *p == 'e' || *p == 'E') {
  1818.         ret = FNUMBER;
  1819.         p = strtof(nstart, &yylval.fval);
  1820.     } else {
  1821.         temp = (int)v;
  1822.             if((double)temp != v)
  1823.             {
  1824.                 ret = FNUMBER;
  1825.                 yylval.fval = v;
  1826.             }
  1827.             else
  1828.             {
  1829.  
  1830.                 ret = NUMBER;
  1831.                 yylval.ival = v;
  1832.             }
  1833.     }
  1834.     } else if (*p=='"') {
  1835.     /* This storage is never freed.  Oh well.  -MDW */
  1836.     char *ptr;
  1837.         ptr = p+1;
  1838.         while(*ptr && *ptr++ != '"');
  1839.         ptr = xmalloc((unsigned)(ptr-p));
  1840.     yylval.sval = ptr;
  1841.     p += 1;
  1842.     while (*p && *p!='"') *ptr++ = *p++;
  1843.     *ptr = 0;
  1844.     if (*p) p += 1;
  1845.     ret = STRING;
  1846.     } else if (*p=='[') {
  1847.     while (*p && *p!=']') p++;
  1848.     if (*p) p++;
  1849.     linelim = p-line;
  1850.     return yylex();
  1851.     } else ret = *p++;
  1852.     linelim = p-line;
  1853.     return ret;
  1854. }
  1855.  
  1856. #ifdef SIMPLE
  1857.  
  1858. initkbd()
  1859. {}
  1860.  
  1861. resetkbd()
  1862. {}
  1863.  
  1864. nmgetch()
  1865. {
  1866.     return (getchar() & 0x7f);
  1867. }
  1868.  
  1869. #else /*SIMPLE*/
  1870.  
  1871. #if defined(BSD42) || defined (SYSIII) || defined(BSD43)
  1872.  
  1873. #define N_KEY 4
  1874.  
  1875. struct key_map {
  1876.     char *k_str;
  1877.     char k_val;
  1878.     char k_index;
  1879. }; 
  1880.  
  1881. struct key_map km[N_KEY];
  1882.  
  1883. char keyarea[N_KEY*10];
  1884.  
  1885. char *tgetstr();
  1886. char *getenv();
  1887.  
  1888. #ifdef TIOCSLTC
  1889. struct ltchars old_chars, new_chars;
  1890. #endif
  1891.  
  1892. char dont_use[] = {
  1893.     ctl(z), ctl(r), ctl(l), ctl(b), ctl(c), ctl(f), ctl(g), ctl([),
  1894.     ctl(h), ctl(m), ctl(j), ctl(n), ctl(p), ctl(q), ctl(s), ctl(t),
  1895.     ctl(u), ctl(v), ctl(e), ctl(a), 0,
  1896. };
  1897.  
  1898. initkbd()
  1899. {
  1900.     register struct key_map *kp;
  1901.     register i,j;
  1902.     char *ks;
  1903.     char *p = keyarea;
  1904.     static char buf[1024]; /* Why do I have to do this again? */
  1905.  
  1906.     if (tgetent(buf, getenv("TERM")) <= 0)
  1907.     return;
  1908.  
  1909.     km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl(b);
  1910.     km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl(f);
  1911.     km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl(p);
  1912.     km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl(n);
  1913.     ks = tgetstr("ks",&p);
  1914.     if (ks) 
  1915.     printf("%s",ks);
  1916.  
  1917.     /* Unmap arrow keys which conflict with our ctl keys   */
  1918.     /* Ignore unset, longer than length 1, and 1-1 mapped keys */
  1919.  
  1920.     for (i = 0; i < N_KEY; i++) {
  1921.     kp = &km[i];
  1922.     if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val))
  1923.         for (j = 0; dont_use[j] != 0; j++)
  1924.             if (kp->k_str[0] == dont_use[j]) {
  1925.              kp->k_str = (char *)0;
  1926.              break;
  1927.         }
  1928.     }
  1929.  
  1930.  
  1931. #ifdef TIOCSLTC
  1932.     ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars);
  1933.     new_chars = old_chars;
  1934.     if (old_chars.t_lnextc == ctl(v))
  1935.     new_chars.t_lnextc = -1;
  1936.     if (old_chars.t_rprntc == ctl(r))
  1937.     new_chars.t_rprntc = -1;
  1938.     ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
  1939. #endif
  1940. }
  1941.  
  1942. resetkbd()
  1943. {
  1944. #ifdef TIOCSLTC
  1945.     ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars);
  1946. #endif
  1947. }
  1948.  
  1949. nmgetch() 
  1950. {
  1951.     register int c;
  1952.     register struct key_map *kp;
  1953.     register struct key_map *biggest;
  1954.     register int i;
  1955.     int almost;
  1956.     int maybe;
  1957.  
  1958.     static char dumpbuf[10];
  1959.     static char *dumpindex;
  1960.  
  1961.     int timeout();
  1962.  
  1963.     if (dumpindex && *dumpindex)
  1964.         return (*dumpindex++);
  1965.  
  1966.     c = getchar() & 0x7f;
  1967.     biggest = 0;
  1968.     almost = 0;
  1969.  
  1970.     for (kp = &km[0]; kp < &km[N_KEY]; kp++) {
  1971.     if (!kp->k_str)
  1972.         continue;
  1973.     if (c == kp->k_str[kp->k_index]) {
  1974.         almost = 1;
  1975.         kp->k_index++;
  1976.         if (kp->k_str[kp->k_index] == 0) {
  1977.         c = kp->k_val;
  1978.                    for (kp = &km[0]; kp < &km[N_KEY]; kp++)
  1979.                 kp->k_index = 0;
  1980.             return(c);
  1981.         }
  1982.     }
  1983.     if (!biggest && kp->k_index)
  1984.         biggest = kp;
  1985.         else if (kp->k_index && biggest->k_index < kp->k_index)
  1986.         biggest = kp;
  1987.     }
  1988.  
  1989.     if (almost) { 
  1990.  
  1991.         signal(SIGALRM, timeout);
  1992.         alarm(1);
  1993.  
  1994.     if (setjmp(wakeup) == 0) { 
  1995.         maybe = nmgetch();
  1996.         alarm(0);
  1997.         return(maybe);
  1998.     }
  1999.  
  2000.     }
  2001.     
  2002.     if (biggest) {
  2003.     for (i = 0; i<biggest->k_index; i++) 
  2004.         dumpbuf[i] = biggest->k_str[i];
  2005.     dumpbuf[i++] = c;
  2006.     dumpbuf[i] = 0;
  2007.     dumpindex = &dumpbuf[1];
  2008.            for (kp = &km[0]; kp < &km[N_KEY]; kp++)
  2009.         kp->k_index = 0;
  2010.     return (dumpbuf[0]);
  2011.     }
  2012.  
  2013.     return(c);
  2014. }
  2015.  
  2016. #endif
  2017.  
  2018. #if defined(SYSV2) || defined(SYSV3)
  2019.  
  2020. initkbd()
  2021. {
  2022.     keypad(stdscr, TRUE);
  2023. }
  2024.  
  2025. resetkbd()
  2026. {}
  2027.  
  2028. nmgetch()
  2029. {
  2030.     register int c;
  2031.  
  2032.     c = getch();
  2033.     switch (c) {
  2034.     case KEY_LEFT:  c = ctl(b); break;
  2035.     case KEY_RIGHT: c = ctl(f); break;
  2036.     case KEY_UP:    c = ctl(p); break;
  2037.     case KEY_DOWN:  c = ctl(n); break;
  2038.     default:   c = c & 0x7f; 
  2039.     }
  2040.     return (c);
  2041. }
  2042.  
  2043. #endif /* SYSV2 || SYSV3 */
  2044.  
  2045. #endif /* SIMPLE */
  2046.  
  2047. timeout()
  2048. {
  2049.     longjmp(wakeup, -1);
  2050. }
  2051.  
  2052. int dbline;
  2053.  
  2054. /*VARARGS*/
  2055. void
  2056. debug (str)
  2057. char *str;
  2058. {
  2059.     mvprintw (2+(dbline++%22),80-70,str);
  2060.     clrtoeol();
  2061. }
  2062.  
  2063. /*
  2064.  * This converts a floating point number of the form
  2065.  * [s]ddd[.d*][esd*]  where s can be a + or - and e is E or e.
  2066.  * to floating point. 
  2067.  * p is advanced.
  2068.  */
  2069.  
  2070. char *
  2071. strtof(p, res)
  2072. register char *p;
  2073. double *res;
  2074. {
  2075.     double acc;
  2076.     int sign;
  2077.     double fpos;
  2078.     int exp;
  2079.     int exps;
  2080.  
  2081.     acc = 0.0;
  2082.     sign = 1;
  2083.     exp = 0;
  2084.     exps = 1;
  2085.     if (*p == '+')
  2086.         p++;
  2087.     else if (*p == '-') {
  2088.         p++;
  2089.         sign = -1;
  2090.     }
  2091.     while (isdigit(*p)) {
  2092.         acc = acc * 10.0 + (double)(*p - '0');
  2093.         p++;
  2094.     }
  2095.     if (*p == 'e' || *p == 'E') {
  2096.         p++;
  2097.         if (*p == '+')
  2098.         p++;
  2099.         else if (*p == '-') {
  2100.         p++;
  2101.         exps = -1;
  2102.         }
  2103.         while(isdigit(*p)) {
  2104.         exp = exp * 10 + (*p - '0');
  2105.         p++;
  2106.         }
  2107.     }
  2108.     if (*p == '.') {
  2109.     fpos = 1.0/10.0;
  2110.     p++;
  2111.     while(isdigit(*p)) {
  2112.         acc += (*p - '0') * fpos;
  2113.         fpos *= 1.0/10.0;
  2114.         p++;
  2115.     }
  2116.     }
  2117.     if (*p == 'e' || *p == 'E') {
  2118.     exp = 0;
  2119.     exps = 1;
  2120.         p++;
  2121.     if (*p == '+')
  2122.         p++;
  2123.     else if (*p == '-') {
  2124.         p++;
  2125.         exps = -1;
  2126.     }
  2127.     while(isdigit(*p)) {
  2128.         exp = exp * 10 + (*p - '0');
  2129.         p++;
  2130.     }
  2131.     }
  2132.     if (exp) {
  2133.     if (exps > 0)
  2134.         while (exp--)
  2135.         acc *= 10.0;
  2136.     else
  2137.         while (exp--)
  2138.         acc *= 1.0/10.0;
  2139.     }
  2140.     if (sign > 0)
  2141.         *res = acc;
  2142.     else
  2143.     *res = -acc;
  2144.  
  2145.     return(p);
  2146. }
  2147.  
  2148. help () {
  2149.     move(2,0);
  2150.     clrtobot();
  2151.     dbline = 0;
  2152.     debug ("Cursor:     ^n j next row       ^p k prev. row  ESC ^g erase cmd");
  2153.     debug ("            ^f l fwd col        ^b h back col    ^l ^r redraw screen");
  2154.     debug ("               0 col A             $ last col        g goto ");
  2155.     debug ("               ^ row 0             # last row");
  2156.     debug ("Cell:      \" < > enter label       = enter value     x clear cell");
  2157.     debug ("               c copy cell         m mark cell      ^t line 1 on/off");  
  2158.     debug ("              ^a type value       ^e type expr.     ^v type vbl name");
  2159.     debug ("Row, Col:  ar ac dup           ir ic insert      sr sc show");
  2160.     debug ("           dr dc delete        zr zc hide        pr pc pull");
  2161.     debug ("           vr vc value only        f format");
  2162.     debug ("Region:       /c copy             /x clear          /f fill");
  2163.     debug ("              /u undefine range   /s show ranges    /d define range");
  2164.     debug ("File:          G get database      M merge database  T write tbl fmt");
  2165.     debug ("               P put database      W write listing");
  2166.     debug ("Misc:        Q q quit             pm pull (merge)");
  2167.     debug ("Expr:      +-*/^ arithmetic     ?e:e conditional   & | booleans");
  2168.     debug ("           < = > relations     <= >= relations      != relations");
  2169.     debug ("                 @sum(range)         @avg(range)       @prod(range)");
  2170.     debug ("                 @func(e) - lots of other math functions");
  2171. }
  2172. \SHAR\EOF\
  2173. else
  2174.   echo "will not over write ./lex.c"
  2175. fi
  2176. if [ `wc -c ./lex.c | awk '{printf $1}'` -ne 9916 ]
  2177. then
  2178. echo `wc -c ./lex.c | awk '{print "Got " $1 ", Expected " 9916}'`
  2179. fi
  2180. echo "Finished archive 2 of 3"
  2181. # if you want to concatenate archives, remove anything after this line
  2182. exit
  2183.  
  2184. -- 
  2185.  
  2186. Rich $alz
  2187. Cronus Project, BBN Labs            rsalz@bbn.com
  2188. Moderator, comp.sources.unix            sources@uunet.uu.net
  2189.