v23i024: The SC Spreadsheet, release 6.8, Part04/06

Rich Salz rsalz at bbn.com
Wed Sep 5 05:21:48 AEST 1990


Submitted-by: Jeff Buhrt <sawmill!buhrt>
Posting-number: Volume 23, Issue 24
Archive-name: sc6.8/part04

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# 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:  cmds.c lex.c psc.c xmalloc.c
# Wrapped by rsalz at litchi.bbn.com on Fri Jul 13 15:24:21 1990
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 4 (of 6)."'
if test -f 'cmds.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cmds.c'\"
else
  echo shar: Extracting \"'cmds.c'\" \(30867 characters\)
  sed "s/^X//" >'cmds.c' <<'END_OF_FILE'
X/*	SC	A Spreadsheet Calculator
X *		Command routines
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 *
X *		$Revision: 6.8 $
X */
X
X#include <curses.h>
X#if defined(BSD42) || defined(BSD43)
X#include <sys/file.h>
X#else
X#include <fcntl.h>
X#endif
X#include "sc.h"
X#include <signal.h>
X#include <errno.h>
X
X#ifdef BSD42
X#include <strings.h>
X#else
X#ifndef SYSIII
X#include <string.h>
X#endif
X#endif
X
X#ifdef SYSV3
Xextern void exit();
X#else
Xextern int exit();
X#endif
X
Xextern	int	errno;
X
X#define DEFCOLDELIM ':'
X
Xvoid
Xduprow()
X{
X    if (currow >= maxrows - 1 || maxrow >= maxrows - 1) {
X	if (!growtbl(GROWROW, 0, 0))
X		return;
X    }
X    modflg++;
X    currow++;
X    openrow (currow);
X    for (curcol = 0; curcol <= maxcol; curcol++) {
X	register struct ent *p = *ATBL(tbl, currow - 1, curcol);
X	if (p) {
X	    register struct ent *n;
X	    n = lookat (currow, curcol);
X	    (void)copyent ( n, p, 1, 0);
X	}
X    }
X    for (curcol = 0; curcol <= maxcol; curcol++) {
X	register struct ent *p = *ATBL(tbl, currow, curcol);
X	if (p && (p -> flags & is_valid) && !p -> expr)
X	    break;
X    }
X    if (curcol > maxcol)
X	curcol = 0;
X}
X
Xvoid
Xdupcol() 
X{
X    if (curcol >= maxcols - 1 || maxcol >= maxcols - 1) {
X	if (!growtbl(GROWCOL, 0, 0))
X		return;
X    }
X    modflg++;
X    curcol++;
X    opencol (curcol, 1);
X    for (currow = 0; currow <= maxrow; currow++) {
X	register struct ent *p = *ATBL(tbl, currow, curcol - 1);
X	if (p) {
X	    register struct ent *n;
X	    n = lookat (currow, curcol);
X	    copyent ( n, p, 0, 1);
X	}
X    }
X    for (currow = 0; currow <= maxrow; currow++) {
X	register struct ent *p = *ATBL(tbl, currow, curcol);
X	if (p && (p -> flags & is_valid) && !p -> expr)
X	    break;
X    }
X    if (currow > maxrow)
X	currow = 0;
X}
X
Xvoid
Xinsertrow(arg)
Xregister int arg;
X{
X    while (--arg>=0) openrow (currow);
X}
X
Xvoid
Xdeleterow(arg)
Xregister int arg;
X{
X    flush_saved();
X    erase_area(currow, 0, currow + arg - 1, maxcol);
X    currow += arg;
X    while (--arg>=0) closerow (--currow);
X    sync_refs();
X}
X
Xvoid
Xrowvalueize(arg)
Xregister int arg;
X{
X    valueize_area(currow, 0, currow + arg - 1, maxcol);
X}
X
Xvoid
Xcolvalueize(arg)
Xregister int arg;
X{
X    valueize_area(0, curcol, maxrow, curcol + arg - 1);
X}
X
Xvoid
Xerase_area(sr, sc, er, ec)
Xint sr, sc, er, ec;
X{
X    register int r, c;
X    register struct ent **pp;
X
X    if (sr > er) {
X	r = sr; sr = er; er= r;	
X    }
X
X    if (sc > ec) {
X	c = sc; sc = ec; ec= c;	
X    }
X
X    if (sr < 0)
X	sr = 0; 
X    if (sc < 0)
X	sc = 0;
X    checkbounds(&er, &ec);
X
X    for (r = sr; r <= er; r++) {
X	for (c = sc; c <= ec; c++) {
X	    pp = ATBL(tbl, r, c);
X	    if (*pp) {
X		free_ent(*pp);
X		*pp = (struct ent *)0;
X	    }
X	}
X    }
X}
X
Xvoid
Xvalueize_area(sr, sc, er, ec)
Xint sr, sc, er, ec;
X{
X    register int r, c;
X    register struct ent *p;
X
X    if (sr > er) {
X	r = sr; sr = er; er= r;	
X    }
X
X    if (sc > ec) {
X	c = sc; sc = ec; ec= c;	
X    }
X
X    if (sr < 0)
X	sr = 0; 
X    if (sc < 0)
X	sc = 0;
X    checkbounds(&er, &ec);
X
X    for (r = sr; r <= er; r++) {
X	for (c = sc; c <= ec; c++) {
X	    p = *ATBL(tbl, r, c);
X	    if (p && p->expr) {
X		efree(p, p->expr);
X		p->expr = (struct enode *)0;
X		p->flags &= ~is_strexpr;
X	    }
X	}
X    }
X
X}
X
Xvoid
Xpullcells(to_insert)
Xint to_insert;
X{
X    register struct ent *p, *n;
X    register int deltar, deltac;
X    int minrow, mincol;
X    int mxrow, mxcol;
X    int numrows, numcols;
X
X    if (! to_fix)
X    {
X	error ("No data to pull");
X	return;
X    }
X
X    minrow = maxrows; 
X    mincol = maxcols;
X    mxrow = 0;
X    mxcol = 0;
X
X    for (p = to_fix; p; p = p->next) {
X	if (p->row < minrow)
X	    minrow = p->row;
X	if (p->row > mxrow)
X	    mxrow = p->row;
X	if (p->col < mincol)
X	    mincol = p->col;
X	if (p->col > mxcol)
X	    mxcol = p->col;
X    }
X
X    numrows = mxrow - minrow + 1;
X    numcols = mxcol - mincol + 1;
X    deltar = currow - minrow;
X    deltac = curcol - mincol;
X
X    if (to_insert == 'r') {
X	insertrow(numrows);
X	deltac = 0;
X    } else if (to_insert == 'c') {
X	opencol(curcol, numcols);
X	deltar = 0;
X    }
X
X    FullUpdate++;
X    modflg++;
X
X    for (p = to_fix; p; p = p->next) {
X	n = lookat (p->row + deltar, p->col + deltac);
X	(void) clearent(n);
X	copyent( n, p, deltar, deltac);
X	n -> flags = p -> flags & ~is_deleted;
X    }
X}
X
Xvoid
Xcolshow_op()
X{
X    register int i,j;
X    for (i=0; i<maxcols; i++)
X	if (col_hidden[i]) 
X	    break;
X    for(j=i; j<maxcols; j++)
X	if (!col_hidden[j])
X	    break;
X    j--;
X    if (i>=maxcols)
X	error ("No hidden columns to show");
X    else {
X	(void) sprintf(line,"show %s:", coltoa(i));
X	(void) sprintf(line + strlen(line),"%s",coltoa(j));
X	linelim = strlen (line);
X    }
X}
X
Xvoid
Xrowshow_op()
X{
X    register int i,j;
X    for (i=0; i<maxrows; i++)
X	if (row_hidden[i]) 
X	    break;
X    for(j=i; j<maxrows; j++)
X	if (!row_hidden[j]) {
X	    break;
X	}
X    j--;
X
X    if (i>=maxrows)
X	error ("No hidden rows to show");
X    else {
X	(void) sprintf(line,"show %d:%d", i, j);
X        linelim = strlen (line);
X    }
X}
X
X/*
X * Given a row/column command letter, emit a small menu, then read a qualifier
X * character for a row/column command and convert it to 'r' (row), 'c'
X * (column), or 0 (unknown).  If ch is 'p', an extra qualifier 'm' is allowed.
X */
X
Xint
Xget_rcqual (ch)
X    int ch;
X{
X    error ("%sow/column:  r: row  c: column%s",
X
X	    (ch == 'i') ? "Insert r" :
X	    (ch == 'a') ? "Append r" :
X	    (ch == 'd') ? "Delete r" :
X	    (ch == 'p') ? "Pull r" :
X	    (ch == 'v') ? "Values r" :
X	    (ch == 'z') ? "Zap r" :
X	    (ch == 's') ? "Show r" : "R",
X
X	    (ch == 'p') ? "  m: merge" : "");
X
X    (void) refresh();
X
X    switch (nmgetch())
X    {
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    /*NOTREACHED*/
X}
X
Xvoid
Xopenrow (rs)
Xint	rs;
X{
X    register	r, c;
X    struct ent	**tmprow, **pp;
X
X    if (rs > maxrow) maxrow = rs;
X    if (maxrow >= maxrows - 1 || rs > maxrows - 1) {
X	if (!growtbl(GROWROW, rs, 0))
X		return;
X    }
X	/*
X	 * save the last active row+1, shift the rows downward, put the last
X	 * row in place of the first
X	 */
X    tmprow = tbl[++maxrow];
X    for (r = maxrow; r > rs; r--) {
X	row_hidden[r] = row_hidden[r-1];
X	tbl[r] = tbl[r-1];
X	pp = ATBL(tbl, r, 0);
X	for (c = 0; c < maxcols; c++, pp++)
X		if (*pp)
X			(*pp)->row = r;
X    }
X    tbl[r] = tmprow;	/* the last row was never used.... */
X    FullUpdate++;
X    modflg++;
X}
X
Xvoid
Xcloserow (r)
Xregister r;
X{
X    register struct ent **pp;
X    register c;
X    struct ent	**tmprow;
X
X    if (r > maxrow) return;
X
X    /* save the row and empty it out */
X    tmprow = tbl[r];
X    pp = ATBL(tbl, r, 0);
X    for (c=maxcol+1; --c>=0; pp++) {
X	if (*pp)
X	{	free_ent(*pp);
X		*pp = (struct ent *)0;
X	}
X    }
X
X    /* move the rows, put the deleted row at the end */
X    for (; r < maxrows - 1; r++) {
X	row_hidden[r] = row_hidden[r+1];
X	tbl[r] = tbl[r+1];
X	pp = ATBL(tbl, r, 0);
X	for (c = 0; c < maxcols; c++, pp++)
X		if (*pp)
X			(*pp)->row = r;
X    }
X    tbl[r] = tmprow;
X
X    maxrow--;
X    FullUpdate++;
X    modflg++;
X}
X
Xvoid
Xopencol (cs, numcol)
Xint	cs;
Xint	numcol;
X{
X    register r;
X    register struct ent **pp;
X    register c;
X    register lim = maxcol-cs+1;
X    int i;
X
X    if (cs > maxcol)
X	maxcol = cs;
X    maxcol += numcol;
X
X    if ((maxcol >= maxcols - 1) && !growtbl(GROWCOL, 0, maxcol))
X		return;
X
X    for (i = maxcol; i > cs; i--) {
X	fwidth[i] = fwidth[i-numcol];
X	precision[i] = precision[i-numcol];
X	col_hidden[i] = col_hidden[i-numcol];
X    }
X    for (c = cs; c - cs < numcol; c++)
X    {	fwidth[c] = DEFWIDTH;
X	precision[c] =  DEFPREC;
X    }
X	
X    for (r=0; r<=maxrow; r++) {
X	pp = ATBL(tbl, r, maxcol);
X	for (c=lim; --c>=0; pp--)
X	    if (pp[0] = pp[-numcol])
X		pp[0]->col += numcol;
X
X	pp = ATBL(tbl, r, cs);
X	for (c = cs; c - cs < numcol; c++, pp++)
X		*pp = (struct ent *)0;
X    }
X    FullUpdate++;
X    modflg++;
X}
X
Xvoid
Xclosecol (cs, numcol)
Xint cs;
Xint	numcol;
X{
X    register r;
X    register struct ent **pp;
X    register struct ent *q;
X    register c;
X    register lim = maxcol-cs;
X    int i;
X    char buf[50];
X
X    if (lim - numcol < -1)
X    {	sprintf(buf, "Can't delete %d column%s %d columns left", numcol,
X			(numcol > 1 ? "s," : ","), lim+1);
X	error(buf);
X	return;
X    }
X    flush_saved();
X    erase_area(0, curcol, maxrow, curcol + numcol - 1);
X    sync_refs();
X
X    /* clear then copy the block left */
X    lim = maxcols - numcol - 1;
X    for (r=0; r<=maxrow; r++) {
X	for (c = cs; c - cs < numcol; c++)
X		if (q = *ATBL(tbl, r, c))
X			free_ent(q);
X
X	pp = ATBL(tbl, r, cs);
X	for (c=cs; c <= lim; c++, pp++)
X	{   if (c > lim)
X		*pp = (struct ent *)0;
X	    else
X	    if (pp[0] = pp[numcol])
X		pp[0]->col -= numcol;
X	}
X
X	c = numcol;
X	for (; --c >= 0; pp++)		
X		*pp = (struct ent *)0;
X    }
X
X    for (i = cs; i < maxcols - numcol - 1; i++) {
X	fwidth[i] = fwidth[i+numcol];
X	precision[i] = precision[i+numcol];
X	col_hidden[i] = col_hidden[i+numcol];
X    }
X    for (; i < maxcols - 1; i++) {
X	fwidth[i] = DEFWIDTH;
X	precision[i] = DEFPREC;
X	col_hidden[i] = 0;
X    }
X
X    maxcol -= numcol;
X    FullUpdate++;
X    modflg++;
X}
X
Xvoid
Xdoend(rowinc, colinc)
Xint rowinc, colinc;
X{
X    register struct ent *p;
X    int r, c;
X
X    if (VALID_CELL(p, currow, curcol)) {
X	r = currow + rowinc;
X	c = curcol + colinc;
X	if (r >= 0 && r < maxrows && 
X	    c >= 0 && c < maxcols &&
X	    !VALID_CELL(p, r, c)) {
X		currow = r;
X		curcol = c;
X	}
X    }
X
X    if (!VALID_CELL(p, currow, curcol)) {
X        switch (rowinc) {
X        case -1:
X	    while (!VALID_CELL(p, currow, curcol) && currow > 0)
X		currow--;
X	    break;
X        case  1:
X	    while (!VALID_CELL(p, currow, curcol) && currow < maxrows-1)
X		currow++;
X	    break;
X        case  0:
X            switch (colinc) {
X 	    case -1:
X	        while (!VALID_CELL(p, currow, curcol) && curcol > 0)
X		    curcol--;
X	        break;
X 	    case  1:
X	        while (!VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
X		    curcol++;
X	        break;
X	    }
X            break;
X        }
X
X	error ("");	/* clear line */
X	return;
X    }
X
X    switch (rowinc) {
X    case -1:
X	while (VALID_CELL(p, currow, curcol) && currow > 0)
X	    currow--;
X	break;
X    case  1:
X	while (VALID_CELL(p, currow, curcol) && currow < maxrows-1)
X	    currow++;
X	break;
X    case  0:
X	switch (colinc) {
X	case -1:
X	    while (VALID_CELL(p, currow, curcol) && curcol > 0)
X		curcol--;
X	    break;
X	case  1:
X	    while (VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
X		curcol++;
X	    break;
X	}
X	break;
X    }
X    if (!VALID_CELL(p, currow, curcol)) {
X        currow -= rowinc;
X        curcol -= colinc;
X    }
X}
X
Xvoid
Xdoformat(c1,c2,w,p)
Xint c1,c2,w,p;
X{
X    register int i;
X
X    if (w > COLS - RESCOL - 2) {
X	error("Format too large - Maximum = %d", COLS - RESCOL - 2);
X	w = COLS-RESCOL-2;
X    }
X
X    if (p > w) {
X	error("Precision too large");
X	p = w;
X    }
X
X    for(i = c1; i<=c2; i++)
X	fwidth[i] = w, precision[i] = p;
X
X    FullUpdate++;
X    modflg++;
X}
X
Xvoid
Xprint_options(f)
XFILE *f;
X{
X    if(
X       autocalc &&
X       propagation == 10 &&
X       calc_order == BYROWS &&
X       !numeric &&
X       prescale == 1.0 &&
X       !extfunc &&
X       showcell &&
X       showtop &&
X       tbl_style == 0
X      )
X		return;		/* No reason to do this */
X
X    (void) fprintf(f, "set");
X    if(!autocalc) 
X	(void) fprintf(f," !autocalc");
X    if(propagation != 10)
X	(void) fprintf(f, " iterations = %d", propagation);
X    if(calc_order != BYROWS )
X	(void) fprintf(f, " bycols");
X    if (numeric)
X	(void) fprintf(f, " numeric");
X    if (prescale != 1.0)
X	(void) fprintf(f, " prescale");
X    if (extfunc)
X	(void) fprintf(f, " extfun");
X    if (!showcell)
X	(void) fprintf(f, " !cellcur");
X    if (!showtop)
X	(void) fprintf(f, " !toprow");
X    if (tbl_style)
X	(void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" :
X					tbl_style == LATEX ? "latex" :
X					tbl_style == TEX ? "tex" : "0" );
X    (void) fprintf(f, "\n");
X}
X
Xvoid
Xprintfile (fname, r0, c0, rn, cn)
Xchar *fname;
Xint r0, c0, rn, cn;
X{
X    FILE *f;
X    char pline[FBUFLEN];
X    int plinelim;
X    int pid;
X    int fieldlen, nextcol;
X    register row, col;
X    register struct ent **pp;
X
X    if ((strcmp(fname, curfile) == 0) &&
X	!yn_ask("Confirm that you want to destroy the data base: (y,n)"))
X	return;
X
X    if ((f = openout(fname, &pid)) == (FILE *)0)
X    {	error ("Can't create file \"%s\"", fname);
X	return;
X    }
X    for (row=r0;row<=rn; row++) {
X	register c = 0;
X
X	if (row_hidden[row])
X	    continue;
X
X	pline[plinelim=0] = '\0';
X	for (pp = ATBL(tbl, row, col=c0); col<=cn;
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	    if (*pp) {
X		char *s;
X
X		while (plinelim<c) pline[plinelim++] = ' ';
X		plinelim = c;
X		if ((*pp)->flags&is_valid) {
X		    (void)sprintf (pline+plinelim,"%*.*f",fwidth[col],
X		                                precision[col], (*pp)->v);
X		    plinelim += strlen (pline+plinelim);
X		}
X		if (s = (*pp)->label) {
X		    int slen;
X		    char *start, *last;
X		    register char *fp;
X		    struct ent *nc;
X
X		    /* Figure out if the label slops over to a blank field */
X		    slen = strlen(s);
X		    while (slen > fieldlen && nextcol <= cn &&
X			    !((nc = lookat(row,nextcol))->flags & is_valid) &&
X			    !(nc->label)) {
X			
X	                if (!col_hidden[nextcol])
X		 	    fieldlen += fwidth[nextcol];
X
X			nextcol++;
X		    }
X		    if (slen > fieldlen)
X			slen = fieldlen;
X		    
X		    /* Now justify and print */
X		    start = (*pp)->flags & is_leftflush ? pline + c
X					: pline + c + fieldlen - slen;
X		    last = pline + c + fieldlen;
X		    fp = plinelim < c ? pline + plinelim : pline + c;
X		    while (fp < start)
X			*fp++ = ' ';
X		    while (slen--)
X			*fp++ = *s++;
X		    if (!((*pp)->flags & is_valid) || fieldlen != fwidth[col])
X			while(fp < last)
X			    *fp++ = ' ';
X		    if (plinelim < fp - pline)
X			plinelim = fp - pline;
X		}
X	    }
X	}
X	pline[plinelim++] = '\n';
X	pline[plinelim] = '\0';
X	(void) fputs (pline, f);
X    }
X
X    closeout(f, pid);
X}
X
Xvoid
Xtblprintfile (fname, r0, c0, rn, cn)
Xchar *fname;
Xint r0, c0, rn, cn;
X{
X    FILE *f;
X    int pid;
X    register row, col;
X    register struct ent **pp;
X    char coldelim = DEFCOLDELIM;
X
X    if ((strcmp(fname, curfile) == 0) &&
X	!yn_ask("Confirm that you want to destroy the data base: (y,n)"))
X	    return;
X
X    if ((f = openout(fname, &pid)) == (FILE *)0)
X    {	error ("Can't create file \"%s\"", fname);
X	return;
X    }
X
X    if ( tbl_style == TBL ) {
X	fprintf(f,".\\\" ** %s spreadsheet output \n.TS\n",progname);
X	fprintf(f,"tab(%c);\n",coldelim);
X	for (col=c0;col<=cn; col++) fprintf(f," n");
X	fprintf(f, ".\n");
X	}
X    else if ( tbl_style == LATEX ) {
X	fprintf(f,"%% ** %s spreadsheet output\n\\begin{tabular}{",progname);
X	for (col=c0;col<=cn; col++) fprintf(f,"c");
X	fprintf(f, "}\n");
X	coldelim = '&';
X	}
X    else if ( tbl_style == TEX ) {
X	fprintf(f,"{\t%% ** %s spreadsheet output\n\\settabs %d \\columns\n",
X		progname, cn-c0+1);
X	coldelim = '&';
X	}
X
X    for (row=r0; row<=rn; row++) {
X	if ( tbl_style == TEX )
X	    (void) fprintf (f, "\\+");
X	
X	for (pp = ATBL(tbl, row, col=c0); col<=cn; col++, pp++) {
X	    if (*pp) {
X		char *s;
X		if ((*pp)->flags&is_valid) {
X		    (void) fprintf (f,"%.*f",precision[col],
X				(*pp)->v);
X		}
X		if (s = (*pp)->label) {
X	            (void) fprintf (f,"%s",s);
X		}
X	    }
X	    if ( col < cn )
X		(void) fprintf(f,"%c",coldelim);
X	}
X	if ( tbl_style == LATEX ) {
X	    if ( row < rn ) (void) fprintf (f, "\\\\");
X	    }
X	else if ( tbl_style == TEX ) {
X	    (void) fprintf (f, "\\cr");
X	    }
X	(void) fprintf (f,"\n");
X    }
X
X    if ( tbl_style == TBL )
X    (void) fprintf (f,".TE\n.\\\" ** end of %s spreadsheet output\n", progname);
X    else if ( tbl_style == LATEX )
X    (void) fprintf (f,"\\end{tabular}\n%% ** end of %s spreadsheet output\n", progname);
X    else if ( tbl_style == TEX )
X    (void) fprintf (f,"}\n%% ** end of %s spreadsheet output\n", progname);
X
X    closeout(f, pid);
X}
X
Xstruct enode *
Xcopye (e, Rdelta, Cdelta)
Xregister struct enode *e;
Xint Rdelta, Cdelta;
X{
X    register struct enode *ret;
X
X    if (e == (struct enode *)0) {
X        ret = (struct enode *)0;
X    } else if (e->op & REDUCE) {
X	int newrow, newcol;
X	ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
X	ret->op = e->op;
X	newrow=e->e.r.left.vf & FIX_ROW ? e->e.r.left.vp->row :
X					  e->e.r.left.vp->row+Rdelta;
X	newcol=e->e.r.left.vf & FIX_COL ? e->e.r.left.vp->col :
X					  e->e.r.left.vp->col+Cdelta;
X	ret->e.r.left.vp = lookat (newrow, newcol);
X	ret->e.r.left.vf = e->e.r.left.vf;
X	newrow=e->e.r.right.vf & FIX_ROW ? e->e.r.right.vp->row :
X					   e->e.r.right.vp->row+Rdelta;
X	newcol=e->e.r.right.vf & FIX_COL ? e->e.r.right.vp->col :
X					   e->e.r.right.vp->col+Cdelta;
X	ret->e.r.right.vp = lookat (newrow, newcol);
X	ret->e.r.right.vf = e->e.r.right.vf;
X    } else {
X	ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
X	ret->op = e->op;
X	switch (ret->op) {
X	case 'v':
X		{
X		    int newrow, newcol;
X		    newrow=e->e.v.vf & FIX_ROW ? e->e.v.vp->row :
X						 e->e.v.vp->row+Rdelta;
X		    newcol=e->e.v.vf & FIX_COL ? e->e.v.vp->col :
X						 e->e.v.vp->col+Cdelta;
X		    ret->e.v.vp = lookat (newrow, newcol);
X		    ret->e.v.vf = e->e.v.vf;
X		    break;
X		}
X	case 'k':
X		ret->e.k = e->e.k;
X		break;
X	case 'f':
X		ret->e.o.right = copye (e->e.o.right,0,0);
X		ret->e.o.left = (struct enode *)0;
X 		break;
X	case '$':
X		ret->e.s = xmalloc((unsigned) strlen(e->e.s)+1);
X		(void) strcpy(ret->e.s, e->e.s);
X		break;
X	default:
X		ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
X		ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
X		break;
X	}
X    }
X    return ret;
X}
X
X/*
X * sync_refs and syncref are used to remove references to
X * deleted struct ents.  Note that the deleted structure must still
X * be hanging around before the call, but not referenced by an entry
X * in tbl.  Thus the free_ent, fix_ent calls in sc.c
X */
Xvoid
Xsync_refs ()
X{
X    register i,j;
X    register struct ent *p;
X    sync_ranges();
X    for (i=0; i<=maxrow; i++)
X	for (j=0; j<=maxcol; j++)
X	    if ((p = *ATBL(tbl, i, j)) && p->expr)
X		syncref(p->expr);
X}
X
Xvoid
Xsyncref(e)
Xregister struct enode *e;
X{
X    if (e == (struct enode *)0)
X	return;
X    else if (e->op & REDUCE) {
X 	e->e.r.right.vp = lookat(e->e.r.right.vp->row, e->e.r.right.vp->col);
X 	e->e.r.left.vp = lookat(e->e.r.left.vp->row, e->e.r.left.vp->col);
X    } else {
X	switch (e->op) {
X	case 'v':
X		e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col);
X		break;
X	case 'k':
X		break;
X	case '$':
X		break;
X	default:
X		syncref(e->e.o.right);
X		syncref(e->e.o.left);
X		break;
X	}
X    }
X}
X
Xvoid
Xhiderow(arg)
Xint arg;
X{
X    register int r1;
X    register int r2;
X
X    r1 = currow;
X    r2 = r1 + arg - 1;
X    if (r1 < 0 || r1 > r2) {
X	error ("Invalid range");
X	return;
X    }
X    if (r2 >= maxrows-1)
X    {	if (!growtbl(GROWROW, arg+1, 0))
X	{	error("You can't hide the last row");
X		return;
X	}
X    }
X    FullUpdate++;
X    modflg++;
X    while (r1 <= r2)
X	row_hidden[r1++] = 1;
X}
X
Xvoid
Xhidecol(arg)
Xint arg;
X{
X    register int c1;
X    register int c2;
X
X    c1 = curcol;
X    c2 = c1 + arg - 1;
X    if (c1 < 0 || c1 > c2) {
X	error ("Invalid range");
X	return;
X    }
X    if (c2 >= maxcols-1)
X    {	if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1))
X	{	error("You can't hide the last col");
X		return;
X	}
X    }
X    FullUpdate++;
X    modflg++;
X    while (c1 <= c2)
X	col_hidden[c1++] = 1;
X}
X
Xvoid
Xshowrow(r1, r2)
Xint r1, r2;
X{
X    if (r1 < 0 || r1 > r2) {
X	error ("Invalid range");
X	return;
X    }
X    if (r2 > maxrows-1) {
X	r2 = maxrows-1;
X    }
X    FullUpdate++;
X    modflg++;
X    while (r1 <= r2)
X	row_hidden[r1++] = 0;
X}
X
Xvoid
Xshowcol(c1, c2)
Xint c1, c2;
X{
X    if (c1 < 0 || c1 > c2) {
X	error ("Invalid range");
X	return;
X    }
X    if (c2 > maxcols-1) {
X	c2 = maxcols-1;
X    }
X    FullUpdate++;
X    modflg++;
X    while (c1 <= c2)
X	col_hidden[c1++] = 0;
X}
X
X/* Open the output file, setting up a pipe if needed */
X
XFILE *
Xopenout(fname, rpid)
Xchar *fname;
Xint *rpid;
X{
X    int pipefd[2];
X    int pid;
X    FILE *f;
X    char *efname;
X
X    while (*fname && (*fname == ' '))  /* Skip leading blanks */
X	fname++;
X
X    if (*fname != '|') {		/* Open file if not pipe */
X	*rpid = 0;
X	
X	efname = findhome(fname);
X#ifdef DOBACKUPS
X	if (!backup_file(efname) &&
X	    (yn_ask("Could not create backup copy, Save anyhow?: (y,n)") != 1))
X		return(0);
X#endif
X	return(fopen(efname, "w"));
X    }
X
X    fname++;				/* Skip | */
X    if ( pipe (pipefd) < 0) {
X	error("Can't make pipe to child");
X	*rpid = 0;
X	return(0);
X    }
X
X    deraw();
X#ifdef VMS
X    fprintf(stderr, "No son tasks available yet under VMS--sorry\n");
X#else /* VMS */
X
X    if ((pid=fork()) == 0)			  /* if child  */
X    {
X	(void) close (0);			  /* close stdin */
X	(void) close (pipefd[1]);
X	(void) dup (pipefd[0]);		  /* connect to pipe input */
X	(void) signal (SIGINT, SIG_DFL);	  /* reset */
X	(void) execl ("/bin/sh", "sh", "-c", fname, 0);
X	exit (-127);
X    }
X    else				  /* else parent */
X    {
X	*rpid = pid;
X	if ((f = fdopen (pipefd[1], "w")) == (FILE *)0)
X	{
X	    (void) kill (pid, -9);
X	    error ("Can't fdopen output");
X	    (void) close (pipefd[1]);
X	    *rpid = 0;
X	    return(0);
X	}
X    }
X#endif /* VMS */
X    return(f);
X}
X
Xvoid
Xcloseout(f, pid)
XFILE *f;
Xint pid;
X{
X    int temp;
X
X    (void) fclose (f);
X    if (pid) {
X         while (pid != wait(&temp)) /**/;
X	 (void) printf("Press RETURN to continue ");
X	 (void) fflush(stdout);
X	 (void) nmgetch();
X	 goraw();
X    }
X}
X
Xvoid
Xcopyent(n,p,dr,dc)
X	    register struct ent *n, *p;
X	    int dr, dc;
X{
X    if(!n||!p){error("internal error");return;}
X    n -> v = p -> v;
X    n -> flags = p -> flags;
X    n -> expr = copye (p -> expr, dr, dc);
X    n -> label = (char *)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
Xvoid
Xwrite_fd (f, r0, c0, rn, cn)
Xregister FILE *f;
Xint r0, c0, rn, cn;
X{
X    register struct ent **pp;
X    register r, c;
X
X    (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
X    (void) fprintf (f, "Calculator.\n");
X    (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
X    print_options(f);
X    for (c=0; c<maxcols; c++)
X	if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
X	    (void) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
X    for (c=c0; c<cn; c++) {
X        if (col_hidden[c]) {
X            (void) fprintf(f, "hide %s\n", coltoa(c));
X        }
X    }
X    for (r=r0; r<=rn; r++) {
X	if (row_hidden[r]) {
X	    (void) fprintf(f, "hide %d\n", r);
X	}
X    }
X
X    write_range(f);
X
X    if (mdir) 
X	    (void) fprintf(f, "mdir \"%s\"\n", mdir);
X    for (r=r0; r<=rn; r++) {
X	pp = ATBL(tbl, r, c0);
X	for (c=c0; c<=cn; c++, pp++)
X	    if (*pp) {
X		if ((*pp)->label) {
X		    edits(r,c);
X		    (void) fprintf(f, "%s\n",line);
X		}
X		if ((*pp)->flags&is_valid) {
X		    editv (r, c);
X		    (void) fprintf (f, "%s\n",line);
X		}
X	    }
X    }
X}
X
Xint
Xwritefile (fname, r0, c0, rn, cn)
Xchar *fname;
Xint r0, c0, rn, cn;
X{
X    register FILE *f;
X    char save[PATHLEN];
X    int pid;
X
X#ifndef VMS
X    if (Crypt) {
X	return (cwritefile(fname, r0, c0, rn, cn));
X    }
X#endif /* VMS */
X
X    if (*fname == '\0') fname = curfile;
X
X    (void) strcpy(save,fname);
X
X    if ((f= openout(fname, &pid)) == (FILE *)0)
X    {	error ("Can't create file \"%s\"", fname);
X	return (-1);
X    }
X
X    write_fd(f, r0, c0, rn, cn);
X    
X    closeout(f, pid);
X
X    if (!pid) {
X        (void) strcpy(curfile, save);
X        modflg = 0;
X        error("File \"%s\" written.",curfile);
X    }
X
X    return (0);
X}
X
Xvoid
Xreadfile (fname,eraseflg)
Xchar *fname;
Xint eraseflg;
X{
X    register FILE *f;
X    char save[PATHLEN];
X
X    if (*fname == '*' && mdir) { 
X       (void) strcpy(save, mdir);
X       *fname = '/';
X       (void) strcat(save, fname);
X    } else {
X        if (*fname == '\0')
X	    fname = curfile;
X        (void) strcpy(save,fname);
X    }
X
X#ifndef VMS
X    if (Crypt)  {
X	creadfile(save, eraseflg);
X	return;
X    }
X#endif /* VMS */
X
X    if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
X
X    if ((f = fopen(findhome(save), "r")) == (FILE *)0)
X    {	error ("Can't read file \"%s\"", save);
X	return;
X    }
X
X    if (eraseflg) erasedb ();
X
X    loading++;
X    while (fgets(line,sizeof line,f)) {
X	linelim = 0;
X	if (line[0] != '#') (void) yyparse ();
X    }
X    --loading;
X    (void) fclose (f);
X    linelim = -1;
X    modflg++;
X    if (eraseflg) {
X	(void) strcpy(curfile,save);
X	modflg = 0;
X    }
X    EvalAll();
X}
X
Xvoid
Xerasedb ()
X{
X    register r, c;
X    for (c = 0; c<=maxcol; c++) {
X	fwidth[c] = DEFWIDTH;
X	precision[c] = DEFPREC;
X    }
X
X    for (r = 0; r<=maxrow; r++) {
X	register struct ent **pp = ATBL(tbl, r, 0);
X	for (c=0; c++<=maxcol; pp++)
X	    if (*pp) {
X		if ((*pp)->expr) efree (*pp, (*pp) -> expr);
X		if ((*pp)->label) xfree ((char *)((*pp) -> label));
X		xfree ((char *)(*pp));
X		*pp = (struct ent *)0;
X	    }
X    }
X    maxrow = 0;
X    maxcol = 0;
X    clean_range();
X    FullUpdate++;
X}
X
Xvoid
Xbackcol(arg)
X	int arg;
X{
X    while (--arg>=0) {
X	if (curcol)
X	    curcol--;
X	else
X	    {error ("At column A"); break;}
X	while(col_hidden[curcol] && curcol)
X	    curcol--;
X    }
X}
X
Xvoid
Xforwcol(arg)
X	int arg;
X{
X    while (--arg>=0) {
X	if (curcol < maxcols - 1)
X	    curcol++;
X	else
X	if (!growtbl(GROWCOL, 0, arg))	/* get as much as needed */
X		break;
X	while(col_hidden[curcol]&&(curcol<maxcols-1))
X	    curcol++;
X    }
X}
X
Xvoid
Xforwrow(arg)
X	int arg;
X{
X    while (--arg>=0) {
X	if (currow < maxrows - 1)
X	    currow++;
X	else
X	if (!growtbl(GROWROW, arg, 0))	/* get as much as needed */
X		break;
X	while (row_hidden[currow]&&(currow<maxrows-1))
X	    currow++;
X    }
X}
X
Xvoid
Xbackrow(arg)
X	int arg;
X{
X    while (--arg>=0) {
X	if (currow)
X	    currow--;
X	else
X	    {error ("At row zero"); break;}
X	while (row_hidden[currow] && currow)
X	    currow--;
X    }
X}
X
X
X/*
X * Show a cell's label string or expression value.  May overwrite value if
X * there is one already displayed in the cell.  Created from old code in
X * update(), copied with minimal changes.
X */
X
Xvoid
Xshowstring (string, leftflush, hasvalue, row, col, nextcolp, mxcol, fieldlenp, r, c)
X    char *string;	/* to display */
X    int leftflush;	/* or rightflush */
X    int hasvalue;	/* is there a numeric value? */
X    int row, col;	/* spreadsheet location */
X    int *nextcolp;	/* value returned through it */
X    int mxcol;		/* last column displayed? */
X    int *fieldlenp;	/* value returned through it */
X    int r, c;		/* screen row and column */
X{
X    register int nextcol  = *nextcolp;
X    register int fieldlen = *fieldlenp;
X
X    char field[FBUFLEN];
X    int  slen;
X    char *start, *last;
X    register char *fp;
X    struct ent *nc;
X
X    /* This figures out if the label is allowed to
X       slop over into the next blank field */
X
X    slen = strlen (string);
X    while ((slen > fieldlen) && (nextcol <= mxcol) &&
X	   !((nc = lookat (row, nextcol)) -> flags & is_valid) &&
X	   !(nc->label)) {
X
X	if (! col_hidden [nextcol])
X	    fieldlen += fwidth [nextcol];
X
X	nextcol++;
X    }
X    if (slen > fieldlen)
X	slen = fieldlen;
X
X    /* Now justify and print */
X    start = leftflush ? field : field + fieldlen - slen;
X    last = field+fieldlen;
X    fp = field;
X    while (fp < start)
X	*fp++ = ' ';
X    while (slen--)
X	*fp++ = *string++;
X    if ((! hasvalue) || fieldlen != fwidth[col]) 
X	while (fp < last)
X	    *fp++ = ' ';
X    *fp = '\0';
X#ifdef VMS
X    mvaddstr(r, c, field);	/* this is a macro */
X#else
X    (void) mvaddstr(r, c, field);
X#endif
X
X    *nextcolp  = nextcol;
X    *fieldlenp = fieldlen;
X}
X
Xint
Xetype(e)
Xregister struct enode *e;
X{
X    if (e == (struct enode *)0)
X	return NUM;
X    switch (e->op) {
X    case O_SCONST: case '#': case DATE: case FMT: case STINDEX:
X    case EXT: case SVAL: case SUBSTR:
X        return (STR);
X
X    case '?':
X    case IF:
X        return(etype(e->e.o.right->e.o.left));
X
X    case 'f':
X        return(etype(e->e.o.right));
X
X    case O_VAR: {
X	register struct ent *p;
X	p = e->e.v.vp;
X	if (p->expr) 
X	    return(p->flags & is_strexpr ? STR : NUM);
X	else if (p->label)
X	    return(STR);
X	else
X	    return(NUM);
X	}
X
X    default:
X	return(NUM);
X    }
X}
X
X/* return 1 if yes given, 0 otherwise */
Xint
Xyn_ask(msg)
Xchar	*msg;
X{	char ch;
X
X	(void) move (0, 0);
X	(void) clrtoeol ();
X	(void) addstr (msg);
X	(void) refresh();
X	ch = nmgetch();
X	if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) {
X		if (ch == ctl('g') || ch == ESC)
X			return(-1);
X		error("y or n response required");
X		return (-1);
X	}
X	if (ch == 'y' || ch == 'Y')
X		return(1);
X	else
X		return(0);
X}
X
X#include <pwd.h>
Xchar	*
Xfindhome(path)
Xchar	*path;
X{
X	static	char	*HomeDir = NULL;
X	extern	char	*getenv();
X
X	if (*path == '~')
X	{	char	*pathptr;
X		char	tmppath[PATHLEN];
X
X		if (HomeDir == NULL)
X		{	HomeDir = getenv("HOME");
X			if (HomeDir == NULL)
X				HomeDir = "/";
X		}
X		pathptr = path + 1;
X		if ((*pathptr == '/') || (*pathptr == '\0'))
X		{	strcpy(tmppath, HomeDir);
X		}
X		else
X		{	struct	passwd *pwent;
X			extern	struct	passwd *getpwnam();
X			char	*namep;
X			char	name[50];
X
X			namep = name;
X			while ((*pathptr != '\0') && (*pathptr != '/'))
X				*(namep++) = *(pathptr++);
X			*namep = '\0';
X			if ((pwent = getpwnam(name)) == NULL)
X			{	sprintf(path, "Can't find user %s", name);
X				return(NULL);
X			}
X			strcpy(tmppath, pwent->pw_dir);
X		}
X
X		strcat(tmppath, pathptr);
X		strcpy(path, tmppath);
X	}
X	return(path);
X}
X
X#ifdef DOBACKUPS
X#include <sys/types.h>
X#include <sys/stat.h>
X
X/*
X * make a backup copy of a file, use the same mode and name in the format
X * [path/]#file~
X * return 1 if we were successful, 0 otherwise
X */
Xint
Xbackup_file(path)
Xchar	*path;
X{
X	struct	stat	statbuf;
X	char	fname[PATHLEN];
X	char	tpath[PATHLEN];
X#ifdef sequent
X	char	*buf;
X#else
X	char	buf[BUFSIZ];
X#endif
X	char	*tpp;
X	int	infd, outfd;
X	int	count;
X
X	/* tpath will be the [path/]file ---> [path/]#file~ */
X	strcpy(tpath, path);
X	if ((tpp = strrchr(tpath, '/')) == NULL)
X		tpp = tpath;
X	else
X		tpp++;
X	strcpy(fname, tpp);
X	sprintf(tpp, "#%s~", fname);
X
X	if (stat(path, &statbuf) == 0)
X	{
X#ifdef sequent
X		if ((buf = xmalloc(statbuf.st_blksize)) == (char *)0)
X			return(0);
X#endif
X
X		if ((infd = open(path, O_RDONLY, 0)) < 0)
X		{
X#ifdef sequent
X			xfree(buf);
X#endif
X			return(0);
X		}
X		if ((outfd = open(tpath, O_TRUNC|O_WRONLY|O_CREAT,
X					statbuf.st_mode)) < 0)
X		{
X#ifdef sequent
X			xfree(buf);
X#endif
X			return(0);
X		}
X#ifdef sequent
X		while((count = read(infd, buf, statbuf.st_blksize)) > 0)
X#else
X		while((count = read(infd, buf, sizeof(buf))) > 0)
X#endif
X		{	if (write(outfd, buf, count) != count)
X			{	count = -1;
X				break;
X			}
X		}
X		close(infd);
X		close(outfd);
X#ifdef sequent
X		xfree(buf);
X#endif
X		return((count < 0) ? 0 : 1);
X	}
X	else
X	if (errno == ENOENT)
X		return(1);
X	return(0);
X}
X#endif
END_OF_FILE
  if test 30867 -ne `wc -c <'cmds.c'`; then
    echo shar: \"'cmds.c'\" unpacked with wrong size!
  fi
  # end of 'cmds.c'
fi
if test -f 'lex.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lex.c'\"
else
  echo shar: Extracting \"'lex.c'\" \(13128 characters\)
  sed "s/^X//" >'lex.c' <<'END_OF_FILE'
X/*	SC	A Spreadsheet Calculator
X *		Lexical analyser
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/88, see list of changes.
X *		$Revision: 6.8 $
X *
X */
X
X
X
X#if defined(BSD42) || defined(BSD43)
X#include <sys/ioctl.h>
X#endif 
X
X#ifdef IEEE_MATH
X#include <ieeefp.h>
X#endif /* IEEE_MATH */
X
X#include <curses.h>
X#include <signal.h>
X#include <setjmp.h>
X#include "sc.h"
X#include <ctype.h>
X
X#ifdef BSD42
X#include <strings.h>
X#else
X#ifndef SYSIII
X#include <string.h>
X#endif
X#endif
X
X#ifdef VMS
X#include "gram_tab.h"
Xtypedef union {
X    int ival;
X    double fval;
X    struct ent *ent;
X    struct enode *enode;
X    char *sval;
X    struct range_s rval;
X} YYSTYPE;
Xextern YYSTYPE yylval;
Xextern int VMS_read_raw;   /*sigh*/
X#else	/* VMS */
X#include "y.tab.h"
X#endif /* VMS */
X
Xchar *strtof();
X
Xjmp_buf wakeup;
Xjmp_buf fpe_buf;
X
Xstruct key {
X    char *key;
X    int val;
X};
X
Xstruct key experres[] = {
X#include "experres.h"
X    0, 0};
X
Xstruct key statres[] = {
X#include "statres.h"
X    0, 0};
X
Xyylex ()
X{
X    register char *p = line+linelim;
X    int ret;
X    while (isspace(*p)) p++;
X    if (*p == '\0') ret = -1;
X    else if (isalpha(*p)) {
X	char *tokenst = p;
X	register tokenl;
X	register struct key *tblp;
X	tokenl = 0;
X	/*
X	 * This picks up either 1 or 2 alpha characters (a column) or
X	 * tokens with at least three leading alphas and '_' or digits
X	 * (a function or token or command or a range name)
X	*/
X	while (isalpha(*p) || ((*p == '_') || isdigit(*p)) && (tokenl > 2)) {
X	    p++;
X	    tokenl++;
X	}
X	if (tokenl <= 2) { /* a COL is 1 or 2 char alpha
X		(but not pi, ln, fv, pv, if -- this should be fixed!) */
X	    if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'i') {
X		ret = K_PI;
X	    } else if (tokenl == 2 && tokenst[0] == 'l' && tokenst[1] == 'n') {
X		ret = K_LN;
X	    } else if (tokenl == 2 && tokenst[0] == 'f' && tokenst[1] == 'v') {
X		ret = K_FV;
X	    } else if (tokenl == 2 && tokenst[0] == 'p' && tokenst[1] == 'v') {
X		ret = K_PV;
X	    } else if (tokenl == 2 && tokenst[0] == 'i' && tokenst[1] == 'f') {
X		ret = K_IF;
X
X	    } else {
X		ret = COL;
X		yylval.ival = atocol (tokenst, tokenl);
X	    }
X	} else {
X	    ret = WORD;
X	    for (tblp = linelim ? experres : statres; tblp->key; tblp++)
X		    if (((tblp->key[0]^tokenst[0])&0137)==0
X		     && tblp->key[tokenl]==0) {
X			register i = 1;
X			while (i<tokenl && ((tokenst[i]^tblp->key[i])&0137)==0)
X			    i++;
X			if (i>=tokenl) {
X			    ret = tblp->val;
X			    break;
X			}
X		    }
X	    if (ret==WORD) { 
X		struct range *r;
X		if (r = find_range(tokenst, tokenl,
X				   (struct ent *)0, (struct ent *)0)) {
X		    yylval.rval.left = r->r_left;
X		    yylval.rval.right = r->r_right;
X		    if (r->r_is_range)
X		        ret = RANGE;
X		    else
X			ret = VAR;
X		} else {
X		    linelim = p-line;
X		    yyerror ("Unintelligible word");
X		}
X	    }
X	}
X    } else if ((*p == '.') || isdigit(*p)) {
X	double v = 0;
X	int temp;
X	char *nstart = p;
X	if (*p != '.') {
X	    do v = v*10 + (double)(*p-'0');
X	    while (isdigit(*++p));
X	}
X	if (*p=='.' || *p == 'e' || *p == 'E') {
X	    ret = FNUMBER;
X	    p = strtof(nstart, &yylval.fval);
X	} else {
X	    /* A NUMBER must hold at least MAXROW and MAXCOL */
X	    /* This is consistent with a short row and col in struct ent */
X	    if (v > (double)32767 || v < (double)-32768) {
X		ret = FNUMBER;
X		yylval.fval = v;
X	    } else {
X		temp = (int)v;
X		if((double)temp != v) {
X		    ret = FNUMBER;
X		    yylval.fval = v;
X		} else {
X		    ret = NUMBER;
X		    yylval.ival = temp;
X		}
X	    }
X	}
X    } else if (*p=='"') {
X	char *ptr;
X        ptr = p+1;
X        while(*ptr && *ptr++ != '"');
X        ptr = xmalloc((unsigned)(ptr-p));
X	yylval.sval = ptr;
X	p += 1;
X	while (*p && *p!='"') *ptr++ = *p++;
X	*ptr = 0;
X	if (*p) p += 1;
X	ret = STRING;
X    } else if (*p=='[') {
X	while (*p && *p!=']') p++;
X	if (*p) p++;
X	linelim = p-line;
X	return yylex();
X    } else ret = *p++;
X    linelim = p-line;
X    return ret;
X}
X
X
X/*
X * Given a token string starting with a symbolic column name and its valid
X * length, convert column name ("A"-"Z" or "AA"-"ZZ") to a column number (0-N).
X * Never mind if the column number is illegal (too high).  The procedure's name
X * and function are the inverse of coltoa().
X * 
X * Case-insensitivity is done crudely, by ignoring the 040 bit.
X */
X
Xint
Xatocol (string, len)
X	char	*string;
X	int	len;
X{
X	register int col;
X
X	col = (string [0] & 0137) - 'A';
X
X	if (len == 2)		/* has second char */
X	    col = ((col + 1) * 26) + ((string [1] & 0137) - 'A');
X
X	return (col);
X}
X
X
X#ifdef SIMPLE
X
Xinitkbd()
X{}
X
Xkbd_again()
X{}
X
Xresetkbd()
X{}
X
X#ifndef VMS
X
Xnmgetch()
X{
X    return (toascii(getchar()));
X}
X
X#else /* VMS */
X
Xnmgetch()
X/*
X   This is not perfect, it doesn't move the cursor when goraw changes
X   over to deraw, but it works well enough since the whole sc package
X   is incredibly stable (loop constantly positions cursor).
X
X   Question, why didn't the VMS people just implement cbreak?
X
X   NOTE: During testing it was discovered that the DEBUGGER and curses
X   and this method of reading would collide (the screen was not updated
X   when continuing from screen mode in the debugger).
X*/
X{
X    short c;
X    static int key_id=0;
X    int status;
X#define VMScheck(a) {if (~(status = (a)) & 1) VMS_MSG (status);}
X
X    if (VMS_read_raw) {
X      VMScheck(smg$read_keystroke (&stdkb->_id, &c, 0, 0, 0));
X    }
X    else
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
X
XVMS_MSG (status)
Xint status;
X/*
X   Routine to put out the VMS operating system error (if one occurs).
X*/
X{
X#include <descrip.h>
X   char errstr[81], buf[120];
X   $DESCRIPTOR(errdesc, errstr);
X   short int length;
X#define err_out(msg) fprintf (stderr,msg)
X
X/* Check for no error or standard error */
X
X   if (~status & 1) {
X      status = status & 0x8000 ? status & 0xFFFFFFF : status & 0xFFFF;
X      if (SYS$GETMSG(status, &length, &errdesc, 1, 0) == SS$_NORMAL) {
X         errstr[length] = '\0';
X         sprintf (buf, "<0x%x> %s", status, errdesc.dsc$a_pointer);
X         err_out (buf);
X      }
X      else
X         err_out ("System error");
X   }
X}
X#endif /* VMS */
X
X#else /*SIMPLE*/
X
X#if defined(BSD42) || defined (SYSIII) || defined(BSD43)
X
X#define N_KEY 4
X
Xstruct key_map {
X    char *k_str;
X    char k_val;
X    char k_index;
X}; 
X
Xstruct key_map km[N_KEY];
X
Xchar keyarea[N_KEY*30];
X
Xchar *tgetstr();
Xchar *getenv();
Xchar *ks;
Xchar ks_buf[20];
Xchar *ke;
Xchar ke_buf[20];
X
X#ifdef TIOCSLTC
Xstruct ltchars old_chars, new_chars;
X#endif
X
Xchar dont_use[] = {
X	ctl('['), ctl('a'), ctl('b'), ctl('c'), ctl('e'), ctl('f'), ctl('g'), ctl('h'),
X	ctl('i'), ctl('j'),  ctl('l'), ctl('m'), ctl('n'), ctl('p'), ctl('q'),
X	ctl('r'), ctl('s'), ctl('t'), ctl('u'), ctl('v'),  ctl('w'), ctl('x'),
X	ctl('z'), 0
X};
X
Xcharout(c)
Xint c;
X{
X	(void)putchar(c);
X}
X
Xinitkbd()
X{
X    register struct key_map *kp;
X    register i,j;
X    char *p = keyarea;
X    char *ktmp;
X    static char buf[1024]; /* Why do I have to do this again? */
X
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	ks = ks_buf;
X	tputs(ks, 1, charout);
X    }
X    ktmp = tgetstr("ke",&p);
X    if (ktmp)  {
X	(void) strcpy(ke_buf, ktmp);
X	ke = ke_buf;
X    }
X
X    /* Unmap arrow keys which conflict with our ctl keys   */
X    /* Ignore unset, longer than length 1, and 1-1 mapped keys */
X
X    for (i = 0; i < N_KEY; i++) {
X	kp = &km[i];
X	if (kp->k_str && (kp->k_str[1] == 0) && (kp->k_str[0] != kp->k_val))
X	    for (j = 0; dont_use[j] != 0; j++)
X	        if (kp->k_str[0] == dont_use[j]) {
X		     kp->k_str = (char *)0;
X		     break;
X		}
X    }
X
X
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
Xvoid
Xkbd_again()
X{
X    if (ks) 
X	tputs(ks, 1, charout);
X
X#ifdef TIOCSLTC
X    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&new_chars);
X#endif
X}
X
Xvoid
Xresetkbd()
X{
X    if (ke) 
X	tputs(ke, 1, charout);
X
X#ifdef TIOCSLTC
X    (void)ioctl(fileno(stdin), TIOCSLTC, (char *)&old_chars);
X#endif
X}
X
Xnmgetch() 
X{
X    register int c;
X    register struct key_map *kp;
X    register struct key_map *biggest;
X    register int i;
X    int almost;
X    int maybe;
X
X    static char dumpbuf[10];
X    static char *dumpindex;
X
X#ifdef SIGVOID
X    void time_out();
X#else
X    int time_out();
X#endif
X
X    if (dumpindex && *dumpindex)
X	    return (*dumpindex++);
X
X    c = toascii(getchar());
X    biggest = 0;
X    almost = 0;
X
X    for (kp = &km[0]; kp < &km[N_KEY]; kp++) {
X	if (!kp->k_str)
X	    continue;
X	if (c == kp->k_str[kp->k_index]) {
X	    almost = 1;
X	    kp->k_index++;
X	    if (kp->k_str[kp->k_index] == 0) {
X		c = kp->k_val;
X	        for (kp = &km[0]; kp < &km[N_KEY]; kp++)
X	            kp->k_index = 0;
X	        return(c);
X	    }
X	}
X	if (!biggest && kp->k_index)
X	    biggest = kp;
X        else if (kp->k_index && biggest->k_index < kp->k_index)
X	    biggest = kp;
X    }
X
X    if (almost) { 
X        (void) signal(SIGALRM, time_out);
X        (void) alarm(1);
X
X	if (setjmp(wakeup) == 0) { 
X	    maybe = nmgetch();
X	    (void) alarm(0);
X	    return(maybe);
X	}
X    }
X    
X    if (biggest) {
X	for (i = 0; i<biggest->k_index; i++) 
X	    dumpbuf[i] = biggest->k_str[i];
X	if (!almost)
X	    dumpbuf[i++] = c;
X	dumpbuf[i] = '\0';
X	dumpindex = &dumpbuf[1];
X	for (kp = &km[0]; kp < &km[N_KEY]; kp++)
X	    kp->k_index = 0;
X	return (dumpbuf[0]);
X    }
X
X    return(c);
X}
X
X#endif
X
X#if defined(SYSV2) || defined(SYSV3)
X
Xinitkbd()
X{
X    keypad(stdscr, TRUE);
X}
X
Xvoid
Xkbd_again()
X{
X    keypad(stdscr, TRUE);
X}
X
Xvoid
Xresetkbd()
X{
X    keypad(stdscr, FALSE);
X}
X
Xnmgetch()
X{
X    register int c;
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    case KEY_C1:    c = '0'; break;
X    case KEY_A1:    c = '1'; break;
X    case KEY_B2:    c = '2'; break;
X    case KEY_A3:    c = '3'; break;
X    case KEY_F(5):  c = '4'; break;
X    case KEY_F(6):  c = '5'; break;
X    case KEY_F(7):  c = '6'; break;
X    case KEY_F(9):  c = '7'; break;
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    default:   c = toascii(c); 
X    break;
X    }
X    return (c);
X}
X
X#endif /* SYSV2 || SYSV3 */
X
X#endif /* SIMPLE */
X
X#ifdef SIGVOID
Xvoid
X#endif
Xtime_out(signo)
Xint signo;
X{
X#ifdef IEEE_MATH
X	(void)fpsetsticky((fp_except)0); 		/* Clear exception */
X#endif /* IEEE_MATH */
X    longjmp(wakeup, -1);
X}
X
X#ifdef SIGVOID
Xvoid
X#endif
Xfpe_trap(signo)
Xint signo;
X{
X    longjmp(fpe_buf, 1);
X}
X
X/*
X * This converts a floating point number of the form
X * [s]ddd[.d*][esd*]  where s can be a + or - and e is E or e.
X * to floating point. 
X * p is advanced.
X */
X
Xchar *
Xstrtof(p, res)
Xregister char *p;
Xdouble *res;
X{
X    double acc;
X    int sign;
X    double fpos;
X    int exp;
X    int exps;
X#ifdef SIGVOID
X    void (*sig_save)();
X#else
X    int (*sig_save)();
X#endif
X
X    sig_save = signal(SIGFPE, fpe_trap);
X    if (setjmp(fpe_buf)) {
X	error("Floating point exception\n");
X	*res = 0.0; 
X        (void) signal(SIGFPE, sig_save);
X	return(p);
X    }
X    acc = 0.0;
X    sign = 1;
X    exp = 0;
X    exps = 1;
X    if (*p == '+')
X        p++;
X    else if (*p == '-') {
X        p++;
X        sign = -1;
X    }
X    while (isdigit(*p)) {
X        acc = acc * 10.0 + (double)(*p - '0');
X        p++;
X    }
X    if (*p == 'e' || *p == 'E') {
X	    p++;
X        if (*p == '+')
X	    p++;
X        else if (*p == '-') {
X	    p++;
X	    exps = -1;
X        }
X        while(isdigit(*p)) {
X	    exp = exp * 10 + (*p - '0');
X	    p++;
X        }
X    }
X    if (*p == '.') {
X	fpos = 1.0/10.0;
X	p++;
X	while(isdigit(*p)) {
X	    acc += (*p - '0') * fpos;
X	    fpos *= 1.0/10.0;
X	    p++;
X	}
X    }
X    if (*p == 'e' || *p == 'E') {
X	exp = 0;
X	exps = 1;
X        p++;
X	if (*p == '+')
X	    p++;
X	else if (*p == '-') {
X	    p++;
X	    exps = -1;
X	}
X	while(isdigit(*p)) {
X	    exp = exp * 10 + (*p - '0');
X	    p++;
X	}
X    }
X    if (exp) {
X	if (exps > 0)
X	    while (exp--)
X		acc *= 10.0;
X	else
X	    while (exp--)
X		acc *= 1.0/10.0;
X    }
X    if (sign > 0)
X        *res = acc;
X    else
X	*res = -acc;
X
X    (void) signal(SIGFPE, sig_save);
X    return(p);
X}
END_OF_FILE
  if test 13128 -ne `wc -c <'lex.c'`; then
    echo shar: \"'lex.c'\" unpacked with wrong size!
  fi
  # end of 'lex.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'\" \(5741 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 *   
X *  Author: Robert Bond
X *		$Revision: 6.8 $
X */
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 colfirst = 0;
Xint r0 = 0;
Xint c0 = 0;
Xint rinc = 1;
Xint cinc = 1;
Xint leftadj = 0;
Xint len = 20000;
Xchar delim1 = ' ';
Xchar delim2 = '\t';
Xint strip_delim = 1;
Xint drop_format = 0;
Xint *fwidth;
Xint *precision;
Xint maxcols;
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:")) != EOF) {
X	switch(c) {
X	case 'r':
X	    colfirst = 1;
X	    break;
X	case 'L':
X	    leftadj = 1;
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 = 0;
X	    break;
X	case 'f':
X	    drop_format = 1;
X	    break;
X	default:
X	    (void) fprintf(stderr,"Usage: %s [-rkfL] [-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 = 1;
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 (precision[i])
X		    (void) printf("format %s %d %d\n", coltoa(i), 
X			fwidth[i], precision[i]+1);
X	    }
X	    exit(0);
X	case NUM:
X	    first = 0;
X	    (void) printf("let %s%d = %s\n", coltoa(effc), effr, token);
X	    if (effc >= maxcols - 1)
X	    {	if (!growtbl(GROWCOL, 0, 0))
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	    if (precision[effc] < j)
X		precision[effc] = j;
X	    if (fwidth[effc] < i)
X		fwidth[effc] = i;
X	    break;
X	case ALPHA:
X	    first = 0;
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, 0))
X		{	(void) fprintf(stderr, "Invalid column used: %s\n", coltoa(effc));
X			continue;
X		}
X	    }
X	    i = strlen(token);
X	    if (i > precision[effc])
X		precision[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 = 1;
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
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    if (isdigit(c) || c == '.' || c == '-' || c == '+') {
X	while(isdigit(c) || c == '.' || c == '-' || c == '+' || c == 'e'
X	    || c == 'E') {
X		c = *p++;
X	}
X	if (c == 0)
X	    return(NUM);
X	else
X	    return(ALPHA);
X    }
X
X    return(ALPHA);
X}
X    
Xgetcol(p)
Xchar *p;
X{
X    register  col;
X
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
Xgetrow(p)
Xchar *p;
X{
X    int row;
X
X    if (!p)
X	return(0);
X    while(*p && !isdigit(*p))
X	p++; 
X    if (!*p)
X	return(0);
X    if (sscanf(p, "%d", &row) != 1)
X	return(0);
X    return(row);
X}
X
Xchar *
Xcoltoa(col)
Xint col;
X{
X    static char rname[3];
X    register char *p = rname;
X
X    if (col < 0 || col > 25*26) 
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}
X
END_OF_FILE
  if test 5741 -ne `wc -c <'psc.c'`; then
    echo shar: \"'psc.c'\" unpacked with wrong size!
  fi
  # end of 'psc.c'
fi
if test -f 'xmalloc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xmalloc.c'\"
else
  echo shar: Extracting \"'xmalloc.c'\" \(686 characters\)
  sed "s/^X//" >'xmalloc.c' <<'END_OF_FILE'
X/*
X * A safer saner malloc, for careless programmers
X * $Revision: 6.8 $
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "sc.h"
X
Xextern char *malloc();
X
X#ifdef SYSV3
Xextern void free();
Xextern void exit();
X#endif
X
Xchar *
Xxmalloc(n)
Xunsigned n;
X{
Xregister char *ptr;
X
Xif ((ptr = malloc(n + sizeof(double))) == NULL)
X    fatal("xmalloc: no memory");
X*((int *) ptr) = 12345;		/* magic number */
Xreturn(ptr + sizeof(double));
X}
X
Xxfree(p)
Xchar *p;
X{
Xif (p == NULL)
X    fatal("xfree: NULL");
Xp -= sizeof(double);
Xif (*((int *) p) != 12345)
X    fatal("xfree: storage not malloc'ed");
Xfree(p);
X}
X
Xfatal(str)
Xchar *str;
X{
X    deraw();
X    (void) fprintf(stderr,"%s\n", str);
X    exit(1);
X}
END_OF_FILE
  if test 686 -ne `wc -c <'xmalloc.c'`; then
    echo shar: \"'xmalloc.c'\" unpacked with wrong size!
  fi
  # end of 'xmalloc.c'
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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...
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list