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 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 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 96 insertrow(arg) 97 register int arg; 98 { 99 while (--arg>=0) openrow (currow); 100 } 101 102 void 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 114 rowvalueize(arg) 115 register int arg; 116 { 117 valueize_area(currow, 0, currow + arg - 1, maxcol); 118 } 119 120 void 121 colvalueize(arg) 122 register int arg; 123 { 124 valueize_area(0, curcol, maxrow, curcol + arg - 1); 125 } 126 127 void 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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