[alt.sources] format patches to sc 6.1

nagel@ics.uci.edu (Mark Nagel) (03/01/90)

A few people asked about the patches I made to sc using the format
routine I posted yesterday.  I had originally sent them to the
author and he said they'd be in a future release.  Since it's been
awhile, I'll go ahead and post the patches here.  Note that the
patches are not official.  These patches are from my current version
of sc 6.1 based on a virgin copy of sc 6.1 from uunet.  I believe
these include another patch someone else made after the release of
6.1 (changing the ctl macro I think).  This also includes the file
format.c posted yesterday (sorry for the repetition).  Please let me
know if you have any comments or problems...

Mark

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  sc.diffs
# Wrapped by nagel@wintermute.ics.uci.edu on Wed Feb 28 13:00:21 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'sc.diffs' -a "${1}" != "-c" ; then
  echo shar: Will not clobber existing file \"'sc.diffs'\"
else
echo shar: Extracting \"'sc.diffs'\" \(45373 characters\)
sed "s/^X//" >'sc.diffs' <<'END_OF_FILE'
X*** Makefile	Wed Feb 28 12:43:50 1990
X--- /usr/src/uci/usr/public/sc/Makefile	Fri Jul 21 13:40:26 1989
X***************
X*** 5,14 ****
X  NAME=SC
X
X  # This is where the install step puts it.
X! EXDIR=/h/rgb/bin/sym
X
X  # This is where the man page goes.
X! MANDIR=/usr/man/man1
X
X  # Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up
X  #SIMPLE=-DSIMPLE
X--- 5,14 ----
X  NAME=SC
X
X  # This is where the install step puts it.
X! EXDIR=/usr/public
X
X  # This is where the man page goes.
X! MANDIR=/usr/man/manp
X
X  # Set SIMPLE for lex.c if you don't want arrow keys or lex.c blows up
X  #SIMPLE=-DSIMPLE
X***************
X*** 19,29 ****
X
X  # Set SIGVOID if signal routines are type void.  System 5.3, VMS and ANSI C
X  # Compliant systems use this.  Most BSD systems do not.
X! #SIGVOID=-DSIGVOID
X
X  # This is the name of a pager like "more" If the line is commented out
X  # then "more" will be used. "pg" may be appropriate for SYSV
X! PAGER=-DDFLT_PAGER=\"less\"
X
X  # Use this for system V.2
X  # CFLAGS= -O -DSYSV2 $(SIGVOID)
X--- 19,29 ----
X
X  # Set SIGVOID if signal routines are type void.  System 5.3, VMS and ANSI C
X  # Compliant systems use this.  Most BSD systems do not.
X! SIGVOID=-DSIGVOID
X
X  # This is the name of a pager like "more" If the line is commented out
X  # then "more" will be used. "pg" may be appropriate for SYSV
X! PAGER=-DDFLT_PAGER=\"/usr/public/less\"
X
X  # Use this for system V.2
X  # CFLAGS= -O -DSYSV2 $(SIGVOID)
X***************
X*** 31,39 ****
X  # LIB=-lm -lcurses -lPW
X
X  # Use this for system V.3
X! CFLAGS= -O -DSYSV3 -DSIGVOID
X! LDFLAGS=
X! LIB=-lm -lcurses -lPW
X
X  # Use this for BSD 4.2
X  #CFLAGS=  -O -DBSD42 $(SIGVOID)
X--- 31,39 ----
X  # LIB=-lm -lcurses -lPW
X
X  # Use this for system V.3
X! #CFLAGS= -O -DSYSV3 -DSIGVOID
X! #LDFLAGS=
X! #LIB=-lm -lcurses -lPW
X
X  # Use this for BSD 4.2
X  #CFLAGS=  -O -DBSD42 $(SIGVOID)
X***************
X*** 41,49 ****
X  #LIB=-lm -lcurses -ltermcap
X
X  # Use this for BSD 4.3
X! #CFLAGS= -O -DBSD43 $(SIGVOID)
X! #LDFLAGS=
X! #LIB=-lm -lcurses -ltermcap
X
X  # Use this for system III (XENIX)
X  #CFLAGS= -O -DSYSIII $(SIGVOID)
X--- 41,49 ----
X  #LIB=-lm -lcurses -ltermcap
X
X  # Use this for BSD 4.3
X! CFLAGS= -O -DBSD43 $(SIGVOID)
X! LDFLAGS=
X! LIB=-lm -lcurses -ltermcap
X
X  # Use this for system III (XENIX)
X  #CFLAGS= -O -DSYSIII $(SIGVOID)
X***************
X*** 57,66 ****
X
X  # All of the source files
X  SRC=sc.h sc.c lex.c gram.y interp.c crypt.c xmalloc.c cmds.c range.c help.c \
X! 	eres.sed sres.sed Makefile psc.c
X
X  # The objects
X! OBJS=sc.o interp.o cmds.o crypt.o xmalloc.o range.o help.o lex.o gram.o
X
X  # The documents in the Archive
X  DOCS=README CHANGES sc.doc psc.doc tutorial.sc VMS_NOTES BSD_BUGS
X--- 57,67 ----
X
X  # All of the source files
X  SRC=sc.h sc.c lex.c gram.y interp.c crypt.c xmalloc.c cmds.c range.c help.c \
X! 	eres.sed sres.sed Makefile psc.c format.c
X
X  # The objects
X! OBJS=sc.o interp.o cmds.o crypt.o xmalloc.o range.o help.o lex.o gram.o \
X! 	format.o
X
X  # The documents in the Archive
X  DOCS=README CHANGES sc.doc psc.doc tutorial.sc VMS_NOTES BSD_BUGS
X***************
X*** 92,97 ****
X--- 93,100 ----
X  range.o: range.c sc.h
X
X  help.o: help.c sc.h
X+
X+ format.o: format.c
X
X  y.tab.h:	gram.y
X
X*** cmds.c	Wed Feb 28 12:43:45 1990
X--- /usr/src/uci/usr/public/sc/cmds.c	Fri Jul 21 10:06:31 1989
X***************
X*** 7,13 ****
X   *
X   *              More mods Robert Bond, 12/86
X   *
X!  *		$Revision: 6.1 $
X   */
X
X  #include <curses.h>
X--- 7,13 ----
X   *
X   *              More mods Robert Bond, 12/86
X   *
X!  *		$Revision: 6.2 $
X   */
X
X  #include <curses.h>
X***************
X*** 319,337 ****
X  	case 'r':
X  	case 'l':
X  	case 'h':
X! 	case ctl(f):
X! 	case ctl(b):	return ('r');
X
X  	case 'c':
X  	case 'j':
X  	case 'k':
X! 	case ctl(p):
X! 	case ctl(n):	return ('c');
X
X  	case 'm':	return ((ch == 'p') ? 'm' : 0);
X
X  	case ESC:
X! 	case ctl (g):	return (ESC);
X
X  	default:	return (0);
X      }
X--- 319,337 ----
X  	case 'r':
X  	case 'l':
X  	case 'h':
X! 	case ctl('f'):
X! 	case ctl('b'):	return ('r');
X
X  	case 'c':
X  	case 'j':
X  	case 'k':
X! 	case ctl('p'):
X! 	case ctl('n'):	return ('c');
X
X  	case 'm':	return ((ch == 'p') ? 'm' : 0);
X
X  	case ESC:
X! 	case ctl('g'):	return (ESC);
X
X  	default:	return (0);
X      }
X***************
X*** 658,665 ****
X--- 658,672 ----
X  		while (plinelim<c) pline[plinelim++] = ' ';
X  		plinelim = c;
X  		if ((*p)->flags&is_valid) {
X+ 		    if ((*p)->format) {
X+ 		        char field[1024];
X+
X+ 			(void)format((*p)->format, (*p)->v, field, sizeof(field));
X+ 			(void)sprintf(pline+plinelim, "%*s", fwidth[col], field);
X+ 		    } else {
X  		    (void)sprintf (pline+plinelim,"%*.*f",fwidth[col],
X  		                                precision[col], (*p)->v);
X+ 		    }
X  		    plinelim += strlen (pline+plinelim);
X  		}
X  		if (s = (*p)->label) {
X***************
X*** 763,770 ****
X  	    if (*p) {
X  		char *s;
X  		if ((*p)->flags&is_valid) {
X! 		    (void) fprintf (f,"%.*f",precision[col],
X  				(*p)->v);
X  		}
X  		if (s = (*p)->label) {
X  	            (void) fprintf (f,"%s",s);
X--- 770,784 ----
X  	    if (*p) {
X  		char *s;
X  		if ((*p)->flags&is_valid) {
X! 		    if ((*p)->format) {
X! 			char field[1024];
X!
X! 			(void) format((*p)->format, (*p)->v, field, sizeof(field));
X! 			(void) fprintf(f, "%s", field);
X! 		    } else {
X! 			(void) fprintf (f,"%.*f",precision[col],
X  				(*p)->v);
X+ 		    }
X  		}
X  		if (s = (*p)->label) {
X  	            (void) fprintf (f,"%s",s);
X***************
X*** 1051,1059 ****
X      n -> label = 0;
X      if (p -> label) {
X  	n -> label = (char *)
X! 		xmalloc  ((unsigned) (strlen (p -> label) + 1));
X  	(void) strcpy (n -> label, p -> label);
X      }
X  }
X
X  write_fd (f, r0, c0, rn, cn)
X--- 1065,1079 ----
X      n -> label = 0;
X      if (p -> label) {
X  	n -> label = (char *)
X! 		xmalloc ((unsigned) (strlen (p -> label) + 1));
X  	(void) strcpy (n -> label, p -> label);
X      }
X+     n -> format = 0;
X+     if (p -> format) {
X+         n -> format = (char *)
X+ 		xmalloc ((unsigned) (strlen (p -> format) + 1));
X+ 	(void) strcpy (n -> format, p -> format);
X+     }
X  }
X
X  write_fd (f, r0, c0, rn, cn)
X***************
X*** 1095,1100 ****
X--- 1115,1124 ----
X  		}
X  		if ((*p)->flags&is_valid) {
X  		    editv (r, c);
X+ 		    (void) fprintf (f, "%s\n",line);
X+ 		}
X+ 		if ((*p)->format) {
X+ 		    editfmt (r, c);
X  		    (void) fprintf (f, "%s\n",line);
X  		}
X  	    }
X*** gram.y	Wed Feb 28 12:43:40 1990
X--- /usr/src/uci/usr/public/sc/gram.y	Fri Jul 21 10:06:35 1989
X***************
X*** 9,15 ****
X   *
X   *		More mods by Alan Silverstein, 3/88, see list of changes.
X   *
X!  *		$Revision: 6.1 $
X   */
X
X
X--- 9,15 ----
X   *
X   *		More mods by Alan Silverstein, 3/88, see list of changes.
X   *
X!  *		$Revision: 6.2 $
X   */
X
X
X***************
X*** 46,51 ****
X--- 46,52 ----
X  %token <sval> WORD
X  %token <ival> COL
X  %token S_FORMAT
X+ %token S_FMT
X  %token S_LABEL
X  %token S_LEFTSTRING
X  %token S_RIGHTSTRING
X***************
X*** 215,220 ****
X--- 216,223 ----
X  				      lookat(currow, curcol), $2, $3); }
X  	|	S_FILL var_or_range num num
X  				 { fill($2.left.vp, $2.right.vp, $3, $4); }
X+ 	|	S_FMT var_or_range STRING
X+ 				{ format_cell($2.left.vp, $2.right.vp, $3); }
X  	|	S_GOTO var_or_range {moveto($2.left.vp->row, $2.left.vp->col);}
X  	|       S_GOTO num          {num_search($2);}
X  	|       S_GOTO STRING       {str_search($2);}
X*** help.c	Wed Feb 28 12:43:47 1990
X--- /usr/src/uci/usr/public/sc/help.c	Fri Jul 21 10:06:39 1989
X***************
X*** 1,7 ****
X  /*
X   * Help functions for sc
X   * R. Bond, 1988
X!  * $Revision: 6.2 $
X   */
X
X  #include <curses.h>
X--- 1,7 ----
X  /*
X   * Help functions for sc
X   * R. Bond, 1988
X!  * $Revision: 6.3 $
X   */
X
X  #include <curses.h>
X***************
X*** 90,95 ****
X--- 90,96 ----
X  "     \",>  Enter a right justified string or string expression.",
X  "     e    Edit the current cell's numeric value.",
X  "     E    Edit the current cell's string part.",
X+ "     F    Assign a format to the current cell's numeric value.",
X  "     x    Clear the current cell.",
X  "     c    Copy the last marked cell to the current cell.",
X  "     m    Mark a cell to be used as the source for ``c''",
X***************
X*** 165,172 ****
X  "          as ``A10'' or a range such as ``a1:b20''.",
X  "     /s   Shows the currently defined range names.  Pipe output to",
X  "          sort, then to less.",
X! "     /u   Use this command to undefine a previously defined range",
X! "          name.",
X  " ",
X  "     Range operations affect a rectangular region on the screen",
X  "     defined by the upper left and lower right cells in the region.",
X--- 166,173 ----
X  "          as ``A10'' or a range such as ``a1:b20''.",
X  "     /s   Shows the currently defined range names.  Pipe output to",
X  "          sort, then to less.",
X! "     /u   Use this command to undefine a previously defined range name.",
X! "     /F   Assign a format string to a range of cells.",
X  " ",
X  "     Range operations affect a rectangular region on the screen",
X  "     defined by the upper left and lower right cells in the region.",
X***************
X*** 312,326 ****
X  "                       years (360 months).",
X  " ",
X  "     @fv(e1,e2,e3)     @fv(100,.005,36) computes the future value",
X! "                       for of 36 monthly payments of $100 at 6%",
X  "                       interest (.005 per month).  It answers the",
X! "                       question:  ``How much will I have in 2",
X! "                       years if I deposit $100 per month in a",
X  "                       savings account paying 6% interest com-",
X  "                       pounded monthly?''",
X  " ",
X  "     @pv(e1,e2,e3)     @pv(1000,.015,36) computes the present",
X! "                       value of an a ordinary annuity of 36",
X  "                       monthly payments of $1000 at 18% annual",
X  "                       interest.  It answers the question: ``How",
X  "                       much can I borrow at 18% for 30 years if I",
X--- 313,327 ----
X  "                       years (360 months).",
X  " ",
X  "     @fv(e1,e2,e3)     @fv(100,.005,36) computes the future value",
X! "                       of 36 monthly payments of $100 at 6%",
X  "                       interest (.005 per month).  It answers the",
X! "                       question:  ``How much will I have in 36",
X! "                       months if I deposit $100 per month in a",
X  "                       savings account paying 6% interest com-",
X  "                       pounded monthly?''",
X  " ",
X  "     @pv(e1,e2,e3)     @pv(1000,.015,36) computes the present",
X! "                       value of an ordinary annuity of 36",
X  "                       monthly payments of $1000 at 18% annual",
X  "                       interest.  It answers the question: ``How",
X  "                       much can I borrow at 18% for 30 years if I",
X*** interp.c	Wed Feb 28 12:43:42 1990
X--- /usr/src/uci/usr/public/sc/interp.c	Fri Jul 21 10:48:22 1989
X***************
X*** 7,13 ****
X   *
X   *              More mods Robert Bond, 12/86
X   *		More mods by Alan Silverstein, 3-4/88, see list of changes.
X!  *		$Revision: 6.1 $
X   */
X
X  #include <math.h>
X--- 7,13 ----
X   *
X   *              More mods Robert Bond, 12/86
X   *		More mods by Alan Silverstein, 3-4/88, see list of changes.
X!  *		$Revision: 6.3 $
X   */
X
X  #include <math.h>
X***************
X*** 1437,1442 ****
X--- 1437,1475 ----
X      modflg++;
X  }
X
X+ format_cell(v1, v2, s)
X+ struct ent *v1, *v2;
X+ char *s;
X+ {
X+     register r,c;
X+     register struct ent *n;
X+     int maxr, maxc;
X+     int minr, minc;
X+
X+     maxr = v2->row;
X+     maxc = v2->col;
X+     minr = v1->row;
X+     minc = v1->col;
X+     if (minr>maxr) r = maxr, maxr = minr, minr = r;
X+     if (minc>maxc) c = maxc, maxc = minc, minc = c;
X+     if (maxr >= MAXROWS) maxr = MAXROWS-1;
X+     if (maxc >= MAXCOLS) maxc = MAXCOLS-1;
X+     if (minr < 0) minr = 0;
X+     if (minr < 0) minr = 0;
X+
X+     FullUpdate++;
X+     for (r = minr; r <= maxr; r++)
X+ 	for (c = minc; c <= maxc; c++) {
X+ 	    n = lookat (r, c);
X+ 	    if (n->format)
X+ 		xfree(n->format);
X+             n->format = 0;
X+ 	    if (s && *s != '\0')
X+ 		n->format = strcpy((char *)xmalloc(strlen(s)+1), s);
X+ 	    n->flags |= is_changed;
X+ 	}
X+ }
X+
X  hide_row(arg)
X  int arg;
X  {
X***************
X*** 1477,1482 ****
X--- 1510,1518 ----
X      if (v->expr)
X  	efree(v->expr);
X      v->expr = 0;
X+     if (v->format)
X+ 	xfree(v->format);
X+     v->format = 0;
X      v->flags |= (is_changed);
X      v->flags &= ~(is_valid);
X      changed++;
X***************
X*** 1768,1773 ****
X--- 1804,1821 ----
X  	decodev (e->e.r.right);
X      }
X      line[linelim++] = ')';
X+ }
X+
X+ editfmt (row, col)
X+ int row, col;
X+ {
X+     register struct ent *p;
X+
X+     p = lookat (row, col);
X+     if (p->format) {
X+         (void)sprintf (line, "fmt %s \"%s\"", v_name(row, col), p->format);
X+ 	linelim = strlen(line);
X+     }
X  }
X
X  editv (row, col)
X*** lex.c	Wed Feb 28 12:43:38 1990
X--- /usr/src/uci/usr/public/sc/lex.c	Thu Jul 13 10:16:17 1989
X***************
X*** 65,71 ****
X  #include "statres.h"
X      0, 0};
X
X! #define ctl(x) ('x'&037)
X
X  yylex ()
X  {
X--- 65,71 ----
X  #include "statres.h"
X      0, 0};
X
X! #define ctl(x) ((x)&037)
X
X  yylex ()
X  {
X***************
X*** 255,264 ****
X         c = getchar();
X
X      switch (c) {
X!     case SMG$K_TRM_LEFT:  c = ctl(b); break;
X!     case SMG$K_TRM_RIGHT: c = ctl(f); break;
X!     case SMG$K_TRM_UP:    c = ctl(p); break;
X!     case SMG$K_TRM_DOWN:  c = ctl(n); break;
X      default:   c = c & 0x7f;
X      }
X      return (c);
X--- 255,264 ----
X         c = getchar();
X
X      switch (c) {
X!     case SMG$K_TRM_LEFT:  c = ctl('b'); break;
X!     case SMG$K_TRM_RIGHT: c = ctl('f'); break;
X!     case SMG$K_TRM_UP:    c = ctl('p'); break;
X!     case SMG$K_TRM_DOWN:  c = ctl('n'); break;
X      default:   c = c & 0x7f;
X      }
X      return (c);
X***************
X*** 320,328 ****
X  #endif
X
X  char dont_use[] = {
X!     ctl(z), ctl(r), ctl(l), ctl(b), ctl(c), ctl(f), ctl(g), ctl([),
X!     ctl(h), ctl(m), ctl(j), ctl(n), ctl(p), ctl(q), ctl(s), ctl(t),
X!     ctl(u), ctl(v), ctl(e), ctl(a), ctl(i), ctl(w), 0,
X  };
X
X  charout(c)
X--- 320,329 ----
X  #endif
X
X  char dont_use[] = {
X!     ctl('z'), ctl('r'), ctl('l'), ctl('b'), ctl('c'), ctl('f'), ctl('g'),
X!     ctl('['), ctl('h'), ctl('m'), ctl('j'), ctl('n'), ctl('p'), ctl('q'),
X!     ctl('s'), ctl('t'), ctl('u'), ctl('v'), ctl('e'), ctl('a'), ctl('i'),
X!     ctl('w'), 0,
X  };
X
X  charout(c)
X***************
X*** 342,351 ****
X      if (tgetent(buf, getenv("TERM")) <= 0)
X  	return;
X
X!     km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl(b);
X!     km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl(f);
X!     km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl(p);
X!     km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl(n);
X      ktmp = tgetstr("ks",&p);
X      if (ktmp)  {
X  	(void) strcpy(ks_buf, ktmp);
X--- 343,352 ----
X      if (tgetent(buf, getenv("TERM")) <= 0)
X  	return;
X
X!     km[0].k_str = tgetstr("kl", &p); km[0].k_val = ctl('b');
X!     km[1].k_str = tgetstr("kr", &p); km[1].k_val = ctl('f');
X!     km[2].k_str = tgetstr("ku", &p); km[2].k_val = ctl('p');
X!     km[3].k_str = tgetstr("kd", &p); km[3].k_val = ctl('n');
X      ktmp = tgetstr("ks",&p);
X      if (ktmp)  {
X  	(void) strcpy(ks_buf, ktmp);
X***************
X*** 375,383 ****
X  #ifdef TIOCSLTC
X      (void)ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars);
X      new_chars = old_chars;
X!     if (old_chars.t_lnextc == ctl(v))
X  	new_chars.t_lnextc = -1;
X!     if (old_chars.t_rprntc == ctl(r))
X  	new_chars.t_rprntc = -1;
X      (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
X  #endif
X--- 376,384 ----
X  #ifdef TIOCSLTC
X      (void)ioctl(fileno(stdin), TIOCGLTC, (char *)&old_chars);
X      new_chars = old_chars;
X!     if (old_chars.t_lnextc == ctl('v'))
X  	new_chars.t_lnextc = -1;
X!     if (old_chars.t_rprntc == ctl('r'))
X  	new_chars.t_rprntc = -1;
X      (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
X  #endif
X***************
X*** 502,511 ****
X
X      c = getch();
X      switch (c) {
X!     case KEY_LEFT:  c = ctl(b); break;
X!     case KEY_RIGHT: c = ctl(f); break;
X!     case KEY_UP:    c = ctl(p); break;
X!     case KEY_DOWN:  c = ctl(n); break;
X  #ifdef KEY_C1
X  /* This stuff works for a wyse wy75 in ANSI mode under 5.3.  Good luck. */
X  /* It is supposed to map the curses keypad back to the numeric equiv. */
X--- 503,512 ----
X
X      c = getch();
X      switch (c) {
X!     case KEY_LEFT:  c = ctl('b'); break;
X!     case KEY_RIGHT: c = ctl('f'); break;
X!     case KEY_UP:    c = ctl('p'); break;
X!     case KEY_DOWN:  c = ctl('n'); break;
X  #ifdef KEY_C1
X  /* This stuff works for a wyse wy75 in ANSI mode under 5.3.  Good luck. */
X  /* It is supposed to map the curses keypad back to the numeric equiv. */
X***************
X*** 520,526 ****
X      case KEY_F(10): c = '8'; break;
X      case KEY_F0:    c = '9'; break;
X      case KEY_C3:    c = '.'; break;
X!     case KEY_ENTER: c = ctl(m); break;
X  #endif
X  #ifndef INTERNATIONAL
X      default:   c = c & 0x7f;
X--- 521,527 ----
X      case KEY_F(10): c = '8'; break;
X      case KEY_F0:    c = '9'; break;
X      case KEY_C3:    c = '.'; break;
X!     case KEY_ENTER: c = ctl('m'); break;
X  #endif
X  #ifndef INTERNATIONAL
X      default:   c = c & 0x7f;
X*** sc.c	Wed Feb 28 12:43:37 1990
X--- /usr/src/uci/usr/public/sc/sc.c	Fri Jul 21 10:06:49 1989
X***************
X*** 37,43 ****
X   * The part after the first colon, except the last char, appears on the screen.
X   */
X
X! char *rev = "$Revision: 6.1 $";
X
X  #ifndef DFLT_PAGER
X  #define	DFLT_PAGER "more"	/* more is probably more widespread than less */
X--- 37,43 ----
X   * The part after the first colon, except the last char, appears on the screen.
X   */
X
X! char *rev = "$Revision: 6.2 $";
X
X  #ifndef DFLT_PAGER
X  #define	DFLT_PAGER "more"	/* more is probably more widespread than less */
X***************
X*** 82,88 ****
X
X  int  lastmx, lastmy;	/* Screen address of the cursor */
X  int  lastcol;		/* Spreadsheet Column the cursor was in last */
X! char *under_cursor = " "; /* Data under the < cursor */
X
X  #ifdef VMS
X  int VMS_read_raw = 0;
X--- 82,88 ----
X
X  int  lastmx, lastmy;	/* Screen address of the cursor */
X  int  lastcol;		/* Spreadsheet Column the cursor was in last */
X! char under_cursor[] = " "; /* Data under the < cursor */
X
X  #ifdef VMS
X  int VMS_read_raw = 0;
X***************
X*** 121,126 ****
X--- 121,127 ----
X  	(*p)->col = col;
X  	(*p)->expr = 0;
X  	(*p)->v = (double) 0.0;
X+ 	(*p)->format = 0;
X      }
X      return *p;
X  }
X***************
X*** 371,381 ****
X
X  		    if ((*p) -> flags & is_valid) {
X  			char field[1024];
X! 			(void)sprintf(field,"%*.*f", fwidth[col], precision[col], (*p)->v);
X  			if(strlen(field) > fwidth[col]) {
X  			    for(i = 0; i<fwidth[col]; i++)
X  				(void)addch('*');
X  			} else {
X  			    (void)addstr(field);
X  			}
X  		    }
X--- 372,388 ----
X
X  		    if ((*p) -> flags & is_valid) {
X  			char field[1024];
X! 		        if ((*p) -> format) {
X! 			    (void)format((*p) -> format, (*p) -> v, field, sizeof(field));
X! 			} else {
X! 			    (void)sprintf(field,"%*.*f", fwidth[col], precision[col], (*p)->v);
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*** 514,522 ****
X  repaint(x, y, len)
X  int x, y, len;
X  {
X!     char *buf;
X
X!     buf = " ";
X
X      while(len-- > 0) {
X  	(void) move(y,x);
X--- 521,529 ----
X  repaint(x, y, len)
X  int x, y, len;
X  {
X!     char buf[2];
X
X!     buf[1] = '\0';
X
X      while(len-- > 0) {
X  	(void) move(y,x);
X***************
X*** 659,665 ****
X  	if ((c < ' ') || ( c == DEL ))
X  	    switch (c) {
X  #ifdef SIGTSTP
X! 		case ctl (z):
X  		    deraw();
X  		    (void) kill(getpid(),SIGTSTP);
X
X--- 666,672 ----
X  	if ((c < ' ') || ( c == DEL ))
X  	    switch (c) {
X  #ifdef SIGTSTP
X! 		case ctl('z'):
X  		    deraw();
X  		    (void) kill(getpid(),SIGTSTP);
X
X***************
X*** 668,681 ****
X  		    goraw();
X  		    break;
X  #endif
X! 		case ctl (r):
X! 		case ctl (l):
X  		    FullUpdate++;
X! 		    if (c == ctl (r))
X  			showneed = 1;
X  		    (void) clearok(stdscr,1);
X  		    break;
X! 		case ctl (x):
X  		    FullUpdate++;
X  		    showexpr = 1;
X  		    (void) clearok(stdscr,1);
X--- 675,688 ----
X  		    goraw();
X  		    break;
X  #endif
X! 		case ctl('r'):
X! 		case ctl('l'):
X  		    FullUpdate++;
X! 		    if (c == ctl('r'))
X  			showneed = 1;
X  		    (void) clearok(stdscr,1);
X  		    break;
X! 		case ctl('x'):
X  		    FullUpdate++;
X  		    showexpr = 1;
X  		    (void) clearok(stdscr,1);
X***************
X*** 683,707 ****
X  		default:
X  		    error ("No such command (^%c)", c + 0100);
X  		    break;
X! 		case ctl (b):
X  		    backcol(arg);
X  		    break;
X! 		case ctl (c):
X  		    running = 0;
X  		    break;
X
X! 		case ctl (e):
X
X  		    switch (nmgetch()) {
X! 		    case ctl (p): case 'k':	doend (-1, 0);	break;
X! 		    case ctl (n): case 'j':	doend ( 1, 0);	break;
X! 		    case ctl (b): case 'h':
X! 		    case ctl (h):		doend ( 0,-1);	break;
X! 		    case ctl (f): case 'l':
X! 		    case ctl (i): case ' ':	doend ( 0, 1);	break;
X
X  		    case ESC:
X! 		    case ctl (g):
X  			break;
X
X  		    default:
X--- 690,714 ----
X  		default:
X  		    error ("No such command (^%c)", c + 0100);
X  		    break;
X! 		case ctl('b'):
X  		    backcol(arg);
X  		    break;
X! 		case ctl('c'):
X  		    running = 0;
X  		    break;
X
X! 		case ctl('e'):
X
X  		    switch (nmgetch()) {
X! 		    case ctl('p'): case 'k':	doend (-1, 0);	break;
X! 		    case ctl('n'): case 'j':	doend ( 1, 0);	break;
X! 		    case ctl('b'): case 'h':
X! 		    case ctl('h'):		doend ( 0,-1);	break;
X! 		    case ctl('f'): case 'l':
X! 		    case ctl('i'): case ' ':	doend ( 0, 1);	break;
X
X  		    case ESC:
X! 		    case ctl('g'):
X  			break;
X
X  		    default:
X***************
X*** 711,721 ****
X
X  		    break;
X
X! 		case ctl (f):
X  		    forwcol(arg);
X  		    break;
X! 		case ctl (g):
X! 		case ESC:	/* ctl ([) */
X  		    showrange = 0;
X  		    linelim = -1;
X  		    (void) move (1, 0);
X--- 718,728 ----
X
X  		    break;
X
X! 		case ctl('f'):
X  		    forwcol(arg);
X  		    break;
X! 		case ctl('g'):
X! 		case ESC:	/* ctl('[') */
X  		    showrange = 0;
X  		    linelim = -1;
X  		    (void) move (1, 0);
X***************
X*** 722,728 ****
X  		    (void) clrtoeol ();
X  		    break;
X  		case DEL:
X! 		case ctl (h):
X  		    if (linelim <= 0) {	/* not editing line */
X  			backcol(arg);	/* treat like ^B    */
X  			break;
X--- 729,735 ----
X  		    (void) clrtoeol ();
X  		    break;
X  		case DEL:
X! 		case ctl('h'):
X  		    if (linelim <= 0) {	/* not editing line */
X  			backcol(arg);	/* treat like ^B    */
X  			break;
X***************
X*** 730,736 ****
X  		    while (--arg>=0) if (linelim > 0)
X  			line[--linelim] = 0;
X  		    break;
X! 		case ctl (i): 		/* tab */
X  		    if (linelim <= 0) {	/* not editing line */
X  			forwcol(arg);
X  			break;
X--- 737,743 ----
X  		    while (--arg>=0) if (linelim > 0)
X  			line[--linelim] = 0;
X  		    break;
X! 		case ctl('i'): 		/* tab */
X  		    if (linelim <= 0) {	/* not editing line */
X  			forwcol(arg);
X  			break;
X***************
X*** 747,754 ****
X  		    }
X  		    linelim = strlen (line);
X  		    break;
X! 		case ctl (m):
X! 		case ctl (j):
X  		    showrange = 0;
X  		    if (linelim < 0)
X  			line[linelim = 0] = 0;
X--- 754,761 ----
X  		    }
X  		    linelim = strlen (line);
X  		    break;
X! 		case ctl('m'):
X! 		case ctl('j'):
X  		    showrange = 0;
X  		    if (linelim < 0)
X  			line[linelim = 0] = 0;
X***************
X*** 758,774 ****
X  			linelim = -1;
X  		    }
X  		    break;
X! 		case ctl (n):
X  		    forwrow(arg);
X  		    break;
X! 		case ctl (p):
X  		    backrow(arg);
X  		    break;
X! 		case ctl (q):
X  		    break;	/* ignore flow control */
X! 		case ctl (s):
X  		    break;	/* ignore flow control */
X! 		case ctl (t):
X  		    error(
X  "Toggle:  a:auto  c:cell  e:ext funcs  n:numeric  t:top  x:encrypt  $:pre-scale");
X  		    (void) refresh();
X--- 765,781 ----
X  			linelim = -1;
X  		    }
X  		    break;
X! 		case ctl('n'):
X  		    forwrow(arg);
X  		    break;
X! 		case ctl('p'):
X  		    backrow(arg);
X  		    break;
X! 		case ctl('q'):
X  		    break;	/* ignore flow control */
X! 		case ctl('s'):
X  		    break;	/* ignore flow control */
X! 		case ctl('t'):
X  		    error(
X  "Toggle:  a:auto  c:cell  e:ext funcs  n:numeric  t:top  x:encrypt  $:pre-scale");
X  		    (void) refresh();
X***************
X*** 815,821 ****
X  				    extfunc? "en" : "dis");
X  			    break;
X  			case ESC:
X! 			case ctl (g):
X  			    break;
X  			default:
X  			    error ("Invalid toggle command");
X--- 822,828 ----
X  				    extfunc? "en" : "dis");
X  			    break;
X  			case ESC:
X! 			case ctl('g'):
X  			    break;
X  			default:
X  			    error ("Invalid toggle command");
X***************
X*** 823,842 ****
X  		    FullUpdate++;
X  		    modflg++;
X  		    break;
X! 		case ctl (u):
X  		    narg = arg * 4;
X  		    nedistate = 1;
X  		    break;
X! 		case ctl (v):	/* insert variable name */
X  		    if (linelim > 0) {
X  		    (void) sprintf (line+linelim,"%s", v_name(currow, curcol));
X  			linelim = strlen (line);
X  		    }
X  		    break;
X! 		case ctl (w):	/* insert variable expression */
X  		    if (linelim > 0) editexp(currow,curcol);
X  		    break;
X! 		case ctl (a):	/* insert variable value */
X  		    if (linelim > 0) {
X  			struct ent *p = tbl[currow][curcol];
X
X--- 830,849 ----
X  		    FullUpdate++;
X  		    modflg++;
X  		    break;
X! 		case ctl('u'):
X  		    narg = arg * 4;
X  		    nedistate = 1;
X  		    break;
X! 		case ctl('v'):	/* insert variable name */
X  		    if (linelim > 0) {
X  		    (void) sprintf (line+linelim,"%s", v_name(currow, curcol));
X  			linelim = strlen (line);
X  		    }
X  		    break;
X! 		case ctl('w'):	/* insert variable expression */
X  		    if (linelim > 0) editexp(currow,curcol);
X  		    break;
X! 		case ctl('a'):	/* insert variable value */
X  		    if (linelim > 0) {
X  			struct ent *p = tbl[currow][curcol];
X
X***************
X*** 974,980 ****
X
X  			case '/':
X  			    error (
X!     "Range:  x:erase  v:value  c:copy  f:fill  d:define  s:show  u:undefine");
X  			    (void) refresh();
X
X  			    switch (nmgetch()) {
X--- 981,987 ----
X
X  			case '/':
X  			    error (
X!     "Range:  x:erase  v:value  c:copy  f:fill  d:define  s:show  u:undefine  F:fmt");
X  			    (void) refresh();
X
X  			    switch (nmgetch()) {
X***************
X*** 1031,1039 ****
X  				}
X  				else error("No ranges defined");
X  				break;
X
X  			    case ESC:
X! 			    case ctl (g):
X  				break;
X  			   default:
X  				error("Invalid region command");
X--- 1038,1051 ----
X  				}
X  				else error("No ranges defined");
X  				break;
X+ 			    case 'F':
X+ 			        (void) sprintf(line,"fmt [range \"format\"] ");
X+ 				linelim = strlen(line);
X+ 				startshow();
X+ 			        break;
X
X  			    case ESC:
X! 			    case ctl('g'):
X  				break;
X  			   default:
X  				error("Invalid region command");
X***************
X*** 1062,1068 ****
X
X  				error ("");	/* clear line */
X
X! 				if ( rcqual == ESC || rcqual == ctl(g))
X  				    break;
X
X  				switch (c) {
X--- 1074,1080 ----
X
X  				error ("");	/* clear line */
X
X! 				if ( rcqual == ESC || rcqual == ctl('g'))
X  				    break;
X
X  				switch (c) {
X***************
X*** 1213,1218 ****
X--- 1225,1235 ----
X  					fwidth[curcol],precision[curcol]);
X  			    linelim = strlen (line);
X  			    break;
X+ 			case 'F':
X+ 			    (void) sprintf(line, "fmt [format] %s \"",
X+ 					   v_name(currow, curcol));
X+ 			    linelim = strlen(line);
X+ 			    break;
X  			case 'g':
X  			    (void) sprintf (line, "goto [v] ");
X  			    linelim = strlen (line);
X***************
X*** 1474,1480 ****
X   	if (ch != 'n' && ch != 'N') {
X   	    if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
X   		return (1);
X! 	} else if (ch == ctl (g) || ch == ESC) return(1);
X      } else if (modflg) {
X  	char ch, lin[100];
X
X--- 1491,1497 ----
X   	if (ch != 'n' && ch != 'N') {
X   	    if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
X   		return (1);
X! 	} else if (ch == ctl('g') || ch == ESC) return(1);
X      } else if (modflg) {
X  	char ch, lin[100];
X
X*** sc.doc	Wed Feb 28 12:43:31 1990
X--- /usr/src/uci/usr/public/sc/sc.doc	Fri Jul 21 10:06:54 1989
X***************
X*** 15,21 ****
X  .\" - TPs use default indent except for function names, then 18.
X  .\" - Smallify uppercase strings.
X  .\" - Avoid passive voice and third person.
X! .\" $Revision: 6.1 $
X  .\"
X  .TH PNAME 1
X  .SH NAME
X--- 15,21 ----
X  .\" - TPs use default indent except for function names, then 18.
X  .\" - Smallify uppercase strings.
X  .\" - Avoid passive voice and third person.
X! .\" $Revision: 6.2 $
X  .\"
X  .TH PNAME 1
X  .SH NAME
X***************
X*** 504,510 ****
X--- 504,593 ----
X  .B >
X  Enter a label string into the current cell
X  to be flushed right against the right edge of the cell.
X+ .\" ----------
X  .PD
X+ .TP
X+ .B F
X+ Enter a format string into the current cell.  This format string
X+ overrides the precision specified with the ``f'' command.
X+ The format only applies to numeric values.  The following
X+ characters can be used to build a format string:
X+ .RS
X+ .TP
X+ .BR #
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+ .TP
X+ .BR 0
X+ Digit placeholder.
X+ 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+ .TP
X+ .BR .
X+ Decimal point.
X+ 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+ .TP
X+ .BR %
X+ Percentage.
X+ 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+ .TP
X+ .BR ,
X+ Thousands separator.
X+ 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+ .TP
X+ .BR \\
X+ Quote.
X+ This character causes the next character to be
X+ inserted into the formatted string directly with no
X+ special interpretation.
X+ .TP
X+ .BR E-\ E+\ e-\ e+
X+ Scientific format.
X+ 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+ .TP
X+ .BR ;
X+ Format selector.
X+ 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+ .RE
X+ .IP
X+ Some example formats are integer (``0'' or ``#''),
X+ fixed (``0.00''), percentage (``0%'' or ``0.00%''),
X+ scientific (``0.00E+00''),
X+ and currency (``$#,0.00;($#,0.00)'').
X  .\" ----------
X  .PP
X  Strings you enter must start with ".
X***************
X*** 909,914 ****
X--- 992,1001 ----
X  .TP
X  .B /u
X  Use this command to undefine a previously defined range name.
X+ .TP
X+ .B /F
X+ Use this command to assign a value format string (see the ``F''
X+ cell entry commmand) to a range of cells.
X  .\" ==========
X  .SS "Miscellaneous Commands"
X  .\" ----------
X*** sc.h	Wed Feb 28 12:43:36 1990
X--- /usr/src/uci/usr/public/sc/sc.h	Fri Jul 21 10:05:32 1989
X***************
X*** 6,12 ****
X   *			University of Maryland
X   *		R. Bond  12/86
X   *		More mods by Alan Silverstein, 3-4/88, see list of changes.
X!  *		$Revision: 6.1 $
X   *
X   */
X
X--- 6,12 ----
X   *			University of Maryland
X   *		R. Bond  12/86
X   *		More mods by Alan Silverstein, 3-4/88, see list of changes.
X!  *		$Revision: 6.3 $
X   *
X   */
X
X***************
X*** 53,58 ****
X--- 53,59 ----
X      short flags;
X      short row, col;
X      struct ent *next;
X+     char *format;
X  };
X
X  struct range {
X***************
X*** 138,144 ****
X  #define is_leftflush 0010
X  #define is_deleted   0020
X
X! #define ctl(c) ('c'&037)
X  #define ESC 033
X  #define DEL 0177
X
X--- 139,145 ----
X  #define is_leftflush 0010
X  #define is_deleted   0020
X
X! #define ctl(c) ((c)&037)
X  #define ESC 033
X  #define DEL 0177
X
X*** /dev/null	Wed Feb 28 12:50:55 1990
X--- /usr/src/uci/usr/public/sc/format.c	Fri Jul 21 13:29:08 1989
X***************
X*** 0 ****
X--- 1,461 ----
X+ /*****************************************************************************
X+  *
X+  * Mark Nagel <nagel@ics.uci.edu>
X+  * 20 July 1989
X+  *
X+  * $Revision: 6.3 $
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+
X+ #define bool	int
X+ #define true	1
X+ #define false	0
X+ #define EOS	'\0'
X+ #define MAXBUF	256
X+
X+ extern char
X+   *strcpy();
X+
X+ static char
X+   *fmt_int(),
X+   *fmt_frac(),
X+   *fmt_exp();
X+
X+ static void
X+   reverse();
X+
X+ /*****************************************************************************/
X+
X+ bool
X+ format(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, *tmpfmt;
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+   char *mantissa;
X+   char *fraction = NULL;
X+   int zero_pad = 0;
X+
X+   if (fmt == NULL)
X+     return;
X+
X+   fmt = tmpfmt = strcpy((char *) xmalloc(strlen(fmt) + 1), fmt);
X+   mantissa = (char *) xmalloc(buflen + 1);
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 new
X+    * malloc'ed format string
X+    */
X+   tmp = (char *) xmalloc(strlen(fmt) + 1);
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+   xfree(tmpfmt);
X+   fmt = tmp;
X+
X+   /*
X+    * extract the exponent from the format if present
X+    */
X+   for (cp = fmt; *cp != EOS; cp++)
X+   {
X+     if (*cp == '\\')
X+     {
X+       cp++;
X+     }
X+     else if (*cp == 'e' || *cp == 'E')
X+     {
X+       if (cp[1] == '+' || cp[1] == '-')
X+       {
X+         tmp = (char *) xmalloc(strlen(cp) + 1);
X+ 	exponent = strcpy(tmp, cp);
X+ 	*cp = EOS;
X+ 	exp_val = 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+ 	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+   if (val < 0.0)
X+   {
X+     negative = true;
X+     val = -val;
X+   }
X+   sprintf(prtfmt, "%%.%dlf", width);
X+   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+     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+     ci = strcpy((char *)xmalloc((len_ci = strlen(ci)) + 1), ci);
X+     cf = (fraction) ? fmt_frac(fraction, decimal) : "";
X+     cf = strcpy((char *)xmalloc((len_cf = strlen(cf)) + 1), cf);
X+     ce = (exponent) ? fmt_exp(exp_val, exponent) : "";
X+     ce = strcpy((char *)xmalloc((len_ce = strlen(ce)) + 1), ce);
X+     if (len_ci + len_cf + len_ce < buflen)
X+     {
X+       sprintf(buf, "%s%s%s", ci, cf, ce);
X+       ret = true;
X+     }
X+
X+     /*
X+      * free up malloc'ed memory
X+      */
X+     xfree(mantissa);
X+     xfree(fmt);
X+     if (exponent) xfree(exponent);
X+     xfree(ci);
X+     xfree(cf);
X+     xfree(ce);
X+
X+     return (ret);
X+   }
X+ }
X+
X+ /*****************************************************************************/
X+
X+ static char *
X+ fmt_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+
X+ static char *
X+ fmt_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+
X+ static char *
X+ fmt_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+   *bufptr = EOS;
X+
X+   if (val < 0)
X+   {
X+     val = -val;
X+     negative = true;
X+   }
X+   sprintf(valbuf, "%d", val);
X+
X+   strcat(buf, fmt_int(valbuf, fmt, false, negative));
X+   return (buf);
X+ }
X+
X+ /*****************************************************************************/
X+
X+ static void
X+ reverse(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+
END_OF_FILE
if test 45373 -ne `wc -c <'sc.diffs'`; then
    echo shar: \"'sc.diffs'\" unpacked with wrong size!
fi
# end of 'sc.diffs'
fi
echo shar: End of shell archive.
exit 0
--
Mark Nagel
UC Irvine Department of ICS   +----------------------------------------+
ARPA: nagel@ics.uci.edu       | radiation: smog with an attitude       |
UUCP: ucbvax!ucivax!nagel     +----------------------------------------+