1*45330Sbostic /* SC A Spreadsheet Calculator
2*45330Sbostic * Main driver
3*45330Sbostic *
4*45330Sbostic * original by James Gosling, September 1982
5*45330Sbostic * modifications by Mark Weiser and Bruce Israel,
6*45330Sbostic * University of Maryland
7*45330Sbostic *
8*45330Sbostic * More mods Robert Bond, 12/86
9*45330Sbostic * More mods by Alan Silverstein, 3-4/88, see list of changes.
10*45330Sbostic * Currently supported by pur-phy!sawmill!buhrt (Jeff Buhrt)
11*45330Sbostic * $Revision: 6.8 $
12*45330Sbostic *
13*45330Sbostic */
14*45330Sbostic
15*45330Sbostic
16*45330Sbostic #include <signal.h>
17*45330Sbostic #include <curses.h>
18*45330Sbostic #include <ctype.h>
19*45330Sbostic
20*45330Sbostic #ifdef BSD42
21*45330Sbostic #include <strings.h>
22*45330Sbostic #else
23*45330Sbostic #ifndef SYSIII
24*45330Sbostic #include <string.h>
25*45330Sbostic #endif
26*45330Sbostic #endif
27*45330Sbostic
28*45330Sbostic #include <stdio.h>
29*45330Sbostic #include "sc.h"
30*45330Sbostic
31*45330Sbostic char *getenv();
32*45330Sbostic
33*45330Sbostic #ifdef SYSV3
34*45330Sbostic void exit();
35*45330Sbostic #endif
36*45330Sbostic
37*45330Sbostic #ifndef DFLT_PAGER
38*45330Sbostic #define DFLT_PAGER "more" /* more is probably more widespread than less */
39*45330Sbostic #endif /* DFLT_PAGER */
40*45330Sbostic
41*45330Sbostic #define MAXCMD 160 /* for ! command below */
42*45330Sbostic
43*45330Sbostic extern char *rev;
44*45330Sbostic
45*45330Sbostic /* Globals defined in sc.h */
46*45330Sbostic
47*45330Sbostic struct ent ***tbl;
48*45330Sbostic int strow, stcol;
49*45330Sbostic int currow, curcol;
50*45330Sbostic int savedrow, savedcol;
51*45330Sbostic int FullUpdate;
52*45330Sbostic int maxrow, maxcol;
53*45330Sbostic int maxrows, maxcols;
54*45330Sbostic int *fwidth;
55*45330Sbostic int *precision;
56*45330Sbostic char *col_hidden;
57*45330Sbostic char *row_hidden;
58*45330Sbostic char line[FBUFLEN];
59*45330Sbostic int changed;
60*45330Sbostic struct ent *to_fix;
61*45330Sbostic int modflg;
62*45330Sbostic int numeric;
63*45330Sbostic char *mdir;
64*45330Sbostic int showsc, showsr; /* Starting cell for highlighted range */
65*45330Sbostic char mode_ind = '.';
66*45330Sbostic
67*45330Sbostic char curfile[PATHLEN];
68*45330Sbostic char revmsg[80];
69*45330Sbostic
70*45330Sbostic int linelim = -1;
71*45330Sbostic
72*45330Sbostic int showtop = 1; /* Causes current cell value display in top line */
73*45330Sbostic int showcell = 1; /* Causes current cell to be highlighted */
74*45330Sbostic int showrange = 0; /* Causes ranges to be highlighted */
75*45330Sbostic int showneed = 0; /* Causes cells needing values to be highlighted */
76*45330Sbostic int showexpr = 0; /* Causes cell exprs to be displayed, highlighted */
77*45330Sbostic
78*45330Sbostic int autocalc = 1 ; /* 1 to calculate after each update */
79*45330Sbostic int calc_order = BYROWS;
80*45330Sbostic int tbl_style = 0; /* headers for T command output */
81*45330Sbostic
82*45330Sbostic int lastmx, lastmy; /* Screen address of the cursor */
83*45330Sbostic int lastcol; /* Spreadsheet Column the cursor was in last */
84*45330Sbostic char under_cursor[] = " "; /* Data under the < cursor */
85*45330Sbostic
86*45330Sbostic #ifdef VMS
87*45330Sbostic int VMS_read_raw = 0;
88*45330Sbostic #endif
89*45330Sbostic
90*45330Sbostic int seenerr;
91*45330Sbostic
92*45330Sbostic void
yyerror(err)93*45330Sbostic yyerror(err)
94*45330Sbostic char *err; {
95*45330Sbostic if (seenerr) return;
96*45330Sbostic seenerr++;
97*45330Sbostic (void) move(1,0);
98*45330Sbostic (void) clrtoeol();
99*45330Sbostic (void) printw("%s: %.*s<=%s",err,linelim,line,line+linelim);
100*45330Sbostic }
101*45330Sbostic
102*45330Sbostic struct ent *
lookat(row,col)103*45330Sbostic lookat(row,col)
104*45330Sbostic int row, col;
105*45330Sbostic {
106*45330Sbostic register struct ent **pp;
107*45330Sbostic
108*45330Sbostic checkbounds(&row, &col);
109*45330Sbostic pp = ATBL(tbl, row, col);
110*45330Sbostic if (*pp == (struct ent *)0) {
111*45330Sbostic *pp = (struct ent *) xmalloc((unsigned)sizeof(struct ent));
112*45330Sbostic if (row>maxrow) maxrow = row;
113*45330Sbostic if (col>maxcol) maxcol = col;
114*45330Sbostic (*pp)->label = (char *)0;
115*45330Sbostic (*pp)->row = row;
116*45330Sbostic (*pp)->col = col;
117*45330Sbostic (*pp)->flags = 0;
118*45330Sbostic (*pp)->expr = (struct enode *)0;
119*45330Sbostic (*pp)->v = (double) 0.0;
120*45330Sbostic (*pp)->evnext = (struct ent *)0;
121*45330Sbostic }
122*45330Sbostic return *pp;
123*45330Sbostic }
124*45330Sbostic
125*45330Sbostic /*
126*45330Sbostic * This structure is used to keep ent structs around before they
127*45330Sbostic * are deleted to allow the sync_refs routine a chance to fix the
128*45330Sbostic * variable references.
129*45330Sbostic * We also use it as a last-deleted buffer for the 'p' command.
130*45330Sbostic */
131*45330Sbostic
132*45330Sbostic void
free_ent(p)133*45330Sbostic free_ent(p)
134*45330Sbostic register struct ent *p;
135*45330Sbostic {
136*45330Sbostic p->next = to_fix;
137*45330Sbostic to_fix = p;
138*45330Sbostic p->flags |= is_deleted;
139*45330Sbostic }
140*45330Sbostic
141*45330Sbostic void
flush_saved()142*45330Sbostic flush_saved()
143*45330Sbostic {
144*45330Sbostic register struct ent *p;
145*45330Sbostic register struct ent *q;
146*45330Sbostic
147*45330Sbostic if (!(p = to_fix))
148*45330Sbostic return;
149*45330Sbostic while (p) {
150*45330Sbostic (void) clearent(p);
151*45330Sbostic q = p->next;
152*45330Sbostic xfree((char *)p);
153*45330Sbostic p = q;
154*45330Sbostic }
155*45330Sbostic to_fix = 0;
156*45330Sbostic }
157*45330Sbostic
158*45330Sbostic /*
159*45330Sbostic * standout last time in update()?
160*45330Sbostic * At this point we will let curses do work
161*45330Sbostic */
162*45330Sbostic int standlast = FALSE;
163*45330Sbostic
164*45330Sbostic void
update(anychanged)165*45330Sbostic update (anychanged)
166*45330Sbostic int anychanged; /* did any cell really change in value? */
167*45330Sbostic {
168*45330Sbostic register row,
169*45330Sbostic col;
170*45330Sbostic register struct ent **pp;
171*45330Sbostic int mxcol;
172*45330Sbostic int mxrow;
173*45330Sbostic int rows;
174*45330Sbostic int cols;
175*45330Sbostic int minsr, minsc, maxsr, maxsc;
176*45330Sbostic register r;
177*45330Sbostic register i;
178*45330Sbostic
179*45330Sbostic while (row_hidden[currow]) /* You can't hide the last row or col */
180*45330Sbostic currow++;
181*45330Sbostic while (col_hidden[curcol])
182*45330Sbostic curcol++;
183*45330Sbostic /* First see if the last display still covers curcol */
184*45330Sbostic if (stcol <= curcol) {
185*45330Sbostic for (i = stcol, cols = 0, col = RESCOL;
186*45330Sbostic (col + fwidth[i]) < COLS-1 && i < maxcols; i++) {
187*45330Sbostic cols++;
188*45330Sbostic if (col_hidden[i])
189*45330Sbostic continue;
190*45330Sbostic col += fwidth[i];
191*45330Sbostic }
192*45330Sbostic }
193*45330Sbostic while (stcol + cols - 1 < curcol || curcol < stcol) {
194*45330Sbostic FullUpdate++;
195*45330Sbostic if (stcol - 1 == curcol) { /* How about back one? */
196*45330Sbostic stcol--;
197*45330Sbostic } else if (stcol + cols == curcol) { /* Forward one? */
198*45330Sbostic stcol++;
199*45330Sbostic } else {
200*45330Sbostic /* Try to put the cursor in the center of the screen */
201*45330Sbostic col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL;
202*45330Sbostic stcol = curcol;
203*45330Sbostic for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--) {
204*45330Sbostic stcol--;
205*45330Sbostic if (col_hidden[i])
206*45330Sbostic continue;
207*45330Sbostic col -= fwidth[i];
208*45330Sbostic }
209*45330Sbostic }
210*45330Sbostic /* Now pick up the counts again */
211*45330Sbostic for (i = stcol, cols = 0, col = RESCOL;
212*45330Sbostic (col + fwidth[i]) < COLS-1 && i < maxcols; i++) {
213*45330Sbostic cols++;
214*45330Sbostic if (col_hidden[i])
215*45330Sbostic continue;
216*45330Sbostic col += fwidth[i];
217*45330Sbostic }
218*45330Sbostic }
219*45330Sbostic /* Now - same process on the rows */
220*45330Sbostic if (strow <= currow) {
221*45330Sbostic for (i = strow, rows = 0, row=RESROW; row<LINES && i<maxrows; i++) {
222*45330Sbostic rows++;
223*45330Sbostic if (row_hidden[i])
224*45330Sbostic continue;
225*45330Sbostic row++;
226*45330Sbostic }
227*45330Sbostic }
228*45330Sbostic while (strow + rows - 1 < currow || currow < strow) {
229*45330Sbostic FullUpdate++;
230*45330Sbostic if (strow - 1 == currow) { /* How about up one? */
231*45330Sbostic strow--;
232*45330Sbostic } else if (strow + rows == currow) { /* Down one? */
233*45330Sbostic strow++;
234*45330Sbostic } else {
235*45330Sbostic /* Try to put the cursor in the center of the screen */
236*45330Sbostic row = (LINES - RESROW) / 2 + RESROW;
237*45330Sbostic strow = currow;
238*45330Sbostic for (i=currow-1; i >= 0 && row-1 > RESROW; i--) {
239*45330Sbostic strow--;
240*45330Sbostic if (row_hidden[i])
241*45330Sbostic continue;
242*45330Sbostic row--;
243*45330Sbostic }
244*45330Sbostic }
245*45330Sbostic /* Now pick up the counts again */
246*45330Sbostic for (i = strow, rows = 0, row=RESROW; row<LINES && i<maxrows; i++) {
247*45330Sbostic rows++;
248*45330Sbostic if (row_hidden[i])
249*45330Sbostic continue;
250*45330Sbostic row++;
251*45330Sbostic }
252*45330Sbostic }
253*45330Sbostic mxcol = stcol + cols - 1;
254*45330Sbostic mxrow = strow + rows - 1;
255*45330Sbostic if (FullUpdate || standlast) {
256*45330Sbostic (void) move(2, 0);
257*45330Sbostic (void) clrtobot();
258*45330Sbostic (void) standout();
259*45330Sbostic for (row=RESROW, i=strow; i <= mxrow; i++) {
260*45330Sbostic if (row_hidden[i])
261*45330Sbostic continue;
262*45330Sbostic (void) move(row,0);
263*45330Sbostic if (maxrows < 1000)
264*45330Sbostic (void) printw("%-*d", RESCOL-1, i);
265*45330Sbostic else
266*45330Sbostic (void) printw("%-*d", RESCOL, i);
267*45330Sbostic row++;
268*45330Sbostic }
269*45330Sbostic (void) move(2,0);
270*45330Sbostic (void) printw("%*s", RESCOL, " ");
271*45330Sbostic
272*45330Sbostic for (col=RESCOL, i = stcol; i <= mxcol; i++) {
273*45330Sbostic register int k;
274*45330Sbostic if (col_hidden[i])
275*45330Sbostic continue;
276*45330Sbostic (void) move(2, col);
277*45330Sbostic k = fwidth[i]/2;
278*45330Sbostic if (k == 0)
279*45330Sbostic (void) printw("%1s", coltoa(i));
280*45330Sbostic else
281*45330Sbostic (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i));
282*45330Sbostic col += fwidth[i];
283*45330Sbostic }
284*45330Sbostic (void) standend();
285*45330Sbostic }
286*45330Sbostic
287*45330Sbostic /* Get rid of cursor standout on the cell at previous cursor position */
288*45330Sbostic if (showcell)
289*45330Sbostic { (void) move(lastmx, lastmy);
290*45330Sbostic repaint(lastmx, lastmy, fwidth[lastcol]);
291*45330Sbostic }
292*45330Sbostic
293*45330Sbostic if (showrange) {
294*45330Sbostic minsr = showsr < currow ? showsr : currow;
295*45330Sbostic minsc = showsc < curcol ? showsc : curcol;
296*45330Sbostic maxsr = showsr > currow ? showsr : currow;
297*45330Sbostic maxsc = showsc > curcol ? showsc : curcol;
298*45330Sbostic
299*45330Sbostic if (showtop) {
300*45330Sbostic (void) move(1,0);
301*45330Sbostic (void) clrtoeol();
302*45330Sbostic (void) printw("Default range: %s",
303*45330Sbostic r_name(minsr, minsc, maxsr, maxsc));
304*45330Sbostic }
305*45330Sbostic }
306*45330Sbostic
307*45330Sbostic /* Repaint the visible screen */
308*45330Sbostic if (showrange || anychanged || FullUpdate || standlast)
309*45330Sbostic {
310*45330Sbostic /* may be reset in loop, if not next time we will do a FullUpdate */
311*45330Sbostic if (standlast)
312*45330Sbostic { FullUpdate = TRUE;
313*45330Sbostic standlast = FALSE;
314*45330Sbostic }
315*45330Sbostic for (row = strow, r = RESROW; row <= mxrow; row++) {
316*45330Sbostic register c = RESCOL;
317*45330Sbostic int do_stand = 0;
318*45330Sbostic int fieldlen;
319*45330Sbostic int nextcol;
320*45330Sbostic
321*45330Sbostic if (row_hidden[row])
322*45330Sbostic continue;
323*45330Sbostic for (pp = ATBL(tbl, row, col = stcol); col <= mxcol;
324*45330Sbostic pp += nextcol - col, col = nextcol, c += fieldlen) {
325*45330Sbostic
326*45330Sbostic nextcol = col+1;
327*45330Sbostic if (col_hidden[col]) {
328*45330Sbostic fieldlen = 0;
329*45330Sbostic continue;
330*45330Sbostic }
331*45330Sbostic
332*45330Sbostic fieldlen = fwidth[col];
333*45330Sbostic
334*45330Sbostic /*
335*45330Sbostic * Set standout if:
336*45330Sbostic *
337*45330Sbostic * - showing ranges, and not showing cells which need to be filled
338*45330Sbostic * in, and not showing cell expressions, and in a range, OR
339*45330Sbostic *
340*45330Sbostic * - if showing cells which need to be filled in and this one is
341*45330Sbostic * of that type (has a value and doesn't have an expression,
342*45330Sbostic * or it is a string expression), OR
343*45330Sbostic *
344*45330Sbostic * - if showing cells which have expressions and this one does.
345*45330Sbostic */
346*45330Sbostic
347*45330Sbostic if ((showrange && (! showneed) && (! showexpr)
348*45330Sbostic && (row >= minsr) && (row <= maxsr)
349*45330Sbostic && (col >= minsc) && (col <= maxsc))
350*45330Sbostic || (showneed && (*pp) && ((*pp) -> flags & is_valid)
351*45330Sbostic && (((*pp) -> flags & is_strexpr) || !((*pp) -> expr)))
352*45330Sbostic || (showexpr && (*pp) && ((*pp) -> expr)))
353*45330Sbostic {
354*45330Sbostic (void) move(r, c);
355*45330Sbostic (void) standout();
356*45330Sbostic standlast++;
357*45330Sbostic if (!*pp) /* no cell, but standing out */
358*45330Sbostic { (void) printw("%*s", fwidth[col], " ");
359*45330Sbostic (void) standend();
360*45330Sbostic continue;
361*45330Sbostic }
362*45330Sbostic else
363*45330Sbostic do_stand = 1;
364*45330Sbostic }
365*45330Sbostic else
366*45330Sbostic do_stand = 0;
367*45330Sbostic
368*45330Sbostic if ((*pp) && ((*pp) -> flags & is_changed || FullUpdate) || do_stand) {
369*45330Sbostic if (do_stand) {
370*45330Sbostic (*pp) -> flags |= is_changed;
371*45330Sbostic } else {
372*45330Sbostic (void) move(r, c);
373*45330Sbostic (*pp) -> flags &= ~is_changed;
374*45330Sbostic }
375*45330Sbostic
376*45330Sbostic /*
377*45330Sbostic * Show expression; takes priority over other displays:
378*45330Sbostic */
379*45330Sbostic
380*45330Sbostic if (showexpr && ((*pp) -> expr)) {
381*45330Sbostic linelim = 0;
382*45330Sbostic editexp(row, col); /* set line to expr */
383*45330Sbostic linelim = -1;
384*45330Sbostic showstring(line, /* leftflush = */ 1, /* hasvalue = */ 0,
385*45330Sbostic row, col, & nextcol, mxcol, & fieldlen, r, c);
386*45330Sbostic }
387*45330Sbostic else {
388*45330Sbostic
389*45330Sbostic /*
390*45330Sbostic * Show cell's numeric value:
391*45330Sbostic */
392*45330Sbostic
393*45330Sbostic if ((*pp) -> flags & is_valid) {
394*45330Sbostic char field[FBUFLEN];
395*45330Sbostic (void)sprintf(field,"%*.*f", fwidth[col], precision[col], (*pp)->v);
396*45330Sbostic if(strlen(field) > fwidth[col]) {
397*45330Sbostic for(i = 0; i<fwidth[col]; i++)
398*45330Sbostic (void)addch('*');
399*45330Sbostic } else {
400*45330Sbostic (void)addstr(field);
401*45330Sbostic }
402*45330Sbostic }
403*45330Sbostic
404*45330Sbostic /*
405*45330Sbostic * Show cell's label string:
406*45330Sbostic */
407*45330Sbostic
408*45330Sbostic if ((*pp) -> label) {
409*45330Sbostic showstring((*pp) -> label,
410*45330Sbostic (*pp) -> flags & is_leftflush,
411*45330Sbostic (*pp) -> flags & is_valid,
412*45330Sbostic row, col, & nextcol, mxcol,
413*45330Sbostic & fieldlen, r, c);
414*45330Sbostic }
415*45330Sbostic else /* repaint a blank cell: */
416*45330Sbostic if ((do_stand || !FullUpdate) &&
417*45330Sbostic ((*pp)->flags & is_changed) &&
418*45330Sbostic !((*pp)->flags & is_valid) && !(*pp)->label) {
419*45330Sbostic (void) printw("%*s", fwidth[col], " ");
420*45330Sbostic }
421*45330Sbostic } /* else */
422*45330Sbostic
423*45330Sbostic if (do_stand) {
424*45330Sbostic (void) standend();
425*45330Sbostic do_stand = 0;
426*45330Sbostic }
427*45330Sbostic }
428*45330Sbostic }
429*45330Sbostic r++;
430*45330Sbostic }
431*45330Sbostic }
432*45330Sbostic
433*45330Sbostic (void) move(lastmy, lastmx+fwidth[lastcol]);
434*45330Sbostic if((inch() & A_CHARTEXT ) == '<')
435*45330Sbostic (void) addstr(under_cursor);
436*45330Sbostic
437*45330Sbostic lastmy = RESROW;
438*45330Sbostic for (row = strow; row < currow; row++)
439*45330Sbostic if (!row_hidden[row])
440*45330Sbostic lastmy += 1;
441*45330Sbostic lastmx = RESCOL;
442*45330Sbostic for (col = stcol; col < curcol; col++)
443*45330Sbostic if (!col_hidden[col])
444*45330Sbostic lastmx += fwidth[col];
445*45330Sbostic lastcol = curcol;
446*45330Sbostic if (showcell && (! showneed) && (! showexpr)) {
447*45330Sbostic (void) move(lastmy, lastmx);
448*45330Sbostic (void) standout();
449*45330Sbostic repaint(lastmx, lastmy, fwidth[lastcol]);
450*45330Sbostic (void) standend();
451*45330Sbostic }
452*45330Sbostic (void) move(lastmy, lastmx+fwidth[lastcol]);
453*45330Sbostic *under_cursor = (inch() & A_CHARTEXT );
454*45330Sbostic (void) addstr("<");
455*45330Sbostic
456*45330Sbostic (void) move(0, 0);
457*45330Sbostic (void) clrtoeol();
458*45330Sbostic if (linelim >= 0) {
459*45330Sbostic (void) addch(mode_ind);
460*45330Sbostic (void) addstr("> ");
461*45330Sbostic (void) addstr(line);
462*45330Sbostic (void) move(0, linelim+3);
463*45330Sbostic } else {
464*45330Sbostic if (showtop) { /* show top line */
465*45330Sbostic register struct ent *p1;
466*45330Sbostic int printed = 0; /* printed something? */
467*45330Sbostic
468*45330Sbostic (void) printw("%s%d ", coltoa(curcol), currow);
469*45330Sbostic
470*45330Sbostic if (p1 = *ATBL(tbl, currow, curcol)) {
471*45330Sbostic if (p1 -> expr) {
472*45330Sbostic /* has expr of some type */
473*45330Sbostic linelim = 0;
474*45330Sbostic editexp(currow, curcol); /* set line to expr */
475*45330Sbostic linelim = -1;
476*45330Sbostic }
477*45330Sbostic
478*45330Sbostic /*
479*45330Sbostic * Display string part of cell:
480*45330Sbostic */
481*45330Sbostic
482*45330Sbostic if ((p1 -> expr) && (p1 -> flags & is_strexpr)) {
483*45330Sbostic (void) addstr((p1 -> flags & is_leftflush) ? "<{" : ">{");
484*45330Sbostic (void) addstr(line);
485*45330Sbostic (void) addstr("} "); /* and this '}' is for vi % */
486*45330Sbostic printed = 1;
487*45330Sbostic
488*45330Sbostic } else if (p1 -> label) {
489*45330Sbostic /* has constant label only */
490*45330Sbostic (void) addstr ((p1 -> flags & is_leftflush) ? "<\"" : ">\"");
491*45330Sbostic (void) addstr (p1 -> label);
492*45330Sbostic (void) addstr ("\" ");
493*45330Sbostic printed = 1;
494*45330Sbostic }
495*45330Sbostic
496*45330Sbostic /*
497*45330Sbostic * Display value part of cell:
498*45330Sbostic */
499*45330Sbostic
500*45330Sbostic if (p1 -> flags & is_valid) {
501*45330Sbostic /* has value or num expr */
502*45330Sbostic if ((! (p1 -> expr)) || (p1 -> flags & is_strexpr))
503*45330Sbostic (void) sprintf (line, "%.15g", p1 -> v);
504*45330Sbostic
505*45330Sbostic (void) addstr ("[");
506*45330Sbostic (void) addstr (line);
507*45330Sbostic (void) addstr ("]");
508*45330Sbostic printed = 1;
509*45330Sbostic }
510*45330Sbostic }
511*45330Sbostic if (! printed)
512*45330Sbostic (void) addstr ("[]");
513*45330Sbostic }
514*45330Sbostic (void) move (lastmy, lastmx + fwidth[lastcol]);
515*45330Sbostic }
516*45330Sbostic if (revmsg[0]) {
517*45330Sbostic (void) move(0, 0);
518*45330Sbostic (void) clrtoeol (); /* get rid of topline display */
519*45330Sbostic (void) printw(revmsg);
520*45330Sbostic revmsg[0] = '\0'; /* don't show it again */
521*45330Sbostic (void) move (lastmy, lastmx + fwidth[lastcol]);
522*45330Sbostic }
523*45330Sbostic FullUpdate = FALSE;
524*45330Sbostic }
525*45330Sbostic
526*45330Sbostic void
repaint(x,y,len)527*45330Sbostic repaint(x, y, len)
528*45330Sbostic int x, y, len;
529*45330Sbostic {
530*45330Sbostic int c;
531*45330Sbostic
532*45330Sbostic while(len-- > 0) {
533*45330Sbostic (void) move(y,x);
534*45330Sbostic c = inch() & A_CHARTEXT;
535*45330Sbostic (void) addch(c);
536*45330Sbostic x++;
537*45330Sbostic }
538*45330Sbostic }
539*45330Sbostic
540*45330Sbostic char *progname;
541*45330Sbostic
542*45330Sbostic int
main(argc,argv)543*45330Sbostic main (argc, argv)
544*45330Sbostic int argc;
545*45330Sbostic char **argv;
546*45330Sbostic {
547*45330Sbostic int inloop = 1;
548*45330Sbostic register int c;
549*45330Sbostic int edistate = -1;
550*45330Sbostic int arg = 1;
551*45330Sbostic int narg;
552*45330Sbostic int nedistate;
553*45330Sbostic int running;
554*45330Sbostic char *revi;
555*45330Sbostic int anychanged = FALSE;
556*45330Sbostic
557*45330Sbostic /*
558*45330Sbostic * Keep command line options around until the file is read so the
559*45330Sbostic * command line overrides file options
560*45330Sbostic */
561*45330Sbostic
562*45330Sbostic int Mopt = 0;
563*45330Sbostic int Nopt = 0;
564*45330Sbostic int Copt = 0;
565*45330Sbostic int Ropt = 0;
566*45330Sbostic
567*45330Sbostic int tempx, tempy; /* Temp versions of curx, cury */
568*45330Sbostic
569*45330Sbostic if ((revi = strrchr(argv[0], '/')) != NULL)
570*45330Sbostic progname = revi+1;
571*45330Sbostic else
572*45330Sbostic progname = argv[0];
573*45330Sbostic
574*45330Sbostic while (argc > 1 && argv[1][0] == '-') {
575*45330Sbostic argv++;
576*45330Sbostic argc--;
577*45330Sbostic switch (argv[0][1]) {
578*45330Sbostic case 'x':
579*45330Sbostic #ifdef VMS
580*45330Sbostic (void) fprintf(stderr, "Crypt not available for VMS\n");
581*45330Sbostic exit(1);
582*45330Sbostic #else
583*45330Sbostic Crypt = 1;
584*45330Sbostic #endif
585*45330Sbostic break;
586*45330Sbostic case 'm':
587*45330Sbostic Mopt = 1;
588*45330Sbostic break;
589*45330Sbostic case 'n':
590*45330Sbostic Nopt = 1;
591*45330Sbostic break;
592*45330Sbostic case 'c':
593*45330Sbostic Copt = 1;
594*45330Sbostic break;
595*45330Sbostic case 'r':
596*45330Sbostic Ropt = 1;
597*45330Sbostic break;
598*45330Sbostic default:
599*45330Sbostic (void) fprintf(stderr,"%s: unrecognized option: \"%c\"\n",
600*45330Sbostic progname,argv[0][1]);
601*45330Sbostic exit(1);
602*45330Sbostic }
603*45330Sbostic }
604*45330Sbostic
605*45330Sbostic *curfile ='\0';
606*45330Sbostic
607*45330Sbostic signals();
608*45330Sbostic (void) initscr();
609*45330Sbostic
610*45330Sbostic /* setup the spreadsheet arrays, initscr() will get the screen size */
611*45330Sbostic if (!growtbl(GROWNEW, 0, 0))
612*45330Sbostic { endwin();
613*45330Sbostic exit(1);
614*45330Sbostic }
615*45330Sbostic
616*45330Sbostic (void) clear();
617*45330Sbostic #ifdef VMS
618*45330Sbostic VMS_read_raw = 1;
619*45330Sbostic #else
620*45330Sbostic nonl();
621*45330Sbostic noecho ();
622*45330Sbostic cbreak();
623*45330Sbostic #endif
624*45330Sbostic initkbd();
625*45330Sbostic scrollok(stdscr, 1);
626*45330Sbostic
627*45330Sbostic /*
628*45330Sbostic * Build revision message for later use:
629*45330Sbostic */
630*45330Sbostic
631*45330Sbostic (void) strcpy (revmsg, progname);
632*45330Sbostic for (revi = rev; (*revi++) != ':'; ); /* copy after colon */
633*45330Sbostic (void) strcat (revmsg, revi);
634*45330Sbostic revmsg [strlen (revmsg) - 2] = 0; /* erase last character */
635*45330Sbostic (void) strcat (revmsg, ": Type '?' for help.");
636*45330Sbostic
637*45330Sbostic if (argc > 1) {
638*45330Sbostic (void) strcpy(curfile,argv[1]);
639*45330Sbostic readfile (argv[1], 0);
640*45330Sbostic }
641*45330Sbostic
642*45330Sbostic if (Mopt)
643*45330Sbostic autocalc = 0;
644*45330Sbostic if (Nopt)
645*45330Sbostic numeric = 1;
646*45330Sbostic if (Copt)
647*45330Sbostic calc_order = BYCOLS;
648*45330Sbostic if (Ropt)
649*45330Sbostic calc_order = BYROWS;
650*45330Sbostic
651*45330Sbostic modflg = 0;
652*45330Sbostic #ifdef VENIX
653*45330Sbostic setbuf (stdin, NULL);
654*45330Sbostic #endif
655*45330Sbostic FullUpdate++;
656*45330Sbostic while (inloop) { running = 1;
657*45330Sbostic while (running) {
658*45330Sbostic nedistate = -1;
659*45330Sbostic narg = 1;
660*45330Sbostic if (edistate < 0 && linelim < 0 && autocalc && (changed || FullUpdate))
661*45330Sbostic { EvalAll ();
662*45330Sbostic if (changed) /* if EvalAll changed or was before */
663*45330Sbostic anychanged = TRUE;
664*45330Sbostic changed = 0;
665*45330Sbostic }
666*45330Sbostic else /* any cells change? */
667*45330Sbostic if (changed)
668*45330Sbostic anychanged = TRUE;
669*45330Sbostic
670*45330Sbostic update(anychanged);
671*45330Sbostic anychanged = FALSE;
672*45330Sbostic #ifndef SYSV3
673*45330Sbostic (void) refresh(); /* 5.3 does a refresh in getch */
674*45330Sbostic #endif
675*45330Sbostic c = nmgetch();
676*45330Sbostic getyx(stdscr, tempy, tempx);
677*45330Sbostic (void) move (1, 0);
678*45330Sbostic (void) clrtoeol ();
679*45330Sbostic (void) move(tempy, tempx);
680*45330Sbostic (void) fflush (stdout);
681*45330Sbostic seenerr = 0;
682*45330Sbostic showneed = 0; /* reset after each update */
683*45330Sbostic showexpr = 0;
684*45330Sbostic
685*45330Sbostic /* if ((c < ' ') || ( c == DEL )) how about international here ? PB */
686*45330Sbostic if ( iscntrl(c) )
687*45330Sbostic switch (c) {
688*45330Sbostic #ifdef SIGTSTP
689*45330Sbostic case ctl('z'):
690*45330Sbostic (void) deraw();
691*45330Sbostic (void) kill(0, SIGTSTP); /* Nail process group */
692*45330Sbostic
693*45330Sbostic /* the pc stops here */
694*45330Sbostic
695*45330Sbostic (void) goraw();
696*45330Sbostic break;
697*45330Sbostic #endif
698*45330Sbostic case ctl('r'):
699*45330Sbostic showneed = 1;
700*45330Sbostic case ctl('l'):
701*45330Sbostic FullUpdate++;
702*45330Sbostic (void) clearok(stdscr,1);
703*45330Sbostic break;
704*45330Sbostic case ctl('x'):
705*45330Sbostic FullUpdate++;
706*45330Sbostic showexpr = 1;
707*45330Sbostic (void) clearok(stdscr,1);
708*45330Sbostic break;
709*45330Sbostic default:
710*45330Sbostic error ("No such command (^%c)", c + 0100);
711*45330Sbostic break;
712*45330Sbostic case ctl('b'):
713*45330Sbostic backcol(arg);
714*45330Sbostic break;
715*45330Sbostic case ctl('c'):
716*45330Sbostic running = 0;
717*45330Sbostic break;
718*45330Sbostic
719*45330Sbostic case ctl('e'):
720*45330Sbostic
721*45330Sbostic switch (nmgetch()) {
722*45330Sbostic case ctl('p'): case 'k': doend (-1, 0); break;
723*45330Sbostic case ctl('n'): case 'j': doend ( 1, 0); break;
724*45330Sbostic case ctl('b'): case 'h':
725*45330Sbostic case ctl('h'): doend ( 0,-1); break;
726*45330Sbostic case ctl('f'): case 'l':
727*45330Sbostic case ctl('i'): case ' ': doend ( 0, 1); break;
728*45330Sbostic
729*45330Sbostic case ESC:
730*45330Sbostic case ctl('g'):
731*45330Sbostic break;
732*45330Sbostic
733*45330Sbostic default:
734*45330Sbostic error("Invalid ^E command");
735*45330Sbostic break;
736*45330Sbostic }
737*45330Sbostic
738*45330Sbostic break;
739*45330Sbostic
740*45330Sbostic case ctl('f'):
741*45330Sbostic forwcol(arg);
742*45330Sbostic break;
743*45330Sbostic
744*45330Sbostic case ctl('g'):
745*45330Sbostic showrange = 0;
746*45330Sbostic linelim = -1;
747*45330Sbostic (void) move (1, 0);
748*45330Sbostic (void) clrtoeol ();
749*45330Sbostic break;
750*45330Sbostic
751*45330Sbostic case ESC: /* ctl('[') */
752*45330Sbostic write_line(ESC);
753*45330Sbostic break;
754*45330Sbostic
755*45330Sbostic case ctl('d'):
756*45330Sbostic write_line(ctl('d'));
757*45330Sbostic break;
758*45330Sbostic
759*45330Sbostic case DEL:
760*45330Sbostic case ctl('h'):
761*45330Sbostic if (linelim < 0) { /* not editing line */
762*45330Sbostic backcol(arg); /* treat like ^B */
763*45330Sbostic break;
764*45330Sbostic }
765*45330Sbostic write_line(ctl('h'));
766*45330Sbostic break;
767*45330Sbostic
768*45330Sbostic case ctl('i'): /* tab */
769*45330Sbostic if (linelim < 0) { /* not editing line */
770*45330Sbostic forwcol(arg);
771*45330Sbostic break;
772*45330Sbostic }
773*45330Sbostic if (!showrange) {
774*45330Sbostic startshow();
775*45330Sbostic } else {
776*45330Sbostic showdr();
777*45330Sbostic linelim = strlen(line);
778*45330Sbostic line[linelim++] = ' ';
779*45330Sbostic line[linelim] = 0;
780*45330Sbostic showrange = 0;
781*45330Sbostic }
782*45330Sbostic linelim = strlen (line);
783*45330Sbostic break;
784*45330Sbostic
785*45330Sbostic case ctl('m'):
786*45330Sbostic case ctl('j'):
787*45330Sbostic write_line(ctl('m'));
788*45330Sbostic break;
789*45330Sbostic
790*45330Sbostic case ctl('n'):
791*45330Sbostic forwrow(arg);
792*45330Sbostic break;
793*45330Sbostic
794*45330Sbostic case ctl('p'):
795*45330Sbostic backrow(arg);
796*45330Sbostic break;
797*45330Sbostic
798*45330Sbostic case ctl('q'):
799*45330Sbostic break; /* ignore flow control */
800*45330Sbostic
801*45330Sbostic case ctl('s'):
802*45330Sbostic break; /* ignore flow control */
803*45330Sbostic
804*45330Sbostic case ctl('t'):
805*45330Sbostic error(
806*45330Sbostic "Toggle: a:auto c:cell e:ext funcs n:numeric t:top x:encrypt $:pre-scale");
807*45330Sbostic (void) refresh();
808*45330Sbostic
809*45330Sbostic switch (nmgetch()) {
810*45330Sbostic case 'a': case 'A':
811*45330Sbostic case 'm': case 'M':
812*45330Sbostic autocalc ^= 1;
813*45330Sbostic error("Automatic recalculation %sabled.",
814*45330Sbostic autocalc ? "en":"dis");
815*45330Sbostic break;
816*45330Sbostic case 'n': case 'N':
817*45330Sbostic numeric = (! numeric);
818*45330Sbostic error ("Numeric input %sabled.",
819*45330Sbostic numeric ? "en" : "dis");
820*45330Sbostic break;
821*45330Sbostic case 't': case 'T':
822*45330Sbostic showtop = (! showtop);
823*45330Sbostic repaint(lastmx, lastmy, fwidth[lastcol]);
824*45330Sbostic error ("Top line %sabled.", showtop ? "en" : "dis");
825*45330Sbostic break;
826*45330Sbostic case 'c': case 'C':
827*45330Sbostic showcell = (! showcell);
828*45330Sbostic repaint(lastmx, lastmy, fwidth[lastcol]);
829*45330Sbostic error ("Cell highlighting %sabled.",
830*45330Sbostic showcell ? "en" : "dis");
831*45330Sbostic break;
832*45330Sbostic case 'x': case 'X':
833*45330Sbostic Crypt = (! Crypt);
834*45330Sbostic error ("Encryption %sabled.", Crypt? "en" : "dis");
835*45330Sbostic break;
836*45330Sbostic case '$':
837*45330Sbostic if (prescale == 1.0) {
838*45330Sbostic error ("Prescale enabled.");
839*45330Sbostic prescale = 0.01;
840*45330Sbostic } else {
841*45330Sbostic prescale = 1.0;
842*45330Sbostic error ("Prescale disabled.");
843*45330Sbostic }
844*45330Sbostic break;
845*45330Sbostic case 'e': case 'E':
846*45330Sbostic extfunc = (! extfunc);
847*45330Sbostic error ("External functions %sabled.",
848*45330Sbostic extfunc? "en" : "dis");
849*45330Sbostic break;
850*45330Sbostic case ESC:
851*45330Sbostic case ctl('g'):
852*45330Sbostic --modflg; /* negate the modflg++ */
853*45330Sbostic break;
854*45330Sbostic default:
855*45330Sbostic error ("Invalid toggle command");
856*45330Sbostic --modflg; /* negate the modflg++ */
857*45330Sbostic }
858*45330Sbostic FullUpdate++;
859*45330Sbostic modflg++;
860*45330Sbostic break;
861*45330Sbostic
862*45330Sbostic case ctl('u'):
863*45330Sbostic narg = arg * 4;
864*45330Sbostic nedistate = 1;
865*45330Sbostic break;
866*45330Sbostic
867*45330Sbostic case ctl('v'): /* insert variable name */
868*45330Sbostic if (linelim > 0)
869*45330Sbostic ins_string(v_name(currow, curcol));
870*45330Sbostic break;
871*45330Sbostic
872*45330Sbostic case ctl('w'): /* insert variable expression */
873*45330Sbostic if (linelim > 0) {
874*45330Sbostic char *temp, *temp1;
875*45330Sbostic int templim;
876*45330Sbostic
877*45330Sbostic temp = strcpy(xmalloc((unsigned)(strlen(line)+1)),line);
878*45330Sbostic templim = linelim;
879*45330Sbostic editexp(currow,curcol);
880*45330Sbostic temp1= strcpy(xmalloc((unsigned)(strlen(line)+1)),line);
881*45330Sbostic strcpy(line, temp);
882*45330Sbostic linelim = templim;
883*45330Sbostic ins_string(temp1);
884*45330Sbostic xfree(temp);
885*45330Sbostic xfree(temp1);
886*45330Sbostic }
887*45330Sbostic break;
888*45330Sbostic
889*45330Sbostic case ctl('a'): /* insert variable value */
890*45330Sbostic if (linelim > 0) {
891*45330Sbostic struct ent *p = *ATBL(tbl, currow, curcol);
892*45330Sbostic char temp[100];
893*45330Sbostic
894*45330Sbostic if (p && p -> flags & is_valid) {
895*45330Sbostic (void) sprintf (temp, "%.*f",
896*45330Sbostic precision[curcol],p -> v);
897*45330Sbostic ins_string(temp);
898*45330Sbostic }
899*45330Sbostic }
900*45330Sbostic break;
901*45330Sbostic
902*45330Sbostic } /* End of the control char switch stmt */
903*45330Sbostic else if (isdigit(c) && ((numeric && edistate >= 0) ||
904*45330Sbostic (!numeric && (linelim < 0 || edistate >= 0)))) {
905*45330Sbostic /* we got a leading number */
906*45330Sbostic if (edistate != 0) {
907*45330Sbostic /* First char of the count */
908*45330Sbostic if (c == '0') /* just a '0' goes to left col */
909*45330Sbostic curcol = 0;
910*45330Sbostic else {
911*45330Sbostic nedistate = 0;
912*45330Sbostic narg = c - '0';
913*45330Sbostic }
914*45330Sbostic } else {
915*45330Sbostic /* Succeeding count chars */
916*45330Sbostic nedistate = 0;
917*45330Sbostic narg = arg * 10 + (c - '0');
918*45330Sbostic }
919*45330Sbostic } else if (linelim >= 0) {
920*45330Sbostic /* Editing line */
921*45330Sbostic switch(c) {
922*45330Sbostic case ')':
923*45330Sbostic if (showrange) {
924*45330Sbostic showdr();
925*45330Sbostic showrange = 0;
926*45330Sbostic linelim = strlen (line);
927*45330Sbostic }
928*45330Sbostic break;
929*45330Sbostic default:
930*45330Sbostic break;
931*45330Sbostic }
932*45330Sbostic write_line(c);
933*45330Sbostic
934*45330Sbostic } else if (!numeric && ( c == '+' || c == '-' ) ) {
935*45330Sbostic /* increment/decrement ops */
936*45330Sbostic register struct ent *p = *ATBL(tbl, currow, curcol);
937*45330Sbostic if (!p)
938*45330Sbostic continue;
939*45330Sbostic if (p->expr && !(p->flags & is_strexpr)) {
940*45330Sbostic error("Can't increment/decrement a formula\n");
941*45330Sbostic continue;
942*45330Sbostic }
943*45330Sbostic FullUpdate++;
944*45330Sbostic modflg++;
945*45330Sbostic if( c == '+' )
946*45330Sbostic p -> v += (double) arg;
947*45330Sbostic else
948*45330Sbostic p -> v -= (double) arg;
949*45330Sbostic } else
950*45330Sbostic /* switch on a normal command character */
951*45330Sbostic switch (c) {
952*45330Sbostic case ':':
953*45330Sbostic break; /* Be nice to vi users */
954*45330Sbostic
955*45330Sbostic case '@':
956*45330Sbostic EvalAll ();
957*45330Sbostic changed = 0;
958*45330Sbostic anychanged = TRUE;
959*45330Sbostic break;
960*45330Sbostic
961*45330Sbostic case '0': case '1': case '2': case '3': case '4':
962*45330Sbostic case '5': case '6': case '7': case '8': case '9':
963*45330Sbostic case '-': case '.': case '+':
964*45330Sbostic (void) sprintf(line,"let %s = %c",
965*45330Sbostic v_name(currow, curcol), c);
966*45330Sbostic linelim = strlen (line);
967*45330Sbostic insert_mode();
968*45330Sbostic break;
969*45330Sbostic
970*45330Sbostic case '=':
971*45330Sbostic (void) sprintf(line,"let %s = ",
972*45330Sbostic v_name(currow, curcol));
973*45330Sbostic linelim = strlen (line);
974*45330Sbostic insert_mode();
975*45330Sbostic break;
976*45330Sbostic
977*45330Sbostic case '!':
978*45330Sbostic {
979*45330Sbostic /*
980*45330Sbostic * "! command" executes command
981*45330Sbostic * "!" forks a shell
982*45330Sbostic * "!!" repeats last command
983*45330Sbostic */
984*45330Sbostic #ifdef VMS
985*45330Sbostic error("Not implemented on VMS");
986*45330Sbostic #else /* VMS */
987*45330Sbostic char *shl;
988*45330Sbostic int pid, temp;
989*45330Sbostic char cmd[MAXCMD];
990*45330Sbostic static char lastcmd[MAXCMD];
991*45330Sbostic
992*45330Sbostic if (!(shl = getenv("SHELL")))
993*45330Sbostic shl = "/bin/sh";
994*45330Sbostic
995*45330Sbostic deraw();
996*45330Sbostic (void) fputs("! ", stdout);
997*45330Sbostic (void) fflush(stdout);
998*45330Sbostic (void) fgets(cmd, MAXCMD, stdin);
999*45330Sbostic cmd[strlen(cmd) - 1] = '\0'; /* clobber \n */
1000*45330Sbostic if(strcmp(cmd,"!") == 0) /* repeat? */
1001*45330Sbostic (void) strcpy(cmd, lastcmd);
1002*45330Sbostic else
1003*45330Sbostic (void) strcpy(lastcmd, cmd);
1004*45330Sbostic
1005*45330Sbostic if (modflg)
1006*45330Sbostic {
1007*45330Sbostic (void) puts ("[No write since last change]");
1008*45330Sbostic (void) fflush (stdout);
1009*45330Sbostic }
1010*45330Sbostic
1011*45330Sbostic if (!(pid = fork()))
1012*45330Sbostic {
1013*45330Sbostic (void) signal (SIGINT, SIG_DFL); /* reset */
1014*45330Sbostic if(strlen(cmd))
1015*45330Sbostic (void)execl(shl,shl,"-c",cmd,(char *)0);
1016*45330Sbostic else
1017*45330Sbostic (void) execl(shl, shl, (char *)0);
1018*45330Sbostic exit(-127);
1019*45330Sbostic }
1020*45330Sbostic
1021*45330Sbostic while (pid != wait(&temp));
1022*45330Sbostic
1023*45330Sbostic (void) printf("Press RETURN to continue ");
1024*45330Sbostic (void)nmgetch();
1025*45330Sbostic goraw();
1026*45330Sbostic #endif /* VMS */
1027*45330Sbostic break;
1028*45330Sbostic }
1029*45330Sbostic
1030*45330Sbostic /*
1031*45330Sbostic * Range commands:
1032*45330Sbostic */
1033*45330Sbostic
1034*45330Sbostic case '/':
1035*45330Sbostic error (
1036*45330Sbostic "Range: x:erase v:value c:copy f:fill d:define s:show u:undefine");
1037*45330Sbostic (void) refresh();
1038*45330Sbostic
1039*45330Sbostic switch (nmgetch()) {
1040*45330Sbostic case 'c':
1041*45330Sbostic (void) sprintf(line,"copy [dest_range src_range] ");
1042*45330Sbostic linelim = strlen(line);
1043*45330Sbostic startshow();
1044*45330Sbostic insert_mode();
1045*45330Sbostic break;
1046*45330Sbostic case 'x':
1047*45330Sbostic (void) sprintf(line,"erase [range] ");
1048*45330Sbostic linelim = strlen(line);
1049*45330Sbostic startshow();
1050*45330Sbostic insert_mode();
1051*45330Sbostic break;
1052*45330Sbostic case 'v':
1053*45330Sbostic (void) sprintf(line, "value [range] ");
1054*45330Sbostic linelim = strlen(line);
1055*45330Sbostic startshow();
1056*45330Sbostic insert_mode();
1057*45330Sbostic break;
1058*45330Sbostic case 'f':
1059*45330Sbostic (void) sprintf(line,"fill [range start inc] ");
1060*45330Sbostic linelim = strlen(line);
1061*45330Sbostic startshow();
1062*45330Sbostic insert_mode();
1063*45330Sbostic break;
1064*45330Sbostic case 'd':
1065*45330Sbostic (void) sprintf(line,"define [string range] \"");
1066*45330Sbostic linelim = strlen(line);
1067*45330Sbostic startshow();
1068*45330Sbostic insert_mode();
1069*45330Sbostic modflg++;
1070*45330Sbostic break;
1071*45330Sbostic case 'u':
1072*45330Sbostic (void) sprintf(line,"undefine [range] ");
1073*45330Sbostic linelim = strlen(line);
1074*45330Sbostic insert_mode();
1075*45330Sbostic modflg++;
1076*45330Sbostic break;
1077*45330Sbostic case 's':
1078*45330Sbostic if(are_ranges())
1079*45330Sbostic {
1080*45330Sbostic FILE *f;
1081*45330Sbostic int pid;
1082*45330Sbostic char px[MAXCMD] ;
1083*45330Sbostic char *pager;
1084*45330Sbostic
1085*45330Sbostic (void) strcpy(px, "| sort | ");
1086*45330Sbostic if(!(pager = getenv("PAGER")))
1087*45330Sbostic pager = DFLT_PAGER;
1088*45330Sbostic (void) strcat(px,pager);
1089*45330Sbostic f = openout(px, &pid);
1090*45330Sbostic if (!f) {
1091*45330Sbostic error("Can't open pipe to sort");
1092*45330Sbostic break;
1093*45330Sbostic }
1094*45330Sbostic list_range(f);
1095*45330Sbostic closeout(f, pid);
1096*45330Sbostic }
1097*45330Sbostic else error("No ranges defined");
1098*45330Sbostic break;
1099*45330Sbostic
1100*45330Sbostic case ESC:
1101*45330Sbostic case ctl('g'):
1102*45330Sbostic break;
1103*45330Sbostic default:
1104*45330Sbostic error("Invalid region command");
1105*45330Sbostic break;
1106*45330Sbostic }
1107*45330Sbostic break;
1108*45330Sbostic
1109*45330Sbostic /*
1110*45330Sbostic * Row/column commands:
1111*45330Sbostic */
1112*45330Sbostic
1113*45330Sbostic case 'i':
1114*45330Sbostic case 'a':
1115*45330Sbostic case 'd':
1116*45330Sbostic case 'p':
1117*45330Sbostic case 'v':
1118*45330Sbostic case 'z':
1119*45330Sbostic case 's':
1120*45330Sbostic {
1121*45330Sbostic register rcqual;
1122*45330Sbostic
1123*45330Sbostic if (! (rcqual = get_rcqual (c))) {
1124*45330Sbostic error ("Invalid row/column command");
1125*45330Sbostic break;
1126*45330Sbostic }
1127*45330Sbostic
1128*45330Sbostic error (""); /* clear line */
1129*45330Sbostic
1130*45330Sbostic if ( rcqual == ESC || rcqual == ctl('g'))
1131*45330Sbostic break;
1132*45330Sbostic
1133*45330Sbostic switch (c) {
1134*45330Sbostic
1135*45330Sbostic case 'i':
1136*45330Sbostic if (rcqual == 'r') insertrow(arg);
1137*45330Sbostic else opencol(curcol, arg);
1138*45330Sbostic break;
1139*45330Sbostic
1140*45330Sbostic case 'a':
1141*45330Sbostic if (rcqual == 'r') while (arg--) duprow();
1142*45330Sbostic else while (arg--) dupcol();
1143*45330Sbostic break;
1144*45330Sbostic
1145*45330Sbostic case 'd':
1146*45330Sbostic if (rcqual == 'r') deleterow(arg);
1147*45330Sbostic else closecol(curcol, arg);
1148*45330Sbostic break;
1149*45330Sbostic
1150*45330Sbostic case 'p':
1151*45330Sbostic while (arg--) pullcells(rcqual);
1152*45330Sbostic break;
1153*45330Sbostic
1154*45330Sbostic case 'v':
1155*45330Sbostic if (rcqual == 'r') rowvalueize(arg);
1156*45330Sbostic else colvalueize(arg);
1157*45330Sbostic modflg = 1;
1158*45330Sbostic break;
1159*45330Sbostic
1160*45330Sbostic case 'z':
1161*45330Sbostic if (rcqual == 'r') hiderow(arg);
1162*45330Sbostic else hidecol(arg);
1163*45330Sbostic break;
1164*45330Sbostic
1165*45330Sbostic case 's':
1166*45330Sbostic /* special case; no repeat count */
1167*45330Sbostic
1168*45330Sbostic if (rcqual == 'r') rowshow_op();
1169*45330Sbostic else colshow_op();
1170*45330Sbostic break;
1171*45330Sbostic }
1172*45330Sbostic break;
1173*45330Sbostic }
1174*45330Sbostic
1175*45330Sbostic case '$':
1176*45330Sbostic {
1177*45330Sbostic register struct ent *p;
1178*45330Sbostic
1179*45330Sbostic curcol = maxcols - 1;
1180*45330Sbostic while (!VALID_CELL(p, currow, curcol) && curcol > 0)
1181*45330Sbostic curcol--;
1182*45330Sbostic break;
1183*45330Sbostic }
1184*45330Sbostic case '#':
1185*45330Sbostic {
1186*45330Sbostic register struct ent *p;
1187*45330Sbostic
1188*45330Sbostic currow = maxrows - 1;
1189*45330Sbostic while (!VALID_CELL(p, currow, curcol) && currow > 0)
1190*45330Sbostic currow--;
1191*45330Sbostic break;
1192*45330Sbostic }
1193*45330Sbostic case 'w':
1194*45330Sbostic {
1195*45330Sbostic register struct ent *p;
1196*45330Sbostic
1197*45330Sbostic while (--arg>=0) {
1198*45330Sbostic do {
1199*45330Sbostic if (curcol < maxcols - 1)
1200*45330Sbostic curcol++;
1201*45330Sbostic else {
1202*45330Sbostic if (currow < maxrows - 1) {
1203*45330Sbostic while(++currow < maxrows - 1 &&
1204*45330Sbostic row_hidden[currow]) /* */;
1205*45330Sbostic curcol = 0;
1206*45330Sbostic } else {
1207*45330Sbostic error("At end of table");
1208*45330Sbostic break;
1209*45330Sbostic }
1210*45330Sbostic }
1211*45330Sbostic } while(col_hidden[curcol] ||
1212*45330Sbostic !VALID_CELL(p, currow, curcol));
1213*45330Sbostic }
1214*45330Sbostic break;
1215*45330Sbostic }
1216*45330Sbostic case 'b':
1217*45330Sbostic {
1218*45330Sbostic register struct ent *p;
1219*45330Sbostic
1220*45330Sbostic while (--arg>=0) {
1221*45330Sbostic do {
1222*45330Sbostic if (curcol)
1223*45330Sbostic curcol--;
1224*45330Sbostic else {
1225*45330Sbostic if (currow) {
1226*45330Sbostic while(--currow &&
1227*45330Sbostic row_hidden[currow]) /* */;
1228*45330Sbostic curcol = maxcols - 1;
1229*45330Sbostic } else {
1230*45330Sbostic error ("At start of table");
1231*45330Sbostic break;
1232*45330Sbostic }
1233*45330Sbostic }
1234*45330Sbostic } while(col_hidden[curcol] ||
1235*45330Sbostic !VALID_CELL(p, currow, curcol));
1236*45330Sbostic }
1237*45330Sbostic break;
1238*45330Sbostic }
1239*45330Sbostic case '^':
1240*45330Sbostic currow = 0;
1241*45330Sbostic break;
1242*45330Sbostic case '?':
1243*45330Sbostic help();
1244*45330Sbostic break;
1245*45330Sbostic case '"':
1246*45330Sbostic (void) sprintf (line, "label %s = \"",
1247*45330Sbostic v_name(currow, curcol));
1248*45330Sbostic linelim = strlen (line);
1249*45330Sbostic insert_mode();
1250*45330Sbostic break;
1251*45330Sbostic case '<':
1252*45330Sbostic (void) sprintf (line, "leftstring %s = \"",
1253*45330Sbostic v_name(currow, curcol));
1254*45330Sbostic linelim = strlen (line);
1255*45330Sbostic insert_mode();
1256*45330Sbostic break;
1257*45330Sbostic case '>':
1258*45330Sbostic (void) sprintf (line, "rightstring %s = \"",
1259*45330Sbostic v_name(currow, curcol));
1260*45330Sbostic linelim = strlen (line);
1261*45330Sbostic insert_mode();
1262*45330Sbostic break;
1263*45330Sbostic case 'e':
1264*45330Sbostic editv (currow, curcol);
1265*45330Sbostic edit_mode();
1266*45330Sbostic break;
1267*45330Sbostic case 'E':
1268*45330Sbostic edits (currow, curcol);
1269*45330Sbostic edit_mode();
1270*45330Sbostic break;
1271*45330Sbostic case 'f':
1272*45330Sbostic if (arg == 1)
1273*45330Sbostic (void) sprintf (line, "format [for column] %s ",
1274*45330Sbostic coltoa(curcol));
1275*45330Sbostic else {
1276*45330Sbostic (void) sprintf(line, "format [for columns] %s:",
1277*45330Sbostic coltoa(curcol));
1278*45330Sbostic (void) sprintf(line+strlen(line), "%s ",
1279*45330Sbostic coltoa(curcol+arg-1));
1280*45330Sbostic }
1281*45330Sbostic error("Current format is %d %d",
1282*45330Sbostic fwidth[curcol],precision[curcol]);
1283*45330Sbostic linelim = strlen (line);
1284*45330Sbostic insert_mode();
1285*45330Sbostic break;
1286*45330Sbostic case 'g':
1287*45330Sbostic (void) sprintf (line, "goto [v] ");
1288*45330Sbostic linelim = strlen (line);
1289*45330Sbostic insert_mode();
1290*45330Sbostic break;
1291*45330Sbostic case 'P':
1292*45330Sbostic (void) sprintf (line, "put [\"dest\" range] \"");
1293*45330Sbostic if (*curfile)
1294*45330Sbostic error ("Default path is \"%s\"",curfile);
1295*45330Sbostic linelim = strlen (line);
1296*45330Sbostic insert_mode();
1297*45330Sbostic break;
1298*45330Sbostic case 'M':
1299*45330Sbostic (void) sprintf (line, "merge [\"source\"] \"");
1300*45330Sbostic linelim = strlen (line);
1301*45330Sbostic insert_mode();
1302*45330Sbostic break;
1303*45330Sbostic case 'R':
1304*45330Sbostic if (mdir)
1305*45330Sbostic (void) sprintf (line,"merge [\"macro_file\"] \"%s/", mdir);
1306*45330Sbostic else
1307*45330Sbostic (void) sprintf (line,"merge [\"macro_file\"] \"");
1308*45330Sbostic linelim = strlen (line);
1309*45330Sbostic insert_mode();
1310*45330Sbostic break;
1311*45330Sbostic case 'D':
1312*45330Sbostic (void) sprintf (line, "mdir [\"macro_directory\"] \"");
1313*45330Sbostic linelim = strlen (line);
1314*45330Sbostic insert_mode();
1315*45330Sbostic break;
1316*45330Sbostic case 'G':
1317*45330Sbostic (void) sprintf (line, "get [\"source\"] \"");
1318*45330Sbostic if (*curfile)
1319*45330Sbostic error ("Default file is \"%s\"",curfile);
1320*45330Sbostic linelim = strlen (line);
1321*45330Sbostic insert_mode();
1322*45330Sbostic break;
1323*45330Sbostic case 'W':
1324*45330Sbostic (void) sprintf (line, "write [\"dest\" range] \"");
1325*45330Sbostic linelim = strlen (line);
1326*45330Sbostic insert_mode();
1327*45330Sbostic break;
1328*45330Sbostic case 'S': /* set options */
1329*45330Sbostic (void) sprintf (line, "set ");
1330*45330Sbostic error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex)");
1331*45330Sbostic linelim = strlen (line);
1332*45330Sbostic insert_mode();
1333*45330Sbostic break;
1334*45330Sbostic case 'T': /* tbl output */
1335*45330Sbostic (void) sprintf (line, "tbl [\"dest\" range] \"");
1336*45330Sbostic linelim = strlen (line);
1337*45330Sbostic insert_mode();
1338*45330Sbostic break;
1339*45330Sbostic case 'x':
1340*45330Sbostic {
1341*45330Sbostic register struct ent **pp;
1342*45330Sbostic register int c1;
1343*45330Sbostic
1344*45330Sbostic flush_saved();
1345*45330Sbostic if(calc_order == BYROWS) {
1346*45330Sbostic for (c1 = curcol; arg-- && c1 < maxcols; c1++) {
1347*45330Sbostic pp = ATBL(tbl, currow, c1);
1348*45330Sbostic if (*pp) {
1349*45330Sbostic free_ent(*pp);
1350*45330Sbostic *pp = (struct ent *)0;
1351*45330Sbostic }
1352*45330Sbostic }
1353*45330Sbostic }
1354*45330Sbostic else {
1355*45330Sbostic for (c1 = currow; arg-- && c1 < maxrows; c1++) {
1356*45330Sbostic pp = ATBL(tbl, c1, curcol);
1357*45330Sbostic if (*pp) {
1358*45330Sbostic free_ent(*pp);
1359*45330Sbostic *pp = (struct ent *)0;
1360*45330Sbostic }
1361*45330Sbostic }
1362*45330Sbostic }
1363*45330Sbostic sync_refs();
1364*45330Sbostic modflg++;
1365*45330Sbostic FullUpdate++;
1366*45330Sbostic }
1367*45330Sbostic break;
1368*45330Sbostic case 'Q':
1369*45330Sbostic case 'q':
1370*45330Sbostic running = 0;
1371*45330Sbostic break;
1372*45330Sbostic case 'h':
1373*45330Sbostic backcol(arg);
1374*45330Sbostic break;
1375*45330Sbostic case 'j':
1376*45330Sbostic forwrow(arg);
1377*45330Sbostic break;
1378*45330Sbostic case 'k':
1379*45330Sbostic backrow(arg);
1380*45330Sbostic break;
1381*45330Sbostic case ' ':
1382*45330Sbostic case 'l':
1383*45330Sbostic forwcol(arg);
1384*45330Sbostic break;
1385*45330Sbostic case 'm':
1386*45330Sbostic savedrow = currow;
1387*45330Sbostic savedcol = curcol;
1388*45330Sbostic break;
1389*45330Sbostic case 'c': {
1390*45330Sbostic register struct ent *p = *ATBL(tbl, savedrow, savedcol);
1391*45330Sbostic register c1;
1392*45330Sbostic register struct ent *n;
1393*45330Sbostic if (!p)
1394*45330Sbostic break;
1395*45330Sbostic FullUpdate++;
1396*45330Sbostic modflg++;
1397*45330Sbostic for (c1 = curcol; arg-- && c1 < maxcols; c1++) {
1398*45330Sbostic n = lookat (currow, c1);
1399*45330Sbostic (void) clearent(n);
1400*45330Sbostic copyent( n, p, currow - savedrow, c1 - savedcol);
1401*45330Sbostic }
1402*45330Sbostic break;
1403*45330Sbostic }
1404*45330Sbostic default:
1405*45330Sbostic if ((toascii(c)) != c)
1406*45330Sbostic error ("Weird character, decimal %d\n",
1407*45330Sbostic (int) c);
1408*45330Sbostic else
1409*45330Sbostic error ("No such command (%c)", c);
1410*45330Sbostic break;
1411*45330Sbostic }
1412*45330Sbostic edistate = nedistate;
1413*45330Sbostic arg = narg;
1414*45330Sbostic } /* while (running) */
1415*45330Sbostic inloop = modcheck(" before exiting");
1416*45330Sbostic } /* while (inloop) */
1417*45330Sbostic deraw();
1418*45330Sbostic endwin();
1419*45330Sbostic #ifdef VMS /* Unit VMS "fixes" exit we should say 1 here */
1420*45330Sbostic exit(1);
1421*45330Sbostic #else
1422*45330Sbostic exit(0);
1423*45330Sbostic #endif
1424*45330Sbostic /*NOTREACHED*/
1425*45330Sbostic }
1426*45330Sbostic
1427*45330Sbostic void
startshow()1428*45330Sbostic startshow()
1429*45330Sbostic {
1430*45330Sbostic showrange = 1;
1431*45330Sbostic showsr = currow;
1432*45330Sbostic showsc = curcol;
1433*45330Sbostic }
1434*45330Sbostic
1435*45330Sbostic void
showdr()1436*45330Sbostic showdr()
1437*45330Sbostic {
1438*45330Sbostic int minsr, minsc, maxsr, maxsc;
1439*45330Sbostic
1440*45330Sbostic minsr = showsr < currow ? showsr : currow;
1441*45330Sbostic minsc = showsc < curcol ? showsc : curcol;
1442*45330Sbostic maxsr = showsr > currow ? showsr : currow;
1443*45330Sbostic maxsc = showsc > curcol ? showsc : curcol;
1444*45330Sbostic (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc));
1445*45330Sbostic }
1446*45330Sbostic
1447*45330Sbostic void
setorder(i)1448*45330Sbostic setorder(i)
1449*45330Sbostic int i;
1450*45330Sbostic {
1451*45330Sbostic if((i == BYROWS)||(i == BYCOLS))
1452*45330Sbostic calc_order = i;
1453*45330Sbostic else
1454*45330Sbostic error("Not yet implemented");
1455*45330Sbostic }
1456*45330Sbostic
1457*45330Sbostic void
setauto(i)1458*45330Sbostic setauto(i)
1459*45330Sbostic int i;
1460*45330Sbostic {
1461*45330Sbostic autocalc = i;
1462*45330Sbostic }
1463*45330Sbostic
1464*45330Sbostic
1465*45330Sbostic #ifdef VMS
1466*45330Sbostic
goraw()1467*45330Sbostic goraw()
1468*45330Sbostic {
1469*45330Sbostic VMS_read_raw = 1;
1470*45330Sbostic FullUpdate++;
1471*45330Sbostic }
1472*45330Sbostic
deraw()1473*45330Sbostic deraw()
1474*45330Sbostic {
1475*45330Sbostic (void) move (LINES - 1, 0);
1476*45330Sbostic (void) clrtoeol();
1477*45330Sbostic (void) refresh();
1478*45330Sbostic VMS_read_raw = 0;
1479*45330Sbostic }
1480*45330Sbostic
1481*45330Sbostic #else /* VMS */
1482*45330Sbostic void
goraw()1483*45330Sbostic goraw()
1484*45330Sbostic {
1485*45330Sbostic #if SYSV2 || SYSV3
1486*45330Sbostic fixterm();
1487*45330Sbostic #else /* SYSV2 || SYSV3 */
1488*45330Sbostic cbreak();
1489*45330Sbostic nonl();
1490*45330Sbostic noecho ();
1491*45330Sbostic #endif /* SYSV2 || SYSV3 */
1492*45330Sbostic kbd_again();
1493*45330Sbostic (void) clear();
1494*45330Sbostic FullUpdate++;
1495*45330Sbostic }
1496*45330Sbostic
1497*45330Sbostic void
deraw()1498*45330Sbostic deraw()
1499*45330Sbostic {
1500*45330Sbostic (void) move (LINES - 1, 0);
1501*45330Sbostic (void) clrtoeol();
1502*45330Sbostic (void) refresh();
1503*45330Sbostic #if SYSV2 || SYSV3
1504*45330Sbostic resetterm();
1505*45330Sbostic #else
1506*45330Sbostic nocbreak();
1507*45330Sbostic nl();
1508*45330Sbostic echo();
1509*45330Sbostic #endif
1510*45330Sbostic resetkbd();
1511*45330Sbostic }
1512*45330Sbostic
1513*45330Sbostic #endif /* VMS */
1514*45330Sbostic
1515*45330Sbostic void
signals()1516*45330Sbostic signals()
1517*45330Sbostic {
1518*45330Sbostic #ifdef SIGVOID
1519*45330Sbostic void quit();
1520*45330Sbostic void time_out();
1521*45330Sbostic void dump_me();
1522*45330Sbostic #else
1523*45330Sbostic int quit();
1524*45330Sbostic int time_out();
1525*45330Sbostic int dump_me();
1526*45330Sbostic #endif
1527*45330Sbostic
1528*45330Sbostic (void) signal(SIGINT, SIG_IGN);
1529*45330Sbostic (void) signal(SIGQUIT, dump_me);
1530*45330Sbostic (void) signal(SIGPIPE, quit);
1531*45330Sbostic (void) signal(SIGTERM, quit);
1532*45330Sbostic (void) signal(SIGALRM, time_out);
1533*45330Sbostic (void) signal(SIGFPE, quit);
1534*45330Sbostic (void) signal(SIGBUS, quit);
1535*45330Sbostic }
1536*45330Sbostic
1537*45330Sbostic #ifdef SIGVOID
1538*45330Sbostic void
1539*45330Sbostic #endif
quit()1540*45330Sbostic quit()
1541*45330Sbostic {
1542*45330Sbostic diesave();
1543*45330Sbostic deraw();
1544*45330Sbostic resetkbd();
1545*45330Sbostic endwin();
1546*45330Sbostic exit(1);
1547*45330Sbostic }
1548*45330Sbostic
1549*45330Sbostic #ifdef SIGVOID
1550*45330Sbostic void
1551*45330Sbostic #endif
dump_me()1552*45330Sbostic dump_me()
1553*45330Sbostic {
1554*45330Sbostic diesave();
1555*45330Sbostic deraw();
1556*45330Sbostic abort();
1557*45330Sbostic }
1558*45330Sbostic
1559*45330Sbostic /* try to save the current spreadsheet if we can */
diesave()1560*45330Sbostic diesave()
1561*45330Sbostic { char path[PATHLEN];
1562*45330Sbostic if (modcheck(" before Spreadsheet dies") == 1)
1563*45330Sbostic { sprintf(path, "~/SC.SAVE");
1564*45330Sbostic if (writefile(path, 0, 0, maxrow, maxcol) < 0)
1565*45330Sbostic if (writefile("/tmp/SC.SAVE", 0, 0, maxrow, maxcol) < 0)
1566*45330Sbostic error("Couldn't save current spreadsheet, Sorry");
1567*45330Sbostic }
1568*45330Sbostic }
1569*45330Sbostic
1570*45330Sbostic int
modcheck(endstr)1571*45330Sbostic modcheck(endstr)
1572*45330Sbostic char *endstr;
1573*45330Sbostic {
1574*45330Sbostic if (modflg && curfile[0]) {
1575*45330Sbostic int yn_ans;
1576*45330Sbostic char lin[100];
1577*45330Sbostic
1578*45330Sbostic (void) sprintf (lin,"File \"%s\" is modified, save%s? ",curfile,endstr);
1579*45330Sbostic if ((yn_ans = yn_ask(lin)) < 0)
1580*45330Sbostic return(1);
1581*45330Sbostic else
1582*45330Sbostic if (yn_ans == 1)
1583*45330Sbostic { if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
1584*45330Sbostic return (1);
1585*45330Sbostic }
1586*45330Sbostic } else if (modflg) {
1587*45330Sbostic int yn_ans;
1588*45330Sbostic
1589*45330Sbostic if ((yn_ans = yn_ask("Do you want a chance to save the data? ")) < 0)
1590*45330Sbostic return(1);
1591*45330Sbostic else
1592*45330Sbostic return(yn_ans);
1593*45330Sbostic }
1594*45330Sbostic return(0);
1595*45330Sbostic }
1596