1*45320Sbostic /* SC A Spreadsheet Calculator
2*45320Sbostic * Command routines
3*45320Sbostic *
4*45320Sbostic * original by James Gosling, September 1982
5*45320Sbostic * modifications by Mark Weiser and Bruce Israel,
6*45320Sbostic * University of Maryland
7*45320Sbostic *
8*45320Sbostic * More mods Robert Bond, 12/86
9*45320Sbostic *
10*45320Sbostic * $Revision: 6.8 $
11*45320Sbostic */
12*45320Sbostic
13*45320Sbostic #include <curses.h>
14*45320Sbostic #if defined(BSD42) || defined(BSD43)
15*45320Sbostic #include <sys/file.h>
16*45320Sbostic #else
17*45320Sbostic #include <fcntl.h>
18*45320Sbostic #endif
19*45320Sbostic #include "sc.h"
20*45320Sbostic #include <signal.h>
21*45320Sbostic #include <errno.h>
22*45320Sbostic
23*45320Sbostic #ifdef BSD42
24*45320Sbostic #include <strings.h>
25*45320Sbostic #else
26*45320Sbostic #ifndef SYSIII
27*45320Sbostic #include <string.h>
28*45320Sbostic #endif
29*45320Sbostic #endif
30*45320Sbostic
31*45320Sbostic #ifdef SYSV3
32*45320Sbostic extern void exit();
33*45320Sbostic #else
34*45320Sbostic extern int exit();
35*45320Sbostic #endif
36*45320Sbostic
37*45320Sbostic extern int errno;
38*45320Sbostic
39*45320Sbostic #define DEFCOLDELIM ':'
40*45320Sbostic
41*45320Sbostic void
duprow()42*45320Sbostic duprow()
43*45320Sbostic {
44*45320Sbostic if (currow >= maxrows - 1 || maxrow >= maxrows - 1) {
45*45320Sbostic if (!growtbl(GROWROW, 0, 0))
46*45320Sbostic return;
47*45320Sbostic }
48*45320Sbostic modflg++;
49*45320Sbostic currow++;
50*45320Sbostic openrow (currow);
51*45320Sbostic for (curcol = 0; curcol <= maxcol; curcol++) {
52*45320Sbostic register struct ent *p = *ATBL(tbl, currow - 1, curcol);
53*45320Sbostic if (p) {
54*45320Sbostic register struct ent *n;
55*45320Sbostic n = lookat (currow, curcol);
56*45320Sbostic (void)copyent ( n, p, 1, 0);
57*45320Sbostic }
58*45320Sbostic }
59*45320Sbostic for (curcol = 0; curcol <= maxcol; curcol++) {
60*45320Sbostic register struct ent *p = *ATBL(tbl, currow, curcol);
61*45320Sbostic if (p && (p -> flags & is_valid) && !p -> expr)
62*45320Sbostic break;
63*45320Sbostic }
64*45320Sbostic if (curcol > maxcol)
65*45320Sbostic curcol = 0;
66*45320Sbostic }
67*45320Sbostic
68*45320Sbostic void
dupcol()69*45320Sbostic dupcol()
70*45320Sbostic {
71*45320Sbostic if (curcol >= maxcols - 1 || maxcol >= maxcols - 1) {
72*45320Sbostic if (!growtbl(GROWCOL, 0, 0))
73*45320Sbostic return;
74*45320Sbostic }
75*45320Sbostic modflg++;
76*45320Sbostic curcol++;
77*45320Sbostic opencol (curcol, 1);
78*45320Sbostic for (currow = 0; currow <= maxrow; currow++) {
79*45320Sbostic register struct ent *p = *ATBL(tbl, currow, curcol - 1);
80*45320Sbostic if (p) {
81*45320Sbostic register struct ent *n;
82*45320Sbostic n = lookat (currow, curcol);
83*45320Sbostic copyent ( n, p, 0, 1);
84*45320Sbostic }
85*45320Sbostic }
86*45320Sbostic for (currow = 0; currow <= maxrow; currow++) {
87*45320Sbostic register struct ent *p = *ATBL(tbl, currow, curcol);
88*45320Sbostic if (p && (p -> flags & is_valid) && !p -> expr)
89*45320Sbostic break;
90*45320Sbostic }
91*45320Sbostic if (currow > maxrow)
92*45320Sbostic currow = 0;
93*45320Sbostic }
94*45320Sbostic
95*45320Sbostic void
insertrow(arg)96*45320Sbostic insertrow(arg)
97*45320Sbostic register int arg;
98*45320Sbostic {
99*45320Sbostic while (--arg>=0) openrow (currow);
100*45320Sbostic }
101*45320Sbostic
102*45320Sbostic void
deleterow(arg)103*45320Sbostic deleterow(arg)
104*45320Sbostic register int arg;
105*45320Sbostic {
106*45320Sbostic flush_saved();
107*45320Sbostic erase_area(currow, 0, currow + arg - 1, maxcol);
108*45320Sbostic currow += arg;
109*45320Sbostic while (--arg>=0) closerow (--currow);
110*45320Sbostic sync_refs();
111*45320Sbostic }
112*45320Sbostic
113*45320Sbostic void
rowvalueize(arg)114*45320Sbostic rowvalueize(arg)
115*45320Sbostic register int arg;
116*45320Sbostic {
117*45320Sbostic valueize_area(currow, 0, currow + arg - 1, maxcol);
118*45320Sbostic }
119*45320Sbostic
120*45320Sbostic void
colvalueize(arg)121*45320Sbostic colvalueize(arg)
122*45320Sbostic register int arg;
123*45320Sbostic {
124*45320Sbostic valueize_area(0, curcol, maxrow, curcol + arg - 1);
125*45320Sbostic }
126*45320Sbostic
127*45320Sbostic void
erase_area(sr,sc,er,ec)128*45320Sbostic erase_area(sr, sc, er, ec)
129*45320Sbostic int sr, sc, er, ec;
130*45320Sbostic {
131*45320Sbostic register int r, c;
132*45320Sbostic register struct ent **pp;
133*45320Sbostic
134*45320Sbostic if (sr > er) {
135*45320Sbostic r = sr; sr = er; er= r;
136*45320Sbostic }
137*45320Sbostic
138*45320Sbostic if (sc > ec) {
139*45320Sbostic c = sc; sc = ec; ec= c;
140*45320Sbostic }
141*45320Sbostic
142*45320Sbostic if (sr < 0)
143*45320Sbostic sr = 0;
144*45320Sbostic if (sc < 0)
145*45320Sbostic sc = 0;
146*45320Sbostic checkbounds(&er, &ec);
147*45320Sbostic
148*45320Sbostic for (r = sr; r <= er; r++) {
149*45320Sbostic for (c = sc; c <= ec; c++) {
150*45320Sbostic pp = ATBL(tbl, r, c);
151*45320Sbostic if (*pp) {
152*45320Sbostic free_ent(*pp);
153*45320Sbostic *pp = (struct ent *)0;
154*45320Sbostic }
155*45320Sbostic }
156*45320Sbostic }
157*45320Sbostic }
158*45320Sbostic
159*45320Sbostic void
valueize_area(sr,sc,er,ec)160*45320Sbostic valueize_area(sr, sc, er, ec)
161*45320Sbostic int sr, sc, er, ec;
162*45320Sbostic {
163*45320Sbostic register int r, c;
164*45320Sbostic register struct ent *p;
165*45320Sbostic
166*45320Sbostic if (sr > er) {
167*45320Sbostic r = sr; sr = er; er= r;
168*45320Sbostic }
169*45320Sbostic
170*45320Sbostic if (sc > ec) {
171*45320Sbostic c = sc; sc = ec; ec= c;
172*45320Sbostic }
173*45320Sbostic
174*45320Sbostic if (sr < 0)
175*45320Sbostic sr = 0;
176*45320Sbostic if (sc < 0)
177*45320Sbostic sc = 0;
178*45320Sbostic checkbounds(&er, &ec);
179*45320Sbostic
180*45320Sbostic for (r = sr; r <= er; r++) {
181*45320Sbostic for (c = sc; c <= ec; c++) {
182*45320Sbostic p = *ATBL(tbl, r, c);
183*45320Sbostic if (p && p->expr) {
184*45320Sbostic efree(p, p->expr);
185*45320Sbostic p->expr = (struct enode *)0;
186*45320Sbostic p->flags &= ~is_strexpr;
187*45320Sbostic }
188*45320Sbostic }
189*45320Sbostic }
190*45320Sbostic
191*45320Sbostic }
192*45320Sbostic
193*45320Sbostic void
pullcells(to_insert)194*45320Sbostic pullcells(to_insert)
195*45320Sbostic int to_insert;
196*45320Sbostic {
197*45320Sbostic register struct ent *p, *n;
198*45320Sbostic register int deltar, deltac;
199*45320Sbostic int minrow, mincol;
200*45320Sbostic int mxrow, mxcol;
201*45320Sbostic int numrows, numcols;
202*45320Sbostic
203*45320Sbostic if (! to_fix)
204*45320Sbostic {
205*45320Sbostic error ("No data to pull");
206*45320Sbostic return;
207*45320Sbostic }
208*45320Sbostic
209*45320Sbostic minrow = maxrows;
210*45320Sbostic mincol = maxcols;
211*45320Sbostic mxrow = 0;
212*45320Sbostic mxcol = 0;
213*45320Sbostic
214*45320Sbostic for (p = to_fix; p; p = p->next) {
215*45320Sbostic if (p->row < minrow)
216*45320Sbostic minrow = p->row;
217*45320Sbostic if (p->row > mxrow)
218*45320Sbostic mxrow = p->row;
219*45320Sbostic if (p->col < mincol)
220*45320Sbostic mincol = p->col;
221*45320Sbostic if (p->col > mxcol)
222*45320Sbostic mxcol = p->col;
223*45320Sbostic }
224*45320Sbostic
225*45320Sbostic numrows = mxrow - minrow + 1;
226*45320Sbostic numcols = mxcol - mincol + 1;
227*45320Sbostic deltar = currow - minrow;
228*45320Sbostic deltac = curcol - mincol;
229*45320Sbostic
230*45320Sbostic if (to_insert == 'r') {
231*45320Sbostic insertrow(numrows);
232*45320Sbostic deltac = 0;
233*45320Sbostic } else if (to_insert == 'c') {
234*45320Sbostic opencol(curcol, numcols);
235*45320Sbostic deltar = 0;
236*45320Sbostic }
237*45320Sbostic
238*45320Sbostic FullUpdate++;
239*45320Sbostic modflg++;
240*45320Sbostic
241*45320Sbostic for (p = to_fix; p; p = p->next) {
242*45320Sbostic n = lookat (p->row + deltar, p->col + deltac);
243*45320Sbostic (void) clearent(n);
244*45320Sbostic copyent( n, p, deltar, deltac);
245*45320Sbostic n -> flags = p -> flags & ~is_deleted;
246*45320Sbostic }
247*45320Sbostic }
248*45320Sbostic
249*45320Sbostic void
colshow_op()250*45320Sbostic colshow_op()
251*45320Sbostic {
252*45320Sbostic register int i,j;
253*45320Sbostic for (i=0; i<maxcols; i++)
254*45320Sbostic if (col_hidden[i])
255*45320Sbostic break;
256*45320Sbostic for(j=i; j<maxcols; j++)
257*45320Sbostic if (!col_hidden[j])
258*45320Sbostic break;
259*45320Sbostic j--;
260*45320Sbostic if (i>=maxcols)
261*45320Sbostic error ("No hidden columns to show");
262*45320Sbostic else {
263*45320Sbostic (void) sprintf(line,"show %s:", coltoa(i));
264*45320Sbostic (void) sprintf(line + strlen(line),"%s",coltoa(j));
265*45320Sbostic linelim = strlen (line);
266*45320Sbostic }
267*45320Sbostic }
268*45320Sbostic
269*45320Sbostic void
rowshow_op()270*45320Sbostic rowshow_op()
271*45320Sbostic {
272*45320Sbostic register int i,j;
273*45320Sbostic for (i=0; i<maxrows; i++)
274*45320Sbostic if (row_hidden[i])
275*45320Sbostic break;
276*45320Sbostic for(j=i; j<maxrows; j++)
277*45320Sbostic if (!row_hidden[j]) {
278*45320Sbostic break;
279*45320Sbostic }
280*45320Sbostic j--;
281*45320Sbostic
282*45320Sbostic if (i>=maxrows)
283*45320Sbostic error ("No hidden rows to show");
284*45320Sbostic else {
285*45320Sbostic (void) sprintf(line,"show %d:%d", i, j);
286*45320Sbostic linelim = strlen (line);
287*45320Sbostic }
288*45320Sbostic }
289*45320Sbostic
290*45320Sbostic /*
291*45320Sbostic * Given a row/column command letter, emit a small menu, then read a qualifier
292*45320Sbostic * character for a row/column command and convert it to 'r' (row), 'c'
293*45320Sbostic * (column), or 0 (unknown). If ch is 'p', an extra qualifier 'm' is allowed.
294*45320Sbostic */
295*45320Sbostic
296*45320Sbostic int
get_rcqual(ch)297*45320Sbostic get_rcqual (ch)
298*45320Sbostic int ch;
299*45320Sbostic {
300*45320Sbostic error ("%sow/column: r: row c: column%s",
301*45320Sbostic
302*45320Sbostic (ch == 'i') ? "Insert r" :
303*45320Sbostic (ch == 'a') ? "Append r" :
304*45320Sbostic (ch == 'd') ? "Delete r" :
305*45320Sbostic (ch == 'p') ? "Pull r" :
306*45320Sbostic (ch == 'v') ? "Values r" :
307*45320Sbostic (ch == 'z') ? "Zap r" :
308*45320Sbostic (ch == 's') ? "Show r" : "R",
309*45320Sbostic
310*45320Sbostic (ch == 'p') ? " m: merge" : "");
311*45320Sbostic
312*45320Sbostic (void) refresh();
313*45320Sbostic
314*45320Sbostic switch (nmgetch())
315*45320Sbostic {
316*45320Sbostic case 'r':
317*45320Sbostic case 'l':
318*45320Sbostic case 'h':
319*45320Sbostic case ctl('f'):
320*45320Sbostic case ctl('b'): return ('r');
321*45320Sbostic
322*45320Sbostic case 'c':
323*45320Sbostic case 'j':
324*45320Sbostic case 'k':
325*45320Sbostic case ctl('p'):
326*45320Sbostic case ctl('n'): return ('c');
327*45320Sbostic
328*45320Sbostic case 'm': return ((ch == 'p') ? 'm' : 0);
329*45320Sbostic
330*45320Sbostic case ESC:
331*45320Sbostic case ctl('g'): return (ESC);
332*45320Sbostic
333*45320Sbostic default: return (0);
334*45320Sbostic }
335*45320Sbostic /*NOTREACHED*/
336*45320Sbostic }
337*45320Sbostic
338*45320Sbostic void
openrow(rs)339*45320Sbostic openrow (rs)
340*45320Sbostic int rs;
341*45320Sbostic {
342*45320Sbostic register r, c;
343*45320Sbostic struct ent **tmprow, **pp;
344*45320Sbostic
345*45320Sbostic if (rs > maxrow) maxrow = rs;
346*45320Sbostic if (maxrow >= maxrows - 1 || rs > maxrows - 1) {
347*45320Sbostic if (!growtbl(GROWROW, rs, 0))
348*45320Sbostic return;
349*45320Sbostic }
350*45320Sbostic /*
351*45320Sbostic * save the last active row+1, shift the rows downward, put the last
352*45320Sbostic * row in place of the first
353*45320Sbostic */
354*45320Sbostic tmprow = tbl[++maxrow];
355*45320Sbostic for (r = maxrow; r > rs; r--) {
356*45320Sbostic row_hidden[r] = row_hidden[r-1];
357*45320Sbostic tbl[r] = tbl[r-1];
358*45320Sbostic pp = ATBL(tbl, r, 0);
359*45320Sbostic for (c = 0; c < maxcols; c++, pp++)
360*45320Sbostic if (*pp)
361*45320Sbostic (*pp)->row = r;
362*45320Sbostic }
363*45320Sbostic tbl[r] = tmprow; /* the last row was never used.... */
364*45320Sbostic FullUpdate++;
365*45320Sbostic modflg++;
366*45320Sbostic }
367*45320Sbostic
368*45320Sbostic void
closerow(r)369*45320Sbostic closerow (r)
370*45320Sbostic register r;
371*45320Sbostic {
372*45320Sbostic register struct ent **pp;
373*45320Sbostic register c;
374*45320Sbostic struct ent **tmprow;
375*45320Sbostic
376*45320Sbostic if (r > maxrow) return;
377*45320Sbostic
378*45320Sbostic /* save the row and empty it out */
379*45320Sbostic tmprow = tbl[r];
380*45320Sbostic pp = ATBL(tbl, r, 0);
381*45320Sbostic for (c=maxcol+1; --c>=0; pp++) {
382*45320Sbostic if (*pp)
383*45320Sbostic { free_ent(*pp);
384*45320Sbostic *pp = (struct ent *)0;
385*45320Sbostic }
386*45320Sbostic }
387*45320Sbostic
388*45320Sbostic /* move the rows, put the deleted row at the end */
389*45320Sbostic for (; r < maxrows - 1; r++) {
390*45320Sbostic row_hidden[r] = row_hidden[r+1];
391*45320Sbostic tbl[r] = tbl[r+1];
392*45320Sbostic pp = ATBL(tbl, r, 0);
393*45320Sbostic for (c = 0; c < maxcols; c++, pp++)
394*45320Sbostic if (*pp)
395*45320Sbostic (*pp)->row = r;
396*45320Sbostic }
397*45320Sbostic tbl[r] = tmprow;
398*45320Sbostic
399*45320Sbostic maxrow--;
400*45320Sbostic FullUpdate++;
401*45320Sbostic modflg++;
402*45320Sbostic }
403*45320Sbostic
404*45320Sbostic void
opencol(cs,numcol)405*45320Sbostic opencol (cs, numcol)
406*45320Sbostic int cs;
407*45320Sbostic int numcol;
408*45320Sbostic {
409*45320Sbostic register r;
410*45320Sbostic register struct ent **pp;
411*45320Sbostic register c;
412*45320Sbostic register lim = maxcol-cs+1;
413*45320Sbostic int i;
414*45320Sbostic
415*45320Sbostic if (cs > maxcol)
416*45320Sbostic maxcol = cs;
417*45320Sbostic maxcol += numcol;
418*45320Sbostic
419*45320Sbostic if ((maxcol >= maxcols - 1) && !growtbl(GROWCOL, 0, maxcol))
420*45320Sbostic return;
421*45320Sbostic
422*45320Sbostic for (i = maxcol; i > cs; i--) {
423*45320Sbostic fwidth[i] = fwidth[i-numcol];
424*45320Sbostic precision[i] = precision[i-numcol];
425*45320Sbostic col_hidden[i] = col_hidden[i-numcol];
426*45320Sbostic }
427*45320Sbostic for (c = cs; c - cs < numcol; c++)
428*45320Sbostic { fwidth[c] = DEFWIDTH;
429*45320Sbostic precision[c] = DEFPREC;
430*45320Sbostic }
431*45320Sbostic
432*45320Sbostic for (r=0; r<=maxrow; r++) {
433*45320Sbostic pp = ATBL(tbl, r, maxcol);
434*45320Sbostic for (c=lim; --c>=0; pp--)
435*45320Sbostic if (pp[0] = pp[-numcol])
436*45320Sbostic pp[0]->col += numcol;
437*45320Sbostic
438*45320Sbostic pp = ATBL(tbl, r, cs);
439*45320Sbostic for (c = cs; c - cs < numcol; c++, pp++)
440*45320Sbostic *pp = (struct ent *)0;
441*45320Sbostic }
442*45320Sbostic FullUpdate++;
443*45320Sbostic modflg++;
444*45320Sbostic }
445*45320Sbostic
446*45320Sbostic void
closecol(cs,numcol)447*45320Sbostic closecol (cs, numcol)
448*45320Sbostic int cs;
449*45320Sbostic int numcol;
450*45320Sbostic {
451*45320Sbostic register r;
452*45320Sbostic register struct ent **pp;
453*45320Sbostic register struct ent *q;
454*45320Sbostic register c;
455*45320Sbostic register lim = maxcol-cs;
456*45320Sbostic int i;
457*45320Sbostic char buf[50];
458*45320Sbostic
459*45320Sbostic if (lim - numcol < -1)
460*45320Sbostic { sprintf(buf, "Can't delete %d column%s %d columns left", numcol,
461*45320Sbostic (numcol > 1 ? "s," : ","), lim+1);
462*45320Sbostic error(buf);
463*45320Sbostic return;
464*45320Sbostic }
465*45320Sbostic flush_saved();
466*45320Sbostic erase_area(0, curcol, maxrow, curcol + numcol - 1);
467*45320Sbostic sync_refs();
468*45320Sbostic
469*45320Sbostic /* clear then copy the block left */
470*45320Sbostic lim = maxcols - numcol - 1;
471*45320Sbostic for (r=0; r<=maxrow; r++) {
472*45320Sbostic for (c = cs; c - cs < numcol; c++)
473*45320Sbostic if (q = *ATBL(tbl, r, c))
474*45320Sbostic free_ent(q);
475*45320Sbostic
476*45320Sbostic pp = ATBL(tbl, r, cs);
477*45320Sbostic for (c=cs; c <= lim; c++, pp++)
478*45320Sbostic { if (c > lim)
479*45320Sbostic *pp = (struct ent *)0;
480*45320Sbostic else
481*45320Sbostic if (pp[0] = pp[numcol])
482*45320Sbostic pp[0]->col -= numcol;
483*45320Sbostic }
484*45320Sbostic
485*45320Sbostic c = numcol;
486*45320Sbostic for (; --c >= 0; pp++)
487*45320Sbostic *pp = (struct ent *)0;
488*45320Sbostic }
489*45320Sbostic
490*45320Sbostic for (i = cs; i < maxcols - numcol - 1; i++) {
491*45320Sbostic fwidth[i] = fwidth[i+numcol];
492*45320Sbostic precision[i] = precision[i+numcol];
493*45320Sbostic col_hidden[i] = col_hidden[i+numcol];
494*45320Sbostic }
495*45320Sbostic for (; i < maxcols - 1; i++) {
496*45320Sbostic fwidth[i] = DEFWIDTH;
497*45320Sbostic precision[i] = DEFPREC;
498*45320Sbostic col_hidden[i] = 0;
499*45320Sbostic }
500*45320Sbostic
501*45320Sbostic maxcol -= numcol;
502*45320Sbostic FullUpdate++;
503*45320Sbostic modflg++;
504*45320Sbostic }
505*45320Sbostic
506*45320Sbostic void
doend(rowinc,colinc)507*45320Sbostic doend(rowinc, colinc)
508*45320Sbostic int rowinc, colinc;
509*45320Sbostic {
510*45320Sbostic register struct ent *p;
511*45320Sbostic int r, c;
512*45320Sbostic
513*45320Sbostic if (VALID_CELL(p, currow, curcol)) {
514*45320Sbostic r = currow + rowinc;
515*45320Sbostic c = curcol + colinc;
516*45320Sbostic if (r >= 0 && r < maxrows &&
517*45320Sbostic c >= 0 && c < maxcols &&
518*45320Sbostic !VALID_CELL(p, r, c)) {
519*45320Sbostic currow = r;
520*45320Sbostic curcol = c;
521*45320Sbostic }
522*45320Sbostic }
523*45320Sbostic
524*45320Sbostic if (!VALID_CELL(p, currow, curcol)) {
525*45320Sbostic switch (rowinc) {
526*45320Sbostic case -1:
527*45320Sbostic while (!VALID_CELL(p, currow, curcol) && currow > 0)
528*45320Sbostic currow--;
529*45320Sbostic break;
530*45320Sbostic case 1:
531*45320Sbostic while (!VALID_CELL(p, currow, curcol) && currow < maxrows-1)
532*45320Sbostic currow++;
533*45320Sbostic break;
534*45320Sbostic case 0:
535*45320Sbostic switch (colinc) {
536*45320Sbostic case -1:
537*45320Sbostic while (!VALID_CELL(p, currow, curcol) && curcol > 0)
538*45320Sbostic curcol--;
539*45320Sbostic break;
540*45320Sbostic case 1:
541*45320Sbostic while (!VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
542*45320Sbostic curcol++;
543*45320Sbostic break;
544*45320Sbostic }
545*45320Sbostic break;
546*45320Sbostic }
547*45320Sbostic
548*45320Sbostic error (""); /* clear line */
549*45320Sbostic return;
550*45320Sbostic }
551*45320Sbostic
552*45320Sbostic switch (rowinc) {
553*45320Sbostic case -1:
554*45320Sbostic while (VALID_CELL(p, currow, curcol) && currow > 0)
555*45320Sbostic currow--;
556*45320Sbostic break;
557*45320Sbostic case 1:
558*45320Sbostic while (VALID_CELL(p, currow, curcol) && currow < maxrows-1)
559*45320Sbostic currow++;
560*45320Sbostic break;
561*45320Sbostic case 0:
562*45320Sbostic switch (colinc) {
563*45320Sbostic case -1:
564*45320Sbostic while (VALID_CELL(p, currow, curcol) && curcol > 0)
565*45320Sbostic curcol--;
566*45320Sbostic break;
567*45320Sbostic case 1:
568*45320Sbostic while (VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
569*45320Sbostic curcol++;
570*45320Sbostic break;
571*45320Sbostic }
572*45320Sbostic break;
573*45320Sbostic }
574*45320Sbostic if (!VALID_CELL(p, currow, curcol)) {
575*45320Sbostic currow -= rowinc;
576*45320Sbostic curcol -= colinc;
577*45320Sbostic }
578*45320Sbostic }
579*45320Sbostic
580*45320Sbostic void
doformat(c1,c2,w,p)581*45320Sbostic doformat(c1,c2,w,p)
582*45320Sbostic int c1,c2,w,p;
583*45320Sbostic {
584*45320Sbostic register int i;
585*45320Sbostic
586*45320Sbostic if (w > COLS - RESCOL - 2) {
587*45320Sbostic error("Format too large - Maximum = %d", COLS - RESCOL - 2);
588*45320Sbostic w = COLS-RESCOL-2;
589*45320Sbostic }
590*45320Sbostic
591*45320Sbostic if (p > w) {
592*45320Sbostic error("Precision too large");
593*45320Sbostic p = w;
594*45320Sbostic }
595*45320Sbostic
596*45320Sbostic for(i = c1; i<=c2; i++)
597*45320Sbostic fwidth[i] = w, precision[i] = p;
598*45320Sbostic
599*45320Sbostic FullUpdate++;
600*45320Sbostic modflg++;
601*45320Sbostic }
602*45320Sbostic
603*45320Sbostic void
print_options(f)604*45320Sbostic print_options(f)
605*45320Sbostic FILE *f;
606*45320Sbostic {
607*45320Sbostic if(
608*45320Sbostic autocalc &&
609*45320Sbostic propagation == 10 &&
610*45320Sbostic calc_order == BYROWS &&
611*45320Sbostic !numeric &&
612*45320Sbostic prescale == 1.0 &&
613*45320Sbostic !extfunc &&
614*45320Sbostic showcell &&
615*45320Sbostic showtop &&
616*45320Sbostic tbl_style == 0
617*45320Sbostic )
618*45320Sbostic return; /* No reason to do this */
619*45320Sbostic
620*45320Sbostic (void) fprintf(f, "set");
621*45320Sbostic if(!autocalc)
622*45320Sbostic (void) fprintf(f," !autocalc");
623*45320Sbostic if(propagation != 10)
624*45320Sbostic (void) fprintf(f, " iterations = %d", propagation);
625*45320Sbostic if(calc_order != BYROWS )
626*45320Sbostic (void) fprintf(f, " bycols");
627*45320Sbostic if (numeric)
628*45320Sbostic (void) fprintf(f, " numeric");
629*45320Sbostic if (prescale != 1.0)
630*45320Sbostic (void) fprintf(f, " prescale");
631*45320Sbostic if (extfunc)
632*45320Sbostic (void) fprintf(f, " extfun");
633*45320Sbostic if (!showcell)
634*45320Sbostic (void) fprintf(f, " !cellcur");
635*45320Sbostic if (!showtop)
636*45320Sbostic (void) fprintf(f, " !toprow");
637*45320Sbostic if (tbl_style)
638*45320Sbostic (void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" :
639*45320Sbostic tbl_style == LATEX ? "latex" :
640*45320Sbostic tbl_style == TEX ? "tex" : "0" );
641*45320Sbostic (void) fprintf(f, "\n");
642*45320Sbostic }
643*45320Sbostic
644*45320Sbostic void
printfile(fname,r0,c0,rn,cn)645*45320Sbostic printfile (fname, r0, c0, rn, cn)
646*45320Sbostic char *fname;
647*45320Sbostic int r0, c0, rn, cn;
648*45320Sbostic {
649*45320Sbostic FILE *f;
650*45320Sbostic char pline[FBUFLEN];
651*45320Sbostic int plinelim;
652*45320Sbostic int pid;
653*45320Sbostic int fieldlen, nextcol;
654*45320Sbostic register row, col;
655*45320Sbostic register struct ent **pp;
656*45320Sbostic
657*45320Sbostic if ((strcmp(fname, curfile) == 0) &&
658*45320Sbostic !yn_ask("Confirm that you want to destroy the data base: (y,n)"))
659*45320Sbostic return;
660*45320Sbostic
661*45320Sbostic if ((f = openout(fname, &pid)) == (FILE *)0)
662*45320Sbostic { error ("Can't create file \"%s\"", fname);
663*45320Sbostic return;
664*45320Sbostic }
665*45320Sbostic for (row=r0;row<=rn; row++) {
666*45320Sbostic register c = 0;
667*45320Sbostic
668*45320Sbostic if (row_hidden[row])
669*45320Sbostic continue;
670*45320Sbostic
671*45320Sbostic pline[plinelim=0] = '\0';
672*45320Sbostic for (pp = ATBL(tbl, row, col=c0); col<=cn;
673*45320Sbostic pp += nextcol-col, col = nextcol, c += fieldlen) {
674*45320Sbostic
675*45320Sbostic nextcol = col+1;
676*45320Sbostic if (col_hidden[col]) {
677*45320Sbostic fieldlen = 0;
678*45320Sbostic continue;
679*45320Sbostic }
680*45320Sbostic
681*45320Sbostic fieldlen = fwidth[col];
682*45320Sbostic if (*pp) {
683*45320Sbostic char *s;
684*45320Sbostic
685*45320Sbostic while (plinelim<c) pline[plinelim++] = ' ';
686*45320Sbostic plinelim = c;
687*45320Sbostic if ((*pp)->flags&is_valid) {
688*45320Sbostic (void)sprintf (pline+plinelim,"%*.*f",fwidth[col],
689*45320Sbostic precision[col], (*pp)->v);
690*45320Sbostic plinelim += strlen (pline+plinelim);
691*45320Sbostic }
692*45320Sbostic if (s = (*pp)->label) {
693*45320Sbostic int slen;
694*45320Sbostic char *start, *last;
695*45320Sbostic register char *fp;
696*45320Sbostic struct ent *nc;
697*45320Sbostic
698*45320Sbostic /* Figure out if the label slops over to a blank field */
699*45320Sbostic slen = strlen(s);
700*45320Sbostic while (slen > fieldlen && nextcol <= cn &&
701*45320Sbostic !((nc = lookat(row,nextcol))->flags & is_valid) &&
702*45320Sbostic !(nc->label)) {
703*45320Sbostic
704*45320Sbostic if (!col_hidden[nextcol])
705*45320Sbostic fieldlen += fwidth[nextcol];
706*45320Sbostic
707*45320Sbostic nextcol++;
708*45320Sbostic }
709*45320Sbostic if (slen > fieldlen)
710*45320Sbostic slen = fieldlen;
711*45320Sbostic
712*45320Sbostic /* Now justify and print */
713*45320Sbostic start = (*pp)->flags & is_leftflush ? pline + c
714*45320Sbostic : pline + c + fieldlen - slen;
715*45320Sbostic last = pline + c + fieldlen;
716*45320Sbostic fp = plinelim < c ? pline + plinelim : pline + c;
717*45320Sbostic while (fp < start)
718*45320Sbostic *fp++ = ' ';
719*45320Sbostic while (slen--)
720*45320Sbostic *fp++ = *s++;
721*45320Sbostic if (!((*pp)->flags & is_valid) || fieldlen != fwidth[col])
722*45320Sbostic while(fp < last)
723*45320Sbostic *fp++ = ' ';
724*45320Sbostic if (plinelim < fp - pline)
725*45320Sbostic plinelim = fp - pline;
726*45320Sbostic }
727*45320Sbostic }
728*45320Sbostic }
729*45320Sbostic pline[plinelim++] = '\n';
730*45320Sbostic pline[plinelim] = '\0';
731*45320Sbostic (void) fputs (pline, f);
732*45320Sbostic }
733*45320Sbostic
734*45320Sbostic closeout(f, pid);
735*45320Sbostic }
736*45320Sbostic
737*45320Sbostic void
tblprintfile(fname,r0,c0,rn,cn)738*45320Sbostic tblprintfile (fname, r0, c0, rn, cn)
739*45320Sbostic char *fname;
740*45320Sbostic int r0, c0, rn, cn;
741*45320Sbostic {
742*45320Sbostic FILE *f;
743*45320Sbostic int pid;
744*45320Sbostic register row, col;
745*45320Sbostic register struct ent **pp;
746*45320Sbostic char coldelim = DEFCOLDELIM;
747*45320Sbostic
748*45320Sbostic if ((strcmp(fname, curfile) == 0) &&
749*45320Sbostic !yn_ask("Confirm that you want to destroy the data base: (y,n)"))
750*45320Sbostic return;
751*45320Sbostic
752*45320Sbostic if ((f = openout(fname, &pid)) == (FILE *)0)
753*45320Sbostic { error ("Can't create file \"%s\"", fname);
754*45320Sbostic return;
755*45320Sbostic }
756*45320Sbostic
757*45320Sbostic if ( tbl_style == TBL ) {
758*45320Sbostic fprintf(f,".\\\" ** %s spreadsheet output \n.TS\n",progname);
759*45320Sbostic fprintf(f,"tab(%c);\n",coldelim);
760*45320Sbostic for (col=c0;col<=cn; col++) fprintf(f," n");
761*45320Sbostic fprintf(f, ".\n");
762*45320Sbostic }
763*45320Sbostic else if ( tbl_style == LATEX ) {
764*45320Sbostic fprintf(f,"%% ** %s spreadsheet output\n\\begin{tabular}{",progname);
765*45320Sbostic for (col=c0;col<=cn; col++) fprintf(f,"c");
766*45320Sbostic fprintf(f, "}\n");
767*45320Sbostic coldelim = '&';
768*45320Sbostic }
769*45320Sbostic else if ( tbl_style == TEX ) {
770*45320Sbostic fprintf(f,"{\t%% ** %s spreadsheet output\n\\settabs %d \\columns\n",
771*45320Sbostic progname, cn-c0+1);
772*45320Sbostic coldelim = '&';
773*45320Sbostic }
774*45320Sbostic
775*45320Sbostic for (row=r0; row<=rn; row++) {
776*45320Sbostic if ( tbl_style == TEX )
777*45320Sbostic (void) fprintf (f, "\\+");
778*45320Sbostic
779*45320Sbostic for (pp = ATBL(tbl, row, col=c0); col<=cn; col++, pp++) {
780*45320Sbostic if (*pp) {
781*45320Sbostic char *s;
782*45320Sbostic if ((*pp)->flags&is_valid) {
783*45320Sbostic (void) fprintf (f,"%.*f",precision[col],
784*45320Sbostic (*pp)->v);
785*45320Sbostic }
786*45320Sbostic if (s = (*pp)->label) {
787*45320Sbostic (void) fprintf (f,"%s",s);
788*45320Sbostic }
789*45320Sbostic }
790*45320Sbostic if ( col < cn )
791*45320Sbostic (void) fprintf(f,"%c",coldelim);
792*45320Sbostic }
793*45320Sbostic if ( tbl_style == LATEX ) {
794*45320Sbostic if ( row < rn ) (void) fprintf (f, "\\\\");
795*45320Sbostic }
796*45320Sbostic else if ( tbl_style == TEX ) {
797*45320Sbostic (void) fprintf (f, "\\cr");
798*45320Sbostic }
799*45320Sbostic (void) fprintf (f,"\n");
800*45320Sbostic }
801*45320Sbostic
802*45320Sbostic if ( tbl_style == TBL )
803*45320Sbostic (void) fprintf (f,".TE\n.\\\" ** end of %s spreadsheet output\n", progname);
804*45320Sbostic else if ( tbl_style == LATEX )
805*45320Sbostic (void) fprintf (f,"\\end{tabular}\n%% ** end of %s spreadsheet output\n", progname);
806*45320Sbostic else if ( tbl_style == TEX )
807*45320Sbostic (void) fprintf (f,"}\n%% ** end of %s spreadsheet output\n", progname);
808*45320Sbostic
809*45320Sbostic closeout(f, pid);
810*45320Sbostic }
811*45320Sbostic
812*45320Sbostic struct enode *
copye(e,Rdelta,Cdelta)813*45320Sbostic copye (e, Rdelta, Cdelta)
814*45320Sbostic register struct enode *e;
815*45320Sbostic int Rdelta, Cdelta;
816*45320Sbostic {
817*45320Sbostic register struct enode *ret;
818*45320Sbostic
819*45320Sbostic if (e == (struct enode *)0) {
820*45320Sbostic ret = (struct enode *)0;
821*45320Sbostic } else if (e->op & REDUCE) {
822*45320Sbostic int newrow, newcol;
823*45320Sbostic ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
824*45320Sbostic ret->op = e->op;
825*45320Sbostic newrow=e->e.r.left.vf & FIX_ROW ? e->e.r.left.vp->row :
826*45320Sbostic e->e.r.left.vp->row+Rdelta;
827*45320Sbostic newcol=e->e.r.left.vf & FIX_COL ? e->e.r.left.vp->col :
828*45320Sbostic e->e.r.left.vp->col+Cdelta;
829*45320Sbostic ret->e.r.left.vp = lookat (newrow, newcol);
830*45320Sbostic ret->e.r.left.vf = e->e.r.left.vf;
831*45320Sbostic newrow=e->e.r.right.vf & FIX_ROW ? e->e.r.right.vp->row :
832*45320Sbostic e->e.r.right.vp->row+Rdelta;
833*45320Sbostic newcol=e->e.r.right.vf & FIX_COL ? e->e.r.right.vp->col :
834*45320Sbostic e->e.r.right.vp->col+Cdelta;
835*45320Sbostic ret->e.r.right.vp = lookat (newrow, newcol);
836*45320Sbostic ret->e.r.right.vf = e->e.r.right.vf;
837*45320Sbostic } else {
838*45320Sbostic ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
839*45320Sbostic ret->op = e->op;
840*45320Sbostic switch (ret->op) {
841*45320Sbostic case 'v':
842*45320Sbostic {
843*45320Sbostic int newrow, newcol;
844*45320Sbostic newrow=e->e.v.vf & FIX_ROW ? e->e.v.vp->row :
845*45320Sbostic e->e.v.vp->row+Rdelta;
846*45320Sbostic newcol=e->e.v.vf & FIX_COL ? e->e.v.vp->col :
847*45320Sbostic e->e.v.vp->col+Cdelta;
848*45320Sbostic ret->e.v.vp = lookat (newrow, newcol);
849*45320Sbostic ret->e.v.vf = e->e.v.vf;
850*45320Sbostic break;
851*45320Sbostic }
852*45320Sbostic case 'k':
853*45320Sbostic ret->e.k = e->e.k;
854*45320Sbostic break;
855*45320Sbostic case 'f':
856*45320Sbostic ret->e.o.right = copye (e->e.o.right,0,0);
857*45320Sbostic ret->e.o.left = (struct enode *)0;
858*45320Sbostic break;
859*45320Sbostic case '$':
860*45320Sbostic ret->e.s = xmalloc((unsigned) strlen(e->e.s)+1);
861*45320Sbostic (void) strcpy(ret->e.s, e->e.s);
862*45320Sbostic break;
863*45320Sbostic default:
864*45320Sbostic ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
865*45320Sbostic ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
866*45320Sbostic break;
867*45320Sbostic }
868*45320Sbostic }
869*45320Sbostic return ret;
870*45320Sbostic }
871*45320Sbostic
872*45320Sbostic /*
873*45320Sbostic * sync_refs and syncref are used to remove references to
874*45320Sbostic * deleted struct ents. Note that the deleted structure must still
875*45320Sbostic * be hanging around before the call, but not referenced by an entry
876*45320Sbostic * in tbl. Thus the free_ent, fix_ent calls in sc.c
877*45320Sbostic */
878*45320Sbostic void
sync_refs()879*45320Sbostic sync_refs ()
880*45320Sbostic {
881*45320Sbostic register i,j;
882*45320Sbostic register struct ent *p;
883*45320Sbostic sync_ranges();
884*45320Sbostic for (i=0; i<=maxrow; i++)
885*45320Sbostic for (j=0; j<=maxcol; j++)
886*45320Sbostic if ((p = *ATBL(tbl, i, j)) && p->expr)
887*45320Sbostic syncref(p->expr);
888*45320Sbostic }
889*45320Sbostic
890*45320Sbostic void
syncref(e)891*45320Sbostic syncref(e)
892*45320Sbostic register struct enode *e;
893*45320Sbostic {
894*45320Sbostic if (e == (struct enode *)0)
895*45320Sbostic return;
896*45320Sbostic else if (e->op & REDUCE) {
897*45320Sbostic e->e.r.right.vp = lookat(e->e.r.right.vp->row, e->e.r.right.vp->col);
898*45320Sbostic e->e.r.left.vp = lookat(e->e.r.left.vp->row, e->e.r.left.vp->col);
899*45320Sbostic } else {
900*45320Sbostic switch (e->op) {
901*45320Sbostic case 'v':
902*45320Sbostic e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col);
903*45320Sbostic break;
904*45320Sbostic case 'k':
905*45320Sbostic break;
906*45320Sbostic case '$':
907*45320Sbostic break;
908*45320Sbostic default:
909*45320Sbostic syncref(e->e.o.right);
910*45320Sbostic syncref(e->e.o.left);
911*45320Sbostic break;
912*45320Sbostic }
913*45320Sbostic }
914*45320Sbostic }
915*45320Sbostic
916*45320Sbostic void
hiderow(arg)917*45320Sbostic hiderow(arg)
918*45320Sbostic int arg;
919*45320Sbostic {
920*45320Sbostic register int r1;
921*45320Sbostic register int r2;
922*45320Sbostic
923*45320Sbostic r1 = currow;
924*45320Sbostic r2 = r1 + arg - 1;
925*45320Sbostic if (r1 < 0 || r1 > r2) {
926*45320Sbostic error ("Invalid range");
927*45320Sbostic return;
928*45320Sbostic }
929*45320Sbostic if (r2 >= maxrows-1)
930*45320Sbostic { if (!growtbl(GROWROW, arg+1, 0))
931*45320Sbostic { error("You can't hide the last row");
932*45320Sbostic return;
933*45320Sbostic }
934*45320Sbostic }
935*45320Sbostic FullUpdate++;
936*45320Sbostic modflg++;
937*45320Sbostic while (r1 <= r2)
938*45320Sbostic row_hidden[r1++] = 1;
939*45320Sbostic }
940*45320Sbostic
941*45320Sbostic void
hidecol(arg)942*45320Sbostic hidecol(arg)
943*45320Sbostic int arg;
944*45320Sbostic {
945*45320Sbostic register int c1;
946*45320Sbostic register int c2;
947*45320Sbostic
948*45320Sbostic c1 = curcol;
949*45320Sbostic c2 = c1 + arg - 1;
950*45320Sbostic if (c1 < 0 || c1 > c2) {
951*45320Sbostic error ("Invalid range");
952*45320Sbostic return;
953*45320Sbostic }
954*45320Sbostic if (c2 >= maxcols-1)
955*45320Sbostic { if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1))
956*45320Sbostic { error("You can't hide the last col");
957*45320Sbostic return;
958*45320Sbostic }
959*45320Sbostic }
960*45320Sbostic FullUpdate++;
961*45320Sbostic modflg++;
962*45320Sbostic while (c1 <= c2)
963*45320Sbostic col_hidden[c1++] = 1;
964*45320Sbostic }
965*45320Sbostic
966*45320Sbostic void
showrow(r1,r2)967*45320Sbostic showrow(r1, r2)
968*45320Sbostic int r1, r2;
969*45320Sbostic {
970*45320Sbostic if (r1 < 0 || r1 > r2) {
971*45320Sbostic error ("Invalid range");
972*45320Sbostic return;
973*45320Sbostic }
974*45320Sbostic if (r2 > maxrows-1) {
975*45320Sbostic r2 = maxrows-1;
976*45320Sbostic }
977*45320Sbostic FullUpdate++;
978*45320Sbostic modflg++;
979*45320Sbostic while (r1 <= r2)
980*45320Sbostic row_hidden[r1++] = 0;
981*45320Sbostic }
982*45320Sbostic
983*45320Sbostic void
showcol(c1,c2)984*45320Sbostic showcol(c1, c2)
985*45320Sbostic int c1, c2;
986*45320Sbostic {
987*45320Sbostic if (c1 < 0 || c1 > c2) {
988*45320Sbostic error ("Invalid range");
989*45320Sbostic return;
990*45320Sbostic }
991*45320Sbostic if (c2 > maxcols-1) {
992*45320Sbostic c2 = maxcols-1;
993*45320Sbostic }
994*45320Sbostic FullUpdate++;
995*45320Sbostic modflg++;
996*45320Sbostic while (c1 <= c2)
997*45320Sbostic col_hidden[c1++] = 0;
998*45320Sbostic }
999*45320Sbostic
1000*45320Sbostic /* Open the output file, setting up a pipe if needed */
1001*45320Sbostic
1002*45320Sbostic FILE *
openout(fname,rpid)1003*45320Sbostic openout(fname, rpid)
1004*45320Sbostic char *fname;
1005*45320Sbostic int *rpid;
1006*45320Sbostic {
1007*45320Sbostic int pipefd[2];
1008*45320Sbostic int pid;
1009*45320Sbostic FILE *f;
1010*45320Sbostic char *efname;
1011*45320Sbostic
1012*45320Sbostic while (*fname && (*fname == ' ')) /* Skip leading blanks */
1013*45320Sbostic fname++;
1014*45320Sbostic
1015*45320Sbostic if (*fname != '|') { /* Open file if not pipe */
1016*45320Sbostic *rpid = 0;
1017*45320Sbostic
1018*45320Sbostic efname = findhome(fname);
1019*45320Sbostic #ifdef DOBACKUPS
1020*45320Sbostic if (!backup_file(efname) &&
1021*45320Sbostic (yn_ask("Could not create backup copy, Save anyhow?: (y,n)") != 1))
1022*45320Sbostic return(0);
1023*45320Sbostic #endif
1024*45320Sbostic return(fopen(efname, "w"));
1025*45320Sbostic }
1026*45320Sbostic
1027*45320Sbostic fname++; /* Skip | */
1028*45320Sbostic if ( pipe (pipefd) < 0) {
1029*45320Sbostic error("Can't make pipe to child");
1030*45320Sbostic *rpid = 0;
1031*45320Sbostic return(0);
1032*45320Sbostic }
1033*45320Sbostic
1034*45320Sbostic deraw();
1035*45320Sbostic #ifdef VMS
1036*45320Sbostic fprintf(stderr, "No son tasks available yet under VMS--sorry\n");
1037*45320Sbostic #else /* VMS */
1038*45320Sbostic
1039*45320Sbostic if ((pid=fork()) == 0) /* if child */
1040*45320Sbostic {
1041*45320Sbostic (void) close (0); /* close stdin */
1042*45320Sbostic (void) close (pipefd[1]);
1043*45320Sbostic (void) dup (pipefd[0]); /* connect to pipe input */
1044*45320Sbostic (void) signal (SIGINT, SIG_DFL); /* reset */
1045*45320Sbostic (void) execl ("/bin/sh", "sh", "-c", fname, 0);
1046*45320Sbostic exit (-127);
1047*45320Sbostic }
1048*45320Sbostic else /* else parent */
1049*45320Sbostic {
1050*45320Sbostic *rpid = pid;
1051*45320Sbostic if ((f = fdopen (pipefd[1], "w")) == (FILE *)0)
1052*45320Sbostic {
1053*45320Sbostic (void) kill (pid, -9);
1054*45320Sbostic error ("Can't fdopen output");
1055*45320Sbostic (void) close (pipefd[1]);
1056*45320Sbostic *rpid = 0;
1057*45320Sbostic return(0);
1058*45320Sbostic }
1059*45320Sbostic }
1060*45320Sbostic #endif /* VMS */
1061*45320Sbostic return(f);
1062*45320Sbostic }
1063*45320Sbostic
1064*45320Sbostic void
closeout(f,pid)1065*45320Sbostic closeout(f, pid)
1066*45320Sbostic FILE *f;
1067*45320Sbostic int pid;
1068*45320Sbostic {
1069*45320Sbostic int temp;
1070*45320Sbostic
1071*45320Sbostic (void) fclose (f);
1072*45320Sbostic if (pid) {
1073*45320Sbostic while (pid != wait(&temp)) /**/;
1074*45320Sbostic (void) printf("Press RETURN to continue ");
1075*45320Sbostic (void) fflush(stdout);
1076*45320Sbostic (void) nmgetch();
1077*45320Sbostic goraw();
1078*45320Sbostic }
1079*45320Sbostic }
1080*45320Sbostic
1081*45320Sbostic void
copyent(n,p,dr,dc)1082*45320Sbostic copyent(n,p,dr,dc)
1083*45320Sbostic register struct ent *n, *p;
1084*45320Sbostic int dr, dc;
1085*45320Sbostic {
1086*45320Sbostic if(!n||!p){error("internal error");return;}
1087*45320Sbostic n -> v = p -> v;
1088*45320Sbostic n -> flags = p -> flags;
1089*45320Sbostic n -> expr = copye (p -> expr, dr, dc);
1090*45320Sbostic n -> label = (char *)0;
1091*45320Sbostic if (p -> label) {
1092*45320Sbostic n -> label = (char *)
1093*45320Sbostic xmalloc ((unsigned) (strlen (p -> label) + 1));
1094*45320Sbostic (void) strcpy (n -> label, p -> label);
1095*45320Sbostic }
1096*45320Sbostic }
1097*45320Sbostic
1098*45320Sbostic void
write_fd(f,r0,c0,rn,cn)1099*45320Sbostic write_fd (f, r0, c0, rn, cn)
1100*45320Sbostic register FILE *f;
1101*45320Sbostic int r0, c0, rn, cn;
1102*45320Sbostic {
1103*45320Sbostic register struct ent **pp;
1104*45320Sbostic register r, c;
1105*45320Sbostic
1106*45320Sbostic (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
1107*45320Sbostic (void) fprintf (f, "Calculator.\n");
1108*45320Sbostic (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
1109*45320Sbostic print_options(f);
1110*45320Sbostic for (c=0; c<maxcols; c++)
1111*45320Sbostic if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
1112*45320Sbostic (void) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
1113*45320Sbostic for (c=c0; c<cn; c++) {
1114*45320Sbostic if (col_hidden[c]) {
1115*45320Sbostic (void) fprintf(f, "hide %s\n", coltoa(c));
1116*45320Sbostic }
1117*45320Sbostic }
1118*45320Sbostic for (r=r0; r<=rn; r++) {
1119*45320Sbostic if (row_hidden[r]) {
1120*45320Sbostic (void) fprintf(f, "hide %d\n", r);
1121*45320Sbostic }
1122*45320Sbostic }
1123*45320Sbostic
1124*45320Sbostic write_range(f);
1125*45320Sbostic
1126*45320Sbostic if (mdir)
1127*45320Sbostic (void) fprintf(f, "mdir \"%s\"\n", mdir);
1128*45320Sbostic for (r=r0; r<=rn; r++) {
1129*45320Sbostic pp = ATBL(tbl, r, c0);
1130*45320Sbostic for (c=c0; c<=cn; c++, pp++)
1131*45320Sbostic if (*pp) {
1132*45320Sbostic if ((*pp)->label) {
1133*45320Sbostic edits(r,c);
1134*45320Sbostic (void) fprintf(f, "%s\n",line);
1135*45320Sbostic }
1136*45320Sbostic if ((*pp)->flags&is_valid) {
1137*45320Sbostic editv (r, c);
1138*45320Sbostic (void) fprintf (f, "%s\n",line);
1139*45320Sbostic }
1140*45320Sbostic }
1141*45320Sbostic }
1142*45320Sbostic }
1143*45320Sbostic
1144*45320Sbostic int
writefile(fname,r0,c0,rn,cn)1145*45320Sbostic writefile (fname, r0, c0, rn, cn)
1146*45320Sbostic char *fname;
1147*45320Sbostic int r0, c0, rn, cn;
1148*45320Sbostic {
1149*45320Sbostic register FILE *f;
1150*45320Sbostic char save[PATHLEN];
1151*45320Sbostic int pid;
1152*45320Sbostic
1153*45320Sbostic #ifndef VMS
1154*45320Sbostic if (Crypt) {
1155*45320Sbostic return (cwritefile(fname, r0, c0, rn, cn));
1156*45320Sbostic }
1157*45320Sbostic #endif /* VMS */
1158*45320Sbostic
1159*45320Sbostic if (*fname == '\0') fname = curfile;
1160*45320Sbostic
1161*45320Sbostic (void) strcpy(save,fname);
1162*45320Sbostic
1163*45320Sbostic if ((f= openout(fname, &pid)) == (FILE *)0)
1164*45320Sbostic { error ("Can't create file \"%s\"", fname);
1165*45320Sbostic return (-1);
1166*45320Sbostic }
1167*45320Sbostic
1168*45320Sbostic write_fd(f, r0, c0, rn, cn);
1169*45320Sbostic
1170*45320Sbostic closeout(f, pid);
1171*45320Sbostic
1172*45320Sbostic if (!pid) {
1173*45320Sbostic (void) strcpy(curfile, save);
1174*45320Sbostic modflg = 0;
1175*45320Sbostic error("File \"%s\" written.",curfile);
1176*45320Sbostic }
1177*45320Sbostic
1178*45320Sbostic return (0);
1179*45320Sbostic }
1180*45320Sbostic
1181*45320Sbostic void
readfile(fname,eraseflg)1182*45320Sbostic readfile (fname,eraseflg)
1183*45320Sbostic char *fname;
1184*45320Sbostic int eraseflg;
1185*45320Sbostic {
1186*45320Sbostic register FILE *f;
1187*45320Sbostic char save[PATHLEN];
1188*45320Sbostic
1189*45320Sbostic if (*fname == '*' && mdir) {
1190*45320Sbostic (void) strcpy(save, mdir);
1191*45320Sbostic *fname = '/';
1192*45320Sbostic (void) strcat(save, fname);
1193*45320Sbostic } else {
1194*45320Sbostic if (*fname == '\0')
1195*45320Sbostic fname = curfile;
1196*45320Sbostic (void) strcpy(save,fname);
1197*45320Sbostic }
1198*45320Sbostic
1199*45320Sbostic #ifndef VMS
1200*45320Sbostic if (Crypt) {
1201*45320Sbostic creadfile(save, eraseflg);
1202*45320Sbostic return;
1203*45320Sbostic }
1204*45320Sbostic #endif /* VMS */
1205*45320Sbostic
1206*45320Sbostic if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
1207*45320Sbostic
1208*45320Sbostic if ((f = fopen(findhome(save), "r")) == (FILE *)0)
1209*45320Sbostic { error ("Can't read file \"%s\"", save);
1210*45320Sbostic return;
1211*45320Sbostic }
1212*45320Sbostic
1213*45320Sbostic if (eraseflg) erasedb ();
1214*45320Sbostic
1215*45320Sbostic loading++;
1216*45320Sbostic while (fgets(line,sizeof line,f)) {
1217*45320Sbostic linelim = 0;
1218*45320Sbostic if (line[0] != '#') (void) yyparse ();
1219*45320Sbostic }
1220*45320Sbostic --loading;
1221*45320Sbostic (void) fclose (f);
1222*45320Sbostic linelim = -1;
1223*45320Sbostic modflg++;
1224*45320Sbostic if (eraseflg) {
1225*45320Sbostic (void) strcpy(curfile,save);
1226*45320Sbostic modflg = 0;
1227*45320Sbostic }
1228*45320Sbostic EvalAll();
1229*45320Sbostic }
1230*45320Sbostic
1231*45320Sbostic void
erasedb()1232*45320Sbostic erasedb ()
1233*45320Sbostic {
1234*45320Sbostic register r, c;
1235*45320Sbostic for (c = 0; c<=maxcol; c++) {
1236*45320Sbostic fwidth[c] = DEFWIDTH;
1237*45320Sbostic precision[c] = DEFPREC;
1238*45320Sbostic }
1239*45320Sbostic
1240*45320Sbostic for (r = 0; r<=maxrow; r++) {
1241*45320Sbostic register struct ent **pp = ATBL(tbl, r, 0);
1242*45320Sbostic for (c=0; c++<=maxcol; pp++)
1243*45320Sbostic if (*pp) {
1244*45320Sbostic if ((*pp)->expr) efree (*pp, (*pp) -> expr);
1245*45320Sbostic if ((*pp)->label) xfree ((char *)((*pp) -> label));
1246*45320Sbostic xfree ((char *)(*pp));
1247*45320Sbostic *pp = (struct ent *)0;
1248*45320Sbostic }
1249*45320Sbostic }
1250*45320Sbostic maxrow = 0;
1251*45320Sbostic maxcol = 0;
1252*45320Sbostic clean_range();
1253*45320Sbostic FullUpdate++;
1254*45320Sbostic }
1255*45320Sbostic
1256*45320Sbostic void
backcol(arg)1257*45320Sbostic backcol(arg)
1258*45320Sbostic int arg;
1259*45320Sbostic {
1260*45320Sbostic while (--arg>=0) {
1261*45320Sbostic if (curcol)
1262*45320Sbostic curcol--;
1263*45320Sbostic else
1264*45320Sbostic {error ("At column A"); break;}
1265*45320Sbostic while(col_hidden[curcol] && curcol)
1266*45320Sbostic curcol--;
1267*45320Sbostic }
1268*45320Sbostic }
1269*45320Sbostic
1270*45320Sbostic void
forwcol(arg)1271*45320Sbostic forwcol(arg)
1272*45320Sbostic int arg;
1273*45320Sbostic {
1274*45320Sbostic while (--arg>=0) {
1275*45320Sbostic if (curcol < maxcols - 1)
1276*45320Sbostic curcol++;
1277*45320Sbostic else
1278*45320Sbostic if (!growtbl(GROWCOL, 0, arg)) /* get as much as needed */
1279*45320Sbostic break;
1280*45320Sbostic while(col_hidden[curcol]&&(curcol<maxcols-1))
1281*45320Sbostic curcol++;
1282*45320Sbostic }
1283*45320Sbostic }
1284*45320Sbostic
1285*45320Sbostic void
forwrow(arg)1286*45320Sbostic forwrow(arg)
1287*45320Sbostic int arg;
1288*45320Sbostic {
1289*45320Sbostic while (--arg>=0) {
1290*45320Sbostic if (currow < maxrows - 1)
1291*45320Sbostic currow++;
1292*45320Sbostic else
1293*45320Sbostic if (!growtbl(GROWROW, arg, 0)) /* get as much as needed */
1294*45320Sbostic break;
1295*45320Sbostic while (row_hidden[currow]&&(currow<maxrows-1))
1296*45320Sbostic currow++;
1297*45320Sbostic }
1298*45320Sbostic }
1299*45320Sbostic
1300*45320Sbostic void
backrow(arg)1301*45320Sbostic backrow(arg)
1302*45320Sbostic int arg;
1303*45320Sbostic {
1304*45320Sbostic while (--arg>=0) {
1305*45320Sbostic if (currow)
1306*45320Sbostic currow--;
1307*45320Sbostic else
1308*45320Sbostic {error ("At row zero"); break;}
1309*45320Sbostic while (row_hidden[currow] && currow)
1310*45320Sbostic currow--;
1311*45320Sbostic }
1312*45320Sbostic }
1313*45320Sbostic
1314*45320Sbostic
1315*45320Sbostic /*
1316*45320Sbostic * Show a cell's label string or expression value. May overwrite value if
1317*45320Sbostic * there is one already displayed in the cell. Created from old code in
1318*45320Sbostic * update(), copied with minimal changes.
1319*45320Sbostic */
1320*45320Sbostic
1321*45320Sbostic void
showstring(string,leftflush,hasvalue,row,col,nextcolp,mxcol,fieldlenp,r,c)1322*45320Sbostic showstring (string, leftflush, hasvalue, row, col, nextcolp, mxcol, fieldlenp, r, c)
1323*45320Sbostic char *string; /* to display */
1324*45320Sbostic int leftflush; /* or rightflush */
1325*45320Sbostic int hasvalue; /* is there a numeric value? */
1326*45320Sbostic int row, col; /* spreadsheet location */
1327*45320Sbostic int *nextcolp; /* value returned through it */
1328*45320Sbostic int mxcol; /* last column displayed? */
1329*45320Sbostic int *fieldlenp; /* value returned through it */
1330*45320Sbostic int r, c; /* screen row and column */
1331*45320Sbostic {
1332*45320Sbostic register int nextcol = *nextcolp;
1333*45320Sbostic register int fieldlen = *fieldlenp;
1334*45320Sbostic
1335*45320Sbostic char field[FBUFLEN];
1336*45320Sbostic int slen;
1337*45320Sbostic char *start, *last;
1338*45320Sbostic register char *fp;
1339*45320Sbostic struct ent *nc;
1340*45320Sbostic
1341*45320Sbostic /* This figures out if the label is allowed to
1342*45320Sbostic slop over into the next blank field */
1343*45320Sbostic
1344*45320Sbostic slen = strlen (string);
1345*45320Sbostic while ((slen > fieldlen) && (nextcol <= mxcol) &&
1346*45320Sbostic !((nc = lookat (row, nextcol)) -> flags & is_valid) &&
1347*45320Sbostic !(nc->label)) {
1348*45320Sbostic
1349*45320Sbostic if (! col_hidden [nextcol])
1350*45320Sbostic fieldlen += fwidth [nextcol];
1351*45320Sbostic
1352*45320Sbostic nextcol++;
1353*45320Sbostic }
1354*45320Sbostic if (slen > fieldlen)
1355*45320Sbostic slen = fieldlen;
1356*45320Sbostic
1357*45320Sbostic /* Now justify and print */
1358*45320Sbostic start = leftflush ? field : field + fieldlen - slen;
1359*45320Sbostic last = field+fieldlen;
1360*45320Sbostic fp = field;
1361*45320Sbostic while (fp < start)
1362*45320Sbostic *fp++ = ' ';
1363*45320Sbostic while (slen--)
1364*45320Sbostic *fp++ = *string++;
1365*45320Sbostic if ((! hasvalue) || fieldlen != fwidth[col])
1366*45320Sbostic while (fp < last)
1367*45320Sbostic *fp++ = ' ';
1368*45320Sbostic *fp = '\0';
1369*45320Sbostic #ifdef VMS
1370*45320Sbostic mvaddstr(r, c, field); /* this is a macro */
1371*45320Sbostic #else
1372*45320Sbostic (void) mvaddstr(r, c, field);
1373*45320Sbostic #endif
1374*45320Sbostic
1375*45320Sbostic *nextcolp = nextcol;
1376*45320Sbostic *fieldlenp = fieldlen;
1377*45320Sbostic }
1378*45320Sbostic
1379*45320Sbostic int
etype(e)1380*45320Sbostic etype(e)
1381*45320Sbostic register struct enode *e;
1382*45320Sbostic {
1383*45320Sbostic if (e == (struct enode *)0)
1384*45320Sbostic return NUM;
1385*45320Sbostic switch (e->op) {
1386*45320Sbostic case O_SCONST: case '#': case DATE: case FMT: case STINDEX:
1387*45320Sbostic case EXT: case SVAL: case SUBSTR:
1388*45320Sbostic return (STR);
1389*45320Sbostic
1390*45320Sbostic case '?':
1391*45320Sbostic case IF:
1392*45320Sbostic return(etype(e->e.o.right->e.o.left));
1393*45320Sbostic
1394*45320Sbostic case 'f':
1395*45320Sbostic return(etype(e->e.o.right));
1396*45320Sbostic
1397*45320Sbostic case O_VAR: {
1398*45320Sbostic register struct ent *p;
1399*45320Sbostic p = e->e.v.vp;
1400*45320Sbostic if (p->expr)
1401*45320Sbostic return(p->flags & is_strexpr ? STR : NUM);
1402*45320Sbostic else if (p->label)
1403*45320Sbostic return(STR);
1404*45320Sbostic else
1405*45320Sbostic return(NUM);
1406*45320Sbostic }
1407*45320Sbostic
1408*45320Sbostic default:
1409*45320Sbostic return(NUM);
1410*45320Sbostic }
1411*45320Sbostic }
1412*45320Sbostic
1413*45320Sbostic /* return 1 if yes given, 0 otherwise */
1414*45320Sbostic int
yn_ask(msg)1415*45320Sbostic yn_ask(msg)
1416*45320Sbostic char *msg;
1417*45320Sbostic { char ch;
1418*45320Sbostic
1419*45320Sbostic (void) move (0, 0);
1420*45320Sbostic (void) clrtoeol ();
1421*45320Sbostic (void) addstr (msg);
1422*45320Sbostic (void) refresh();
1423*45320Sbostic ch = nmgetch();
1424*45320Sbostic if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) {
1425*45320Sbostic if (ch == ctl('g') || ch == ESC)
1426*45320Sbostic return(-1);
1427*45320Sbostic error("y or n response required");
1428*45320Sbostic return (-1);
1429*45320Sbostic }
1430*45320Sbostic if (ch == 'y' || ch == 'Y')
1431*45320Sbostic return(1);
1432*45320Sbostic else
1433*45320Sbostic return(0);
1434*45320Sbostic }
1435*45320Sbostic
1436*45320Sbostic #include <pwd.h>
1437*45320Sbostic char *
findhome(path)1438*45320Sbostic findhome(path)
1439*45320Sbostic char *path;
1440*45320Sbostic {
1441*45320Sbostic static char *HomeDir = NULL;
1442*45320Sbostic extern char *getenv();
1443*45320Sbostic
1444*45320Sbostic if (*path == '~')
1445*45320Sbostic { char *pathptr;
1446*45320Sbostic char tmppath[PATHLEN];
1447*45320Sbostic
1448*45320Sbostic if (HomeDir == NULL)
1449*45320Sbostic { HomeDir = getenv("HOME");
1450*45320Sbostic if (HomeDir == NULL)
1451*45320Sbostic HomeDir = "/";
1452*45320Sbostic }
1453*45320Sbostic pathptr = path + 1;
1454*45320Sbostic if ((*pathptr == '/') || (*pathptr == '\0'))
1455*45320Sbostic { strcpy(tmppath, HomeDir);
1456*45320Sbostic }
1457*45320Sbostic else
1458*45320Sbostic { struct passwd *pwent;
1459*45320Sbostic extern struct passwd *getpwnam();
1460*45320Sbostic char *namep;
1461*45320Sbostic char name[50];
1462*45320Sbostic
1463*45320Sbostic namep = name;
1464*45320Sbostic while ((*pathptr != '\0') && (*pathptr != '/'))
1465*45320Sbostic *(namep++) = *(pathptr++);
1466*45320Sbostic *namep = '\0';
1467*45320Sbostic if ((pwent = getpwnam(name)) == NULL)
1468*45320Sbostic { sprintf(path, "Can't find user %s", name);
1469*45320Sbostic return(NULL);
1470*45320Sbostic }
1471*45320Sbostic strcpy(tmppath, pwent->pw_dir);
1472*45320Sbostic }
1473*45320Sbostic
1474*45320Sbostic strcat(tmppath, pathptr);
1475*45320Sbostic strcpy(path, tmppath);
1476*45320Sbostic }
1477*45320Sbostic return(path);
1478*45320Sbostic }
1479*45320Sbostic
1480*45320Sbostic #ifdef DOBACKUPS
1481*45320Sbostic #include <sys/types.h>
1482*45320Sbostic #include <sys/stat.h>
1483*45320Sbostic
1484*45320Sbostic /*
1485*45320Sbostic * make a backup copy of a file, use the same mode and name in the format
1486*45320Sbostic * [path/]#file~
1487*45320Sbostic * return 1 if we were successful, 0 otherwise
1488*45320Sbostic */
1489*45320Sbostic int
backup_file(path)1490*45320Sbostic backup_file(path)
1491*45320Sbostic char *path;
1492*45320Sbostic {
1493*45320Sbostic struct stat statbuf;
1494*45320Sbostic char fname[PATHLEN];
1495*45320Sbostic char tpath[PATHLEN];
1496*45320Sbostic #ifdef sequent
1497*45320Sbostic char *buf;
1498*45320Sbostic #else
1499*45320Sbostic char buf[BUFSIZ];
1500*45320Sbostic #endif
1501*45320Sbostic char *tpp;
1502*45320Sbostic int infd, outfd;
1503*45320Sbostic int count;
1504*45320Sbostic
1505*45320Sbostic /* tpath will be the [path/]file ---> [path/]#file~ */
1506*45320Sbostic strcpy(tpath, path);
1507*45320Sbostic if ((tpp = strrchr(tpath, '/')) == NULL)
1508*45320Sbostic tpp = tpath;
1509*45320Sbostic else
1510*45320Sbostic tpp++;
1511*45320Sbostic strcpy(fname, tpp);
1512*45320Sbostic sprintf(tpp, "#%s~", fname);
1513*45320Sbostic
1514*45320Sbostic if (stat(path, &statbuf) == 0)
1515*45320Sbostic {
1516*45320Sbostic #ifdef sequent
1517*45320Sbostic if ((buf = xmalloc(statbuf.st_blksize)) == (char *)0)
1518*45320Sbostic return(0);
1519*45320Sbostic #endif
1520*45320Sbostic
1521*45320Sbostic if ((infd = open(path, O_RDONLY, 0)) < 0)
1522*45320Sbostic {
1523*45320Sbostic #ifdef sequent
1524*45320Sbostic xfree(buf);
1525*45320Sbostic #endif
1526*45320Sbostic return(0);
1527*45320Sbostic }
1528*45320Sbostic if ((outfd = open(tpath, O_TRUNC|O_WRONLY|O_CREAT,
1529*45320Sbostic statbuf.st_mode)) < 0)
1530*45320Sbostic {
1531*45320Sbostic #ifdef sequent
1532*45320Sbostic xfree(buf);
1533*45320Sbostic #endif
1534*45320Sbostic return(0);
1535*45320Sbostic }
1536*45320Sbostic #ifdef sequent
1537*45320Sbostic while((count = read(infd, buf, statbuf.st_blksize)) > 0)
1538*45320Sbostic #else
1539*45320Sbostic while((count = read(infd, buf, sizeof(buf))) > 0)
1540*45320Sbostic #endif
1541*45320Sbostic { if (write(outfd, buf, count) != count)
1542*45320Sbostic { count = -1;
1543*45320Sbostic break;
1544*45320Sbostic }
1545*45320Sbostic }
1546*45320Sbostic close(infd);
1547*45320Sbostic close(outfd);
1548*45320Sbostic #ifdef sequent
1549*45320Sbostic xfree(buf);
1550*45320Sbostic #endif
1551*45320Sbostic return((count < 0) ? 0 : 1);
1552*45320Sbostic }
1553*45320Sbostic else
1554*45320Sbostic if (errno == ENOENT)
1555*45320Sbostic return(1);
1556*45320Sbostic return(0);
1557*45320Sbostic }
1558*45320Sbostic #endif
1559