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