chen@digital.sps.mot.com (Jinfu Chen) (10/31/90)
Since my posting request for patch to make sc 6.8 to 6.9, I received it from Rob Boldbear <uunet!mtdiablo.Concord.CA.US!rob>. Several persons also sent me mail for a copy and I believe someone else also posted in comp.sources.bugs asking for a copy too. I decide to post the copy Rob sent to me here. However, I will not pretend to claim this is official nor unofficial. Make your own judgement. P.S. crypt.c (6.9) didn't compile in a line with array initialization, sc 6.10 fixed it. ============================================ From: uunet!mtdiablo.Concord.CA.US!rob (Rob Boldbear) Message-Id: <9010301514.AA10691@mtdiablo.Concord.CA.US> Subject: Re: SC 6.9 patch To: chen@digital.sps.mot.com (Jinfu Chen) Date: Tue, 30 Oct 90 7:14:23 PST X-Mailer: ELM [version 2.4dev PL6] Status: OR Here's the patch to make sc 6.9 from 6.8 Article: 491 of comp.sources.bugs Path: mtdiablo!premenos!pacbell!pacbell.com!ucsd!swrinde!zaphod.mps.ohio-state.edu!julius.cs.uiuc.edu!apple!olivea!orc!bbn.com!papaya.bbn.com!rsalz From: rsalz@bbn.com (Rich Salz) Newsgroups: comp.sources.bugs Subject: Patches to sc6.8 Message-ID: <2866@litchi.bbn.com> Date: 27 Sep 90 18:50:14 GMT Organization: BBN Systems and Technology, Inc. Lines: 3026 [ Posted for Jeff Buhrt. --r$ ] From: Jeffery A Buhrt <sequent!sawmill!buhrt@uunet.uu.net> Message-Id: <9009270058.AA26213@sawmill.UUCP> To: uunet!rsalz@uunet.uu.net Subject: Sc6.8 -> 6.9 patches... Status: R Things here in Lafayette, IN are acting funny (thus the mail via sequent). No-one has seen the patches I posted to comp.sources.bugs a few days ago. Our upline feed person is out of town, the system is a mac (hmmm), and our normal mail feed is down (dead HDA). Here is a copy of the patches posted to comp.sources.bugs. Thank you -Jeff Buhrt 317-477-6000 sequent!sawmill!buhrt *** posted/CHANGES Mon Sep 24 09:33:48 1990 --- CHANGES Mon Sep 24 09:44:14 1990 *************** *** 1,3 CHANGES BETWEEN 6.1 and 6.7 Dave Lewis - --- 1,114 ----- + + CHANGES BETWEEN 6.9 and 6.8 + + Jim Richardson + - pointed out vi mode was not documented in sc.doc + - found a nasty buffer limit bug in savedot() + - a side effect was ^D could cause a core dump (-Jeff) + Tim Wilson + - Hints on compiling on Ultrix + Eric Putz + -patch for printfile() (sc died on huge # of columns in a W) + Jeffrey C Honig + -patch for lex.c which bombed on SunOS 4.1 if $TERM was not set + Tom Kloos + -psc now calls [+-.] strings vs numbers. + -also pointed out a format reversal problem + Jack Goral + -changes to Makefile to compile under SCO Unix V rel 3.2.0 + Mark Nagel + -changes to allow arbitrarily complex formatting of cells + Kim Sanders + -^W generated an incorrect equation (line was not started at beginning) + Mike Schwartz + -a put command will use the same encryption key as when the + file was read. + >I have a suggestion for making the encyrption option of "sc" more + >usable: Right now, if you use the -x option when you start up sc, it + >prompts you for the key (just like "vi -x" does). But when you try to + >write the file out using the Put command, it asks for the key again + >each time. Why not make it use the same key you used before (as "vi + >-x" does)? That would really help, because as it is, each time you try + >to save the file you run the risk of mistyping the key. + > + >You might think this causes a security problem, since the key is then + >an argument to crypt, and hence is visible from ps. But when crypt + >runs, the first thing it does is to copy the key to an internal buffer + >and then zero out the argv copy, so the window of vulnerability is + >vanishingly small. + Adri Verhoef + - pointed out a ^D caused a core dump (fixed) + Gene H. Olson + - format now grows the spreadsheet before setting the column format. + - removed an extra ';' that caused a possible column number trashing + Paul Eggert + -sc now also has round-to-even, also known as ``banker's rounding''. + >With round-to-even, a number exactly halfway between two values is + >rounded to whichever is even; e.g. rnd(0.5)=0, rnd(1.5)=2, + >rnd(2.5)=2, rnd(3.5)=4. This is the default rounding mode for + >IEEE floating point, for good reason: it has better numeric + >properties. For example, if X+Y is an integer, + >then X+Y = rnd(X)+rnd(Y) with round-to-even, + >but not always with sc's rounding (which is + >round-to-positive-infinity). I ran into this problem when trying to + >split interest in an account to two people fairly. + -While we're on the subject, @round(X,Y) should also work when Y + >is negative. For example, @round(123,-2) should yield 100. + + + CHANGES BETWEEN 6.8 and 6.7 + + Jeff Buhrt (with help from some beta testers-Thank you) + 1) added a per row memory allocation + -runs in about 1/2 run time and 1/3 the space of 6.6vm.1 + -insert/delete row now just moves pointers (# == maxrow+1-currow) + and blanks one row (of columns (maxcol)) + -as the number of cells grows the size is more linear + (no more ##Meg images except for 100,000's of rows....) + -row to column pointer translation is done by a macro (ATBL) + that returns a pointer to the cell pointer. + *ATBL would be a pointer to a *ent (cell). + -the maximum # of columns is limited by ABSMAXCOLS or + sizeof(struct ent *)*maxcols (whichever is smaller) + (702 * 4 = 2808 is no real limit even for 286 large model) + -the maximum # of rows is limited by the virtual memory limit or + sizeof(struct ent **)*maxrows (whichever is smaller) + (4*X=64k, X=16384 rows (excluding malloc overhead) on + a '286 large model. Even w/ 3.25Meg and 10Mhz) + (plus of course any memory used for cells) + 2) dolookup (int vs double) + 3) dolookup calling eval w/ ent * not enode * + (dolookup called w/ ent * not enode *) + 4) cleaned up a lot of .... *x = 0 to (.... *)0 (cmds, interp) + 5) psc: fwidth/precision were reversed on the output + 6) Backup copy (on save) using same mode to [path/]#file~ + (will prompt if a backup fails) + 7) put y/n prompt function into yn_ask(mesg) + 8) found a move(x,y) in sc -> move(y,x) and only move when needed + 9) we use FullUpdate || changed (to see if ANY cells changed) + before trying to redraw the screen in update + (now we don't try to redraw every time a key is hit) + -if we are stand[ing]out we do not create a cell just to force a + standout inside the repaint section of update() + -only draw blank cells if we cleared it or it is standing out + reason: the less work (what to update) curses has to do, the faster + a screen update will be (less cpu required) + 14) {insert, delete}col replaced w/ {open,close}col(currow, numcol_to_insert) + (limits looping) + 6.7.1.1 + 15) goto nonexistant cell may loop + 16) make sure that startup size will at least fill the screen w/ cells. + 17) added version.c + 6.7.1.2 + 18) When we would normally die w/o saving (SIGQUIT, etc), we now ask + if people would like to save the current spreadsheet. + If 'y', saves to the current file name, otherwise ~/SC.SAVE, + then /tmp/SC.SAVE if all else fails. + 6.7.1.3 + 19) don't use malloc.c for production code + 20) progname is now truncated to just the basename (systems w/ long paths + caused problems) + CHANGES BETWEEN 6.1 and 6.7 Dave Lewis - *** posted/Makefile Mon Sep 24 09:33:59 1990 --- Makefile Mon Sep 24 09:48:25 1990 *************** *** 5,11 NAME=SC # This is where the install step puts it. ! #EXDIR=/v/rgb/bin/psx EXDIR=/usr/local/bin # This is where the man page goes. --- 5,11 ----- NAME=SC # This is where the install step puts it. ! #EXDIR=/site/bin EXDIR=/usr/local/bin # This is where the man page goes. *************** *** 9,15 EXDIR=/usr/local/bin # This is where the man page goes. ! #MANDIR=/usr/man/man1 MANDIR=/usr/man/manl # Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up --- 9,15 ----- EXDIR=/usr/local/bin # This is where the man page goes. ! #MANDIR=/site/man/man1 MANDIR=/usr/man/manl # This is where the library file (tutorial) goes. *************** *** 12,17 #MANDIR=/usr/man/man1 MANDIR=/usr/man/manl # Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up #SIMPLE=-DSIMPLE --- 12,21 ----- #MANDIR=/site/man/man1 MANDIR=/usr/man/manl + # This is where the library file (tutorial) goes. + #LIBDIR=/site/lib/sc + LIBDIR=/usr/local/lib/sc + # Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up #SIMPLE=-DSIMPLE *************** *** 29,34 # #IEEE_MATH=-DIEEE_MATH # This is the name of a pager like "more" If the line is commented out # then "more" will be used. "pg" may be appropriate for SYSV PAGER=-DDFLT_PAGER=\"less\" --- 33,41 ----- # #IEEE_MATH=-DIEEE_MATH + # Set RINT if you do not have rint() in math.h + RINT=-DRINT + # This is the name of a pager like "more" If the line is commented out # then "more" will be used. "pg" may be appropriate for SYSV PAGER=-DDFLT_PAGER=\"less\" *************** *** 33,38 # then "more" will be used. "pg" may be appropriate for SYSV PAGER=-DDFLT_PAGER=\"less\" # Use this for system V.2 #CFLAGS= -O -DSYSV2 #LDFLAGS= --- 40,48 ----- # then "more" will be used. "pg" may be appropriate for SYSV PAGER=-DDFLT_PAGER=\"less\" + # For ULTRIX: define the BSD4.2 section and SIGVOID above + # tdw@cl.cam.ac.uk tested on Ultrix 3.1C-0 + # Use this for system V.2 #CFLAGS= -O -DSYSV2 #LDFLAGS= *************** *** 56,62 # Use this for Sequent boxes CC=atscc CFLAGS=-O -DBSD42 ! LDFLAGS= -s LIB=-lm -lcurses -ltermcap PSCLIB=-lseq --- 66,72 ----- # Use this for Sequent boxes CC=atscc CFLAGS=-O -DBSD42 ! #LDFLAGS= -s LIB=-lm -lcurses -ltermcap PSCLIB=-lseq *************** *** 75,80 #LDFLAGS= -z -i #LIB=-lm -lcurses -ltermcap # All of the source files SRC=sc.h sc.c lex.c gram.y interp.c crypt.c xmalloc.c cmds.c range.c help.c \ vi.c eres.sed sres.sed Makefile psc.c vmtbl.c version.c --- 85,101 ----- #LDFLAGS= -z -i #LIB=-lm -lcurses -ltermcap + # For SCO Unix V rel. 3.2.0 + # -compile using rcc, cc does not cope with gram.c + # -edit /usr/include/curses.h, rcc does not understand #error + # -link: make CC=cc, rcc's loader gets unresolved __cclass, __range + # (rather strange,?) + #CC=rcc + #SIGVOID=-DSIGVOID + #CFLAGS= -O -DSYSV3 + #LDFLAGS= + #LIB=-lm -lcurses -ltinfo -lPW + # All of the source files SRC=sc.h sc.c lex.c gram.y interp.c crypt.c xmalloc.c cmds.c range.c help.c \ vi.c eres.sed sres.sed Makefile psc.c vmtbl.c version.c *************** *** 81,87 # The objects OBJS=sc.o interp.o cmds.o crypt.o xmalloc.o range.o help.o vi.o lex.o gram.o \ ! vmtbl.o version.o # The documents in the Archive DOCS=README CHANGES sc.doc psc.doc tutorial.sc VMS_NOTES BSD_BUGS --- 102,108 ----- # The objects OBJS=sc.o interp.o cmds.o crypt.o xmalloc.o range.o help.o vi.o lex.o gram.o \ ! vmtbl.o format.o version.o # The documents in the Archive DOCS=README CHANGES sc.doc psc.doc tutorial.sc VMS_NOTES BSD_BUGS *************** *** 107,113 $(CC) ${CFLAGS} ${INTERNATIONAL} ${PAGER} ${SIGVOID} -c sc.c interp.o: interp.c sc.h ! $(CC) ${CFLAGS} ${IEEE_MATH} ${SIGVOID} -c interp.c gram.o: sc.h y.tab.h --- 128,134 ----- $(CC) ${CFLAGS} ${INTERNATIONAL} ${PAGER} ${SIGVOID} -c sc.c interp.o: interp.c sc.h ! $(CC) ${CFLAGS} ${IEEE_MATH} ${SIGVOID} ${RINT} -c interp.c gram.o: sc.h y.tab.h *************** *** 121,126 help.o: help.c sc.h vi.o: vi.c sc.h y.tab.h: gram.y --- 142,149 ----- help.o: help.c sc.h + format.o: format.c + vi.o: vi.c sc.h y.tab.h: gram.y *************** *** 154,160 prc sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c | lpr $(name).1: sc.doc ! sed -e s/pname/$(name)/g -e s/PNAME/$(NAME)/g sc.doc > $(name).1 $(name).man: $(name).1 nroff -man $(name).1 > $(name).man --- 177,184 ----- prc sc.h gram.y sc.c lex.c interp.c cmds.c crypt.c | lpr $(name).1: sc.doc ! sed -e s/pname/$(name)/g -e s/PNAME/$(NAME)/g \ ! -e s%#LIBDIR#%$(LIBDIR)%g sc.doc > $(name).1 $(name).man: $(name).1 nroff -man $(name).1 > $(name).man *************** *** 168,174 p$(name).man: p$(name).1 nroff -man p$(name).1 > p$(name).man ! install: $(EXDIR)/$(name) inst-man: $(MANDIR)/$(name).1 --- 192,198 ----- p$(name).man: p$(name).1 nroff -man p$(name).1 > p$(name).man ! install: $(EXDIR)/$(name) $(LIBDIR)/tutorial inst-man: $(MANDIR)/$(name).1 *************** *** 176,181 -mv $(EXDIR)/$(name) $(EXDIR)/$(name).old cp $(name) $(EXDIR) strip $(EXDIR)/$(name) $(MANDIR)/$(name).1: $(name).1 cp $(name).1 $(MANDIR) --- 200,209 ----- -mv $(EXDIR)/$(name) $(EXDIR)/$(name).old cp $(name) $(EXDIR) strip $(EXDIR)/$(name) + + $(LIBDIR)/tutorial: tutorial.sc + -mkdir $(LIBDIR) + cp tutorial.sc $(LIBDIR) $(MANDIR)/$(name).1: $(name).1 cp $(name).1 $(MANDIR) *** posted/TODO Mon Sep 24 09:34:09 1990 --- TODO Wed Sep 5 15:19:17 1990 *************** *** 1,54 - done/tested: (Jeff Buhrt) - 6.7 - 1) added a per row memory allocation - -runs in about 1/2 run time and 1/3 the space of 6.6vm.1 - -insert/delete row now just moves pointers (# == maxrow+1-currow) - and blanks one row (of columns (maxcol)) - -as the number of cells grows the size is more linear - (no more ##Meg images except for 100,000's of rows....) - -row to column pointer translation is done by a macro (ATBL) - that returns a pointer to the cell pointer. - *ATBL would be a pointer to a *ent (cell). - -the maximum # of columns is limited by ABSMAXCOLS or - sizeof(struct ent *)*maxcols (whichever is smaller) - (702 * 4 = 2808 is no real limit even for 286 large model) - -the maximum # of rows is limited by the virtual memory limit or - sizeof(struct ent **)*maxrows (whichever is smaller) - (4*X=64k, X=16384 rows (excluding malloc overhead) on - a '286 large model. Even w/ 3.25Meg and 10Mhz) - (plus of course any memory used for cells) - 2) dolookup (int vs double) - 3) dolookup calling eval w/ ent * not enode * - (dolookup called w/ ent * not enode *) - 4) cleaned up a lot of .... *x = 0 to (.... *)0 (cmds, interp) - 5) psc: fwidth/precision were reversed on the output - 6) Backup copy (on save) using same mode to [path/]#file~ - (will prompt if a backup fails) - 7) put y/n prompt function into yn_ask(mesg) - 8) found a move(x,y) in sc -> move(y,x) and only move when needed - 9) we use FullUpdate || changed (to see if ANY cells changed) - before trying to redraw the screen in update - (now we don't try to redraw every time a key is hit) - -if we are stand[ing]out we do not create a cell just to force a - standout inside the repaint section of update() - -only draw blank cells if we cleared it or it is standing out - reason: the less work (what to update) curses has to do, the faster - a screen update will be (less cpu required) - 14) {insert, delete}col replaced w/ {open,close}col(currow, numcol_to_insert) - (limits looping) - 6.7.1.1 - 15) goto nonexistant cell may loop - 16) make sure that startup size will at least fill the screen w/ cells. - 17) added version.c - 6.7.1.2 - 18) When we would normally die w/o saving (SIGQUIT, etc), we now ask - if people would like to save the current spreadsheet. - If 'y', saves to the current file name, otherwise ~/SC.SAVE, - then /tmp/SC.SAVE if all else fails. - 6.7.1.3 - 19) don't use malloc.c for production code - 20) progname is now truncated to just the basename (systems w/ long paths - caused problems) todo: 1) autobackup of things typed in. --- 1,3 ----- todo: 1) autobackup of things typed in. *** posted/cmds.c Mon Sep 24 09:34:48 1990 --- cmds.c Mon Sep 24 09:41:56 1990 *************** *** 7,13 * * More mods Robert Bond, 12/86 * ! * $Revision: 6.8 $ */ #include <curses.h> --- 7,13 ----- * * More mods Robert Bond, 12/86 * ! * $Revision: 6.9 $ */ #include <curses.h> *************** *** 583,588 { register int i; if (w > COLS - RESCOL - 2) { error("Format too large - Maximum = %d", COLS - RESCOL - 2); w = COLS-RESCOL-2; --- 583,591 ----- { register int i; + if (c1 >= maxcols && !growtbl(GROWCOL, 0, c1)) c1 = maxcols-1 ; + if (c2 >= maxcols && !growtbl(GROWCOL, 0, c2)) c2 = maxcols-1 ; + if (w > COLS - RESCOL - 2) { error("Format too large - Maximum = %d", COLS - RESCOL - 2); w = COLS-RESCOL-2; *************** *** 647,653 int r0, c0, rn, cn; { FILE *f; ! char pline[FBUFLEN]; int plinelim; int pid; int fieldlen, nextcol; --- 650,656 ----- int r0, c0, rn, cn; { FILE *f; ! char *pline; int plinelim; int fbufs_allocated = 0; int pid; *************** *** 649,654 FILE *f; char pline[FBUFLEN]; int plinelim; int pid; int fieldlen, nextcol; register row, col; --- 652,658 ----- FILE *f; char *pline; int plinelim; + int fbufs_allocated = 0; int pid; int fieldlen, nextcol; register row, col; *************** *** 654,659 register row, col; register struct ent **pp; if ((strcmp(fname, curfile) == 0) && !yn_ask("Confirm that you want to destroy the data base: (y,n)")) return; --- 658,668 ----- register row, col; register struct ent **pp; + if((pline = (char *)malloc(FBUFLEN * ++fbufs_allocated)) == (char *)NULL) { + error("Malloc failed in printfile()"); + return; + } + if ((strcmp(fname, curfile) == 0) && !yn_ask("Confirm that you want to destroy the data base: (y,n)")) { free((char *)pline); *************** *** 655,661 register struct ent **pp; if ((strcmp(fname, curfile) == 0) && ! !yn_ask("Confirm that you want to destroy the data base: (y,n)")) return; if ((f = openout(fname, &pid)) == (FILE *)0) --- 664,671 ----- } if ((strcmp(fname, curfile) == 0) && ! !yn_ask("Confirm that you want to destroy the data base: (y,n)")) { ! free((char *)pline); return; } *************** *** 657,662 if ((strcmp(fname, curfile) == 0) && !yn_ask("Confirm that you want to destroy the data base: (y,n)")) return; if ((f = openout(fname, &pid)) == (FILE *)0) { error ("Can't create file \"%s\"", fname); --- 667,673 ----- !yn_ask("Confirm that you want to destroy the data base: (y,n)")) { free((char *)pline); return; + } if ((f = openout(fname, &pid)) == (FILE *)0) { error ("Can't create file \"%s\"", fname); *************** *** 660,665 if ((f = openout(fname, &pid)) == (FILE *)0) { error ("Can't create file \"%s\"", fname); return; } for (row=r0;row<=rn; row++) { --- 671,677 ----- if ((f = openout(fname, &pid)) == (FILE *)0) { error ("Can't create file \"%s\"", fname); + free((char *)pline); return; } for (row=r0;row<=rn; row++) { *************** *** 682,687 if (*pp) { char *s; while (plinelim<c) pline[plinelim++] = ' '; plinelim = c; if ((*pp)->flags&is_valid) { --- 694,713 ----- if (*pp) { char *s; + /* + * dynamically allocate pline, making sure we are not + * attempting to write 'out of bounds'. + */ + while(c > (fbufs_allocated * FBUFLEN)) { + if((pline = ((char *)realloc + ((char *)pline, + (unsigned)(FBUFLEN * ++fbufs_allocated)))) + == NULL) { + error ("Realloc failed in printfile()"); + free((char *)pline); + return; + } + } while (plinelim<c) pline[plinelim++] = ' '; plinelim = c; if ((*pp)->flags&is_valid) { *************** *** 685,692 while (plinelim<c) pline[plinelim++] = ' '; plinelim = c; if ((*pp)->flags&is_valid) { ! (void)sprintf (pline+plinelim,"%*.*f",fwidth[col], ! precision[col], (*pp)->v); plinelim += strlen (pline+plinelim); } if (s = (*pp)->label) { --- 711,738 ----- while (plinelim<c) pline[plinelim++] = ' '; plinelim = c; if ((*pp)->flags&is_valid) { ! while(plinelim + fwidth[col] > ! (fbufs_allocated * FBUFLEN)) { ! if((pline = ((char *)realloc ! ((char *)pline, ! (unsigned)(FBUFLEN * ++fbufs_allocated)))) ! == NULL) { ! error ("Realloc failed in printfile()"); ! free((char *)pline); ! return; ! } ! } ! if ((*pp)->format) { ! char field[FBUFLEN]; ! ! (void) format ((*pp)->format, (*pp)->v, field, ! sizeof(field)); ! (void) sprintf (pline+plinelim, "%*s", fwidth[col], ! field); ! } else { ! (void)sprintf (pline+plinelim,"%*.*f",fwidth[col], ! precision[col], (*pp)->v); ! } plinelim += strlen (pline+plinelim); } if (s = (*pp)->label) { *************** *** 709,714 if (slen > fieldlen) slen = fieldlen; /* Now justify and print */ start = (*pp)->flags & is_leftflush ? pline + c : pline + c + fieldlen - slen; --- 755,771 ----- if (slen > fieldlen) slen = fieldlen; + while(c + fieldlen + 2 > (fbufs_allocated * FBUFLEN)) { + if((pline = ((char *)realloc + ((char *)pline, + (unsigned)(FBUFLEN * ++fbufs_allocated)))) + == NULL) { + error ("Realloc failed in printfile()"); + free((char *)pline); + return; + } + } + /* Now justify and print */ start = (*pp)->flags & is_leftflush ? pline + c : pline + c + fieldlen - slen; *************** *** 731,736 (void) fputs (pline, f); } closeout(f, pid); } --- 788,795 ----- (void) fputs (pline, f); } + free((char *)pline); + closeout(f, pid); } *************** *** 780,787 if (*pp) { char *s; if ((*pp)->flags&is_valid) { ! (void) fprintf (f,"%.*f",precision[col], ! (*pp)->v); } if (s = (*pp)->label) { (void) fprintf (f,"%s",s); --- 839,854 ----- if (*pp) { char *s; if ((*pp)->flags&is_valid) { ! if ((*pp)->format) { ! char field[FBUFLEN]; ! ! (void) format ((*pp)->format, (*pp)->v, field, ! sizeof(field)); ! (void) fprintf (f, "%s", field); ! } else { ! (void) fprintf (f,"%.*f",precision[col], ! (*pp)->v); ! } } if (s = (*pp)->label) { (void) fprintf (f,"%s",s); *************** *** 1090,1096 n -> label = (char *)0; if (p -> label) { n -> label = (char *) ! xmalloc ((unsigned) (strlen (p -> label) + 1)); (void) strcpy (n -> label, p -> label); } } --- 1157,1163 ----- n -> label = (char *)0; if (p -> label) { n -> label = (char *) ! xmalloc ((unsigned) (strlen (p -> label) + 1)); (void) strcpy (n -> label, p -> label); } n -> format = 0; *************** *** 1093,1098 xmalloc ((unsigned) (strlen (p -> label) + 1)); (void) strcpy (n -> label, p -> label); } } void --- 1160,1171 ----- xmalloc ((unsigned) (strlen (p -> label) + 1)); (void) strcpy (n -> label, p -> label); } + n -> format = 0; + if (p -> format) { + n -> format = (char *) + xmalloc ((unsigned) (strlen (p -> format) + 1)); + (void) strcpy (n -> format, p -> format); + } } void *************** *** 1137,1142 editv (r, c); (void) fprintf (f, "%s\n",line); } } } } --- 1210,1219 ----- editv (r, c); (void) fprintf (f, "%s\n",line); } + if ((*pp)->format) { + editfmt (r, c); + (void) fprintf (f, "%s\n",line); + } } } if (rndinfinity) *************** *** 1139,1144 } } } } int --- 1216,1223 ----- } } } + if (rndinfinity) + fprintf(f, "set rndinfinity\n"); } int *** posted/crypt.c Mon Sep 24 09:34:53 1990 --- crypt.c Mon Sep 24 09:41:59 1990 *************** *** 2,8 * Encryption utilites * Bradley Williams * {allegra,ihnp4,uiucdcs,ctvax}!convex!williams ! * $Revision: 6.8 $ */ #include <stdio.h> --- 2,8 ----- * Encryption utilites * Bradley Williams * {allegra,ihnp4,uiucdcs,ctvax}!convex!williams ! * $Revision: 6.9 $ */ #include <stdio.h> *************** *** 23,28 #endif int Crypt = 0; creadfile (save, eraseflg) char *save; --- 23,30 ----- #endif int Crypt = 0; + #define MAXKEYWORDSIZE 30 + char KeyWord[MAXKEYWORDSIZE] = NULL; creadfile (save, eraseflg) char *save; *************** *** 49,54 } deraw(); if ((pid=fork()) == 0) /* if child */ { (void) close (0); /* close stdin */ --- 51,59 ----- } deraw(); + strcpy(KeyWord, getpass("Enter key:")); + goraw(); + if ((pid=fork()) == 0) /* if child */ { (void) close (0); /* close stdin */ *************** *** 57,63 (void) dup (fildes); /* standard in from file */ (void) dup (pipefd[1]); /* connect to pipe */ (void) fprintf (stderr, " "); ! (void) execl ("/bin/sh", "sh", "-c", "crypt", (char *)0); exit (-127); } else /* else parent */ --- 62,69 ----- (void) dup (fildes); /* standard in from file */ (void) dup (pipefd[1]); /* connect to pipe */ (void) fprintf (stderr, " "); ! (void) execl ("/bin/crypt", "crypt", KeyWord, 0); ! exit (-127); } else /* else parent */ *************** *** 82,88 (void) fclose (f); (void) close (pipefd[0]); while (pid != wait(&fildes)) /**/; - goraw(); linelim = -1; modflg++; if (eraseflg) { --- 88,93 ----- (void) fclose (f); (void) close (pipefd[0]); while (pid != wait(&fildes)) /**/; linelim = -1; modflg++; if (eraseflg) { *************** *** 134,140 return(-1); } ! deraw(); if ((pid=fork()) == 0) /* if child */ { (void) close (0); /* close stdin */ --- 139,150 ----- return(-1); } ! if (KeyWord[0] == NULL) { ! deraw(); ! strcpy(KeyWord, getpass("Enter key:")); ! goraw(); ! } ! if ((pid=fork()) == 0) /* if child */ { (void) close (0); /* close stdin */ *************** *** 143,149 (void) dup (pipefd[0]); /* connect to pipe input */ (void) dup (fildes); /* standard out to file */ (void) fprintf (stderr, " "); ! (void) execl ("/bin/sh", "sh", "-c", "crypt", 0); exit (-127); } else /* else parent */ --- 153,159 ----- (void) dup (pipefd[0]); /* connect to pipe input */ (void) dup (fildes); /* standard out to file */ (void) fprintf (stderr, " "); ! (void) execl ("/bin/crypt", "crypt", KeyWord, 0); exit (-127); } else /* else parent */ *************** *** 168,175 (void) strcpy(curfile,save); modflg = 0; ! error ("File \"%s\" written", curfile); ! goraw(); return(0); } --- 178,184 ----- (void) strcpy(curfile,save); modflg = 0; ! error ("File \"%s\" written (encrypted).", curfile); return(0); } *** posted/format.c Mon Sep 24 09:54:28 1990 --- format.c Mon Sep 24 09:42:10 1990 *************** *** 0 --- 1,461 ----- + /***************************************************************************** + * + * Mark Nagel <nagel@ics.uci.edu> + * 20 July 1989 + * + * $Revision: 6.9 $ + * + * bool + * format(fmt, num, buf, buflen) + * char *fmt; + * double num; + * char buf[]; + * int buflen; + * + * The format function will produce a string representation of a number + * given a _format_ (described below) and a double value. The result is + * written into the passed buffer -- if the resulting string is too + * long to fit into the passed buffer, the function returns false. + * Otherwise the function returns true. + * + * The fmt parameter contains the format to use to convert the number. + * + * # Digit placeholder. If the number has fewer digits on either + * side of the decimal point than there are '#' characters in + * the format, the extra '#' characters are ignored. The number + * is rounded to the number of digit placeholders as there are + * to the right of the decimal point. If there are more digits + * in the number than there are digit placeholders on the left + * side of the decimal point, then those digits are displayed. + * + * 0 Digit placeholder. Same as for '#' except that the number + * is padded with zeroes on either side of the decimal point. + * The number of zeroes used in padding is determined by the + * number of digit placeholders after the '0' for digits on + * the left side of the decimal point and by the number of + * digit placeholders before the '0' for digits on the right + * side of the decimal point. + * + * . Decimal point. Determines how many digits are placed on + * the right and left sides of the decimal point in the number. + * Note that numbers smaller than 1 will begin with a decimal + * point if the left side of the decimal point contains only + * a '#' digit placeholder. Use a '0' placeholder to get a + * leading zero in decimal formats. + * + * % Percentage. For each '%' character in the format, the actual + * number gets multiplied by 100 (only for purposes of formatting + * -- the original number is left unmodified) and the '%' character + * is placed in the same position as it is in the format. + * + * , Thousands separator. The presence of a ',' in the format + * (multiple commas are treated as one) will cause the number + * to be formatted with a ',' separating each set of three digits + * in the integer part of the number with numbering beginning + * from the right end of the integer. + * + * \ Quote. This character causes the next character to be + * inserted into the formatted string directly with no + * special interpretation. + * + * E- E+ e- e+ + * Scientific format. Causes the number to formatted in scientific + * notation. The case of the 'E' or 'e' given is preserved. If + * the format uses a '+', then the sign is always given for the + * exponent value. If the format uses a '-', then the sign is + * only given when the exponent value is negative. Note that if + * there is no digit placeholder following the '+' or '-', then + * that part of the formatted number is left out. In general, + * there should be one or more digit placeholders after the '+' + * or '-'. + * + * ; Format selector. Use this character to separate the format + * into two distinct formats. The format to the left of the + * ';' character will be used if the number given is zero or + * positive. The format to the right of the ';' character is + * used if the number given is negative. + * + * Any + * Self insert. Any other character will be inserted directly + * into the formatted number with no change made to the actual + * number. + * + *****************************************************************************/ + + /*****************************************************************************/ + + #include <stdio.h> + + #define bool int + #define true 1 + #define false 0 + #define EOS '\0' + #define MAXBUF 256 + + extern char + *strcpy(); + + static char + *fmt_int(), + *fmt_frac(), + *fmt_exp(); + + static void + reverse(); + + /*****************************************************************************/ + + bool + format(fmt, val, buf, buflen) + char *fmt; + double val; + char *buf; + int buflen; + { + register char *cp; + char *tmp, *tp, *tmpfmt; + bool comma = false, negative = false; + char *integer = NULL, *decimal = NULL; + char *exponent = NULL; + int exp_val, width; + char prtfmt[32]; + char *mantissa; + char *fraction = NULL; + int zero_pad = 0; + + if (fmt == NULL) + return; + + fmt = tmpfmt = strcpy((char *) xmalloc(strlen(fmt) + 1), fmt); + mantissa = (char *) xmalloc(buflen + 1); + + /* + * select positive or negative format if necessary + */ + for (cp = fmt; *cp != ';' && *cp != EOS; cp++) + { + if (*cp == '\\') + cp++; + } + if (*cp == ';') + { + if (val < 0.0) + { + val = -val; /* format should provide sign if desired */ + fmt = cp + 1; + } + else + { + *cp = EOS; + } + } + + /* + * extract other information from format and produce new + * malloc'ed format string + */ + tmp = (char *) xmalloc(strlen(fmt) + 1); + for (cp = fmt, tp = tmp; *cp != EOS; cp++) + { + switch (*cp) + { + case '\\': + *tp++ = *cp++; + *tp++ = *cp; + break; + + case ',': + comma = true; + break; + + case '.': + if (decimal == NULL) + decimal = tp; + *tp++ = *cp; + break; + + case '%': + val *= 100.0; + *tp++ = *cp; + break; + + default: + *tp++ = *cp; + break; + } + } + *tp = EOS; + xfree(tmpfmt); + fmt = tmp; + + /* + * extract the exponent from the format if present + */ + for (cp = fmt; *cp != EOS; cp++) + { + if (*cp == '\\') + { + cp++; + } + else if (*cp == 'e' || *cp == 'E') + { + if (cp[1] == '+' || cp[1] == '-') + { + tmp = (char *) xmalloc(strlen(cp) + 1); + exponent = strcpy(tmp, cp); + *cp = EOS; + exp_val = 0; + while (val < 1.0) + { + val *= 10.0; + exp_val--; + } + while (val >= 10.0) + { + val /= 10.0; + exp_val++; + } + break; + } + } + } + + /* + * determine maximum decimal places and use sprintf + * to build initial character form of formatted value. + */ + width = 0; + if (decimal) + { + *decimal++ = EOS; + for (cp = decimal; *cp != EOS; cp++) + { + switch (*cp) + { + case '\\': + cp++; + break; + + case '#': + width++; + break; + + case '0': + zero_pad = ++width; + break; + } + } + zero_pad = strlen(decimal) - zero_pad; + } + if (val < 0.0) + { + negative = true; + val = -val; + } + sprintf(prtfmt, "%%.%dlf", width); + sprintf(mantissa, prtfmt, val); + for (cp = integer = mantissa; *cp != '.' && *cp != EOS; cp++) + { + if (*integer == '0') + integer++; + } + if (*cp == '.') + { + fraction = cp + 1; + *cp = EOS; + cp = fraction + strlen(fraction) - 1; + for (; zero_pad > 0; zero_pad--, cp--) + { + if (*cp == '0') + *cp = EOS; + } + } + + /* + * format the puppy + */ + { + char *ci, *cf, *ce; + int len_ci, len_cf, len_ce; + bool ret = false; + + ci = fmt_int(integer, fmt, comma, negative); + ci = strcpy((char *)xmalloc((len_ci = strlen(ci)) + 1), ci); + cf = (fraction) ? fmt_frac(fraction, decimal) : ""; + cf = strcpy((char *)xmalloc((len_cf = strlen(cf)) + 1), cf); + ce = (exponent) ? fmt_exp(exp_val, exponent) : ""; + ce = strcpy((char *)xmalloc((len_ce = strlen(ce)) + 1), ce); + if (len_ci + len_cf + len_ce < buflen) + { + sprintf(buf, "%s%s%s", ci, cf, ce); + ret = true; + } + + /* + * free up malloc'ed memory + */ + xfree(mantissa); + xfree(fmt); + if (exponent) xfree(exponent); + xfree(ci); + xfree(cf); + xfree(ce); + + return (ret); + } + } + + /*****************************************************************************/ + + static char * + fmt_int(val, fmt, comma, negative) + char *val; /* integer part of the value to be formatted */ + char *fmt; /* integer part of the format */ + bool comma; /* true if we should comma-ify the value */ + bool negative; /* true if the value is actually negative */ + { + int digit, f, v; + int thousands = 0; + char *cp; + static char buf[MAXBUF]; + char *bufptr = buf; + + /* + * locate the leftmost digit placeholder + */ + for (cp = fmt; *cp != EOS; cp++) + { + if (*cp == '\\') + cp++; + else if (*cp == '#' || *cp == '0') + break; + } + digit = (*cp == EOS) ? -1 : cp - fmt; + + /* + * format the value + */ + f = strlen(fmt) - 1; + v = (digit >= 0) ? strlen(val) - 1 : -1; + while (f >= 0 || v >= 0) + { + if (f > 0 && fmt[f-1] == '\\') + { + *bufptr++ = fmt[f--]; + } + else if (f >= 0 && (fmt[f] == '#' || fmt[f] == '0')) + { + if (v >= 0 || fmt[f] == '0') + { + *bufptr++ = v < 0 ? '0' : val[v]; + if (comma && (thousands = (thousands + 1) % 3) == 0 && v > 0) + { + *bufptr++ = ','; + } + v--; + } + } + else if (f >= 0) + { + *bufptr++ = fmt[f]; + } + if (v >= 0 && f == digit) + { + continue; + } + f--; + } + + if (negative && digit >= 0) + *bufptr++ = '-'; + *bufptr = EOS; + reverse(buf); + + return (buf); + } + + /*****************************************************************************/ + + static char * + fmt_frac(val, fmt) + char *val; /* fractional part of the value to be formatted */ + char *fmt; /* fractional portion of format */ + { + static char buf[MAXBUF]; + register char *bufptr = buf; + register char *fmtptr = fmt, *valptr = val; + + *bufptr++ = '.'; + while (*fmtptr != EOS) + { + if (*fmtptr == '\\') + { + *bufptr++ = *++fmtptr; + } + else if (*fmtptr == '#' || *fmtptr == '0') + { + if (*valptr != EOS || *fmtptr == '0') + { + *bufptr++ = (*valptr != EOS) ? *valptr++ : *fmtptr; + } + } + else + { + *bufptr++ = *fmtptr; + } + fmtptr++; + } + *bufptr = EOS; + + return (buf); + } + + /*****************************************************************************/ + + static char * + fmt_exp(val, fmt) + int val; /* value of the exponent */ + char *fmt; /* exponent part of the format */ + { + static char buf[MAXBUF]; + register char *bufptr = buf; + char valbuf[64]; + bool negative = false; + + *bufptr++ = *fmt++; + if (*fmt++ == '+') + *bufptr++ = (val < 0) ? '-' : '+'; + else if (val < 0) + *bufptr++ = '-'; + *bufptr = EOS; + + if (val < 0) + { + val = -val; + negative = true; + } + sprintf(valbuf, "%d", val); + + strcat(buf, fmt_int(valbuf, fmt, false, negative)); + return (buf); + } + + /*****************************************************************************/ + + static void + reverse(buf) + register char *buf; + { + register char *cp = buf + strlen(buf) - 1; + register char tmp; + + while (buf < cp) + { + tmp = *cp; + *cp-- = *buf; + *buf++ = tmp; + } + } + + /*****************************************************************************/ + *** posted/gram.y Mon Sep 24 09:35:10 1990 --- gram.y Mon Sep 24 09:42:13 1990 *************** *** 9,15 * * More mods by Alan Silverstein, 3/88, see list of changes. * ! * $Revision: 6.8 $ */ --- 9,15 ----- * * More mods by Alan Silverstein, 3/88, see list of changes. * ! * $Revision: 6.9 $ */ *************** *** 46,51 %token <sval> WORD %token <ival> COL %token S_FORMAT %token S_LABEL %token S_LEFTSTRING %token S_RIGHTSTRING --- 46,52 ----- %token <sval> WORD %token <ival> COL %token S_FORMAT + %token S_FMT %token S_LABEL %token S_LEFTSTRING %token S_RIGHTSTRING *************** *** 140,145 %token K_TBL %token K_LATEX %token K_TEX %left '?' ':' %left '|' --- 141,147 ----- %token K_TBL %token K_LATEX %token K_TEX + %token K_RNDINFINITY %left '?' ':' %left '|' *************** *** 223,228 lookat(currow, curcol), $2, $3); } | S_FILL var_or_range num num { fill($2.left.vp, $2.right.vp, $3, $4); } | S_GOTO var_or_range {moveto($2.left.vp->row, $2.left.vp->col);} | S_GOTO num {num_search($2);} | S_GOTO STRING {str_search($2);} --- 225,232 ----- lookat(currow, curcol), $2, $3); } | S_FILL var_or_range num num { fill($2.left.vp, $2.right.vp, $3, $4); } + | S_FMT var_or_range STRING + { format_cell($2.left.vp, $2.right.vp, $3); } | S_GOTO var_or_range {moveto($2.left.vp->row, $2.left.vp->col);} | S_GOTO num {num_search($2);} | S_GOTO STRING {str_search($2);} *************** *** 418,421 | K_TBLSTYLE '=' K_TBL { tbl_style = TBL; } | K_TBLSTYLE '=' K_LATEX { tbl_style = LATEX; } | K_TBLSTYLE '=' K_TEX { tbl_style = TEX; } ; --- 422,427 ----- | K_TBLSTYLE '=' K_TBL { tbl_style = TBL; } | K_TBLSTYLE '=' K_LATEX { tbl_style = LATEX; } | K_TBLSTYLE '=' K_TEX { tbl_style = TEX; } + | K_RNDINFINITY { rndinfinity = 1; FullUpdate++;} + | '!' K_RNDINFINITY { rndinfinity = 0; FullUpdate++;} ; *** posted/help.c Mon Sep 24 09:35:31 1990 --- help.c Mon Sep 24 09:42:17 1990 *************** *** 1,7 /* * Help functions for sc * R. Bond, 1988 ! * $Revision: 6.8 $ */ #include <curses.h> --- 1,7 ----- /* * Help functions for sc * R. Bond, 1988 ! * $Revision: 6.9 $ */ #include <curses.h> *************** *** 53,58 " iterations=n Set the number of iterations allowed. (10)", " tblstyle=xx Set ``T'' output style to:", " 0 (none), tex, latex, or tbl.", (char *)0 }; --- 53,59 ----- " iterations=n Set the number of iterations allowed. (10)", " tblstyle=xx Set ``T'' output style to:", " 0 (none), tex, latex, or tbl.", + " rndinfinity Round to infinity (round .5 up vs to nearest even).", (char *)0 }; *************** *** 91,96 " \",> Enter a right justified string or string expression.", " e Edit the current cell's numeric value.", " E Edit the current cell's string part.", " x Clear the current cell.", " c Copy the last marked cell to the current cell.", " m Mark a cell to be used as the source for ``c''", --- 92,98 ----- " \",> Enter a right justified string or string expression.", " e Edit the current cell's numeric value.", " E Edit the current cell's string part.", + " F Assign a format to the current cell's numeric value.", " x Clear the current cell.", " c Copy the last marked cell to the current cell.", " m Mark a cell to be used as the source for ``c''", *************** *** 192,199 " as ``A10'' or a range such as ``a1:b20''.", " /s Shows the currently defined range names. Pipe output to", " sort, then to less.", ! " /u Use this command to undefine a previously defined range", ! " name.", " ", " Range operations affect a rectangular region on the screen", " defined by the upper left and lower right cells in the region.", --- 194,201 ----- " as ``A10'' or a range such as ``a1:b20''.", " /s Shows the currently defined range names. Pipe output to", " sort, then to less.", ! " /u Use this command to undefine a previously defined range name.", ! " /F Assign a format string to a range of cells.", " ", " Range operations affect a rectangular region on the screen", " defined by the upper left and lower right cells in the region.", *** posted/interp.c Mon Sep 24 09:36:32 1990 --- interp.c Mon Sep 24 09:42:28 1990 *************** *** 7,13 * * More mods Robert Bond, 12/86 * More mods by Alan Silverstein, 3-4/88, see list of changes. ! * $Revision: 6.8 $ */ #define DEBUGDTS 1 /* REMOVE ME */ --- 7,13 ----- * * More mods Robert Bond, 12/86 * More mods by Alan Silverstein, 3-4/88, see list of changes. ! * $Revision: 6.9 $ */ #define DEBUGDTS 1 /* REMOVE ME */ *************** *** 86,91 double fn1_eval(); double fn2_eval(); struct ent *firstev = (struct ent *)0; /* first expr in the eval list */ #define PI (double)3.14159265358979323846 #define dtr(x) ((x)*(PI/(double)180.0)) --- 86,92 ----- double fn1_eval(); double fn2_eval(); struct ent *firstev = (struct ent *)0; /* first expr in the eval list */ + double rint(); #define PI (double)3.14159265358979323846 #define dtr(x) ((x)*(PI/(double)180.0)) *************** *** 719,729 case TAN: return (fn1_eval( tan, eval(e->e.o.right))); case DTR: return (dtr(eval(e->e.o.right))); case RTD: return (rtd(eval(e->e.o.right))); ! case RND: { ! double temp; ! temp = eval(e->e.o.right); ! return(temp-floor(temp) < 0.5 ? ! floor(temp) : ceil(temp)); } case ROUND: { double temp = eval(e->e.o.left); --- 720,747 ----- case TAN: return (fn1_eval( tan, eval(e->e.o.right))); case DTR: return (dtr(eval(e->e.o.right))); case RTD: return (rtd(eval(e->e.o.right))); ! case RND: ! if (rndinfinity) ! { double temp = eval(e->e.o.right); ! return(temp-floor(temp) < 0.5 ? ! floor(temp) : ceil(temp)); ! } ! else ! return rint(eval(e->e.o.right)); ! case ROUND: ! { int prec = (int) eval(e->e.o.right); ! double scal = 1; ! if (0 < prec) ! do scal *= 10; while (0 < --prec); ! else if (prec < 0) ! do scal /= 10; while (++prec < 0); ! ! if (rndinfinity) ! { double temp = eval(e->e.o.left); ! temp *= scal; ! temp = ((temp-floor(temp)) < 0.5 ? ! floor(temp) : ceil(temp)); ! return(temp / scal); } else return(rint(eval(e->e.o.left) * scal) / scal); *************** *** 725,739 return(temp-floor(temp) < 0.5 ? floor(temp) : ceil(temp)); } ! case ROUND: { ! double temp = eval(e->e.o.left); ! int prec = (int) eval(e->e.o.right), scal = 1; ! while (prec-- > 0) scal *= 10; ! temp *= scal; ! temp = ((temp-floor(temp)) < 0.5 ? ! floor(temp) : ceil(temp)); ! return(temp / scal); ! } case FV: case PV: case PMT: return(finfunc(e->op,eval(e->e.o.left), --- 743,751 ----- floor(temp) : ceil(temp)); return(temp / scal); } ! else ! return(rint(eval(e->e.o.left) * scal) / scal); ! } case FV: case PV: case PMT: return(finfunc(e->op,eval(e->e.o.left), *************** *** 1732,1737 } #endif /* EXPRTREE*/ void hide_row(arg) int arg; --- 1744,1781 ----- } #endif /* EXPRTREE*/ + format_cell(v1, v2, s) + struct ent *v1, *v2; + char *s; + { + register r,c; + register struct ent *n; + int maxr, maxc; + int minr, minc; + + maxr = v2->row; + maxc = v2->col; + minr = v1->row; + minc = v1->col; + if (minr>maxr) r = maxr, maxr = minr, minr = r; + if (minc>maxc) c = maxc, maxc = minc, minc = c; + checkbounds(&maxr, &maxc); + if (minr < 0) minr = 0; + if (minr < 0) minr = 0; + + FullUpdate++; + for (r = minr; r <= maxr; r++) + for (c = minc; c <= maxc; c++) { + n = lookat (r, c); + if (n->format) + xfree(n->format); + n->format = 0; + if (s && *s != '\0') + n->format = strcpy((char *)xmalloc(strlen(s)+1), s); + n->flags |= is_changed; + } + } + void hide_row(arg) int arg; *************** *** 1780,1785 if (v->expr) efree(v, v->expr); v->expr = (struct enode *)0; v->flags |= (is_changed); v->flags &= ~(is_valid); changed++; --- 1824,1832 ----- if (v->expr) efree(v, v->expr); v->expr = (struct enode *)0; + if (v->format) + xfree(v->format); + v->format = (char *)0; v->flags |= (is_changed); v->flags &= ~(is_valid); changed++; *************** *** 2118,2123 line[linelim++] = ')'; } void editv (row, col) int row, col; --- 2165,2182 ----- line[linelim++] = ')'; } + editfmt (row, col) + int row, col; + { + register struct ent *p; + + p = lookat (row, col); + if (p->format) { + (void)sprintf (line, "fmt %s \"%s\"", v_name(row, col), p->format); + linelim = strlen(line); + } + } + void editv (row, col) int row, col; *************** *** 2167,2169 linelim += 1; } } --- 2226,2242 ----- linelim += 1; } } + + #ifdef RINT + double rint(d) double d; + { + /* as sent */ + double fl = floor(d), fr = d-fl; + return + fr<0.5 || fr==0.5 && fl==floor(fl/2)*2 ? fl : ceil(d); + /**/ + /* double fl = floor(d), fr = d-fl; + return((fr<0.5) || ((fr==0.5) && (fl==floor(fl/2)*2)) ? fl : ceil(d)); + */ + } + #endif *** posted/lex.c Mon Sep 24 09:36:49 1990 --- lex.c Mon Sep 24 09:42:31 1990 *************** *** 7,13 * * More mods Robert Bond, 12/86 * More mods by Alan Silverstein, 3/88, see list of changes. ! * $Revision: 6.8 $ * */ --- 7,13 ----- * * More mods Robert Bond, 12/86 * More mods by Alan Silverstein, 3/88, see list of changes. ! * $Revision: 6.9 $ * */ *************** *** 340,346 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'); --- 340,350 ----- char *ktmp; static char buf[1024]; /* Why do I have to do this again? */ ! if (!(ktmp = getenv("TERM"))) { ! (void) fprintf(stderr, "TERM environment variable not set\n"); ! exit (1); ! } ! if (tgetent(buf, ktmp) <= 0) return; km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl('b'); *** posted/psc.c Mon Sep 24 09:37:00 1990 --- psc.c Wed Sep 12 10:32:18 1990 *************** *** 13,19 * -f suppress 'format' lines in output * * Author: Robert Bond ! * $Revision: 6.8 $ */ #include <ctype.h> --- 13,20 ----- * -f suppress 'format' lines in output * * Author: Robert Bond ! * Adjustments: Jeff Buhrt and Eric Putz ! * $Revision: 6.10 $ */ #include <ctype.h> *************** *** 128,134 case END: if(drop_format) exit(0); for (i = 0; i<maxcols; i++) { ! if (precision[i]) (void) printf("format %s %d %d\n", coltoa(i), fwidth[i], precision[i]+1); } --- 129,135 ----- case END: if(drop_format) exit(0); for (i = 0; i<maxcols; i++) { ! if (fwidth[i]) (void) printf("format %s %d %d\n", coltoa(i), fwidth[i]+1, precision[i]); } *************** *** 130,136 for (i = 0; i<maxcols; i++) { if (precision[i]) (void) printf("format %s %d %d\n", coltoa(i), ! fwidth[i], precision[i]+1); } exit(0); case NUM: --- 131,137 ----- for (i = 0; i<maxcols; i++) { if (fwidth[i]) (void) printf("format %s %d %d\n", coltoa(i), ! fwidth[i]+1, precision[i]); } exit(0); case NUM: *************** *** 154,163 while (*p) { p++; i++; j++; } ! if (precision[effc] < j) ! precision[effc] = j; ! if (fwidth[effc] < i) ! fwidth[effc] = i; break; case ALPHA: first = 0; --- 155,178 ----- while (*p) { p++; i++; j++; } ! { int ow, nw; ! ! ow = fwidth[effc] - precision[effc]; ! if (precision[effc] < j) ! precision[effc] = j; ! ! if (fwidth[effc] < i) ! fwidth[effc] = i; ! ! /* now make sure: ! * 1234.567890 (format 11 6) ! * 1234567.890 (format 11 3) ! * both show (format 14 6) ! * (really it uses 15 6 to separate columns) ! */ ! if ((nw = i - j) > ow) ! fwidth[effc] += nw - (fwidth[effc] - precision[effc]); ! } break; case ALPHA: first = 0; *************** *** 172,179 } } i = strlen(token); ! if (i > precision[effc]) ! precision[effc] = i; break; case SPACE: if (first && strip_delim) --- 187,194 ----- } } i = strlen(token); ! if (i > fwidth[effc]) ! fwidth[effc] = i; break; case SPACE: if (first && strip_delim) *************** *** 214,219 { register int c; register char *p; p = token; c = getchar(); --- 229,235 ----- { register int c; register char *p; + register int founddigit; p = token; c = getchar(); *************** *** 251,256 p = token; c = *p; if (isdigit(c) || c == '.' || c == '-' || c == '+') { while(isdigit(c) || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E') { --- 267,273 ----- p = token; c = *p; + founddigit = 0; if (isdigit(c) || c == '.' || c == '-' || c == '+') { while(isdigit(c) || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E') { *************** *** 254,259 if (isdigit(c) || c == '.' || c == '-' || c == '+') { while(isdigit(c) || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E') { c = *p++; } if (c == 0) --- 271,278 ----- if (isdigit(c) || c == '.' || c == '-' || c == '+') { while(isdigit(c) || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E') { + if (isdigit(c)) + founddigit = 1; c = *p++; } if (c == 0 && founddigit) *************** *** 256,262 || c == 'E') { c = *p++; } ! if (c == 0) return(NUM); else return(ALPHA); --- 275,281 ----- founddigit = 1; c = *p++; } ! if (c == 0 && founddigit) return(NUM); else return(ALPHA); *** posted/sc.c Mon Sep 24 09:37:52 1990 --- sc.c Mon Sep 24 09:42:47 1990 *************** *** 8,14 * More mods Robert Bond, 12/86 * More mods by Alan Silverstein, 3-4/88, see list of changes. * Currently supported by pur-phy!sawmill!buhrt (Jeff Buhrt) ! * $Revision: 6.8 $ * */ --- 8,14 ----- * More mods Robert Bond, 12/86 * More mods by Alan Silverstein, 3-4/88, see list of changes. * Currently supported by pur-phy!sawmill!buhrt (Jeff Buhrt) ! * $Revision: 6.9 $ * */ *************** *** 78,83 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 */ --- 78,84 ----- int autocalc = 1 ; /* 1 to calculate after each update */ int calc_order = BYROWS; int tbl_style = 0; /* headers for T command output */ + int rndinfinity = 0; int lastmx, lastmy; /* Screen address of the cursor */ int lastcol; /* Spreadsheet Column the cursor was in last */ *************** *** 117,122 (*pp)->flags = 0; (*pp)->expr = (struct enode *)0; (*pp)->v = (double) 0.0; (*pp)->evnext = (struct ent *)0; } return *pp; --- 118,124 ----- (*pp)->flags = 0; (*pp)->expr = (struct enode *)0; (*pp)->v = (double) 0.0; + (*pp)->format = (char *)0; (*pp)->evnext = (struct ent *)0; } return *pp; *************** *** 392,398 if ((*pp) -> flags & is_valid) { char field[FBUFLEN]; ! (void)sprintf(field,"%*.*f", fwidth[col], precision[col], (*pp)->v); if(strlen(field) > fwidth[col]) { for(i = 0; i<fwidth[col]; i++) (void)addch('*'); --- 394,406 ----- if ((*pp) -> flags & is_valid) { char field[FBUFLEN]; ! if ((*pp) -> format) { ! (void)format((*pp) -> format, (*pp) -> v, field, ! sizeof(field)); ! } else { ! (void)sprintf(field,"%*.*f", fwidth[col], ! precision[col], (*pp)->v); ! } if(strlen(field) > fwidth[col]) { for(i = 0; i<fwidth[col]; i++) (void)addch('*'); *************** *** 397,402 for(i = 0; i<fwidth[col]; i++) (void)addch('*'); } else { (void)addstr(field); } } --- 405,412 ----- for(i = 0; i<fwidth[col]; i++) (void)addch('*'); } else { + for(i = 0; i < fwidth[col] - strlen(field); i++) + (void)addch(' '); (void)addstr(field); } } *************** *** 803,809 case ctl('t'): error( ! "Toggle: a:auto c:cell e:ext funcs n:numeric t:top x:encrypt $:pre-scale"); (void) refresh(); switch (nmgetch()) { --- 813,819 ----- case ctl('t'): error( ! "Toggle: a:auto c:cell e:ext funcs n:numeric t:top x:encrypt $:pre-scale"); (void) refresh(); switch (nmgetch()) { *************** *** 876,881 temp = strcpy(xmalloc((unsigned)(strlen(line)+1)),line); templim = linelim; editexp(currow,curcol); temp1= strcpy(xmalloc((unsigned)(strlen(line)+1)),line); strcpy(line, temp); --- 886,892 ----- temp = strcpy(xmalloc((unsigned)(strlen(line)+1)),line); templim = linelim; + linelim = 0; /* reset line to empty */ editexp(currow,curcol); temp1= strcpy(xmalloc((unsigned)(strlen(line)+1)),line); strcpy(line, temp); *************** *** 1033,1039 case '/': error ( ! "Range: x:erase v:value c:copy f:fill d:define s:show u:undefine"); (void) refresh(); switch (nmgetch()) { --- 1044,1050 ----- case '/': error ( ! "Range: x:erase v:value c:copy f:fill d:define s:show u:undefine F:fmt"); (void) refresh(); switch (nmgetch()) { *************** *** 1096,1101 } else error("No ranges defined"); break; case ESC: case ctl('g'): --- 1107,1118 ----- } else error("No ranges defined"); break; + case 'F': + (void) sprintf(line, "fmt [range \"format\"] "); + linelim = strlen(line); + startshow(); + insert_mode(); + break; case ESC: case ctl('g'): *************** *** 1283,1288 linelim = strlen (line); insert_mode(); break; case 'g': (void) sprintf (line, "goto [v] "); linelim = strlen (line); --- 1300,1311 ----- linelim = strlen (line); insert_mode(); break; + case 'F': + (void) sprintf(line, "fmt [format] %s \"", + v_name(currow, curcol)); + linelim = strlen(line); + insert_mode(); + break; case 'g': (void) sprintf (line, "goto [v] "); linelim = strlen (line); *************** *** 1327,1333 break; case 'S': /* set options */ (void) sprintf (line, "set "); ! error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex)"); linelim = strlen (line); insert_mode(); break; --- 1350,1356 ----- break; case 'S': /* set options */ (void) sprintf (line, "set "); ! error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex), rndinfinity"); linelim = strlen (line); insert_mode(); break; *** posted/sc.doc Mon Sep 24 09:38:48 1990 --- sc.doc Mon Sep 24 09:48:12 1990 *************** *** 15,21 .\" - TPs use default indent except for function names, then 18. .\" - Smallify uppercase strings. .\" - Avoid passive voice and third person. ! .\" $Revision: 6.8 $ .\" .TH PNAME 1 .SH NAME --- 15,21 ----- .\" - TPs use default indent except for function names, then 18. .\" - Smallify uppercase strings. .\" - Avoid passive voice and third person. ! .\" $Revision: 6.9 $ .\" .TH PNAME 1 .SH NAME *************** *** 61,66 and/or an expression (formula) which evaluates to a numeric value or label string, often based on other cell values. .\" ---------- .PP Options are: --- 61,70 ----- and/or an expression (formula) which evaluates to a numeric value or label string, often based on other cell values. + .LP + For a on-line tutorial, type the command: + .IP + pname #LIBDIR#/tutorial.sc .\" ---------- .SH OPTIONS .\" ---------- *************** *** 62,69 which evaluates to a numeric value or label string, often based on other cell values. .\" ---------- ! .PP ! Options are: .\" ---------- .TP .B \-c --- 66,72 ----- .IP pname #LIBDIR#/tutorial.sc .\" ---------- ! .SH OPTIONS .\" ---------- .TP .B \-c *************** *** 324,329 .TP .BR toprow / !toprow Set/clear top row display mode. .RE .\" ========== .SS "Cursor Control Commands" --- 327,337 ----- .TP .BR toprow / !toprow Set/clear top row display mode. + .TP + .BR rndinfinity / !rndinfinity + default: round-to-even (banker's round), *.5 will round to the closest even + number; doing a 'set rndinfinity' will round *.5 up to the next integer + (rounding to infinity). .RE .\" ========== .SS "Cursor Control Commands" *************** *** 504,509 .B > Enter a label string into the current cell to be flushed right against the right edge of the cell. .PD .\" ---------- .PP --- 512,518 ----- .B > Enter a label string into the current cell to be flushed right against the right edge of the cell. + .\" ---------- .PD .TP .B F *************** *** 505,510 Enter a label string into the current cell to be flushed right against the right edge of the cell. .PD .\" ---------- .PP Strings you enter must start with ". --- 514,601 ----- to be flushed right against the right edge of the cell. .\" ---------- .PD + .TP + .B F + Enter a format string into the current cell. This format string + overrides the precision specified with the ``f'' command. + The format only applies to numeric values. The following + characters can be used to build a format string: + .RS + .TP + .BR # + Digit placeholder. If the number has fewer digits on either + side of the decimal point than there are `#' characters in + the format, the extra `#' characters are ignored. The number + is rounded to the number of digit placeholders as there are + to the right of the decimal point. If there are more digits + in the number than there are digit placeholders on the left + side of the decimal point, then those digits are displayed. + .TP + .BR 0 + Digit placeholder. + Same as for `#' except that the number + is padded with zeroes on either side of the decimal point. + The number of zeroes used in padding is determined by the + number of digit placeholders after the `0' for digits on + the left side of the decimal point and by the number of + digit placeholders before the `0' for digits on the right + side of the decimal point. + .TP + .BR . + Decimal point. + Determines how many digits are placed on + the right and left sides of the decimal point in the number. + Note that numbers smaller than 1 will begin with a decimal + point if the left side of the decimal point contains only + a `#' digit placeholder. Use a `0' placeholder to get a + leading zero in decimal formats. + .TP + .BR % + Percentage. + For each `%' character in the format, the actual + number gets multiplied by 100 (only for purposes of formatting + -- the original number is left unmodified) and the `%' character + is placed in the same position as it is in the format. + .TP + .BR , + Thousands separator. + The presence of a `,' in the format + (multiple commas are treated as one) will cause the number + to be formatted with a `,' separating each set of three digits + in the integer part of the number with numbering beginning + from the right end of the integer. + .TP + .BR \\ + Quote. + This character causes the next character to be + inserted into the formatted string directly with no + special interpretation. + .TP + .BR E-\ E+\ e-\ e+ + Scientific format. + Causes the number to formatted in scientific + notation. The case of the `E' or `e' given is preserved. If + the format uses a `+', then the sign is always given for the + exponent value. If the format uses a `-', then the sign is + only given when the exponent value is negative. Note that if + there is no digit placeholder following the `+' or `-', then + that part of the formatted number is left out. In general, + there should be one or more digit placeholders after the `+' + or `-'. + .TP + .BR ; + Format selector. + Use this character to separate the format + into two distinct formats. The format to the left of the + `;' character will be used if the number given is zero or + positive. The format to the right of the `;' character is + used if the number given is negative. + .RE + .IP + Some example formats are integer (``0'' or ``#''), + fixed (``0.00''), percentage (``0%'' or ``0.00%''), + scientific (``0.00E+00''), + and currency (``$#,0.00;($#,0.00)''). .\" ---------- .PP Strings you enter must start with ". *************** *** 520,525 This is identical to ``='' except that the command line starts out containing the old numeric value or expression associated with the cell. .\" ---------- .TP .B E --- 611,662 ----- This is identical to ``='' except that the command line starts out containing the old numeric value or expression associated with the cell. + The editing in this mode is vi-like. + ^h move back a character + + forward through history (neat) (same as j) + - backward through history (neat) (same as k) + ESC done editing + TAB mark && append a range (ex: A0:A0) + TAB, move around w/i a range, TAB (appends range string) + CR save + $ goto last col + . insert current dot buffer + / search for a string in the history + ESC edit the you typed + CR search + ^h backspace + 0 goto column 0 + D Delete to send + I Insert at column 0 + ESC revert back to edit mode + R Replace mode + ESC revert back to edit mode + X delete the char to the left + a append mode + b move back a word + c change mode + d delete ... + b back word + f forward (right) + h back char + l forward + t delete forward up to a given char (next char typed) + w delete next word forward + f find the next char typed + h move left a char + i insert mode + ESC revert back to edit mode + j forward through history (neat) (same as +) + k backward " " (same as +) + l move right a char + n continue search + q stop editing + r replace char + t goto a char + u undo + w forward a word + x delete the current char (moving to the right) + .\" ---------- .TP .B E *************** *** 527,532 This is identical to ``<'', ``"'', or ``>'' except that the command line starts out containing the old string value or expression associated with the cell. .\" ---------- .PP To enter and edit a cell's number part, use the ``='' and --- 664,672 ----- This is identical to ``<'', ``"'', or ``>'' except that the command line starts out containing the old string value or expression associated with the cell. + SEE + .B e + ABOVE. .\" ---------- .PP To enter and edit a cell's number part, use the ``='' and *************** *** 909,914 .TP .B /u Use this command to undefine a previously defined range name. .\" ========== .SS "Miscellaneous Commands" .\" ---------- --- 1049,1058 ----- .TP .B /u Use this command to undefine a previously defined range name. + .TP + .B /F + Use this command to assign a value format string (see the ``F'' + cell entry commmand) to a range of cells. .\" ========== .SS "Miscellaneous Commands" .\" ---------- *************** *** 1378,1383 Round .I e to the nearest integer. .TP 18 .BR @round (e,n) Round --- 1522,1529 ----- Round .I e to the nearest integer. + default: round-to-even (banker's round), *.5 will round to the closest even + number; 'set rndinfinity' will round *.5 up to the next integer. .TP 18 .BR @round (e,n) Round *************** *** 1385,1390 to .I n decimal places. .\" ---------- .TP 18 .BR @abs (e) --- 1531,1539 ----- to .I n decimal places. + n may be positive to round off the right side of the decimal, + and negative to round off the left side. See @rnd(e) above for rounding + types. .\" ---------- .TP 18 .BR @abs (e) *************** *** 1778,1794 with (perhaps) recourse to relaxation should be implemented. .\" ---------- .PP - Editing is crude. - All you can do is backspace over and retype text to be altered. - There is no easy way to switch a leftstring to a rightstring or vice versa. - Of course, you can always write the spreadsheet to a file with - .IR Put , - edit it by calling an editor on the file with ``!'', - and read it back with - .I Get - -- if you are comfortable editing spreadsheet files. - .\" ---------- - .PP Only one previous value is saved from any call of .IR @ext (). If it is used more than once in a spreadsheet --- 1927,1932 ----- with (perhaps) recourse to relaxation should be implemented. .\" ---------- .PP Only one previous value is saved from any call of .IR @ext (). If it is used more than once in a spreadsheet *************** *** 1808,1810 .PP Many commands give no indication (a message or beep) if they have null effect. Some should give confirmation of their action, but they don't. --- 1946,1983 ----- .PP Many commands give no indication (a message or beep) if they have null effect. Some should give confirmation of their action, but they don't. + .SH AUTHORS + This is a much modified version of a public domain spread sheet + originally authored by James Gosling, + and subsequently modified and posted to USENET by Mark Weiser under the name + .IR vc . + The program was subsequently renamed + .IR sc , + and further modified by numerous contributors, + Jeff Buhrt + of Grauel Enterprises, Inc. + ({pur-phy (aka: newton.physics.purdue.edu), sequent}!sawmill!buhrt) + and Robert Bond of Sequent, + prominent among them. + Other contributors include: + Gregory Bond, + Peter Brower, + John Campbell, + Lawrence Cipriani, + Chris Cole, + Glen Ditchfield + Sam Drake, + Kurt Horton, + Peter King, + Dave Lewis, + Rick Linck, + Soren Lundsgaard, + Tad Mannes, + Rob McMahon, + Marius Olafsson, + Rick Perry, + R. P. C. Rodgers, + Alan Silverstein, + and + Andy Valencia. + .\" end of man page *** posted/sc.h Mon Sep 24 09:38:59 1990 --- sc.h Mon Sep 24 09:42:50 1990 *************** *** 6,12 * University of Maryland * R. Bond 12/86 * More mods by Alan Silverstein, 3-4/88, see list of changes. ! * $Revision: 6.8 $ * */ --- 6,12 ----- * University of Maryland * R. Bond 12/86 * More mods by Alan Silverstein, 3-4/88, see list of changes. ! * $Revision: 6.9 $ * */ *************** *** 68,73 struct ent *next; /* next deleted ent */ struct ent *evnext; /* next ent w/ a object to eval */ struct ent *evprev; /* prev ent w/ a object to eval */ }; struct range { --- 68,74 ----- struct ent *next; /* next deleted ent */ struct ent *evnext; /* next ent w/ a object to eval */ struct ent *evprev; /* prev ent w/ a object to eval */ + char *format; }; struct range { *************** *** 338,343 extern int loading; extern int getrcqual; extern int tbl_style; extern char *progname; #if BSD42 || SYSIII --- 339,345 ----- extern int loading; extern int getrcqual; extern int tbl_style; + extern int rndinfinity; extern char *progname; #if BSD42 || SYSIII *** posted/version.c Mon Sep 24 09:39:08 1990 --- version.c Mon Sep 24 09:45:54 1990 *************** *** 4,7 * The part after the first colon, except the last char, appears on the screen. */ ! char *rev = "$Revision: 6.8 $"; --- 4,7 ----- * The part after the first colon, except the last char, appears on the screen. */ ! char *rev = "$Revision: 6.9 $"; *** posted/vi.c Mon Sep 24 09:39:19 1990 --- vi.c Mon Sep 24 09:42:58 1990 *************** *** 1,7 /* SC A Spreadsheet Calculator * * One line vi emulation ! * $Revision: 6.8 $ */ --- 1,7 ----- /* SC A Spreadsheet Calculator * * One line vi emulation ! * $Revision: 6.9 $ */ *************** *** 36,42 #define EDIT_MODE 1 /* Edit mode */ #define REP_MODE 2 /* Replace mode */ #define SEARCH_MODE 3 /* Get arguments for '/' command */ ! static int mode = INSERT_MODE; static char *history[HISTLEN]; static int histp = -1; --- 36,44 ----- #define EDIT_MODE 1 /* Edit mode */ #define REP_MODE 2 /* Replace mode */ #define SEARCH_MODE 3 /* Get arguments for '/' command */ ! ! #define DOTLEN 200 ! static int mode = INSERT_MODE; static char *history[HISTLEN]; static int histp = -1; *************** *** 43,49 static char *last_search; static char *undo_line; static int undo_lim; ! static char dotb[100]; static int doti = 0; static int do_dot = 0; --- 45,51 ----- static char *last_search; static char *undo_line; static int undo_lim; ! static char dotb[DOTLEN]; static int doti = 0; static int do_dot = 0; *************** *** 47,52 static int doti = 0; static int do_dot = 0; void write_line(c) int c; --- 49,55 ----- static int doti = 0; static int do_dot = 0; + void write_line(c) int c; *************** *** 116,121 mode = EDIT_MODE; mode_ind = 'e'; histp = -1; if (line[linelim] == '\0') linelim = back_line(); } --- 119,126 ----- mode = EDIT_MODE; mode_ind = 'e'; histp = -1; + if (linelim < 0) /* -1 says stop editing, ...so we still aren't */ + return; if (line[linelim] == '\0') linelim = back_line(); } *************** *** 151,158 if (do_dot) return; ! dotb[doti++] = c; ! dotb[doti] = 0; } dotcmd() --- 156,166 ----- if (do_dot) return; ! if (doti < DOTLEN-1) ! { ! dotb[doti++] = c; ! dotb[doti] = NULL; ! } } static int dotcalled = 0; *************** *** 155,160 dotb[doti] = 0; } dotcmd() { int c; --- 163,170 ----- } } + static int dotcalled = 0; + dotcmd() { int c; *************** *** 159,164 { int c; do_dot = 1; doti = 0; while(dotb[doti] != 0) { --- 169,176 ----- { int c; + if (dotcalled) /* stop recursive calling of dotcmd() */ + return; do_dot = 1; doti = 0; while(dotb[doti] != 0) { *************** *** 163,168 doti = 0; while(dotb[doti] != 0) { c = dotb[doti++]; write_line(c); } do_dot = 0; --- 175,181 ----- doti = 0; while(dotb[doti] != 0) { c = dotb[doti++]; + dotcalled = 1; write_line(c); } do_dot = 0; *************** *** 167,172 } do_dot = 0; doti = 0; } vigetch() --- 180,186 ----- } do_dot = 0; doti = 0; + dotcalled = 0; } vigetch() *************** *** 351,356 { register int i, len; len = strlen(line); for (i = len; i >= linelim; --i) line[i+1] = line[i]; --- 365,374 ----- { register int i, len; + if (linelim < 0) + { *line = 0; + linelim = 0; + } len = strlen(line); for (i = len; i >= linelim; --i) line[i+1] = line[i]; *************** *** 380,385 { int c; c = vigetch(); if (line[linelim] != 0) { line[linelim] = c; --- 398,407 ----- { int c; + if (linelim < 0) + { linelim = 0; + *line = 0; + } c = vigetch(); if (line[linelim] != 0) { line[linelim] = c; *************** *** 393,398 { register int len; len = strlen(line); line[linelim++] = c; if (linelim > len) --- 415,424 ----- { register int len; + if (linelim < 0) + { linelim = 0; + *line = 0; + } len = strlen(line); line[linelim++] = c; if (linelim > len) *** posted/vmtbl.c Mon Sep 24 09:39:25 1990 --- vmtbl.c Mon Sep 24 09:43:00 1990 *************** *** 49,55 if (*colp < 0) *colp = 0; else if (*colp >= maxcols) ! { if (!growtbl(GROWCOL, 0, *colp)); *colp = maxcols-1; } } --- 49,55 ----- if (*colp < 0) *colp = 0; else if (*colp >= maxcols) ! { if (!growtbl(GROWCOL, 0, *colp)) *colp = maxcols-1; } }