rsalz@uunet.uu.net (Rich Salz) (03/22/89)
Submitted-by: Robert Bond <sequent!rgb@uunet.uu.net> Posting-number: Volume 18, Issue 46 Archive-name: sc6.1/part02 # This is a shell archive. Remove anything before this line # then unpack it by saving it in a file and typing "sh file" # (Files unpacked will be owned by you and have default permissions). # This archive contains the following files: # ./tutorial.sc # ./VMS_NOTES # ./BSD_BUGS # ./sc.h # ./sc.c # ./lex.c # if `test ! -s ./tutorial.sc` then echo "Extracting ./tutorial.sc" cat > ./tutorial.sc << '\SHAR\EOF\' # This data file was generated by the Spreadsheet Calculator. # You almost certainly shouldn't edit it. define "page4" A70 define "page3" A49 define "page2" A29 define "page1" A9 define "page5" A89 leftstring A1 = "This is a brief sc tutorial." leftstring A3 = "Cells are named by their column and row number. For example," leftstring A4 = "Cell A4" leftstring B4 = "Cell B4" leftstring C4 = "Cell C4" leftstring A5 = "Cell A5" leftstring A6 = "Cell A6" leftstring C6 = "Cell C6" leftstring A7 = "Cells range from A0 to AN199." leftstring A8 = "Cells can also be named by the user. See 'range names' in the manual." leftstring page1 = "You can move the cursor a couple of different ways:" leftstring A11 = "^n, j and the <DOWN> arrow key go down" leftstring A12 = "^p, k and the <UP> arrow key go up" leftstring A13 = "^b, h and the <LEFT> arrow key go left" leftstring A14 = "^f, l and the <RIGHT> arrow key go right" leftstring A15 = "You can go directly to a cell by typing 'g' and the cell name. " leftstring A16 = "'g c6' will take you to cell c6." leftstring A18 = "Cells can contain numbers, formulas, or text." leftstring A19 = "Most of the cells on this page contain text." leftstring C20 = "<Type 'g page2' to continue>" leftstring A22 = "Cell d22 contains text" leftstring D22 = "Text " leftstring A23 = "Cell d23 contains a number" let D23 = 123.34 leftstring A24 = "Cell d24 contains a formula" let D24 = D23+88 leftstring A26 = "To see what the cell contains, just move the cursor" leftstring A27 = "onto the cell. The contents will show up on line 1 in the brackets." leftstring page2 = "You can enter data into cells like this:" leftstring B30 = "'<text' enters left justified text." leftstring B31 = "'>text' enters right justified text." leftstring B32 = "'=number' enters a number" leftstring B33 = "'=formula' enters a formula." leftstring A35 = "Try duplicating d22 through d24 in e22 though e24." leftstring A37 = "You erase a cell by typing 'x' with the cursor on the cell." leftstring C40 = "<Type 'g page3' to continue>" leftstring A42 = "Here is a typical use for numbers and formulas:" let A44 = 10.3 let B44 = 1877.5 let C44 = 234.7 let E44 = @sum(A44:C44) let A45 = 44.56 let B45 = 44.3 let C45 = -3 let E45 = @sum(A45:C45) let A46 = 88.74 let B46 = 8000 let C46 = -9 let E46 = @sum(A46:C46) let A47 = 99.2 let B47 = -88 let C47 = -44.6 let E47 = @sum(A47:C47) let page3 = @sum(A44:A47) let B49 = @sum(B44:B47) let C49 = @sum(C44:C47) let E49 = @sum(A44:C47) leftstring A51 = "The data is entered in a44 through c47." leftstring A52 = "Cells a49, b49 and c49 sum their respective columns." leftstring A53 = "Cells e44, e45, e46, and e47 sum their respective rows." leftstring A54 = "Cell E49 is a grand total." leftstring A55 = "Try changing some of the data cells and watch the sums change." leftstring A57 = "You can also edit cells by putting the cursor on the cell and typing:" leftstring B58 = "'e' to edit the numeric portion." leftstring B59 = "'E' to edit the string portion." leftstring C60 = "<Type 'g page4' to continue>" leftstring A62 = "Since you are reading this, you know that you can load " leftstring A63 = "a data base from a file by typing the file name as an" leftstring A64 = "argument to the program. You can also load or save a " leftstring A65 = "data base using the file commands:" leftstring B67 = "'G file'" leftstring C67 = "Gets the data from an sc file." leftstring B68 = "'P file'" leftstring C68 = "Puts the data from the spreadsheet into a file." leftstring page4 = "Try 'P foo.sc' to write this to the file foo.sc" leftstring A71 = "The Get command erases the current spreadsheet. " leftstring A72 = "To merge a spreadsheet with the one currently in" leftstring A73 = "the machine, use:" leftstring B75 = "'M file'" leftstring C75 = "Merge the data from a saved sc file." leftstring A77 = "You can also get human readable versions of the data" leftstring A78 = "by using the Write command:" leftstring C80 = "<Type 'g page5' to continue>" leftstring A82 = "Try 'W tut.txt' for a clear text version of the tutorial." leftstring A85 = "This is the end of the tutorial. We have explored" leftstring A86 = "The basic commands. Much more detail is available" leftstring A87 = "in the man page." leftstring D91 = "GOOD LUCK!" \SHAR\EOF\ else echo "will not over write ./tutorial.sc" fi if [ `wc -c ./tutorial.sc | awk '{printf $1}'` -ne 4292 ] then echo `wc -c ./tutorial.sc | awk '{print "Got " $1 ", Expected " 4292}'` fi if `test ! -s ./VMS_NOTES` then echo "Extracting ./VMS_NOTES" cat > ./VMS_NOTES << '\SHAR\EOF\' From: ihnp4!gargoyle!oddjob!noao!arizona!naucse!jdc (John Campbell) To: arizona!noao!oddjob!gargoyle!ihnp4!nsc!nscpdc!rgb Subject: VMS SC VMS USERS: Bob Bond has been generous enough to give me free rein in adding what I think is needed to make SC run on VMS. Any problems with VMS should be directed to me--they are not Bob's fault. The VMS SC is "SIMPLE" for the most part, except that the arrow keys (instead of hjkl) will move you around the cells. The VMS version of SC will not interact with the Bourne shell (obviously), which means that CRYPT and EXTERNAL FUNCTIONS will not be available. If you have a 'C' compiler and GNU Bison then you should be able to get SC running on VMS by following the instructions below. Step 1: Get all the files I've heard of a few sites that can unpack unix shar files directly on VMS. Most people, however, will need access to a unix machine to get the original distribution unpacked. At this time you should also build experres.h and statres.h and perhaps run the man pages off if you need to port the documentation. To build the two "missing" hearder files: sed <gram.y >experres.h -f eres.sed sed <gram.y >statres.h -f sres.sed Step 2: Cut out BUILD.COM and GETOPT.C At the end of this file are two other pieces: BUILD.COM and GETOPT.C. After you've moved everything to VMS, cut BUILD.COM and GETOPT.C out of here and put them in the same directory as the rest of the SC distribution. Step 3: Build it Theoretically all you now need to do is @BUILD and SC (as well as PSC) will be running on VMS. If you have problems feel free to contact me at ...!arizona!naucse!jdc (or even call at 602-523-6259). ---------------------cut here for BUILD.COM-------------------------- $! VMS command file to build SC and PSC (requires bison) $! SC: $ bison -d gram.y $ ren gram_tab.c gram.c $ cc /define=("SIMPLE","SIGVOID") sc.c $ cc /define=("SIMPLE","SIGVOID") gram.c $ cc /define=("SIMPLE","SIGVOID") lex.c $ cc /define=("SIMPLE","SIGVOID") interp $ cc /define=("SIMPLE","SIGVOID") cmds $ cc /define=("SIMPLE","SIGVOID") xmalloc $ cc /define=("SIMPLE","SIGVOID") range $ cc /define=("SIMPLE","SIGVOID") help $ link sc.obj,lex.obj,gram.obj,interp.obj,cmds.obj,xmalloc.obj,- range.obj,help.obj,sys$library:vaxcrtl.olb/lib $ ! $ ! Create VMS foreign command symbol to test SC $ ! $ sc == "$" + f$logical("SYS$DISK") + f$directory() + "SC.EXE" $! $! Now PSC $! $ cc psc.c $ cc getopt.c $ link psc,getopt,sys$library:vaxcrtl.olb/lib $ ! $ ! Create VMS foreign command symbol to test PSC (Note that $ ! PSC reads SYS$INPUT and writes to SYS$OUTPUT, so use $ ! DEFINE/USER to redirect.) $ ! $ psc == "$" + f$logical("SYS$DISK") + f$directory() + "PSC.EXE" ---------------------cut here for GETOPT.C------------------------ /* * getopt - get option letter from argv * This software is in the public domain * Originally written by Henry Spencer at the U. of Toronto */ #include <stdio.h> char *optarg; /* Global argument pointer. */ int optind = 0; /* Global argv index. */ static char *scan = NULL; /* Private scan pointer. */ /* extern char *index(); obsolete, used strchr (JDC). */ int getopt(argc, argv, optstring) int argc; char *argv[]; char *optstring; { register char c; register char *place; optarg = NULL; if (scan == NULL || *scan == '\0') { if (optind == 0) optind++; if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') return(EOF); if (strcmp(argv[optind], "--")==0) { optind++; return(EOF); } scan = argv[optind]+1; optind++; } c = *scan++; place = strchr(optstring, c); if (place == NULL || c == ':') { fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); return('?'); } place++; if (*place == ':') { if (*scan != '\0') { optarg = scan; scan = NULL; } else { optarg = argv[optind]; optind++; } } return(c); } \SHAR\EOF\ else echo "will not over write ./VMS_NOTES" fi if [ `wc -c ./VMS_NOTES | awk '{printf $1}'` -ne 4341 ] then echo `wc -c ./VMS_NOTES | awk '{print "Got " $1 ", Expected " 4341}'` fi if `test ! -s ./BSD_BUGS` then echo "Extracting ./BSD_BUGS" cat > ./BSD_BUGS << '\SHAR\EOF\' My well known but much maligned position on this is that you should all fix your curses include file per Dr. Goldman's recommendations. Consider it to be my bit to make the world cleaner. Bob --------------------------------------------------------------------------- Bob-- sc/vc compiled and ran fine on a VAX running 4.3 BSD at my site. However, it compiled, but screwed up the nl()/nonl() stuff, when run on my MicroVAX II running Ultrix 1.2; the same problem occurred on a VAX running vanilla 4.2 BSD. I traced it to a bug in the nl()/nonl() definitions in /usr/include/curses.h that appears to exist only in the 4.2 BSD and Ultrix 1.X versions of that file. I suspect that someone had fixed those definitions on the 4.2 BSD system you tested it on. (In fact, on a Sun 2 at my site running Sun UNIX 3.0 [basically 4.2 BSD with Sun enhancements], the nl()/nonl() stuff in /usr/include/curses.h has been fixed [by Sun]. I haven't tried compiling sc/vc on it yet, however.) The following patch to sc.c is necessary for vanilla 4.2 BSD machines and Ultrix 1.2 (and presumably Ultrix 1.0 and 1.1) machines: *** sc.c Tue Jan 27 15:54:31 1987 --- sc.c.new Tue Jan 27 15:55:06 1987 *************** *** 14,19 **** --- 14,26 ---- #include <curses.h> + #ifdef BSD42 + #undef nl + #undef nonl + #define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty)) + #define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty)) + #endif + #ifdef BSD42 #include <strings.h> #else #ifndef SYSIII Perhaps you should post it to comp.sources.d. Thanks. --Eric ------------------------------------------- Eric S. Goldman, M.D. UCSF School of Medicine INET: goldman@cope.ucsf.edu UUCP: ...ucbvax!ucsfcgl!cope.ucsf!goldman BITNET: GOLDMAN@UCSFCOPE.BITNET \SHAR\EOF\ else echo "will not over write ./BSD_BUGS" fi if [ `wc -c ./BSD_BUGS | awk '{printf $1}'` -ne 1819 ] then echo `wc -c ./BSD_BUGS | awk '{print "Got " $1 ", Expected " 1819}'` fi if `test ! -s ./sc.h` then echo "Extracting ./sc.h" cat > ./sc.h << '\SHAR\EOF\' /* SC A Table Calculator * Common definitions * * original by James Gosling, September 1982 * modified by Mark Weiser and Bruce Israel, * University of Maryland * R. Bond 12/86 * More mods by Alan Silverstein, 3-4/88, see list of changes. * $Revision: 6.1 $ * */ #define MAXROWS 200 #define MAXCOLS 40 #define RESCOL 4 /* columns reserved for row numbers */ #define RESROW 3 /* rows reserved for prompt, error, and column numbers */ #define DEFWIDTH 10 /* Default column width and precision */ #define DEFPREC 2 #define error move(1,0), clrtoeol(), (void) printw struct ent_ptr { int vf; struct ent *vp; }; struct range_s { struct ent_ptr left, right; }; /* * If you want to save room, make row and col below into unsigned * chars and make sure MAXROWS and MAXCOLS above are both less * than 256. (128 if your compiler doesn't support unsigned char). * * Some not too obvious things about the flags: * is_valid means there is a valid number in v. * label set means it points to a valid constant string. * is_strexpr set means expr yields a string expression. * If is_strexpr is not set, and expr points to an expression tree, the * expression yields a numeric expression. * So, either v or label can be set to a constant. * Either (but not both at the same time) can be set from an expression. */ #define VALID_CELL(p, r, c) ((p = tbl[r][c])&&((p->flags&is_valid)||p->label)) struct ent { double v; char *label; struct enode *expr; short flags; short row, col; struct ent *next; }; struct range { struct ent_ptr r_left, r_right; char *r_name; struct range *r_next, *r_prev; int r_is_range; }; #define FIX_ROW 1 #define FIX_COL 2 struct enode { int op; union { double k; struct ent_ptr v; struct range_s r; char *s; struct { struct enode *left, *right; } o; } e; }; /* op values */ #define O_VAR 'v' #define O_CONST 'k' #define O_SCONST '$' #define REDUCE 0200 /* Or'ed into OP if operand is a range */ #define OP_BASE 256 #define ACOS OP_BASE + 0 #define ASIN OP_BASE + 1 #define ATAN OP_BASE + 2 #define CEIL OP_BASE + 3 #define COS OP_BASE + 4 #define EXP OP_BASE + 5 #define FABS OP_BASE + 6 #define FLOOR OP_BASE + 7 #define HYPOT OP_BASE + 8 #define LOG OP_BASE + 9 #define LOG10 OP_BASE + 10 #define POW OP_BASE + 11 #define SIN OP_BASE + 12 #define SQRT OP_BASE + 13 #define TAN OP_BASE + 14 #define DTR OP_BASE + 15 #define RTD OP_BASE + 16 #define MIN OP_BASE + 17 #define MAX OP_BASE + 18 #define RND OP_BASE + 19 #define HOUR OP_BASE + 20 #define MINUTE OP_BASE + 21 #define SECOND OP_BASE + 22 #define MONTH OP_BASE + 23 #define DAY OP_BASE + 24 #define YEAR OP_BASE + 25 #define NOW OP_BASE + 26 #define DATE OP_BASE + 27 #define FMT OP_BASE + 28 #define SUBSTR OP_BASE + 29 #define STON OP_BASE + 30 #define EQS OP_BASE + 31 #define EXT OP_BASE + 32 #define ELIST OP_BASE + 33 /* List of expressions */ #define LMAX OP_BASE + 34 #define LMIN OP_BASE + 35 #define NVAL OP_BASE + 36 #define SVAL OP_BASE + 37 #define PV OP_BASE + 38 #define FV OP_BASE + 39 #define PMT OP_BASE + 40 #define STINDEX OP_BASE + 41 #define LOOKUP OP_BASE + 42 #define ATAN2 OP_BASE + 43 #define INDEX OP_BASE + 44 /* flag values */ #define is_valid 0001 #define is_changed 0002 #define is_strexpr 0004 #define is_leftflush 0010 #define is_deleted 0020 #define ctl(c) ('c'&037) #define ESC 033 #define DEL 0177 #define BYCOLS 1 #define BYROWS 2 #define BYGRAPH 4 /* Future */ #define TBL 1 /* tblprint style output for 'tbl' */ #define LATEX 2 /* tblprint style output for 'LaTeX' */ #define TEX 3 /* tblprint style output for 'TeX' */ /* Types for etype() */ #define NUM 1 #define STR 2 extern struct ent *tbl[MAXROWS][MAXCOLS]; extern char curfile[]; extern int strow, stcol; extern int currow, curcol; extern int savedrow, savedcol; extern int FullUpdate; extern int maxrow, maxcol; extern int fwidth[MAXCOLS]; extern int precision[MAXCOLS]; extern char col_hidden[MAXCOLS]; extern char row_hidden[MAXROWS]; extern char line[1000]; extern int linelim; extern int changed; extern struct ent *to_fix; extern int showsc, showsr; extern struct enode *new(); extern struct enode *new_const(); extern struct enode *new_var(); extern struct enode *new_str(); extern struct enode *new_range(); extern struct ent *lookat(); extern struct enode *copye(); extern char *coltoa(); extern FILE *openout(); extern struct range *find_range(); extern char *v_name(); extern char *r_name(); extern double eval(); extern char *seval(); extern int modflg; extern int Crypt; extern char *mdir; extern char *xmalloc(); extern int xfree(); extern double prescale; extern int extfunc; extern int propagation; extern int calc_order; extern int autocalc; extern int numeric; extern int showcell; extern int showtop; extern int loading; extern int tbl_style; extern char *progname; #if BSD42 || SYSIII #ifndef cbreak #define cbreak crmode #define nocbreak nocrmode #endif #endif \SHAR\EOF\ else echo "will not over write ./sc.h" fi if [ `wc -c ./sc.h | awk '{printf $1}'` -ne 5028 ] then echo `wc -c ./sc.h | awk '{print "Got " $1 ", Expected " 5028}'` fi if `test ! -s ./sc.c` then echo "Extracting ./sc.c" cat > ./sc.c << '\SHAR\EOF\' /* SC A Spreadsheet Calculator * Main driver * * original by James Gosling, September 1982 * modifications by Mark Weiser and Bruce Israel, * University of Maryland * * More mods Robert Bond, 12/86 * More mods by Alan Silverstein, 3-4/88, see list of changes. * */ #include <signal.h> #include <curses.h> #ifdef BSD42 #include <strings.h> #else #ifndef SYSIII #include <string.h> #endif #endif #include <stdio.h> #include "sc.h" char *getenv(); #ifdef SYSV3 void exit(); #endif /* * CODE REVISION NUMBER: * * The part after the first colon, except the last char, appears on the screen. */ char *rev = "$Revision: 6.1 $"; #ifndef DFLT_PAGER #define DFLT_PAGER "more" /* more is probably more widespread than less */ #endif /* DFLT_PAGER */ #define MAXCMD 160 /* for ! command below */ /* Globals defined in sc.h */ struct ent *tbl[MAXROWS][MAXCOLS]; int strow, stcol; int currow, curcol; int savedrow, savedcol; int FullUpdate; int maxrow, maxcol; int fwidth[MAXCOLS]; int precision[MAXCOLS]; char col_hidden[MAXCOLS]; char row_hidden[MAXROWS]; char line[1000]; int changed; struct ent *to_fix; int modflg; int numeric; char *mdir; int showsc, showsr; /* Starting cell for highlighted range */ char curfile[1024]; char revmsg[80]; int linelim = -1; int showtop = 1; /* Causes current cell value display in top line */ int showcell = 1; /* Causes current cell to be highlighted */ int showrange = 0; /* Causes ranges to be highlighted */ int showneed = 0; /* Causes cells needing values to be highlighted */ int showexpr = 0; /* Causes cell exprs to be displayed, highlighted */ int autocalc = 1 ; /* 1 to calculate after each update */ int calc_order = BYROWS; int tbl_style = 0; /* headers for T command output */ int lastmx, lastmy; /* Screen address of the cursor */ int lastcol; /* Spreadsheet Column the cursor was in last */ char *under_cursor = " "; /* Data under the < cursor */ #ifdef VMS int VMS_read_raw = 0; #endif int seenerr; yyerror (err) char *err; { if (seenerr) return; seenerr++; (void) move (1,0); (void) clrtoeol (); (void) printw ("%s: %.*s<=%s",err,linelim,line,line+linelim); } struct ent * lookat(row,col){ register struct ent **p; if (row < 0) row = 0; else if (row > MAXROWS-1) row = MAXROWS-1; if (col < 0) col = 0; else if (col > MAXCOLS-1) col = MAXCOLS-1; p = &tbl[row][col]; if (*p==0) { *p = (struct ent *) xmalloc ((unsigned)sizeof (struct ent)); if (row>maxrow) maxrow = row; if (col>maxcol) maxcol = col; (*p)->label = 0; (*p)->flags = 0; (*p)->row = row; (*p)->col = col; (*p)->expr = 0; (*p)->v = (double) 0.0; } return *p; } /* * This structure is used to keep ent structs around before they * are deleted to allow the sync_refs routine a chance to fix the * variable references. * We also use it as a last-deleted buffer for the 'p' command. */ free_ent(p) register struct ent *p; { p->next = to_fix; to_fix = p; p->flags |= is_deleted; } flush_saved() { register struct ent *p; register struct ent *q; if (!(p = to_fix)) return; while (p) { (void) clearent(p); q = p->next; xfree((char *)p); p = q; } to_fix = 0; } update () { register row, col; register struct ent **p; int mxcol; int mxrow; int rows; int cols; int minsr, minsc, maxsr, maxsc; register r; register i; while (row_hidden[currow]) /* You can't hide the last row or col */ currow++; while (col_hidden[curcol]) curcol++; /* First see if the last display still covers curcol */ if (stcol <= curcol) { for (i = stcol, cols = 0, col = RESCOL; (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) { cols++; if (col_hidden[i]) continue; col += fwidth[i]; } } while (stcol + cols - 1 < curcol || curcol < stcol) { FullUpdate++; if (stcol - 1 == curcol) { /* How about back one? */ stcol--; } else if (stcol + cols == curcol) { /* Forward one? */ stcol++; } else { /* Try to put the cursor in the center of the screen */ col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL; stcol = curcol; for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--) { stcol--; if (col_hidden[i]) continue; col -= fwidth[i]; } } /* Now pick up the counts again */ for (i = stcol, cols = 0, col = RESCOL; (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) { cols++; if (col_hidden[i]) continue; col += fwidth[i]; } } /* Now - same process on the rows */ if (strow <= currow) { for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) { rows++; if (row_hidden[i]) continue; row++; } } while (strow + rows - 1 < currow || currow < strow) { FullUpdate++; if (strow - 1 == currow) { /* How about up one? */ strow--; } else if (strow + rows == currow) { /* Down one? */ strow++; } else { /* Try to put the cursor in the center of the screen */ row = (LINES - RESROW) / 2 + RESROW; strow = currow; for (i=currow-1; i >= 0 && row-1 > RESROW; i--) { strow--; if (row_hidden[i]) continue; row--; } } /* Now pick up the counts again */ for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) { rows++; if (row_hidden[i]) continue; row++; } } mxcol = stcol + cols - 1; mxrow = strow + rows - 1; if (FullUpdate) { (void) move (2, 0); (void) clrtobot (); (void) standout(); for (row=RESROW, i=strow; i <= mxrow; i++) { if (row_hidden[i]) continue; (void) move(row,0); #if MAXROW < 1000 (void) printw("%-*d", RESCOL-1, i); #else (void) printw("%-*d", RESCOL, i); #endif row++; } (void) move (2,0); (void) printw("%*s", RESCOL, " "); for (col=RESCOL, i = stcol; i <= mxcol; i++) { register int k; if (col_hidden[i]) continue; (void) move(2, col); k = fwidth[i]/2; if (k == 0) (void) printw("%1s", coltoa(i)); else (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i)); col += fwidth[i]; } (void) standend(); } /* Get rid of cursor standout on the cell at previous cursor position */ (void) move(lastmx, lastmy); if (showcell) repaint(lastmx, lastmy, fwidth[lastcol]); if (showrange) { minsr = showsr < currow ? showsr : currow; minsc = showsc < curcol ? showsc : curcol; maxsr = showsr > currow ? showsr : currow; maxsc = showsc > curcol ? showsc : curcol; if (showtop) { (void) move(1,0); (void) clrtoeol(); (void) printw("Default range: %s", r_name(minsr, minsc, maxsr, maxsc)); } } /* Repaint the visible screen */ for (row = strow, r = RESROW; row <= mxrow; row++) { register c = RESCOL; int do_stand = 0; int fieldlen; int nextcol; if (row_hidden[row]) continue; for (p = &tbl[row][col = stcol]; col <= mxcol; p += nextcol - col, col = nextcol, c += fieldlen) { nextcol = col+1; if (col_hidden[col]) { fieldlen = 0; continue; } fieldlen = fwidth[col]; /* * Set standout if: * * - showing ranges, and not showing cells which need to be filled * in, and not showing cell expressions, and in a range, OR * * - if showing cells which need to be filled in and this one is * of that type (has a value and doesn't have an expression, or * it is a string expression), OR * * - if showing cells which have expressions and this one does. */ if ((showrange && (! showneed) && (! showexpr) && (row >= minsr) && (row <= maxsr) && (col >= minsc) && (col <= maxsc)) || (showneed && (*p) && ((*p) -> flags & is_valid) && (((*p) -> flags & is_strexpr) || ! ((*p) -> expr))) || (showexpr && (*p) && ((*p) -> expr))) { do_stand = 1; } if (*p && ((*p) -> flags & is_changed || FullUpdate) || do_stand) { (void) move (r, c); if (!*p) *p = lookat(row, col); if (do_stand) { (void) standout(); (*p) -> flags |= is_changed; } else { (*p) -> flags &= ~is_changed; } /* * Show expression; takes priority over other displays: */ if (showexpr && ((*p) -> expr)) { linelim = 0; editexp (row, col); /* set line to expr */ linelim = -1; showstring (line, /* leftflush = */ 1, /* hasvalue = */ 0, row, col, & nextcol, mxcol, & fieldlen, r, c); } else { /* * Show cell's numeric value: */ if ((*p) -> flags & is_valid) { char field[1024]; (void)sprintf(field,"%*.*f", fwidth[col], precision[col], (*p)->v); if(strlen(field) > fwidth[col]) { for(i = 0; i<fwidth[col]; i++) (void)addch('*'); } else { (void)addstr(field); } } /* * Show cell's label string: */ if ((*p) -> label) { showstring ((*p) -> label, (*p) -> flags & is_leftflush, (*p) -> flags & is_valid, row, col, & nextcol, mxcol, & fieldlen, r, c); } /* * repaint a blank cell: */ if (!((*p)->flags & is_valid) && !(*p)->label) { (void) printw ("%*s", fwidth[col], " "); } } /* else */ if (do_stand) { (void) standend(); do_stand = 0; } } } r++; } (void) move(lastmy, lastmx+fwidth[lastcol]); #ifndef INTERNATIONAL if((inch() & 0x7f) == '<') #else if((inch() & 0xff) == '<') #endif /* INTERNATIONAL */ (void) addstr(under_cursor); lastmy = RESROW; for (row = strow; row < currow; row++) if (!row_hidden[row]) lastmy += 1; lastmx = RESCOL; for (col = stcol; col < curcol; col++) if (!col_hidden[col]) lastmx += fwidth[col]; lastcol = curcol; (void) move(lastmx, lastmy); if (showcell && (! showneed) && (! showexpr)) { (void) standout(); repaint(lastmx, lastmy, fwidth[lastcol]); (void) standend(); } (void) move(lastmy, lastmx+fwidth[lastcol]); #ifndef INTERNATIONAL /*changed to make consistent with all other uses of INTERNATIONAL */ *under_cursor = (inch() & 0x7f); #else *under_cursor = (inch() & 0xff); #endif /* INTERNATIONAL */ (void) addstr("<"); (void) move (0, 0); (void) clrtoeol (); if (linelim >= 0) { (void) addstr (">> "); (void) addstr (line); } else { if (showtop) { /* show top line */ register struct ent *p1; int printed = 0; /* printed something? */ (void) printw ("%s%d ", coltoa (curcol), currow); if (p1 = tbl [currow] [curcol]) { if (p1 -> expr) /* has expr of some type */ { linelim = 0; editexp (currow, curcol); /* set line to expr */ linelim = -1; } /* * Display string part of cell: */ if ((p1 -> expr) && (p1 -> flags & is_strexpr)) { (void) addstr ((p1 -> flags & is_leftflush) ? "<{" : ">{"); (void) addstr (line); (void) addstr ("} "); /* and this '}' is for vi % */ printed = 1; } else if (p1 -> label) /* has constant label only */ { (void) addstr ((p1 -> flags & is_leftflush) ? "<\"" : ">\""); (void) addstr (p1 -> label); (void) addstr ("\" "); printed = 1; } /* * Display value part of cell: */ if (p1 -> flags & is_valid) /* has value or num expr */ { if ((! (p1 -> expr)) || (p1 -> flags & is_strexpr)) (void) sprintf (line, "%.15g", p1 -> v); (void) addstr ("["); (void) addstr (line); (void) addstr ("]"); printed = 1; } } if (! printed) (void) addstr ("[]"); } (void) move (lastmy, lastmx + fwidth[lastcol]); } if (revmsg[0]) { (void) move(0, 0); (void) clrtoeol (); /* get rid of topline display */ (void) printw(revmsg); revmsg[0] = 0; /* don't show it again */ (void) move (lastmy, lastmx + fwidth[lastcol]); } FullUpdate = 0; } repaint(x, y, len) int x, y, len; { char *buf; buf = " "; while(len-- > 0) { (void) move(y,x); #ifndef INTERNATIONAL *buf = inch() & 0x7f; #else *buf = inch() & 0xff; #endif /* INTERNATIONAL */ (void) addstr(buf); x++; } } char *progname; main (argc, argv) int argc; char **argv; { int inloop = 1; register int c; int edistate = -1; int arg = 1; int narg; int nedistate; int running; char *revi; /* * Keep command line options around until the file is read so the * command line overrides file options */ int Mopt = 0; int Nopt = 0; int Copt = 0; int Ropt = 0; progname = argv[0]; while (argc > 1 && argv[1][0] == '-') { argv++; argc--; switch (argv[0][1]) { case 'x': #ifdef VMS (void) fprintf(stderr, "Crypt not available for VMS\n"); exit(1); #else Crypt = 1; #endif break; case 'm': Mopt = 1; break; case 'n': Nopt = 1; break; case 'c': Copt = 1; break; case 'r': Ropt = 1; break; default: (void) fprintf(stderr,"%s: unrecognized option: \"%c\"\n", progname,argv[0][1]); exit(1); } } { register i; for (i = 0; i < MAXCOLS; i++) { fwidth[i] = DEFWIDTH; precision[i] = DEFPREC; } } curfile[0]=0; signals(); (void) initscr(); (void) clear(); #ifdef VMS VMS_read_raw = 1; #else nonl(); noecho (); cbreak(); #endif initkbd(); /* * Build revision message for later use: */ (void) strcpy (revmsg, progname); for (revi = rev; (*revi++) != ':'; ); /* copy after colon */ (void) strcat (revmsg, revi); revmsg [strlen (revmsg) - 2] = 0; /* erase last character */ (void) strcat (revmsg, ": Type '?' for help."); if (argc > 1) { (void) strcpy(curfile,argv[1]); readfile (argv[1], 0); } if (Mopt) autocalc = 0; if (Nopt) numeric = 1; if (Copt) calc_order = BYCOLS; if (Ropt) calc_order = BYROWS; modflg = 0; #ifdef VENIX setbuf (stdin, NULL); #endif FullUpdate++; while (inloop) { running = 1; while (running) { nedistate = -1; narg = 1; if (edistate < 0 && linelim < 0 && autocalc && (changed || FullUpdate)) EvalAll (), changed = 0; update(); #ifndef SYSV3 (void) refresh(); /* 5.3 does a refresh in getch */ #endif c = nmgetch(); (void) move (1, 0); (void) clrtoeol (); (void) fflush (stdout); seenerr = 0; showneed = 0; /* reset after each update */ showexpr = 0; if ((c < ' ') || ( c == DEL )) switch (c) { #ifdef SIGTSTP case ctl (z): deraw(); (void) kill(getpid(),SIGTSTP); /* the pc stops here */ goraw(); break; #endif case ctl (r): case ctl (l): FullUpdate++; if (c == ctl (r)) showneed = 1; (void) clearok(stdscr,1); break; case ctl (x): FullUpdate++; showexpr = 1; (void) clearok(stdscr,1); break; default: error ("No such command (^%c)", c + 0100); break; case ctl (b): backcol(arg); break; case ctl (c): running = 0; break; case ctl (e): switch (nmgetch()) { case ctl (p): case 'k': doend (-1, 0); break; case ctl (n): case 'j': doend ( 1, 0); break; case ctl (b): case 'h': case ctl (h): doend ( 0,-1); break; case ctl (f): case 'l': case ctl (i): case ' ': doend ( 0, 1); break; case ESC: case ctl (g): break; default: error("Invalid ^E command"); break; } break; case ctl (f): forwcol(arg); break; case ctl (g): case ESC: /* ctl ([) */ showrange = 0; linelim = -1; (void) move (1, 0); (void) clrtoeol (); break; case DEL: case ctl (h): if (linelim <= 0) { /* not editing line */ backcol(arg); /* treat like ^B */ break; } while (--arg>=0) if (linelim > 0) line[--linelim] = 0; break; case ctl (i): /* tab */ if (linelim <= 0) { /* not editing line */ forwcol(arg); break; } if (!showrange) { startshow(); } else { showdr(); linelim = strlen(line); line[linelim++] = ' '; line[linelim] = 0; showrange = 0; } linelim = strlen (line); break; case ctl (m): case ctl (j): showrange = 0; if (linelim < 0) line[linelim = 0] = 0; else { linelim = 0; (void) yyparse (); linelim = -1; } break; case ctl (n): forwrow(arg); break; case ctl (p): backrow(arg); break; case ctl (q): break; /* ignore flow control */ case ctl (s): break; /* ignore flow control */ case ctl (t): error( "Toggle: a:auto c:cell e:ext funcs n:numeric t:top x:encrypt $:pre-scale"); (void) refresh(); switch (nmgetch()) { case 'a': case 'A': case 'm': case 'M': autocalc ^= 1; error("Automatic recalculation %sabled.", autocalc ? "en":"dis"); break; case 'n': case 'N': numeric = (! numeric); error ("Numeric input %sabled.", numeric ? "en" : "dis"); break; case 't': case 'T': showtop = (! showtop); repaint(lastmx, lastmy, fwidth[lastcol]); error ("Top line %sabled.", showtop ? "en" : "dis"); break; case 'c': case 'C': showcell = (! showcell); repaint(lastmx, lastmy, fwidth[lastcol]); error ("Cell highlighting %sabled.", showcell ? "en" : "dis"); break; case 'x': case 'X': Crypt = (! Crypt); error ("Encryption %sabled.", Crypt? "en" : "dis"); break; case '$': if (prescale == 1.0) { error ("Prescale enabled."); prescale = 0.01; } else { prescale = 1.0; error ("Prescale disabled."); } break; case 'e': case 'E': extfunc = (! extfunc); error ("External functions %sabled.", extfunc? "en" : "dis"); break; case ESC: case ctl (g): break; default: error ("Invalid toggle command"); } FullUpdate++; modflg++; break; case ctl (u): narg = arg * 4; nedistate = 1; break; case ctl (v): /* insert variable name */ if (linelim > 0) { (void) sprintf (line+linelim,"%s", v_name(currow, curcol)); linelim = strlen (line); } break; case ctl (w): /* insert variable expression */ if (linelim > 0) editexp(currow,curcol); break; case ctl (a): /* insert variable value */ if (linelim > 0) { struct ent *p = tbl[currow][curcol]; if (p && p -> flags & is_valid) { (void) sprintf (line + linelim, "%.*f", precision[curcol],p -> v); linelim = strlen (line); } } break; } else if ('0' <= c && c <= '9' && ( (numeric && edistate >= 0) || (!numeric && (linelim < 0 || edistate >= 0)))) { if (edistate != 0) { if (c == '0') /* just a '0' goes to left col */ curcol = 0; else { nedistate = 0; narg = c - '0'; } } else { nedistate = 0; narg = arg * 10 + (c - '0'); } } else if (linelim >= 0) { /* Editing line */ switch(c) { case ')': if (showrange) { showdr(); showrange = 0; linelim = strlen (line); } break; default: break; } line[linelim++] = c; line[linelim] = 0; } else if (!numeric && ( c == '+' || c == '-' ) ) /* increment/decrement ops */ { register struct ent *p = tbl[currow][curcol]; if (!p) break; FullUpdate++; modflg++; if( c == '+' ) p -> v += (double) arg; else p -> v -= (double) arg; } else switch (c) { case ':': break; /* Be nice to vi users */ case '@': EvalAll (); changed = 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': case '.': case '+': (void) sprintf(line,"let %s = %c", v_name(currow, curcol), c); linelim = strlen (line); break; case '=': (void) sprintf(line,"let %s = ", v_name(currow, curcol)); linelim = strlen (line); break; case '!': { /* * "! command" executes command * "!" forks a shell * "!!" repeats last command */ #ifdef VMS error("Not implemented on VMS"); #else /* VMS */ char *shl; int pid, temp; char cmd[MAXCMD]; static char lastcmd[MAXCMD]; if (!(shl = getenv("SHELL"))) shl = "/bin/sh"; deraw(); (void) fputs("! ", stdout); (void) fflush(stdout); (void) fgets(cmd, MAXCMD, stdin); cmd[strlen(cmd) - 1] = '\0'; /* clobber \n */ if(strcmp(cmd,"!") == 0) /* repeat? */ (void) strcpy(cmd, lastcmd); else (void) strcpy(lastcmd, cmd); if (modflg) { (void) puts ("[No write since last change]"); (void) fflush (stdout); } if (!(pid = fork())) { (void) signal (SIGINT, SIG_DFL); /* reset */ if(strlen(cmd)) (void)execl(shl,shl,"-c",cmd,(char *)0); else (void) execl(shl, shl, (char *)0); exit(-127); } while (pid != wait(&temp)); (void) printf("Press RETURN to continue "); (void)nmgetch(); goraw(); #endif /* VMS */ break; } /* * Range commands: */ case '/': error ( "Range: x:erase v:value c:copy f:fill d:define s:show u:undefine"); (void) refresh(); switch (nmgetch()) { case 'c': (void) sprintf(line,"copy [dest_range src_range] "); linelim = strlen(line); startshow(); break; case 'x': (void) sprintf(line,"erase [range] "); linelim = strlen(line); startshow(); break; case 'v': (void) sprintf(line, "value [range] "); linelim = strlen(line); startshow(); break; case 'f': (void) sprintf(line,"fill [range start inc] "); linelim = strlen(line); startshow(); break; case 'd': (void) sprintf(line,"define [string range] \""); linelim = strlen(line); startshow(); modflg++; break; case 'u': (void) sprintf(line,"undefine [range] "); linelim = strlen(line); modflg++; break; case 's': if(are_ranges()) { FILE *f; int pid; char px[MAXCMD] ; char *pager; (void) strcpy(px, "| sort | "); if(!(pager = getenv("PAGER"))) pager = DFLT_PAGER; (void) strcat(px,pager); f = openout(px, &pid); if (!f) { error("Can't open pipe to sort"); break; } list_range(f); closeout(f, pid); } else error("No ranges defined"); break; case ESC: case ctl (g): break; default: error("Invalid region command"); break; } break; /* * Row/column commands: */ case 'i': case 'a': case 'd': case 'p': case 'v': case 'z': case 's': { register rcqual; if (! (rcqual = get_rcqual (c))) { error ("Invalid row/column command"); break; } error (""); /* clear line */ if ( rcqual == ESC || rcqual == ctl(g)) break; switch (c) { case 'i': if (rcqual == 'r') insertrow (arg); else insertcol (arg); break; case 'a': if (rcqual == 'r') while (arg--) duprow(); else while (arg--) dupcol(); break; case 'd': if (rcqual == 'r') deleterow (arg); else deletecol (arg); break; case 'p': while (arg--) pullcells (rcqual); break; case 'v': if (rcqual == 'r') rowvalueize (arg); else colvalueize (arg); modflg = 1; break; case 'z': if (rcqual == 'r') hiderow (arg); else hidecol (arg); modflg++; break; case 's': /* special case; no repeat count */ if (rcqual == 'r') rowshow_op(); else colshow_op(); break; } break; } case '$': { register struct ent *p; curcol = MAXCOLS - 1; while (!VALID_CELL(p, currow, curcol) && curcol > 0) curcol--; break; } case '#': { register struct ent *p; currow = MAXROWS - 1; while (!VALID_CELL(p, currow, curcol) && currow > 0) currow--; break; } case 'w': { register struct ent *p; while (--arg>=0) { do { if (curcol < MAXCOLS - 1) curcol++; else { if (currow < MAXROWS - 1) { while(++currow < MAXROWS - 1 && row_hidden[currow]) /* */; curcol = 0; } else { error("At end of table"); break; } } } while(col_hidden[curcol] || !VALID_CELL(p, currow, curcol)); } break; } case 'b': { register struct ent *p; while (--arg>=0) { do { if (curcol) curcol--; else { if (currow) { while(--currow && row_hidden[currow]) /* */; curcol = MAXCOLS - 1; } else { error ("At start of table"); break; } } } while(col_hidden[curcol] || !VALID_CELL(p, currow, curcol)); } break; } case '^': currow = 0; break; case '?': help (); break; case '"': (void) sprintf (line, "label %s = \"", v_name(currow, curcol)); linelim = strlen (line); break; case '<': (void) sprintf (line, "leftstring %s = \"", v_name(currow, curcol)); linelim = strlen (line); break; case '>': (void) sprintf (line, "rightstring %s = \"", v_name(currow, curcol)); linelim = strlen (line); break; case 'e': editv (currow, curcol); break; case 'E': edits (currow, curcol); break; case 'f': if (arg == 1) (void) sprintf (line, "format [for column] %s ", coltoa(curcol)); else { (void) sprintf(line, "format [for columns] %s:", coltoa(curcol)); (void) sprintf(line+strlen(line), "%s ", coltoa(curcol+arg-1)); } error("Current format is %d %d", fwidth[curcol],precision[curcol]); linelim = strlen (line); break; case 'g': (void) sprintf (line, "goto [v] "); linelim = strlen (line); break; case 'P': (void) sprintf (line, "put [\"dest\" range] \""); if (*curfile) error ("Default path is \"%s\"",curfile); linelim = strlen (line); break; case 'M': (void) sprintf (line, "merge [\"source\"] \""); linelim = strlen (line); break; case 'R': (void) sprintf (line,"merge [\"macro_file\"] \"%s/", mdir); linelim = strlen (line); break; case 'D': (void) sprintf (line, "mdir [\"macro_directory\"] \""); linelim = strlen (line); break; case 'G': (void) sprintf (line, "get [\"source\"] \""); if (*curfile) error ("Default file is \"%s\"",curfile); linelim = strlen (line); break; case 'W': (void) sprintf (line, "write [\"dest\" range] \""); linelim = strlen (line); break; case 'S': /* set options */ (void) sprintf (line, "set "); error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex)"); linelim = strlen (line); break; case 'T': /* tbl output */ (void) sprintf (line, "tbl [\"dest\" range] \""); linelim = strlen (line); break; case 'x': { register struct ent **p; register int c1; flush_saved(); if(calc_order == BYROWS) { for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) { p = &tbl[currow][c1]; if (*p) { free_ent(*p); *p = 0; } } } else { for (c1 = currow; arg-- && c1 < MAXROWS; c1++) { p = &tbl[c1][curcol]; if (*p) { free_ent(*p); *p = 0; } } } sync_refs(); modflg++; FullUpdate++; } break; case 'Q': case 'q': running = 0; break; case 'h': backcol(arg); break; case 'j': forwrow(arg); break; case 'k': backrow(arg); break; case ' ': case 'l': forwcol(arg); break; case 'm': savedrow = currow; savedcol = curcol; break; case 'c': { register struct ent *p = tbl[savedrow][savedcol]; register c1; register struct ent *n; if (!p) break; FullUpdate++; modflg++; for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) { n = lookat (currow, c1); (void) clearent(n); copyent( n, p, currow - savedrow, c1 - savedcol); } break; } default: if ((c & 0177) != c) /* doesn't this depend on INTERNATIONAL */ error ("Weird character, decimal %d\n", (int) c); else error ("No such command (%c)", c); break; } edistate = nedistate; arg = narg; } /* while (running) */ inloop = modcheck(" before exiting"); } /* while (inloop) */ deraw(); endwin(); #ifdef VMS /* Unit VMS "fixes" exit we should say 1 here */ exit(1); #else exit(0); #endif /*NOTREACHED*/ } startshow() { showrange = 1; showsr = currow; showsc = curcol; } showdr() { int minsr, minsc, maxsr, maxsc; minsr = showsr < currow ? showsr : currow; minsc = showsc < curcol ? showsc : curcol; maxsr = showsr > currow ? showsr : currow; maxsc = showsc > curcol ? showsc : curcol; (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc)); } setorder(i) int i; { if((i == BYROWS)||(i == BYCOLS)) calc_order = i; else error("Not yet implemented"); } setauto(i) int i; { autocalc = i; } #ifdef VMS goraw() { VMS_read_raw = 1; FullUpdate++; } deraw() { (void) move (LINES - 1, 0); (void) clrtoeol(); (void) refresh(); VMS_read_raw = 0; } #else /* VMS */ goraw() { #if SYSV2 || SYSV3 fixterm(); #else /* SYSV2 || SYSV3 */ cbreak(); nonl(); noecho (); #endif /* SYSV2 || SYSV3 */ kbd_again(); (void) clear(); FullUpdate++; } deraw() { (void) move (LINES - 1, 0); (void) clrtoeol(); (void) refresh(); #if SYSV2 || SYSV3 resetterm(); #else nocbreak(); nl(); echo(); #endif resetkbd(); } #endif /* VMS */ signals() { #ifdef SIGVOID void quit(); void time_out(); #else int quit(); int time_out(); #endif (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, quit); (void) signal(SIGPIPE, quit); (void) signal(SIGTERM, quit); (void) signal(SIGALRM, time_out); (void) signal(SIGFPE, quit); (void) signal(SIGBUS, quit); } #ifdef SIGVOID void #endif quit() { deraw(); resetkbd(); endwin(); exit(1); } modcheck(endstr) char *endstr; { if (modflg && curfile[0]) { char ch, lin[100]; (void) move (0, 0); (void) clrtoeol (); (void) sprintf (lin,"File \"%s\" is modified, save%s? ",curfile,endstr); (void) addstr (lin); (void) refresh(); ch = nmgetch(); if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) { error("y or n response required"); return (1); } if (ch != 'n' && ch != 'N') { if (writefile(curfile, 0, 0, maxrow, maxcol) < 0) return (1); } else if (ch == ctl (g) || ch == ESC) return(1); } else if (modflg) { char ch, lin[100]; (void) move (0, 0); (void) clrtoeol (); (void) sprintf (lin,"Do you want a chance to save the data? "); (void) addstr (lin); (void) refresh(); ch = nmgetch(); if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) { error("y or n response required"); return (1); } if (ch == 'n' || ch == 'N') return(0); else return(1); } return(0); } \SHAR\EOF\ else echo "will not over write ./sc.c" fi if [ `wc -c ./sc.c | awk '{printf $1}'` -ne 32278 ] then echo `wc -c ./sc.c | awk '{print "Got " $1 ", Expected " 32278}'` fi if `test ! -s ./lex.c` then echo "Extracting ./lex.c" cat > ./lex.c << '\SHAR\EOF\' /* SC A Spreadsheet Calculator * Lexical analyser * * original by James Gosling, September 1982 * modifications by Mark Weiser and Bruce Israel, * University of Maryland * * More mods Robert Bond, 12/86 * More mods by Alan Silverstein, 3/88, see list of changes. * $Revision: 6.1 $ * */ #if defined(BSD42) || defined(BSD43) #include <sys/ioctl.h> #endif #include <curses.h> #include <signal.h> #include <setjmp.h> #include "sc.h" #include <ctype.h> #ifdef BSD42 #include <strings.h> #else #ifndef SYSIII #include <string.h> #endif #endif #ifdef VMS #include "gram_tab.h" typedef union { int ival; double fval; struct ent *ent; struct enode *enode; char *sval; struct range_s rval; } YYSTYPE; extern YYSTYPE yylval; extern int VMS_read_raw; /*sigh*/ #else /* VMS */ #include "y.tab.h" #endif /* VMS */ char *strtof(); jmp_buf wakeup; jmp_buf fpe_buf; struct key { char *key; int val; }; struct key experres[] = { #include "experres.h" 0, 0}; struct key statres[] = { #include "statres.h" 0, 0}; #define ctl(x) ('x'&037) yylex () { register char *p = line+linelim; int ret; while (isspace(*p)) p++; if (*p==0) ret = -1; else if (isalpha(*p)) { char *tokenst = p; register tokenl; register struct key *tblp; tokenl = 0; /* * This picks up either 1 or 2 alpha characters (a column) or * tokens with at least three leading alphas and '_' or digits * (a function or token or command or a range name) */ while (isalpha(*p) || ((*p == '_') || isdigit(*p)) && (tokenl > 2)) { p++; tokenl++; } if (tokenl <= 2) { /* a COL is 1 or 2 char alpha (and not pi or ln!) */ if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'i') { ret = K_PI; } else if (tokenl == 2 && tokenst[0] == 'l' && tokenst[1] == 'n') { ret = K_LN; } else if (tokenl == 2 && tokenst[0] == 'f' && tokenst[1] == 'v') { ret = K_FV; } else if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'v') { ret = K_PV; } else { ret = COL; yylval.ival = atocol (tokenst, tokenl); } } else { ret = WORD; for (tblp = linelim ? experres : statres; tblp->key; tblp++) if (((tblp->key[0]^tokenst[0])&0137)==0 && tblp->key[tokenl]==0) { register i = 1; while (i<tokenl && ((tokenst[i]^tblp->key[i])&0137)==0) i++; if (i>=tokenl) { ret = tblp->val; break; } } if (ret==WORD) { struct range *r; if (r = find_range(tokenst, tokenl, (struct ent *)0, (struct ent *)0)) { yylval.rval.left = r->r_left; yylval.rval.right = r->r_right; if (r->r_is_range) ret = RANGE; else ret = VAR; } else { linelim = p-line; yyerror ("Unintelligible word"); } } } } else if ((*p == '.') || isdigit(*p)) { double v = 0; int temp; char *nstart = p; if (*p != '.') { do v = v*10 + (double)(*p-'0'); while (isdigit(*++p)); } if (*p=='.' || *p == 'e' || *p == 'E') { ret = FNUMBER; p = strtof(nstart, &yylval.fval); } else { /* A NUMBER must hold at least MAXROW and MAXCOL */ /* This is consistent with a short row and col in struct ent */ if (v > (double)32767 || v < (double)-32768) { ret = FNUMBER; yylval.fval = v; } else { temp = (int)v; if((double)temp != v) { ret = FNUMBER; yylval.fval = v; } else { ret = NUMBER; yylval.ival = temp; } } } } else if (*p=='"') { char *ptr; ptr = p+1; while(*ptr && *ptr++ != '"'); ptr = xmalloc((unsigned)(ptr-p)); yylval.sval = ptr; p += 1; while (*p && *p!='"') *ptr++ = *p++; *ptr = 0; if (*p) p += 1; ret = STRING; } else if (*p=='[') { while (*p && *p!=']') p++; if (*p) p++; linelim = p-line; return yylex(); } else ret = *p++; linelim = p-line; return ret; } /* * Given a token string starting with a symbolic column name and its valid * length, convert column name ("A"-"Z" or "AA"-"ZZ") to a column number (0-N). * Never mind if the column number is illegal (too high). The procedure's name * and function are the inverse of coltoa(). * * Case-insensitivity is done crudely, by ignoring the 040 bit. */ int atocol (string, len) char *string; int len; { register int col; col = (string [0] & 0137) - 'A'; if (len == 2) /* has second char */ col = ((col + 1) * 26) + ((string [1] & 0137) - 'A'); return (col); } #ifdef SIMPLE initkbd() {} kbd_again() {} resetkbd() {} #ifndef VMS nmgetch() { #ifndef INTERNATIONAL return (getchar() & 0x7f); #else return (getchar() & 0xff); #endif /* INTERNATIONAL */ } #else /* VMS */ nmgetch() /* This is not perfect, it doesn't move the cursor when goraw changes over to deraw, but it works well enough since the whole sc package is incredibly stable (loop constantly positions cursor). Question, why didn't the VMS people just implement cbreak? NOTE: During testing it was discovered that the DEBUGGER and curses and this method of reading would collide (the screen was not updated when continuing from screen mode in the debugger). */ { short c; static int key_id=0; int status; #define VMScheck(a) {if (~(status = (a)) & 1) VMS_MSG (status);} if (VMS_read_raw) { VMScheck(smg$read_keystroke (&stdkb->_id, &c, 0, 0, 0)); } else c = getchar(); switch (c) { case SMG$K_TRM_LEFT: c = ctl(b); break; case SMG$K_TRM_RIGHT: c = ctl(f); break; case SMG$K_TRM_UP: c = ctl(p); break; case SMG$K_TRM_DOWN: c = ctl(n); break; default: c = c & 0x7f; } return (c); } VMS_MSG (status) int status; /* Routine to put out the VMS operating system error (if one occurs). */ { #include <descrip.h> char errstr[81], buf[120]; $DESCRIPTOR(errdesc, errstr); short int length; #define err_out(msg) fprintf (stderr,msg) /* Check for no error or standard error */ if (~status & 1) { status = status & 0x8000 ? status & 0xFFFFFFF : status & 0xFFFF; if (SYS$GETMSG(status, &length, &errdesc, 1, 0) == SS$_NORMAL) { errstr[length] = '\0'; sprintf (buf, "<0x%x> %s", status, errdesc.dsc$a_pointer); err_out (buf); } else err_out ("System error"); } } #endif /* VMS */ #else /*SIMPLE*/ #if defined(BSD42) || defined (SYSIII) || defined(BSD43) #define N_KEY 4 struct key_map { char *k_str; char k_val; char k_index; }; struct key_map km[N_KEY]; char keyarea[N_KEY*10]; char *tgetstr(); char *getenv(); char *ks; char ks_buf[20]; char *ke; char ke_buf[20]; #ifdef TIOCSLTC struct ltchars old_chars, new_chars; #endif char dont_use[] = { ctl(z), ctl(r), ctl(l), ctl(b), ctl(c), ctl(f), ctl(g), ctl([), ctl(h), ctl(m), ctl(j), ctl(n), ctl(p), ctl(q), ctl(s), ctl(t), ctl(u), ctl(v), ctl(e), ctl(a), ctl(i), ctl(w), 0, }; charout(c) int c; { (void)putchar(c); } initkbd() { register struct key_map *kp; register i,j; char *p = keyarea; char *ktmp; static char buf[1024]; /* Why do I have to do this again? */ if (tgetent(buf, getenv("TERM")) <= 0) return; km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl(b); km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl(f); km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl(p); km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl(n); ktmp = tgetstr("ks",&p); if (ktmp) { (void) strcpy(ks_buf, ktmp); ks = ks_buf; tputs(ks, 1, charout); } ktmp = tgetstr("ke",&p); if (ktmp) { (void) strcpy(ke_buf, ktmp); ke = ke_buf; } /* Unmap arrow keys which conflict with our ctl keys */ /* Ignore unset, longer than length 1, and 1-1 mapped keys */ for (i = 0; i < N_KEY; i++) { kp = &km[i]; if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val)) for (j = 0; dont_use[j] != 0; j++) if (kp->k_str[0] == dont_use[j]) { kp->k_str = (char *)0; break; } } #ifdef TIOCSLTC (void)ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars); new_chars = old_chars; if (old_chars.t_lnextc == ctl(v)) new_chars.t_lnextc = -1; if (old_chars.t_rprntc == ctl(r)) new_chars.t_rprntc = -1; (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars); #endif } kbd_again() { if (ks) tputs(ks, 1, charout); #ifdef TIOCSLTC (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars); #endif } resetkbd() { if (ke) tputs(ke, 1, charout); #ifdef TIOCSLTC (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars); #endif } nmgetch() { register int c; register struct key_map *kp; register struct key_map *biggest; register int i; int almost; int maybe; static char dumpbuf[10]; static char *dumpindex; #ifdef SIGVOID void time_out(); #else int time_out(); #endif if (dumpindex && *dumpindex) return (*dumpindex++); #ifndef INTERNATIONAL c = getchar() & 0x7f; #else c = getchar() & 0xff; #endif /* INTERNATIONAL */ biggest = 0; almost = 0; for (kp = &km[0]; kp < &km[N_KEY]; kp++) { if (!kp->k_str) continue; if (c == kp->k_str[kp->k_index]) { almost = 1; kp->k_index++; if (kp->k_str[kp->k_index] == 0) { c = kp->k_val; for (kp = &km[0]; kp < &km[N_KEY]; kp++) kp->k_index = 0; return(c); } } if (!biggest && kp->k_index) biggest = kp; else if (kp->k_index && biggest->k_index < kp->k_index) biggest = kp; } if (almost) { (void) signal(SIGALRM, time_out); (void) alarm(1); if (setjmp(wakeup) == 0) { maybe = nmgetch(); (void) alarm(0); return(maybe); } } if (biggest) { for (i = 0; i<biggest->k_index; i++) dumpbuf[i] = biggest->k_str[i]; dumpbuf[i++] = c; dumpbuf[i] = 0; dumpindex = &dumpbuf[1]; for (kp = &km[0]; kp < &km[N_KEY]; kp++) kp->k_index = 0; return (dumpbuf[0]); } return(c); } #endif #if defined(SYSV2) || defined(SYSV3) initkbd() { keypad(stdscr, TRUE); } kbd_again() { keypad(stdscr, TRUE); } resetkbd() { keypad(stdscr, FALSE); } nmgetch() { register int c; c = getch(); switch (c) { case KEY_LEFT: c = ctl(b); break; case KEY_RIGHT: c = ctl(f); break; case KEY_UP: c = ctl(p); break; case KEY_DOWN: c = ctl(n); break; #ifdef KEY_C1 /* This stuff works for a wyse wy75 in ANSI mode under 5.3. Good luck. */ /* It is supposed to map the curses keypad back to the numeric equiv. */ case KEY_C1: c = '0'; break; case KEY_A1: c = '1'; break; case KEY_B2: c = '2'; break; case KEY_A3: c = '3'; break; case KEY_F(5): c = '4'; break; case KEY_F(6): c = '5'; break; case KEY_F(7): c = '6'; break; case KEY_F(9): c = '7'; break; case KEY_F(10): c = '8'; break; case KEY_F0: c = '9'; break; case KEY_C3: c = '.'; break; case KEY_ENTER: c = ctl(m); break; #endif #ifndef INTERNATIONAL default: c = c & 0x7f; #else default: c = c & 0xff; #endif /* INTERNATIONAL */ break; } return (c); } #endif /* SYSV2 || SYSV3 */ #endif /* SIMPLE */ #ifdef SIGVOID void #endif time_out() { longjmp(wakeup, -1); } #ifdef SIGVOID void #endif fpe_trap() { longjmp(fpe_buf, 1); } /* * This converts a floating point number of the form * [s]ddd[.d*][esd*] where s can be a + or - and e is E or e. * to floating point. * p is advanced. */ char * strtof(p, res) register char *p; double *res; { double acc; int sign; double fpos; int exp; int exps; #ifdef SIGVOID void (*sig_save)(); #else int (*sig_save)(); #endif sig_save = signal(SIGFPE, fpe_trap); if (setjmp(fpe_buf)) { error("Floating point exception\n"); *res = 0.0; (void) signal(SIGFPE, sig_save); return(p); } acc = 0.0; sign = 1; exp = 0; exps = 1; if (*p == '+') p++; else if (*p == '-') { p++; sign = -1; } while (isdigit(*p)) { acc = acc * 10.0 + (double)(*p - '0'); p++; } if (*p == 'e' || *p == 'E') { p++; if (*p == '+') p++; else if (*p == '-') { p++; exps = -1; } while(isdigit(*p)) { exp = exp * 10 + (*p - '0'); p++; } } if (*p == '.') { fpos = 1.0/10.0; p++; while(isdigit(*p)) { acc += (*p - '0') * fpos; fpos *= 1.0/10.0; p++; } } if (*p == 'e' || *p == 'E') { exp = 0; exps = 1; p++; if (*p == '+') p++; else if (*p == '-') { p++; exps = -1; } while(isdigit(*p)) { exp = exp * 10 + (*p - '0'); p++; } } if (exp) { if (exps > 0) while (exp--) acc *= 10.0; else while (exp--) acc *= 1.0/10.0; } if (sign > 0) *res = acc; else *res = -acc; (void) signal(SIGFPE, sig_save); return(p); } \SHAR\EOF\ else echo "will not over write ./lex.c" fi if [ `wc -c ./lex.c | awk '{printf $1}'` -ne 12965 ] then echo `wc -c ./lex.c | awk '{print "Got " $1 ", Expected " 12965}'` fi echo "Finished archive 2 of 4" # if you want to concatenate archives, remove anything after this line exit -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.