v20i039: sc - The SC Spreadsheet, release 6.16, Part05/07

Jeff Buhrt prslnk!buhrt at cs.indiana.edu
Thu Jun 6 03:28:36 AEST 1991


Submitted-by: Jeff Buhrt <prslnk!buhrt at cs.indiana.edu>
Posting-number: Volume 20, Issue 39
Archive-name: sc/part05

#! /bin/sh
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# Contents:  CHANGES format.c psc.c screen.c
# Wrapped by kent at sparky on Wed Jun  5 09:22:20 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 5 (of 7)."'
if test -f 'CHANGES' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'CHANGES'\"
else
  echo shar: Extracting \"'CHANGES'\" \(16317 characters\)
  sed "s/^X//" >'CHANGES' <<'END_OF_FILE'
XCHANGES BETWEEN 6.16 and 6.15
XTom Tkacik
X	-fixed a bug in ^W
XJonathan I. Kamens
X	- added Makefile rules so scqref and psc don't clobber .o's
XLarry Philps
X	- fixed a SCO XENIX vs M_XENIX problem
X	- fixed a problem where dosval() might not xmalloc enough memory
XDave Close
X	- fix for Xenix 2.3 to reset terminal modes
X
XCHANGES BETWEEN 6.15 and 6.14
XLowell Skoog
X	- fixed a bug in 'F'ormat
XHenk Hesselink
X	- format.c double neg. sign 
X	- interp.c minr/minc bug, plus modflg wasn't set
X	- fixed a hardcoded path in sc.doc
X	- improvement: 
X		-show current cell format in top line
X		-[buhrt: go into edit mode on the old format if it existed
X			otherwise insert mode]
XJonathan Crompron
X	- made sure doformat() does a checkbounds()
XStephen (Steve) M. Brooks
X	- pointed out -s in psc was broke
XMichael Richardson
X	- fixed negative numbers in exponential format
X
XCHANGES BETWEEN 6.14 and 6.13
XMats Wichmann
X	- Sys V R4 patches, fixed 'Press RETURN ...' on a shell command
XTim Theisen
X	- changed #define for memcpy/memset under ultrix
XRick Walker
X	- Added @myrow and @mycol to give the row/col of the current cell
X	'The two functions are @myrow and @mycol, which return the numerical
X	row and column of the calling cell.  The cell directly above a cell
X	in the D column could then be accessed by @nval("d", at myrow-1).'
X	NOTE: @myrow and @mycol can't be used in specifying ranges.
X
XCHANGES BETWEEN 6.13 and 6.12
XRick Walker
X	- pointed out a move(x,y)-> (y,x) in sc.c
XGlenn Barry
X	- Further SunOS 4.X cleanups
XTom Tkacik
X	- made sure 'J' moves downward 1/2 a screen even at the bottom
XDavid I. Dalva
X	- pointed out crypt may not be in /bin/crypt
XGregory Bond
X	- allows the vi-mode editing of very long expressions
X		(> 1 screen width) to work on 2nd + subsequent lines
XTom Anderson
X	- "let A1 = aaa" (where aaa is defined as A0:A0) is now valid
X	- added autolabeling
X		'When there is an empty cell to the left of a cell that has
X		just been defined (with /d), a label is created in the blank
X		cell.  The label holds the definition that has just been
X		created.  This labeling is only done for definitions of single
X		cells (and not for ranges).'
X		'The feature can be turned on and off with a toggle (^T)
X		command'
XPetri Wessman
X	- Added support for SLaTeX, 'a Scandinavian version of LaTeX, in
X		intensive use ... in Finland and in Sweden'
XJeff Buhrt
X	- vmtbl.c explictly set arrays of pointers to NULL, vs memset()
X	- psc   [-P] plain numbers only:a number only when there is no [-+eE]
X		[-S] all numbers are strings
X	- psc: a number must end in [0-9.eE] anything else makes it a string
X		(4, 4., 4.5, and 4e are numbers; 4-, 4+, etc are not).
X	- psc: made sure we grow enough when we call growtbl()
X	- cleaned up the Makefile w/ a few suggestions
X	- SIGWINCH is delt with next time the screen would update (testing)
X	- added IDLOKBAD to get around a SysV curses bug (see Makefile)
X	- moved screen functions into screen.c (except for one indirect
X		'repaint()' call in sc.c, and help.c)
X
XCHANGES BETWEEN 6.12 and 6.11
XJames Dugal
X	- added format.c to SRCS in Makefile
X	- noted RETURN didn't enter insert mode
XPeter King
X	- pointed out iscntrl is broken on some other systems as well
X	- sent some lint cleanups
XMichael Richardson
X	- patch to stop format looping when scientific notation was selected
XGlenn T. Barry
X	- code to turn on hardware scrolling and added 'slow speed display'
X		speedups, default for SYSV3 or see -DSUNOS41SYSV in Makefile.
XTom Tkacik
X	- fixes to make sure J and K move same amount, and re-added H code
XJeff Buhrt
X	- fixed a possible xfree(NULL) in getent() (found when adding K_VAL)
X	- merged compiler cleanups
X*	- added $(name)qref to print a Quick Reference card
X	- got rid of INVALIDS that may have been left around
X*	- pressing return on a empty line puts you into insert mode
X		(like in <=Sc6.1). When entering you can also press ESC
X		to go into the editor (no change); this is also documented
X		now so it might stay around this time.
X
XCHANGES BETWEEN 6.11 and 6.10
X
XJonathan I. Kamens
X	- sc.doc now mentions the tutorial file in the FILES section
XAndy Fyfe
X	- pointed out 3 locations where a NULL should have been '\0'
XRobert Bond
X	- pointed out the ERROR could hide a cellerror
XPiercarlo Grandi
X	- H,J,I,K now move 1/2 screen
XUlf Noren
X	- changes for AIX V3.1
X		- defined CHTYPE and NLS for the preprocessor. CHTYPE is
X		the type of every character in a curses window.
X		- Added KEY_BACKSPACE to nmgetch
X		- strtof ifdef
X	- Iteration change: when Sc says: "Still changing after 9 iterations"
X	Sc at that point will have eval'd 9 times
XChris Metcalf
X	- pointed out I broke setlist when adding 'goto {error,invalid}'
XJames P. Dugal
X	- iscntrl() wasn't handling TABS though CRs under Pyramid OSx4.1
XPeter King
X	- BROKENCURSES patch for nl()/nonl() bug on some BSD systems
X	- backups, tutorial file, and man references now depend on $name
X	- DFLTPAGER to DFLT_PAGER fix
X
XCHANGES BETWEEN 6.10 and 6.9
X
XTom Tkacik
X	- when moving off the current table (resizing) now move the cursor
X		on 'l' or 'k'.
X	- patches to sc.doc to correctly format the vi-mode notes
XJim Clausing
X	- made sure / doesn't try to divide by zero.
XTom Kloos
X	- correction to substr() example in help.c
XPiercarlo "Peter" Grandi
X	- Disable non-constant expressions while loading
X	- Added extra code in dealing w/ floating point exceptions
X	- #ifdef'd SAVENAME (vs hardcoded SC.SAVE) to allowing changing the
X		emergency save name.
XCasey Leedom
X	- Makefile changes: man extension, RINT note, make values should
X		never be left undefined and then referenced, don't leave
X		around *.old's
XTom Anderson
X	- patches to add type of column format (note format now has 3 args)
XJeff Buhrt
X	- xmalloc/xfree fatal() will now call diesave()
X		(MAKE SURE the saved file is ok if this were to happen)
X	- history[] is now a circular queue, this will cut down on the
X		number of data moves and also xmalloc/xfree calls
X		(idea from Keith Bostic)
X	- cells with an error (ex: divide by 0) will show 'ERROR'
X	- you can 'goto error' (or 'goto') to find an ERROR (for next ERROR)
XRobert Bond
X	- When in numeric mode the ^B, ^F, ^N, ^P key will end a numeric entry.
X
XCHANGES BETWEEN 6.9 and 6.8
X
XJim Richardson
X	- pointed out vi mode was not documented in sc.doc
X	- found a nasty buffer limit bug in savedot()
X	- a side effect was ^D could cause a core dump (-Jeff)
XTim Wilson
X	- Hints on compiling on Ultrix
XEric Putz
X	-patch for printfile() (sc died on huge # of columns in a W)
XJeffrey C Honig
X	-patch for lex.c which bombed on SunOS 4.1 if $TERM was not set
XTom Kloos
X	-psc now calls [+-.] strings vs numbers.
X	-also pointed out a format reversal problem
XJack Goral
X	-changes to Makefile to compile under SCO Unix V rel 3.2.0
XMark Nagel
X	-changes to allow arbitrarily complex formatting of cells 
XKim Sanders
X	-^W generated an incorrect equation (line was not started at beginning)
XMike Schwartz
X	-a put command will use the same encryption key as when the
X	file was read.
X	>I have a suggestion for making the encyrption option of "sc" more
X	>usable:  Right now, if you use the -x option when you start up sc, it
X	>prompts you for the key (just like "vi -x" does).  But when you try to
X	>write the file out using the Put command, it asks for the key again
X	>each time.  Why not make it use the same key you used before (as "vi
X	>-x" does)?  That would really help, because as it is, each time you try
X	>to save the file you run the risk of mistyping the key.
X	>
X	>You might think this causes a security problem, since the key is then
X	>an argument to crypt, and hence is visible from ps.  But when crypt
X	>runs, the first thing it does is to copy the key to an internal buffer
X	>and then zero out the argv copy, so the window of vulnerability is
X	>vanishingly small.
XAdri Verhoef
X	- pointed out a ^D caused a core dump (fixed)
XGene H. Olson
X	- format now grows the spreadsheet before setting the column format.
X	- removed an extra ';' that caused a possible column number trashing
XPaul Eggert
X	-sc now also has round-to-even, also known as ``banker's rounding''.
X	>With round-to-even, a number exactly halfway between two values is
X	>rounded to whichever is even; e.g. rnd(0.5)=0, rnd(1.5)=2,
X	>rnd(2.5)=2, rnd(3.5)=4.  This is the default rounding mode for
X	>IEEE floating point, for good reason: it has better numeric
X	>properties.  For example, if X+Y is an integer,
X	>then X+Y = rnd(X)+rnd(Y) with round-to-even,
X	>but not always with sc's rounding (which is
X	>round-to-positive-infinity).  I ran into this problem when trying to
X	>split interest in an account to two people fairly.
X	-While we're on the subject, @round(X,Y) should also work when Y
X	>is negative. For example, @round(123,-2) should yield 100.
X
X
XCHANGES BETWEEN 6.8 and 6.7
X
XJeff Buhrt (with help from some beta testers-Thank you)
X	  1) added a per row memory allocation
X		-runs in about 1/2 run time and 1/3 the space of 6.6vm.1
X		-insert/delete row now just moves pointers (# == maxrow+1-currow)
X			and blanks one row (of columns (maxcol))
X		-as the number of cells grows the size is more linear
X			(no more ##Meg images except for 100,000's of rows....)
X		-row to column pointer translation is done by a macro (ATBL)
X			that returns a pointer to the cell pointer.
X			*ATBL would be a pointer to a *ent (cell).
X		-the maximum # of columns is limited by ABSMAXCOLS or
X			sizeof(struct ent *)*maxcols (whichever is smaller)
X			(702 * 4 = 2808 is no real limit even for 286 large model)
X		-the maximum # of rows is limited by the virtual memory limit or
X			sizeof(struct ent **)*maxrows (whichever is smaller)
X			(4*X=64k, X=16384 rows (excluding malloc overhead) on
X				a '286 large model. Even w/ 3.25Meg and 10Mhz)
X			(plus of course any memory used for cells)
X	2) dolookup (int vs double)
X	3) dolookup calling eval w/ ent * not enode *
X		 (dolookup called w/ ent * not enode *)
X	4) cleaned up a lot of .... *x = 0 to  (.... *)0 (cmds, interp)
X	5) psc: fwidth/precision were reversed on the output
X	6) Backup copy (on save) using same mode to [path/]#file~
X		 (will prompt if a backup fails)
X	7) put y/n prompt function into yn_ask(mesg)
X	8) found a move(x,y) in sc -> move(y,x) and only move when needed
X	9) we use FullUpdate || changed (to see if ANY cells changed) 
X		before trying to redraw the screen in update
X		(now we don't try to redraw every time a key is hit)
X		-if we are stand[ing]out we do not create a cell just to force a
X		 standout inside the repaint section of update()
X		-only draw blank cells if we cleared it or it is standing out
X		reason: the less work (what to update) curses has to do, the faster
X			a screen update will be (less cpu required)
X	14) {insert, delete}col replaced w/ {open,close}col(currow, numcol_to_insert)
X		(limits looping)
X	6.7.1.1
X	15) goto nonexistant cell may loop
X	16) make sure that startup size will at least fill the screen w/ cells.
X	17) added version.c
X	6.7.1.2
X	18) When we would normally die w/o saving (SIGQUIT, etc), we now ask
X		if people would like to save the current spreadsheet.
X		If 'y', saves to the current file name, otherwise ~/SC.SAVE,
X		then /tmp/SC.SAVE if all else fails.
X	6.7.1.3
X	19) don't use malloc.c for production code
X	20) progname is now truncated to just the basename (systems w/ long paths
X		caused problems)
X
XCHANGES BETWEEN 6.1 and 6.7
X
XDave Lewis - 
X	Found and fixed a null pointer derefrece in the 'R' command.
X
XRob McMahon -
X	Changed the ctl() macro to work with ANSI style compilers.
X	Cleaned up some non-readonly text problems.
X
XRick Linck -
X	Fixed a bug in lex.c - Ann Arbor Ambassadors have long ks and ke
X	termcap entries.
X
XSam Drake -
X	A fix for undefined C_* symbols in AIX.
X
XPeter Brower -
X	Cleaned up the INTERNATIONAL ifdefs with more portable code.
X
XGlen Ditchfield
X	Cleaned up a problem in crypt.c when the encrypted file shrank.
X
XBob Bond -
X	Vi style editing for the command line.
X	A bug in range name aliases.
X
XJeff Buhrt -
X	-Added "~" filename expansion.
X	-702 columns (A-ZZ) and unlimited rows/cells based on max. memory
X	-fixed a few bugs
X	-slightly decreased CPU usage
X	-MAKES backup copies of files
X	-understands ~$HOME stuff
X
XCHANGES BETWEEN 5.1 and 6.1:
X
XAndy Valencia -
X	xmalloc aligns data to a double boundary.
X
XLawrence Cipriani -
X	Fixed a bug in the "do you want to save this" sequence.
X
XSoren Lundsgaard -
X	A null pointer derefrence.
X
XRick Perry -
X	Cleaned up a problem with modchk() in sc.c.
X
XGregory Bond -
X	Added code for multi argument versions of @min and @max.
X
XTad Mannes -
X	Added code to save/restore hidden rows and columns when the
X	data base is saved or restored.
X
XMarius Olafsson -
X	INTERNATIONAL changes.  Allows full 8 bit characters (if
X	curses supports them.)
X
XKurt Horton -
X	Added support for @pv, @fv and @pmt financial functins.
X	Tested lots of different systems, linting.
X
XJohn Campbell -
X	Support for VMS.  See VMS_NOTES.
X
XPeter King -
X	 User selection of row or column order for recalculation.
X		Also affects order of traversing regions in /f and /r
X	 User setting of automatic or manual recalculation.
X	 User setting of number of times to try recalculation.
X	 + and - commands when in non-numeric mode to do 
X		increment and decrement operations.
X	@index, @stindex, @atan2, @lookup  functions.
X	Save/restore options.
X	Support for TeX, LaTeX, and better support for tbl in "T" cmd.
X	Provision of a copyent function to copy entries (same code repeated
X		in several locations)
X	Forwrow, backrow, forwcol, backcol functions to replace
X		repeated code
X	Correct interpretation of ESCAPE or ^G as an abort when in a 
X		two character command such as 'ar' or 'ac'
X	Cleanup in eval() - catches non-trap function errors.
X
XBob Bond - 
X       Added search options to "g".
X       Added supression of hidden columns to "W"
X       Added the mod operator "%"
X       New help functions.
X       Constant prescale "$"
X       Added string matching to @lookup.
X       Some more bug fixes.
X       Testing, integration, documentation.
X
XAlan Silverstein-
X	Greatly revised the manual entry.
X	Added menus for ^E command and row/column commands, which
X	involved a bunch of code cleanup.
X
X	Changed top row display to clearly indicate string labels
X	versus number parts, and to distinguish string functions from
X	constant labels.
X
X	When the character cursor is on a cell (not topline), ^H
X	(backspace) is like ^B (move back one cell), rather than being
X	ignored.
X
X	When the character cursor is on a cell (not topline), ^I (tab)
X	is like ^F (move forward one cell), rather than being ignored.
X	^R is no longer identical with ^L.  Now ^R highlights all cells
X	which should be entered by a user because they contain constant
X	numeric values (not the result of a numeric expression).
X
X	Added a ^X command, similar to ^R, which highlights cells which
X	have expressions.  It also displays the expressions in the
X	highlighted cells as left-justified strings, instead of the
X	label and/or value of the cell.
X
X	Added indirection functions (@nval() and @sval()) for simple
X	table lookups.  Given a column name and row number, they return
X	the numeric or string value of the selected cell.
X
X	Added external functions (@ext()) for non-trivial
X	computations.  Given a command name and argument, it calls the
X	command and reads back one output line.
X
X	Added a ^T,e command to toggle enabling of external functions.
X
X	Changed ^T,t to only control the top line display, and added
X	^T,c to control current cell highlighting.  (Separated the
X	functions.)
X
X	"!" (shell escape) gives a vi-style warning if there were any
X	changes since the last write.  (No change to manual entry.)
X
X	Fixed some startup, error, and prompt messages to be cleaner
X	and/or more consistent.  (No changes to manual entry.)
X
X	Fixed a bug:  If @substr() upper bound (third parameter) is
X	past the end of the string operand, return the substring
X	through the end of the string, rather than returning a null
X	string.
X
X	Fixed a bug:  Reset SIGINT to default after forking before
X	calling shell escape program and before starting pipeline (for
X	commands which support this).  Didn't reset SIGINT before
X	calling crypt and external functions because in both cases it
X	should be irrelevant.  (No change to manual entry.)
X
XCHANGES BETWEEN 6.1 and 6.2:
X
X
XChris Cole-
X	Compatibility with Lotus 1-2-3
X		a) @hlookup(expr,range,expr)
X		b) @vlookup(expr,range,expr)
X		c) @round(expr,expr)
X		d) @if(expr,expr,expr)
X		e) @abs(expr)
END_OF_FILE
  if test 16317 -ne `wc -c <'CHANGES'`; then
    echo shar: \"'CHANGES'\" unpacked with wrong size!
  fi
  # end of 'CHANGES'
fi
if test -f 'format.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'format.c'\"
else
  echo shar: Extracting \"'format.c'\" \(14370 characters\)
  sed "s/^X//" >'format.c' <<'END_OF_FILE'
X/*****************************************************************************
X *
X * Mark Nagel <nagel at ics.uci.edu>
X * 20 July 1989
X *
X * $Revision: 6.16 $
X *
X * bool
X * format(fmt, num, buf, buflen)
X *  char *fmt;
X *  double num;
X *  char buf[];
X *  int buflen;
X *
X * The format function will produce a string representation of a number
X * given a _format_ (described below) and a double value.  The result is
X * written into the passed buffer -- if the resulting string is too
X * long to fit into the passed buffer, the function returns false.
X * Otherwise the function returns true.
X *
X * The fmt parameter contains the format to use to convert the number.
X *
X *  #	Digit placeholder.  If the number has fewer digits on either
X *      side of the decimal point than  there are '#' characters in
X *      the format, the extra '#' characters are ignored.  The number
X *      is rounded to the number of digit placeholders as there are
X *      to the right of the decimal point.  If there are more digits
X *      in the number than there are digit placeholders on the left
X *      side of the decimal point, then those digits are displayed.
X *
X *  0	Digit placeholder.  Same as for '#' except that the number
X *      is padded with zeroes on either side of the decimal point.
X *      The number of zeroes used in padding is determined by the
X *      number of digit placeholders after the '0' for digits on
X *      the left side of the decimal point and by the number of
X *      digit placeholders before the '0' for digits on the right
X *      side of the decimal point.
X *
X *  .	Decimal point.  Determines how many digits are placed on
X *      the right and left sides of the decimal point in the number.
X *      Note that numbers smaller than 1 will begin with a decimal
X *      point if the left side of the decimal point contains only
X *      a '#' digit placeholder.  Use a '0' placeholder to get a
X *      leading zero in decimal formats.
X *
X *  %	Percentage.  For each '%' character in the format, the actual
X *      number gets multiplied by 100 (only for purposes of formatting
X *      -- the original number is left unmodified) and the '%' character
X *      is placed in the same position as it is in the format.
X *
X *  ,	Thousands separator.  The presence of a ',' in the format
X *      (multiple commas are treated as one) will cause the number
X *      to be formatted with a ',' separating each set of three digits
X *      in the integer part of the number with numbering beginning
X *      from the right end of the integer.
X *
X *  \	Quote.  This character causes the next character to be
X *      inserted into the formatted string directly with no
X *      special interpretation.
X *
X *  E- E+ e- e+
X *	Scientific format.  Causes the number to formatted in scientific
X *	notation.  The case of the 'E' or 'e' given is preserved.  If
X *      the format uses a '+', then the sign is always given for the
X *	exponent value.  If the format uses a '-', then the sign is
X *	only given when the exponent value is negative.  Note that if
X *	there is no digit placeholder following the '+' or '-', then
X *	that part of the formatted number is left out.  In general,
X *	there should be one or more digit placeholders after the '+'
X *	or '-'.
X *
X *  ;	Format selector.  Use this character to separate the format
X *	into two distinct formats.  The format to the left of the
X *	';' character will be used if the number given is zero or
X *	positive.  The format to the right of the ';' character is
X *      used if the number given is negative.
X *    
X *  Any
X *	Self insert.  Any other character will be inserted directly
X *	into the formatted number with no change made to the actual
X *      number.
X *
X *****************************************************************************/
X
X/*****************************************************************************/
X
X#include <stdio.h>
X#include "sc.h"
X
X#define bool	int
X#define true	1
X#define false	0
X#define EOS	'\0'
X#define MAXBUF	256
X
Xextern char
X  *strcpy(),
X  *strcat();
X
Xstatic char
X  *fmt_int(),
X  *fmt_frac(),
X  *fmt_exp();
X
Xstatic void
X  reverse();
X
X/*****************************************************************************/
X
Xbool
Xformat(fmt, val, buf, buflen)
X  char *fmt;
X  double val;
X  char *buf;
X  int buflen;
X{
X  register char *cp;
X  char *tmp, *tp;
X  bool comma = false, negative = false;
X  char *integer = NULL, *decimal = NULL;
X  char *exponent = NULL;
X  int exp_val, width;
X  char prtfmt[32];
X  static char		*mantissa = NULL;
X  static char		*tmpfmt1 = NULL, *tmpfmt2 = NULL, *exptmp = NULL;
X  static unsigned	mantlen = 0, fmtlen = 0;
X  char *fraction = NULL;
X  int zero_pad = 0;
X
X  if (fmt == NULL)
X    return(true);
X
X  if (strlen(fmt) + 1 > fmtlen)
X  {	fmtlen = strlen(fmt) + 40;
X	tmpfmt1 = xrealloc(tmpfmt1, fmtlen);
X	tmpfmt2 = xrealloc(tmpfmt2, fmtlen);
X	exptmp = xrealloc(exptmp, fmtlen);
X  }
X  fmt = strcpy(tmpfmt1, fmt);
X  if (buflen + 1 > mantlen)
X  {	mantlen = buflen + 40;
X	mantissa = xrealloc(mantissa, mantlen);
X  }
X
X  /*
X   * select positive or negative format if necessary
X   */
X  for (cp = fmt; *cp != ';' && *cp != EOS; cp++)
X  {
X    if (*cp == '\\')
X      cp++;
X  }
X  if (*cp == ';')
X  {
X    if (val < 0.0)
X    {
X      val = -val;     /* format should provide sign if desired */
X      fmt = cp + 1;
X    }
X    else
X    {
X      *cp = EOS;
X    }
X  }
X  
X  /*
X   * extract other information from format and produce a
X   * format string stored in tmpfmt2 also xmalloc()'d above
X   */
X  tmp = tmpfmt2;
X  for (cp = fmt, tp = tmp; *cp != EOS; cp++)
X  {
X    switch (*cp)
X    {
X      case '\\':
X        *tp++ = *cp++;
X        *tp++ = *cp;
X	break;
X
X      case ',':
X        comma = true;
X	break;
X
X      case '.':
X        if (decimal == NULL)
X	  decimal = tp;
X	*tp++ = *cp;
X	break;
X	
X      case '%':
X        val *= 100.0;
X	*tp++ = *cp;
X	break;
X	
X      default:
X        *tp++ = *cp;
X	break;
X    }
X  }
X  *tp = EOS;
X  fmt = tmpfmt2;
X
X  if (val < 0.0)
X  {	negative = true;
X	val = -val;
X  }
X  /*
X   * extract the exponent from the format if present
X   */
X  for (cp = fmt; *cp != EOS; cp++)
X  { if (*cp == '\\')
X    {
X      cp++;
X    }
X    else if (*cp == 'e' || *cp == 'E')
X    {
X      if (cp[1] == '+' || cp[1] == '-')
X      {
X	exponent = strcpy(exptmp, cp);
X	*cp = EOS;
X	exp_val = 0;
X	if (val!=0.0) {
X	  while (val < 1.0)
X	  {
X	    val *= 10.0;
X	    exp_val--;
X	  }
X	  while (val >= 10.0)
X	  {
X	    val /= 10.0;
X	    exp_val++;
X	  }
X	}
X	break;
X      }
X    }
X  }
X
X  /*
X   * determine maximum decimal places and use sprintf
X   * to build initial character form of formatted value.
X   */
X  width = 0;
X  if (decimal)
X  {
X    *decimal++ = EOS;
X    for (cp = decimal; *cp != EOS; cp++)
X    {
X      switch (*cp)
X      {
X        case '\\':
X          cp++;
X	  break;
X
X        case '#':
X          width++;
X	  break;
X
X	case '0':
X	  zero_pad = ++width;
X	  break;
X      }
X    }
X    zero_pad = strlen(decimal) - zero_pad;
X  }
X  (void) sprintf(prtfmt, "%%.%dlf", width);
X  (void) sprintf(mantissa, prtfmt, val);
X  for (cp = integer = mantissa; *cp != '.' && *cp != EOS; cp++)
X  {
X    if (*integer == '0')
X      integer++;
X  }
X  if (*cp == '.')
X  {
X    fraction = cp + 1;
X    *cp = EOS;
X    cp = fraction + strlen(fraction) - 1;
X    for (; zero_pad > 0; zero_pad--, cp--)
X    {
X      if (*cp == '0')
X        *cp = EOS;
X    }
X  }
X
X  /*
X   * format the puppy
X   */
X  {
X    static	char *citmp = NULL, *cftmp = NULL;
X    static	unsigned cilen = 0, cflen = 0;
X    char *ci, *cf, *ce;
X    int len_ci, len_cf, len_ce;
X    bool ret = false;
X    
X    ci = fmt_int(integer, fmt, comma, negative);
X    len_ci = strlen(ci);
X    if (len_ci >= cilen)
X    {	cilen = len_ci + 40;
X	citmp = xrealloc(citmp, cilen);
X    }
X    ci = strcpy(citmp, ci);
X
X    cf = (fraction) ? fmt_frac(fraction, decimal) : "";
X    len_cf = strlen(cf);
X    if (len_cf >= cflen)
X    {	cflen = len_cf + 40;
X	cftmp = xrealloc(cftmp, cilen);
X    }
X    cf = strcpy(cftmp, cf);
X
X    ce = (exponent) ? fmt_exp(exp_val, exponent) : "";
X    len_ce = strlen(ce);
X/*
X * Skip copy assuming sprintf doesn't call our format functions
X *   ce = strcpy(xmalloc((unsigned)((len_ce = strlen(ce)) + 1)), ce);
X */
X    if (len_ci + len_cf + len_ce < buflen)
X    {
X      (void) sprintf(buf, "%s%s%s", ci, cf, ce);
X      ret = true;
X    }
X
X    return (ret);
X  }
X}
X
X/*****************************************************************************/
X
Xstatic char *
Xfmt_int(val, fmt, comma, negative)
X  char *val;	    /* integer part of the value to be formatted */
X  char *fmt;	    /* integer part of the format */
X  bool comma;	    /* true if we should comma-ify the value */
X  bool negative;    /* true if the value is actually negative */
X{
X  int digit, f, v;
X  int thousands = 0;
X  char *cp;
X  static char buf[MAXBUF];
X  char *bufptr = buf;
X
X  /*
X   * locate the leftmost digit placeholder
X   */
X  for (cp = fmt; *cp != EOS; cp++)
X  {
X    if (*cp == '\\')
X      cp++;
X    else if (*cp == '#' || *cp == '0')
X      break;
X  }
X  digit = (*cp == EOS) ? -1 : cp - fmt;
X
X  /*
X   * format the value
X   */
X  f = strlen(fmt) - 1;
X  v = (digit >= 0) ? strlen(val) - 1 : -1;
X  while (f >= 0 || v >= 0)
X  {
X    if (f > 0 && fmt[f-1] == '\\')
X    {
X      *bufptr++ = fmt[f--];
X    }
X    else if (f >= 0 && (fmt[f] == '#' || fmt[f] == '0'))
X    {
X      if (v >= 0 || fmt[f] == '0')
X      {
X        *bufptr++ = v < 0 ? '0' : val[v];
X	if (comma && (thousands = (thousands + 1) % 3) == 0 && v > 0)
X	{
X	  *bufptr++ = ',';
X	}
X	v--;
X      }
X    }
X    else if (f >= 0)
X    {
X      *bufptr++ = fmt[f];
X    }
X    if (v >= 0 && f == digit)
X    {
X      continue;
X    }
X    f--;
X  }
X    
X  if (negative && digit >= 0)
X    *bufptr++ = '-';
X  *bufptr = EOS;
X  reverse(buf);
X
X  return (buf);
X}
X
X/*****************************************************************************/
X
Xstatic char *
Xfmt_frac(val, fmt)
X  char *val;	    /* fractional part of the value to be formatted */
X  char *fmt;	    /* fractional portion of format */
X{
X  static char buf[MAXBUF];
X  register char *bufptr = buf;
X  register char *fmtptr = fmt, *valptr = val;
X
X  *bufptr++ = '.';
X  while (*fmtptr != EOS)
X  {
X    if (*fmtptr == '\\')
X    {
X      *bufptr++ = *++fmtptr;
X    }
X    else if (*fmtptr == '#' || *fmtptr == '0')
X    {
X      if (*valptr != EOS || *fmtptr == '0')
X      {
X        *bufptr++ = (*valptr != EOS) ? *valptr++ : *fmtptr;
X      }
X    }
X    else
X    {
X      *bufptr++ = *fmtptr;
X    }
X    fmtptr++;
X  }
X  *bufptr = EOS;
X
X  return (buf);
X}
X
X/*****************************************************************************/
X
Xstatic char *
Xfmt_exp(val, fmt)
X  int val;	    /* value of the exponent */
X  char *fmt;	    /* exponent part of the format */
X{
X  static char buf[MAXBUF];
X  register char *bufptr = buf;
X  char valbuf[64];
X  bool negative = false;
X  
X  *bufptr++ = *fmt++;
X  if (*fmt == '+')
X    *bufptr++ = (val < 0) ? '-' : '+';
X  else if (val < 0)
X    *bufptr++ = '-';
X  fmt++;
X  *bufptr = EOS;
X
X  if (val < 0)
X  {
X    val = -val;
X    negative = false;
X  }
X  (void) sprintf(valbuf, "%d", val);
X  
X  (void) strcat(buf, fmt_int(valbuf, fmt, false, negative));
X  return (buf);
X}
X
X/*****************************************************************************/
X
Xstatic void
Xreverse(buf)
X  register char *buf;
X{
X  register char *cp = buf + strlen(buf) - 1;
X  register char tmp;
X
X  while (buf < cp)
X  {
X    tmp = *cp;
X    *cp-- = *buf;
X    *buf++ = tmp;
X  }
X}
X
X/*****************************************************************************/
X/*  
X * Tom Anderson    <toma at hpsad.hp.com>
X * 10/14/90
X *
X * This routine takes a value and formats it using fixed, scientific,
X * or engineering notation.  The format command 'f' determines which
X * format is used.  The formats are:         example
X *    0:   Fixed point (default)             0.00010
X *    1:   Scientific                        1.00E-04
X *    2:   Engineering                       100.00u
X *
X * The format command 'f' now uses three values.  The first two are the
X * width and precision, and the last one is the format value 0, 1, or 2 as
X * described above.  The format value is passed in the variable fmt.
X *
X * This formatted value is written into the passed buffer.  if the
X * resulting string is too long to fit into the passed buffer, the
X * function returns false.  Otherwise the function returns true.
X *
X * When a number is formatted as engineering and is outside of the range
X * of typically used engineering exponents, the format reverts to
X * scientific.
X *
X * To preserve compatability with old spreadsheet files, the third value
X * may be missing, and the default will be fixed point (format 0).
X *
X * When an old style sheet is saved, the third value will be stored.
X *
X */
X
X#define REFMTFIX 0
X#define REFMTFLT 1
X#define REFMTENG 2
Xchar engmult[] = "afpnum kMGT";
X
Xbool
Xengformat(fmt, width, lprecision, val, buf, buflen)
Xint fmt; 
Xint width; 
Xint lprecision;
Xdouble val;
Xchar *buf;
Xint buflen;
X{
X  int engind = 0;
X  double engmant, pow(), engabs, engexp;
X  if (buflen < width) return (false);
X  if (fmt == REFMTFIX)
X  (void) sprintf(buf,"%*.*f", width, lprecision, val);
X  if (fmt == REFMTFLT)
X  (void) sprintf(buf,"%*.*E", width, lprecision, val);
X  if (fmt == REFMTENG)
X  {
X    if (val == 0e0)    /* Hack to get zeroes to line up in engr fmt */
X    {
X      (void) sprintf((buf-1),"%*.*f ", width, lprecision, val);
X    }
X    else
X    {
X      engabs=(val);
X      if (engabs < 0e0) engabs= -engabs;
X      if ((engabs >= 1e-18) && (engabs < 1e-15 )) engind=0;
X      if ((engabs >= 1e-15) && (engabs < 1e-12 )) engind=1;
X      if ((engabs >= 1e-12) && (engabs < 1e-9 )) engind=2;
X      if ((engabs >= 1e-9) && (engabs < 1e-6 )) engind=3;
X      if ((engabs >= 1e-6) && (engabs < 1e-3 )) engind=4;
X      if ((engabs >= 1e-3) && (engabs < 1 )) engind=5;
X      if ((engabs >= 1) && (engabs < 1e3 )) engind=6;
X      if ((engabs >= 1e3) && (engabs < 1e6 )) engind=7;
X      if ((engabs >= 1e6) && (engabs < 1e9 )) engind=8;
X      if ((engabs >= 1e9) && (engabs < 1e12 )) engind=9;
X      if ((engabs >= 1e12) && (engabs < 1e15 )) engind=10;
X      if ((engabs <1e-18) || (engabs >=1e15))
X      {
X      /* Revert to floating point */
X        (void) sprintf(buf,"%*.*E", width, lprecision, val);
X      }
X      else
X      {
X        engexp= (double) (engind-6)*3;
X        engmant= val/pow(10.0e0,engexp);
X        (void) sprintf(buf,"%*.*f%c", width-1,
X                      lprecision, engmant, engmult[engind]);
X      }
X    }
X  }
X  return (true);
X}
END_OF_FILE
  if test 14370 -ne `wc -c <'format.c'`; then
    echo shar: \"'format.c'\" unpacked with wrong size!
  fi
  # end of 'format.c'
fi
if test -f 'psc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'psc.c'\"
else
  echo shar: Extracting \"'psc.c'\" \(7176 characters\)
  sed "s/^X//" >'psc.c' <<'END_OF_FILE'
X/* Sc parse routine
X *
X * usage psc options
X * options:
X *   -L		Left justify strings.  Default is right justify.
X *   -r		Assemble data into rows first, not columns.
X *   -R	n	Increment by n between rows 
X *   -C n	Increment by n between columns
X *   -n n	Length of the row (column) should be n.
X *   -s v	Top left location in the spreadsheet should be v; eg, k5
X *   -d c       Use c as the delimiter between the fields.
X *   -k         Keep all delimiters - Default is strip multiple delimiters to 1.
X *   -f         suppress 'format' lines in output
X *   -S		Use strings vs numbers for numbers
X *   -P		Use numbers only when there is no [-+eE] (plain numbers only)
X *
X *  Author: Robert Bond
X *  Adjustments: Jeff Buhrt and Eric Putz
X */
Xchar *rev = "$Revision: 6.16 $";
X
X#include <ctype.h>
X#include <stdio.h>
X#include "sc.h"
X
X#define END	0
X#define NUM	1
X#define ALPHA	2
X#define SPACE	3
X#define EOL	4
X
Xextern char *optarg;
Xextern int   optind;
Xchar *coltoa();
Xchar *progname;
X
X#ifdef SYSV3
Xextern void exit();
X#else
Xextern int exit();
X#endif
X
Xint *fwidth;
Xint *precision;
Xint maxcols;
Xint *realfmt;
X
X/* option flags reset */
Xint colfirst = FALSE;
Xint leftadj = FALSE;
Xint r0 = 0;
Xint c0 = 0;
Xint rinc = 1;
Xint cinc = 1;
Xint len = 20000;
Xchar delim1 = ' ';
Xchar delim2 = '\t';
Xint strip_delim = TRUE;
Xint drop_format = FALSE;
Xint strnums	= FALSE;
Xint plainnums	= FALSE;
X
Xchar token[1000];
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int curlen;
X    int curcol, coff;
X    int currow, roff;
X    int first;
X    int c;
X    register effr, effc;
X    int i,j;
X    register char *p;
X
X    progname = argv[0];
X    while ((c = getopt(argc, argv, "rfLks:R:C:n:d:SPv")) != EOF) {
X	switch(c) {
X	case 'r':
X	    colfirst = TRUE;
X	    break;
X	case 'L':
X	    leftadj = TRUE;
X	    break;
X	case 's':
X	    c0 = getcol(optarg);
X	    r0 = getrow(optarg);
X	    break;
X	case 'R':
X	    rinc = atoi(optarg);
X	    break;
X	case 'C':
X	    cinc = atoi(optarg);
X	    break;
X	case 'n':
X	    len = atoi(optarg);
X	    break;
X	case 'd':
X	    delim1 = optarg[0];
X	    delim2 = '\0';
X	    break;
X	case 'k':
X	    strip_delim = FALSE;
X	    break;
X	case 'f':
X	    drop_format = TRUE;
X	    break;
X	case 'S':
X	    strnums = TRUE;
X	    break;
X	case 'P':
X	    plainnums = TRUE;
X	    break;
X	case 'v':
X	    (void) fprintf(stderr,"%s: %s\n", progname, rev);
X	default:
X	    (void) fprintf(stderr,"Usage: %s [-rkfLSPv] [-s v] [-R i] [-C i] [-n i] [-d c]\n", progname);
X	    exit(1);
X        }
X    }
X
X    if (optind < argc) {
X	    (void) fprintf(stderr,"Usage: %s [-rL] [-s v] [-R i] [-C i] [-n i] [-d c]\n", progname);
X	    exit(1);
X    }
X
X	/* setup the spreadsheet arrays */
X    if (!growtbl(GROWNEW, 0, 0))
X	exit(1);
X
X    curlen = 0;
X    curcol = c0; coff = 0;
X    currow = r0; roff = 0;
X    first = TRUE;
X
X    while(1) {
X
X	effr = currow+roff;
X	effc = curcol+coff;
X
X	switch(scan()) {
X	case END:
X	    if(drop_format) exit(0);
X	    for (i = 0; i<maxcols; i++) {
X		if (fwidth[i])
X		    (void) printf("format %s %d %d\n", coltoa(i), 
X			fwidth[i]+1, precision[i]);
X	    }
X	    exit(0);
X	case NUM:
X	    first = FALSE;
X	    (void) printf("let %s%d = %s\n", coltoa(effc), effr, token);
X	    if (effc >= maxcols - 1)
X	    {	if (!growtbl(GROWCOL, 0, effc))
X		{	(void) fprintf(stderr, "Invalid column used: %s\n", coltoa(effc));
X			continue;
X		}
X	    }
X	    i = 0;
X	    j = 0;
X	    p = token;
X	    while (*p && *p != '.') {
X		p++; i++;
X	    }
X	    if (*p) {
X		p++; i++;
X	    }
X	    while (*p) {
X		p++; i++; j++;
X	    }
X	    {   int	ow, nw;
X
X		ow = fwidth[effc] - precision[effc];
X		if (precision[effc] < j)
X			precision[effc] = j;
X	
X		if (fwidth[effc] < i)
X			fwidth[effc] = i;
X
X		/* now make sure:
X		 *	1234.567890 (format 11 6)
X		 *	1234567.890 (format 11 3)
X		 *	both show (format 14 6)
X		 *		(really it uses 15 6 to separate columns)
X		 */
X		if ((nw = i - j) > ow)
X			fwidth[effc] += nw - (fwidth[effc] - precision[effc]);
X	    }
X	    break;
X	case ALPHA:
X	    first = FALSE;
X	    if (leftadj)
X		(void) printf("leftstring %s%d = \"%s\"\n", coltoa(effc),effr,token); 
X	    else
X		(void) printf("rightstring %s%d = \"%s\"\n",coltoa(effc),effr,token); 
X	    if (effc >= maxcols - 1)
X	    {	if (!growtbl(GROWCOL, 0, effc))
X		{	(void) fprintf(stderr, "Invalid column used: %s\n", coltoa(effc));
X			continue;
X		}
X	    }
X	    i = strlen(token);
X	    if (i > fwidth[effc])
X		fwidth[effc] = i;
X	    break;
X	case SPACE:
X	    if (first && strip_delim)
X		break;
X	    if (colfirst)
X		roff++;
X	    else
X		coff++;
X	    break;
X	case EOL:
X	    curlen++;
X	    roff = 0;
X	    coff = 0;
X	    first = TRUE;
X	    if (colfirst) {
X		if (curlen >= len) {
X		    curcol = c0;
X		    currow += rinc;
X		    curlen = 0;
X		} else {
X		    curcol += cinc;
X		}
X	    } else {
X		if (curlen >= len) {
X		    currow = r0;
X		    curcol += cinc;
X		    curlen = 0;
X		} else {
X		    currow += rinc;
X		}
X	    }
X	    break;
X	}
X    }
X}
X
Xscan()
X{
X    register int c;
X    register char *p;
X    register int founddigit;
X
X    p = token;
X    c = getchar();
X
X    if (c == EOF)
X	return(END);
X
X    if (c == '\n')
X	return(EOL);
X
X    if (c == delim1 || c == delim2) {
X        if (strip_delim) {
X	    while ((c = getchar()) && (c == delim1 || c == delim2))
X	        ;
X	    (void)ungetc(c, stdin);
X	} 
X	return(SPACE);
X    }
X
X    if (c == '\"') {
X	while ((c = getchar()) && c != '\"' && c != '\n' && c != EOF)
X	    *p++ = c;
X	if (c != '\"')
X	    (void)ungetc(c, stdin);
X	*p = '\0';
X	return(ALPHA);
X    }
X
X    while (c != delim1 && c != delim2 && c!= '\n' && c != EOF) {
X	*p++ = c;
X	c = getchar();
X    }
X    *p = '\0';
X    (void)ungetc(c, stdin);
X
X    p = token;
X    c = *p;
X    founddigit = FALSE;
X    /*
X     * str_nums always returns numbers as strings
X     * plainnums returns 'numbers' with [-+eE] in them as strings
X     * lastprtnum makes sure a number ends in one of [0-9eE.]
X     */
X    if (!strnums && (isdigit(c) || c == '.' || c == '-' || c == '+')) {
X	int	lastprtnum = FALSE;
X
X	while(isdigit(c) || c == '.' || (!plainnums && (c == '-' ||
X					c == '+' || c == 'e' || c == 'E'))) {
X		if (isdigit(c)) 
X			lastprtnum = founddigit = TRUE;
X		else
X		if (!(c == '.' || c == 'e' || c == 'E'))
X			lastprtnum = FALSE;
X		c = *p++;
X	}
X	if (c == '\0' && founddigit && lastprtnum)
X	    return(NUM);
X	else
X	    return(ALPHA);
X    }
X
X    return(ALPHA);
X}
X    
X/* turns [A-Z][A-Z] into a number */
Xgetcol(p)
Xchar *p;
X{
X    register  col;
X
X    col = 0;
X    if (!p)
X	return(0);
X    while(*p && !isalpha(*p)) 
X	p++; 
X    if (!*p)
X	return(0);
X    col = ((*p & 0137) - 'A');
X    if (isalpha(*++p)) 
X	col = (col + 1)*26 + ((*p & 0137) - 'A');
X    return(col);
X}
X
X/* given a string turn it into a row number */
Xgetrow(p)
Xchar *p;
X{
X    int row;
X
X    row = 0;
X    if (!p)
X	return(0);
X    while(*p && !isdigit(*p))
X	p++; 
X    if (!*p)
X	return(0);
X    while(*p && isdigit(*p))
X    {	row = row * 10 + *p - '0';
X	p++;
X    }
X    return(row);
X}
X
X/* turns a column number into [A-Z][A-Z] */
Xchar *
Xcoltoa(col)
Xint col;
X{
X    static char rname[3];
X    register char *p = rname;
X
X    if (col < 0 || col > 27*26)	/* A-Z, AA-ZZ */
X	(void) fprintf(stderr,"coltoa: invalid col: %d", col);
X
X    if (col > 25) {
X	*p++ = col/26 + 'A' - 1;
X	col %= 26;
X    }
X    *p++ = col+'A';
X    *p = '\0';
X    return(rname);
X}
END_OF_FILE
  if test 7176 -ne `wc -c <'psc.c'`; then
    echo shar: \"'psc.c'\" unpacked with wrong size!
  fi
  # end of 'psc.c'
fi
if test -f 'screen.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'screen.c'\"
else
  echo shar: Extracting \"'screen.c'\" \(13867 characters\)
  sed "s/^X//" >'screen.c' <<'END_OF_FILE'
X/*	SC	A Spreadsheet Calculator
X *		Curses based Screen driver
X *
X *		original by James Gosling, September 1982
X *		modifications by Mark Weiser and Bruce Israel,
X *			University of Maryland
X *
X *              More mods Robert Bond, 12/86
X *		More mods by Alan Silverstein, 3-4/88, see list of changes.
X *		Currently supported by sequent!sawmill!buhrt (Jeff Buhrt)
X *		$Revision: 6.16 $
X *
X */
X
X
X#include <curses.h>
X#include "sc.h"
X
X#ifdef BROKENCURSES
X		/* nl/nonl bug fix */
X#undef nl
X#undef nonl
X#define nl()	 (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
X#define nonl()	 (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
X#endif
X
Xvoid	repaint();
X
Xchar	under_cursor = ' '; /* Data under the < cursor */
Xchar	mode_ind = '.';
Xextern	char    revmsg[];
X
Xint	rows, cols;
Xint	lastmx, lastmy;	/* Screen address of the cursor */
Xint	lastcol;	/* Spreadsheet Column the cursor was in last */
Xextern	int *fwidth;
Xextern	int showrange;	/* Causes ranges to be highlighted	*/
Xextern	int showneed;	/* Causes cells needing values to be highlighted */
Xextern	int showexpr;	/* Causes cell exprs to be displayed, highlighted */
X
X/*
X * update() does general screen update
X *
X * standout last time in update()?
X *	At this point we will let curses do work
X */
Xint	standlast	= FALSE;
X
Xvoid
Xupdate (anychanged)
Xint	anychanged;	/* did any cell really change in value? */
X{
X    register    row, col;
X    register struct ent **pp;
X    int	mxrow, mxcol;
X    int	minsr = 0, minsc = 0, maxsr = 0, maxsc = 0;
X    register r;
X    register i;
X    static	int	lastcurcol = -1, lastcurrow = -1;
X
X    /*
X     * place the cursor on the screen, set col, curcol, stcol, lastcol as
X     * needed
X     */
X    if ((curcol != lastcurcol) || FullUpdate)
X    {
X	while (col_hidden[curcol])   /* You can't hide the last row or col */
X		curcol++;
X
X	/* First see if the last display still covers curcol */
X	if (stcol <= curcol) { 
X		for (i = stcol, cols = 0, col = RESCOL;
X			   (col + fwidth[i]) < COLS-1 && i < maxcols; i++) {
X			cols++;
X
X			if (col_hidden[i])
X				continue;
X			col += fwidth[i];
X		}
X	}
X	while (stcol + cols - 1 < curcol || curcol < stcol) {
X		FullUpdate++;
X		if (stcol - 1 == curcol) {    /* How about back one? */
X			stcol--;
X		} else if (stcol + cols == curcol) {   /* Forward one? */
X			stcol++;
X		} else {
X			/* Try to put the cursor in the center of the screen */
X			col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL; 
X			stcol = curcol;
X			for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--)
X			{	stcol--;
X				if (col_hidden[i])
X					continue;
X				col -= fwidth[i];
X			}
X		}
X		/* Now pick up the counts again */
X		for (i = stcol, cols = 0, col = RESCOL;
X			(col + fwidth[i]) < COLS-1 && i < maxcols; i++) {
X			cols++;
X			if (col_hidden[i])
X				continue;
X			col += fwidth[i];
X		}
X	}
X	lastcurcol = curcol;
X    }
X
X    /* Now - same process on the rows as the columns */
X    if ((currow != lastcurrow) || FullUpdate)
X    {
X	while (row_hidden[currow])   /* You can't hide the last row or col */
X		currow++;
X	if (strow <= currow) { 
X		for (i = strow, rows = 0, row=RESROW; row<LINES && i<maxrows; i++)
X		{	rows++;
X			if (row_hidden[i])
X				continue;
X			row++;
X		}
X	}
X
X	while (strow + rows - 1 < currow || currow < strow) {
X		FullUpdate++;
X		if (strow - 1 == currow) {    /* How about up one? */
X			strow--;
X		} else if (strow + rows == currow) {   /* Down one? */
X			strow++;
X		} else {
X			/* Try to put the cursor in the center of the screen */
X			row = (LINES - RESROW) / 2 + RESROW; 
X			strow = currow;
X			for (i=currow-1; i >= 0 && row-1 > RESROW; i--) {
X				strow--;
X				if (row_hidden[i])
X					continue;
X				row--;
X			}
X		}
X		/* Now pick up the counts again */
X		for (i = strow, rows = 0, row=RESROW; row<LINES && i<maxrows; i++) {
X			rows++;
X			if (row_hidden[i])
X				continue;
X			row++;
X		}
X	}
X	lastcurrow = currow;
X    }
X    mxcol = stcol + cols - 1;
X    mxrow = strow + rows - 1;
X
X    /* Get rid of cursor standout on the cell at previous cursor position */
X    if (!FullUpdate)
X    {	if (showcell)
X		repaint(lastmx, lastmy, fwidth[lastcol]);
X
X	(void) move(lastmy, lastmx+fwidth[lastcol]);
X
X	if ((inch() & A_CHARTEXT ) == '<')
X		(void) addch(under_cursor);
X    }
X
X    /* where is the the cursor now? */
X    lastmy =  RESROW;
X    for (row = strow; row < currow; row++)
X	if (!row_hidden[row])
X		lastmy++;
X
X    lastmx = RESCOL;
X    for (col = stcol; col < curcol; col++)
X	if (!col_hidden[col])
X		lastmx += fwidth[col];
X    lastcol = curcol;
X
X    if (FullUpdate || standlast) {
X	(void) move(2, 0);
X	(void) clrtobot();
X	(void) standout();
X
X	for (row=RESROW, i=strow; i <= mxrow; i++) {
X	    if (row_hidden[i]) 
X		continue;
X	    (void) move(row,0);
X	    if (maxrows < 1000)
X		(void) printw("%-*d", RESCOL-1, i);
X	    else
X		(void) printw("%-*d", RESCOL, i);
X	    row++;
X	}
X	(void) move(2,0);
X	(void) printw("%*s", RESCOL, " ");
X
X	for (col=RESCOL, i = stcol; i <= mxcol; i++) {
X	    register int k;
X	    if (col_hidden[i])
X		continue;
X	    (void) move(2, col);
X	    k = fwidth[i]/2;
X	    if (k == 0)
X		(void) printw("%1s", coltoa(i));
X	    else
X	        (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i));
X	    col += fwidth[i];
X	}
X	(void) standend();
X    }
X
X    if (showrange) {
X	minsr = showsr < currow ? showsr : currow;
X	minsc = showsc < curcol ? showsc : curcol;
X	maxsr = showsr > currow ? showsr : currow;
X	maxsc = showsc > curcol ? showsc : curcol;
X
X	if (showtop) {
X	    (void) move(1,0);
X	    (void) clrtoeol();
X	    (void) printw("Default range:  %s",
X			    r_name(minsr, minsc, maxsr, maxsc));
X	}
X    }
X
X
X    /* Repaint the visible screen */
X    if (showrange || anychanged || FullUpdate || standlast)
X    {
X	/* may be reset in loop, if not next time we will do a FullUpdate */
X      if (standlast)
X      {	FullUpdate = TRUE;
X	standlast = FALSE;
X      }
X
X      for (row = strow, r = RESROW; row <= mxrow; row++) {
X	register c = RESCOL;
X	int do_stand = 0;
X	int fieldlen;
X	int nextcol;
X
X	if (row_hidden[row])
X	    continue;
X	for (pp = ATBL(tbl, row, col = stcol); col <= mxcol;
X	         pp += nextcol - col,  col = nextcol, c += fieldlen) {
X
X	    nextcol = col+1;
X	    if (col_hidden[col]) {
X		fieldlen = 0;
X		continue;
X	    }
X
X	    fieldlen = fwidth[col];
X
X	    /*
X	     * Set standout if:
X	     *
X	     * - showing ranges, and not showing cells which need to be filled
X	     *	 in, and not showing cell expressions, and in a range, OR
X	     *
X	     * - if showing cells which need to be filled in and this one is
X	     *	 of that type (has a value and doesn't have an expression,
X	     *	 or it is a string expression), OR
X	     *
X	     * - if showing cells which have expressions and this one does.
X	     */
X	    if ((showrange && (! showneed) && (! showexpr)
X			   && (row >= minsr) && (row <= maxsr)
X			   && (col >= minsc) && (col <= maxsc))
X		    || (showneed && (*pp) && ((*pp) -> flags & is_valid)
X			&& (((*pp) -> flags & is_strexpr) || !((*pp) -> expr)))
X		    || (showexpr && (*pp) && ((*pp) -> expr)))
X	    {
X		(void) move(r, c);
X		(void) standout();
X		standlast++;
X		if (!*pp)	/* no cell, but standing out */
X		{	(void) printw("%*s", fwidth[col], " ");
X			(void) standend();
X			continue;
X		}
X		else
X			do_stand = 1;
X	    }
X	    else
X		do_stand = 0;
X
X	    if ((*pp) && ((*pp) -> flags & is_changed || FullUpdate) || do_stand) {
X		if (do_stand) {
X		    (*pp) -> flags |= is_changed; 
X		} else {
X		    (void) move(r, c);
X		    (*pp) -> flags &= ~is_changed;
X		}
X
X		/*
X		 * Show expression; takes priority over other displays:
X		 */
X
X		if ((*pp)->cellerror)
X			(void) printw("%*.*s", fwidth[col], fwidth[col],
X			  (*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID");
X		else
X		if (showexpr && ((*pp) -> expr)) {
X		    linelim = 0;
X		    editexp(row, col);		/* set line to expr */
X		    linelim = -1;
X		    showstring(line, /* leftflush = */ 1, /* hasvalue = */ 0,
X				row, col, & nextcol, mxcol, & fieldlen, r, c);
X		} else {
X		    /*
X		     * Show cell's numeric value:
X                     */
X
X		    if ((*pp) -> flags & is_valid) {
X			char field[FBUFLEN];
X
X			if ((*pp) -> format) {
X				(void) format((*pp) -> format, (*pp) -> v,
X					     field, sizeof(field));
X			} else {
X				(void) engformat(realfmt[col], fwidth[col], 
X                                             precision[col], (*pp) -> v, 
X                                             field, sizeof(field));
X			}
X			if (strlen(field) > fwidth[col]) {
X				for(i = 0; i<fwidth[col]; i++)
X					(void)addch('*');
X			} else {
X				for(i = 0; i < fwidth[col] - strlen(field);i++)
X					(void)addch(' ');
X				(void)addstr(field);
X			}
X		    }
X
X		    /*
X		     * Show cell's label string:
X		     */
X
X		    if ((*pp) -> label) {
X			showstring((*pp) -> label,
X				    (*pp) -> flags & is_leftflush,
X				    (*pp) -> flags & is_valid,
X				    row, col, & nextcol, mxcol,
X				    & fieldlen, r, c);
X		    }
X		    else	/* repaint a blank cell: */
X		    if ((do_stand || !FullUpdate) &&
X				((*pp)->flags & is_changed) &&
X				!((*pp)->flags & is_valid) && !(*pp)->label) {
X			(void) printw("%*s", fwidth[col], " ");
X		    }
X		} /* else */
X
X		if (do_stand) {
X		    (void) standend();
X		    do_stand = 0;
X		}
X	    }
X	}
X	r++;
X      }
X    }
X
X    /* place 'cursor marker' */
X    if (showcell && (! showneed) && (! showexpr)) {
X	(void) move(lastmy, lastmx);
X        (void) standout();
X        repaint(lastmx, lastmy, fwidth[lastcol]);
X        (void) standend();
X    }
X    (void) move(lastmy, lastmx+fwidth[lastcol]);
X    under_cursor = (inch() & A_CHARTEXT);
X    (void) addch('<');
X
X    (void) move(0, 0);
X    (void) clrtoeol();
X    if (linelim >= 0) {
X	(void) addch(mode_ind);
X	(void) addstr("> ");
X	(void) addstr(line);
X	(void) move((linelim + 3) / COLS, (linelim+3) % COLS);
X    } else {
X	if (showtop) {			/* show top line */
X	    register struct ent *p1;
X
X	    int printed = 0;		/* printed something? */
X
X	    /* show the current cell's format */
X	    (void) printw("%s%d ", coltoa(curcol), currow);
X	    if ((p1 = *ATBL(tbl, currow, curcol)) && p1->format)
X		printw("(%s) ", p1->format);
X	    else
X		printw("(%d %d %d) ", fwidth[curcol], precision[curcol],
X				realfmt[curcol]);
X
X	    if (p1) {
X		if (p1 -> expr) {
X		    /* has expr of some type */
X		    linelim = 0;
X		    editexp(currow, curcol);	/* set line to expr */
X		    linelim = -1;
X		}
X
X		/*
X		 * Display string part of cell:
X		 */
X
X		if ((p1 -> expr) && (p1 -> flags & is_strexpr)) {
X		    (void) addstr((p1 -> flags & is_leftflush) ? "<{" : ">{");
X		    (void) addstr(line);
X		    (void) addstr("} ");	/* and this '}' is for vi % */
X		    printed = 1;
X
X		} else if (p1 -> label) {
X		    /* has constant label only */
X		    (void) addstr ((p1 -> flags & is_leftflush) ? "<\"" : ">\"");
X		    (void) addstr (p1 -> label);
X		    (void) addstr ("\" ");
X		    printed = 1;
X		}
X
X		/*
X		 * Display value part of cell:
X		 */
X
X		if (p1 -> flags & is_valid) {
X		    /* has value or num expr */
X		    if ((! (p1 -> expr)) || (p1 -> flags & is_strexpr))
X			(void) sprintf (line, "%.15g", p1 -> v);
X
X		    (void) addch ('[');
X		    (void) addstr (line);
X		    (void) addch (']');
X		    *line = '\0'; /* this is the input buffer ! */
X		    printed = 1;
X		}
X	    }
X	    if (! printed)
X		(void) addstr ("[]");
X	}
X	(void) move(lastmy, lastmx+fwidth[lastcol]);
X    }
X
X    if (revmsg[0]) {
X	(void) move(0, 0);
X	(void) clrtoeol ();	/* get rid of topline display */
X	(void) printw(revmsg);
X	*revmsg = '\0';		/* don't show it again */
X	(void) move (lastmy, lastmx + fwidth[lastcol]);
X    }
X
X    FullUpdate = FALSE;
X}
X
X/* redraw what is under the cursor from curses' idea of the screen */
Xvoid
Xrepaint(x, y, len)
Xint x, y, len;
X{
X    int c;
X
X    while(len-- > 0) {
X	(void) move(y, x);
X	c = inch() & A_CHARTEXT;
X	(void) addch(c);
X	x++;
X    }
X}
X
Xint seenerr;
X
X/* error routine for yacc (gram.y) */
Xvoid
Xyyerror(err)
Xchar *err; {
X    if (seenerr) return;
X    seenerr++;
X    (void) move(1,0);
X    (void) clrtoeol();
X    (void) printw("%s: %.*s<=%s",err,linelim,line,line+linelim);
X}
X
X#ifdef XENIX2_3
Xstruct termio tmio;
X#endif
X
Xvoid
Xstartdisp()
X{
X#ifdef XENIX2_3
X    (void) ioctl (fileno (stdin), TCGETA, & tmio);
X#endif
X    (void) initscr();
X    (void) clear();
X#ifdef VMS
X    VMS_read_raw = 1;
X#else
X    nonl();
X    noecho ();
X    cbreak();
X#endif
X    initkbd();
X    scrollok(stdscr, 1);
X
X#ifndef IDLOKBAD
X# ifdef SYSV3
X    /*
X     * turn hardware insert/delete on, if possible.
X     * turn on scrolling for systems with SYSVr3.{1,2} (SYSVr3.0 has this set
X     * as the default)
X     */
X     idlok(stdscr,TRUE);
X# endif
X#else	/*
X	 * This seems to fix (with an empty spreadsheet):
X	 *	a) Redrawing the bottom half of the screen when you
X	 *		move between row 9 <-> 10
X	 *	b) the highlighted row labels being trash when you
X	 *		move between row 9 <-> 10
X	 *	c) On an xterm on Esix Rev. D+ from eating lines
X	 *	 -goto (or move) a few lines (or more) past the bottom
X	 *	 of the screen, goto (or move) to the top line on the
X	 *	 screen, move upward and the current line is deleted, the
X	 *	 others move up even when they should not, check by
X	 *	 noticing the rows become 2, 3, 40, 41, 42... (etc).
X	 */
X     idlok(stdscr,FALSE);
X#endif
X
X    FullUpdate++;
X}
X
Xvoid
Xstopdisp()
X{
X    deraw();
X    resetkbd();
X    endwin();
X#ifdef XENIX2_3
X    (void) ioctl (fileno (stdin), TCSETAW, & tmio);
X#endif
X}
X
X/* init curses */
X#ifdef VMS
X
Xgoraw()
X{
X    VMS_read_raw = 1;
X    FullUpdate++;
X}
X
Xderaw()
X{
X    (void) move (LINES - 1, 0);
X    (void) clrtoeol();
X    (void) refresh();
X    VMS_read_raw = 0;
X}
X
X#else /* VMS */
Xvoid
Xgoraw()
X{
X#if SYSV2 || SYSV3
X    fixterm();
X#else /* SYSV2 || SYSV3 */
X    cbreak();
X    nonl();
X    noecho ();
X#endif /* SYSV2 || SYSV3 */
X    kbd_again();
X    (void) clear();
X    FullUpdate++;
X}
X
X/* clean up curses */
Xvoid
Xderaw()
X{
X    (void) move (LINES - 1, 0);
X    (void) clrtoeol();
X    (void) refresh();
X#if SYSV2 || SYSV3
X    resetterm();
X#else
X    nocbreak();
X    nl();
X    echo();
X#endif
X    resetkbd();
X}
X
X#endif /* VMS */
END_OF_FILE
  if test 13867 -ne `wc -c <'screen.c'`; then
    echo shar: \"'screen.c'\" unpacked with wrong size!
  fi
  # end of 'screen.c'
fi
echo shar: End of archive 5 \(of 7\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 7 archives.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent at sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent at uunet.uu.net.



More information about the Comp.sources.misc mailing list