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