[comp.sources.unix] v18i046: SC spreadsheet, version 6.1, Part02/04

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.