xref: /csrg-svn/contrib/sc/cmds.c (revision 45320)
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