1 /*
2 * $Id: ref.c,v 1.15 2001/02/13 23:38:06 danny Exp $
3 *
4 * Copyright � 1990, 1992, 1993, 2001 Free Software Foundation, Inc.
5 *
6 * This file is part of Oleo, the GNU Spreadsheet.
7 *
8 * Oleo is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * Oleo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Oleo; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #ifdef WITH_DMALLOC
27 #include <dmalloc.h>
28 #endif
29
30 #include "funcdef.h"
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <sys/types.h>
34 #include <signal.h>
35 #include "sysdef.h"
36 #include "global.h"
37 #include "cell.h"
38 #include "eval.h"
39 #include "io-abstract.h"
40 #include "io-generic.h"
41 #include "hash.h"
42 #include "byte-compile.h"
43 #include "parse.h"
44 #include "ref.h"
45 #include "cmd.h"
46
47 static void add_ref_fm (struct ref_fm **, CELLREF, CELLREF);
48 static void flush_ref_fm (struct ref_fm **, CELLREF, CELLREF);
49 static void flush_range_ref (struct rng *, CELLREF, CELLREF);
50 extern void shift_formula (int r, int c, int dn, int ov);
51 static void flush_ref_to (struct ref_to **);
52 static void flush_fm_ref (struct ref_fm *);
53
54 /* More tunable paramaters */
55
56 #define FIFO_START 40
57 #define FIFO_INC *=2
58
59 #define TO_MAGIC(row,col) (((long)(row)<<BITS_PER_CELLREF)|(col))
60 #define MAGIC_ROW(magic) (((magic)>>BITS_PER_CELLREF)&CELLREF_MASK)
61 #define MAGIC_COL(magic) ((magic)&CELLREF_MASK)
62
63 #define BETWEEN(mid,lo,hi) ((mid>=lo)&&(mid<=hi))
64
65 static VOIDSTAR moving;
66
67 int timer_active = 0;
68 struct ref_fm *timer_cells;
69
70 CELL *my_cell;
71
72 #ifdef TEST
73 extern int debug;
74 #endif
75
76 /* Functions for dealing exclusively with variables */
77 struct hash_control *the_vars;
78
79 struct value
80 {
81 int type;
82 union vals c_z;
83 };
84
85 /* For the fifo-buffer */
86 struct pos
87 {
88 CELLREF row;
89 CELLREF col;
90 };
91
92 struct cell_buf
93 {
94 unsigned int size;
95 struct pos *buf;
96 struct pos *push_to_here;
97 struct pos *pop_frm_here;
98 };
99
100
101 /* Set the cell ROW,COL to STRING, parsing string as needed */
102 void
set_cell(CELLREF row,CELLREF col,char * string)103 set_cell (CELLREF row, CELLREF col, char *string)
104 {
105 unsigned char *ret;
106
107 cur_row = row;
108 cur_col = col;
109
110 #ifdef TEST
111 if (!string)
112 {
113 io_error_msg ("Null string to set_cell %s", cell_name (row, col));
114 return;
115 }
116 #endif
117 while (*string == ' ')
118 string++;
119
120 if (!*string)
121 {
122 my_cell = find_cell (cur_row, cur_col);
123 if (!my_cell)
124 return;
125 flush_old_value ();
126 return;
127 }
128
129 my_cell = find_or_make_cell (cur_row, cur_col);
130 flush_old_value ();
131
132 ret = parse_and_compile (string);
133 my_cell->cell_formula = ret;
134 }
135
136 extern int default_lock;
137
138 /* new_value() calls set_cell, but refuses to change locked cells, and
139 updates and prints the results. It returns an error msg on error. . .
140 */
141 char *
new_value(CELLREF row,CELLREF col,char * string)142 new_value (CELLREF row, CELLREF col, char *string)
143 {
144 CELL *cp;
145
146 cp = find_cell (row, col);
147 if (((!cp || GET_LCK (cp) == LCK_DEF) && default_lock == LCK_LCK) || (cp && GET_LCK (cp) == LCK_LCK))
148 {
149 return "cell is locked";
150 }
151
152 set_cell (row, col, string);
153 if (my_cell)
154 {
155 update_cell (my_cell);
156 if (is_constant (my_cell->cell_formula))
157 {
158 byte_free (my_cell->cell_formula);
159 my_cell->cell_formula = 0;
160 }
161 io_pr_cell (row, col, my_cell);
162 my_cell = 0;
163 }
164 return 0;
165 }
166
167 char *
quote_new_value(CELLREF row,CELLREF col,char * string)168 quote_new_value(CELLREF row, CELLREF col, char *string)
169 {
170 int l;
171 char *r, *s;
172
173 l = strlen(string);
174
175 s = (char *)malloc(l+3);
176 s[0] = '"';
177 s[1] = '\0';
178 strcat(s, string);
179 strcat(s, "\"");
180
181 r = new_value(row, col, s);
182 free(s);
183
184 return r;
185 }
186
187 /* This sets the cell to a constant, stored in VALUE, whose type is in TYPE */
188 char *
set_new_value(CELLREF row,CELLREF col,int type,union vals * value)189 set_new_value (CELLREF row, CELLREF col, int type, union vals *value)
190 {
191 CELL *cp;
192 extern int default_lock;
193
194 if (type == TYP_ERR)
195 type = 0;
196 cur_row = row;
197 cur_col = col;
198 if (type == 0)
199 {
200 cp = find_cell (row, col);
201 if (cp && GET_TYP (cp))
202 {
203 if ((GET_LCK (cp) == LCK_DEF && default_lock == LCK_LCK) || GET_LCK (cp) == LCK_LCK)
204 return "cell is locked";
205 my_cell = cp;
206 flush_old_value ();
207 SET_TYP (cp, 0);
208 }
209 my_cell = 0;
210 return 0;
211 }
212 else
213 {
214 cp = find_or_make_cell (row, col);
215 if ((GET_LCK (cp) == LCK_DEF && default_lock == LCK_LCK) || GET_LCK (cp) == LCK_LCK)
216 return "cell is locked";
217 my_cell = cp;
218 flush_old_value ();
219 SET_TYP (cp, type);
220 /* cp->c_z= *value; */
221 switch (type)
222 {
223 case TYP_FLT:
224 cp->cell_flt = value->c_d;
225 cp->cell_formula = 0;
226 break;
227
228 case TYP_INT:
229 cp->cell_int = value->c_l;
230 cp->cell_formula = 0;
231 break;
232
233 case TYP_STR:
234 cp->cell_str = strdup (value->c_s);
235 cp->cell_formula = 0;
236 break;
237
238 case TYP_BOL:
239 cp->cell_bol = value->c_i;
240 cp->cell_formula = 0;
241 break;
242
243 case TYP_ERR:
244 cp->cell_err = value->c_i;
245 cp->cell_formula = 0;
246 break;
247 #ifdef TEST
248 default:
249 panic ("Unknown type %d in set_new_value", GET_TYP (cp));
250 #endif
251 }
252 }
253 push_refs (cp->cell_refs_from);
254 io_pr_cell (row, col, cp);
255 my_cell = 0;
256 return 0;
257 }
258
259 /* We're reading in a cell, whose formula is FORM, and whose current value
260 is VAL. Parse both of them. . . (Parsing of VAL is quite primitive)
261 */
262 char *
read_new_value(CELLREF row,CELLREF col,char * form,char * val)263 read_new_value (CELLREF row, CELLREF col, char *form, char *val)
264 {
265 unsigned char *new_bytes;
266 extern double __plinf, __neinf, ___nan;
267
268 cur_row = row;
269 cur_col = col;
270 my_cell = find_or_make_cell (cur_row, cur_col);
271 flush_old_value ();
272 SET_TYP (my_cell, 0);
273
274 if (form)
275 {
276 new_bytes = parse_and_compile (form);
277 my_cell->cell_formula = new_bytes;
278 }
279
280 if (val)
281 {
282 if (val[0] == '"')
283 {
284 char *sp, *nsp;
285
286 sp = val + 1;
287 SET_TYP (my_cell, TYP_STR);
288 while (*sp)
289 sp++;
290 if (*--sp != '"')
291 {
292 if (*sp == '\r' && sp[-1] == '"')
293 --sp;
294 else
295 panic ("Can't find \" in read_new value");
296 }
297 *sp = '\0';
298 nsp = my_cell->cell_str = ck_malloc (sp - val);
299 for (sp = val + 1; *sp;)
300 *nsp++ = *sp++;
301 *nsp++ = '\0';
302 }
303 else if (isdigit (val[0]) || val[0] == '.' || val[0] == '-' || val[0] == '+')
304 {
305 char *v;
306
307 v = val;
308 SET_TYP (my_cell, TYP_INT);
309 my_cell->cell_int = astol (&v);
310 if (*v)
311 {
312 SET_TYP (my_cell, TYP_FLT);
313 v = val;
314 my_cell->cell_flt = astof (&v);
315 if (*v)
316 return "unknown number";
317 }
318 }
319 else if (val[0] == '#')
320 {
321 char **en;
322
323 if (!stricmp (tname, val))
324 {
325 SET_TYP (my_cell, TYP_BOL);
326 my_cell->cell_bol = 1;
327 }
328 else if (!stricmp (fname, val))
329 {
330 SET_TYP (my_cell, TYP_BOL);
331 my_cell->cell_bol = 0;
332 }
333 else if (!stricmp (iname, val))
334 {
335 SET_TYP (my_cell, TYP_FLT);
336 my_cell->cell_flt = __plinf;
337 }
338 else if (!stricmp (iname, val))
339 {
340 SET_TYP (my_cell, TYP_FLT);
341 my_cell->cell_flt = __plinf;
342 }
343 else if (!stricmp (mname, val))
344 {
345 SET_TYP (my_cell, TYP_FLT);
346 my_cell->cell_flt = __neinf;
347 }
348 else if (!stricmp (nname, val))
349 {
350 SET_TYP (my_cell, TYP_FLT);
351 my_cell->cell_flt = ___nan;
352 }
353 else
354 {
355 SET_TYP (my_cell, TYP_ERR);
356 for (en = ename; *en; en++)
357 if (!stricmp (*en, val))
358 break;
359 if (*en)
360 my_cell->cell_err = en - &ename[0];
361 else
362 my_cell->cell_err = 1;
363 }
364 }
365 else
366 panic ("What is a '%s'?", val);
367 }
368
369 my_cell = 0;
370 return 0;
371 }
372
373 /* This moves the contents, format, etc from RF,CF to RT,CT RF or RT may be
374 NON_ROW, in which case the cell's contents are moved to/from a static
375 storage area. Moving anything from NON_ROW before moving anything into it
376 or moving two things at a time into NON_ROW are both bad ideas. . .
377
378 Also note that move_cell does not call move_outside, which may or may not
379 be a bug. . . Move_cell is only called as part of sorting, which is why
380 we may *not* want to call move_outside. . .
381 */
382
383 void
move_cell(CELLREF rf,CELLREF cf,CELLREF rt,CELLREF ct)384 move_cell (CELLREF rf, CELLREF cf, CELLREF rt, CELLREF ct)
385 {
386 CELL *cpf;
387
388 static CELLREF non_rf, non_cf;
389 static struct cell non_cell;
390
391 if (rf == NON_ROW)
392 {
393 cur_row = rt;
394 cur_col = ct;
395 my_cell = find_cell (cur_row, cur_col);
396 if (my_cell)
397 flush_old_value ();
398 else if (((non_cell.cell_flags.cell_format == 0)
399 && (non_cell.cell_flags.cell_precision == 0)
400 && (non_cell.cell_flags.cell_justify == 0)
401 && (non_cell.cell_flags.cell_type == 0))
402 && (non_cell.cell_flags.cell_lock == 0)
403 && !non_cell.cell_formula && !non_cell.cell_font)
404 return;
405 else
406 my_cell = find_or_make_cell (cur_row, cur_col);
407
408 my_cell->cell_flags = non_cell.cell_flags;
409 my_cell->cell_refs_to = non_cell.cell_refs_to;
410 my_cell->cell_formula = non_cell.cell_formula;
411 my_cell->cell_cycle = non_cell.cell_cycle;
412 my_cell->cell_font = non_cell.cell_font;
413 my_cell->c_z = non_cell.c_z;
414 push_refs (my_cell->cell_refs_from);
415 if (my_cell->cell_refs_to)
416 shift_formula (cur_row, cur_col, rt - non_rf, ct - non_cf);
417 my_cell = 0;
418 return;
419 }
420
421 cpf = find_cell (rf, cf);
422
423 if (rt == NON_ROW)
424 {
425 non_rf = rf;
426 non_cf = cf;
427 if (!cpf)
428 bzero (&non_cell, sizeof (non_cell));
429 else
430 {
431 non_cell.cell_flags = cpf->cell_flags;
432 non_cell.cell_refs_to = cpf->cell_refs_to;
433 non_cell.cell_formula = cpf->cell_formula;
434 non_cell.cell_cycle = cpf->cell_cycle;
435 non_cell.cell_font = cpf->cell_font;
436 non_cell.c_z = cpf->c_z;
437 bzero(&(cpf->cell_flags), sizeof(cpf->cell_flags));
438 cpf->cell_refs_to = 0;
439 cpf->cell_formula = 0;
440 cpf->cell_cycle = 0;
441 cpf->cell_font = 0;
442 }
443 return;
444 }
445
446 cur_row = rt;
447 cur_col = ct;
448 my_cell = find_cell (cur_row, cur_col);
449 if ((!cpf ||
450 (((non_cell.cell_flags.cell_format == 0)
451 && (non_cell.cell_flags.cell_precision == 0)
452 && (non_cell.cell_flags.cell_justify == 0)
453 && (non_cell.cell_flags.cell_type == 0))
454 && (non_cell.cell_flags.cell_lock == 0)
455 && !cpf->cell_formula && !cpf->cell_font))
456 && !my_cell)
457 return;
458 if (!my_cell)
459 {
460 my_cell = find_or_make_cell (cur_row, cur_col);
461 cpf = find_cell (rf, cf); /* FOO */
462 }
463 else
464 flush_old_value ();
465
466 if (!cpf)
467 return;
468
469 my_cell->cell_flags = cpf->cell_flags;
470 my_cell->cell_refs_to = cpf->cell_refs_to;
471 my_cell->cell_formula = cpf->cell_formula;
472 my_cell->cell_cycle = cpf->cell_cycle;
473 my_cell->cell_font = cpf->cell_font;
474 my_cell->c_z = cpf->c_z;
475
476 bzero(&(cpf->cell_flags), sizeof(cpf->cell_flags));
477 cpf->cell_refs_to = 0;
478 cpf->cell_formula = 0;
479 cpf->cell_cycle = 0;
480 cpf->cell_font = 0;
481
482 push_refs (my_cell->cell_refs_from);
483 if (my_cell->cell_refs_to)
484 shift_formula (cur_row, cur_col, rt - rf, ct - cf);
485 my_cell = 0;
486 }
487
488 /* Used only in regions.c for copy_region. */
489 void
copy_cell(CELLREF rf,CELLREF cf,CELLREF rt,CELLREF ct)490 copy_cell (CELLREF rf, CELLREF cf, CELLREF rt, CELLREF ct)
491 {
492 CELL *cpf;
493
494 cpf = find_cell (rf, cf);
495 cur_row = rt;
496 cur_col = ct;
497 my_cell = find_cell (cur_row, cur_col);
498 if ((!cpf ||
499 (((cpf->cell_flags.cell_format == 0)
500 && (cpf->cell_flags.cell_precision == 0)
501 && (cpf->cell_flags.cell_justify == 0)
502 && (cpf->cell_flags.cell_type == 0))
503 && (cpf->cell_flags.cell_lock == 0)
504 && !cpf->cell_formula && !cpf->cell_font)) && !my_cell)
505 return;
506 if (!my_cell)
507 {
508 my_cell = find_or_make_cell (cur_row, cur_col);
509 cpf = find_cell (rf, cf); /* FOO */
510 }
511 else
512 flush_old_value ();
513
514 if (!cpf)
515 return;
516
517 my_cell->cell_flags = cpf->cell_flags;
518 my_cell->cell_cycle = cpf->cell_cycle;
519 my_cell->cell_font = cpf->cell_font;
520 my_cell->cell_refs_to = cpf->cell_refs_to;
521
522 if (my_cell->cell_refs_to)
523 my_cell->cell_refs_to->refs_refcnt++;
524
525 if (GET_TYP (my_cell) == TYP_STR)
526 my_cell->cell_str = strdup (cpf->cell_str);
527 else
528 my_cell->c_z = cpf->c_z;
529
530 if (cpf->cell_formula)
531 {
532 unsigned char *fp;
533 unsigned char *hi;
534 unsigned char byte;
535 CELLREF trr, tcc;
536 struct rng trng;
537 struct function *f;
538 size_t len;
539 struct var *v;
540 CELL *tcp;
541
542 fp = cpf->cell_formula;
543 hi = 0;
544 if (!moving)
545 moving = init_stack ();
546 while ((byte = *fp++) != ENDCOMP)
547 {
548 unsigned char * refloc = fp - 1;
549 if (byte < USR1)
550 f = &the_funs[byte];
551 else if (byte < SKIP)
552 {
553 int tmp;
554 #ifdef TEST
555 if (byte - USR1 >= n_usr_funs)
556 panic ("Only have %d usr-function slots, but found byte for slot %d", n_usr_funs, 1 + byte - USR1);
557 #endif
558 tmp = *fp++;
559 f = &usr_funs[byte - USR1][tmp];
560 }
561 else
562 f = &skip_funs[byte - SKIP];
563
564 if (f->fn_argn & X_J)
565 fp++;
566 else if (f->fn_argn & X_JL)
567 fp += 2;
568
569 if ((f->fn_argn & X_ARGS) == X_AN)
570 fp++;
571
572 switch (byte)
573 {
574 case CONST_FLT:
575 fp += sizeof (double);
576 break;
577
578 case CONST_INT:
579 fp += sizeof (long);
580 break;
581
582 case CONST_STR:
583 if (!hi)
584 hi = fp + fp[-1];
585 break;
586
587 case CONST_STR_L:
588 if (!hi)
589 hi = fp + fp[-2] + ((unsigned) (fp[-1]) << 8);
590 break;
591
592 case CONST_ERR:
593 fp += 1 /* +sizeof(char *) */ ;
594 break;
595
596 case VAR:
597 bcopy (fp, &v, sizeof (struct var *));
598 fp += sizeof (struct var *);
599 add_ref_fm (&(v->var_ref_fm), cur_row, cur_col);
600 switch (v->var_flags)
601 {
602 case VAR_UNDEF:
603 break;
604 case VAR_CELL:
605 tcp = find_cell (v->v_rng.lr, v->v_rng.lc);
606 add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
607 break;
608 case VAR_RANGE:
609 add_range_ref (&(v->v_rng));
610 /* sparse array bug fixed here */
611 my_cell = find_cell (cur_row, cur_col);
612 cpf = find_cell (rf, cf);
613 break;
614 }
615 break;
616
617 case R_CELL:
618 case R_CELL | COLREL:
619 case R_CELL | ROWREL:
620 case R_CELL | ROWREL | COLREL:
621 push_stack (moving, fp);
622 fp += EXP_ADD;
623 break;
624
625 case RANGE:
626 case RANGE | LRREL:
627 case RANGE | LRREL | LCREL:
628 case RANGE | LRREL | LCREL | HCREL:
629 case RANGE | LRREL | HCREL:
630 case RANGE | LRREL | HRREL:
631 case RANGE | LRREL | HRREL | LCREL:
632 case RANGE | LRREL | HRREL | LCREL | HCREL:
633 case RANGE | LRREL | HRREL | HCREL:
634 case RANGE | HRREL:
635 case RANGE | HRREL | LCREL:
636 case RANGE | HRREL | LCREL | HCREL:
637 case RANGE | HRREL | HCREL:
638 case RANGE | LCREL:
639 case RANGE | LCREL | HCREL:
640 case RANGE | HCREL:
641 push_stack (moving, fp);
642 fp += EXP_ADD_RNG;
643 break;
644
645 default:
646 {
647 struct function *fun;
648
649 if (byte >= SKIP)
650 break;
651
652 if (byte < USR1)
653 fun = &the_funs[byte];
654 else
655 fun = &usr_funs[byte - USR1][refloc[1]];
656
657 if (fun->fn_comptype & C_T)
658 {
659 add_ref_fm (&timer_cells, rt, ct);
660 ++timer_active;
661 }
662 break;
663 }
664 }
665 }
666 if (!hi)
667 hi = fp;
668 else
669 hi += strlen ((char *) hi);
670 hi++;
671 len = hi - cpf->cell_formula;
672 my_cell->cell_formula = cpf->cell_formula;
673 cpf->cell_formula = ck_malloc (hi - cpf->cell_formula);
674 if (len)
675 bcopy (my_cell->cell_formula, cpf->cell_formula, len);
676 while ((fp = pop_stack (moving)))
677 {
678 byte = fp[-1];
679 if ((byte | ROWREL | COLREL) == (R_CELL | ROWREL | COLREL))
680 {
681 trr = GET_ROW (fp);
682 tcc = GET_COL (fp);
683 if (byte & ROWREL)
684 {
685 trr += rt - rf;
686 PUT_ROW (fp, trr);
687 }
688 if (byte & COLREL)
689 {
690 tcc += ct - cf;
691 PUT_COL (fp, tcc);
692 }
693 tcp = find_or_make_cell (trr, tcc);
694 add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
695 }
696 #ifdef TEST
697 else if ((byte | LRREL | HRREL | LCREL | HCREL) !=
698 (RANGE | LRREL | HRREL | LCREL | HCREL))
699 panic ("Unknown byte %x in copy_cell", byte);
700 #endif
701 else
702 {
703 GET_RNG (fp, &trng);
704 if (byte & LRREL)
705 trng.lr += rt - rf;
706 if (byte & HRREL)
707 trng.hr += rt - rf;
708 if (byte & LCREL)
709 trng.lc += ct - cf;
710 if (byte & HCREL)
711 trng.hc += ct - cf;
712 PUT_RNG (fp, &trng);
713 add_range_ref (&trng);
714 /* sparse array bug fixed here */
715 my_cell = find_cell (cur_row, cur_col);
716 cpf = find_cell (rf, cf);
717 }
718 }
719 update_cell (my_cell);
720 }
721 else
722 {
723 my_cell->cell_formula = 0;
724 }
725 io_pr_cell (cur_row, cur_col, my_cell);
726
727 push_refs (my_cell->cell_refs_from);
728 my_cell = 0;
729 }
730
731 /* Take away the value of CP. This means getting rid of all the references
732 * to it, etc.
733 */
734 void
flush_old_value(void)735 flush_old_value (void)
736 {
737 struct ref_to *ref;
738 unsigned char *refloc;
739 int n;
740 unsigned char byte;
741 CELL *other_cell;
742 struct var *varp;
743
744 ref = my_cell->cell_refs_to;
745 if (ref)
746 {
747 for (n = 0; n < ref->refs_used; n++)
748 {
749 /* Switch on formula[ref->to_refs[n]] */
750 refloc = &(my_cell->cell_formula[ref->to_refs[n]]);
751 byte = refloc[0];
752 switch (byte)
753 {
754 case F_ROW:
755 case F_COL:
756 break;
757
758 case R_CELL:
759 case R_CELL | ROWREL:
760 case R_CELL | COLREL:
761 case R_CELL | ROWREL | COLREL:
762 other_cell = find_cell (GET_ROW (refloc + 1), GET_COL (refloc + 1));
763 if (other_cell)
764 flush_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
765 #ifdef TEST
766 else
767 io_error_msg ("Can't find other_cell in flush_old_value");
768 #endif
769 break;
770 case RANGE:
771 case RANGE | LRREL:
772 case RANGE | LRREL | LCREL:
773 case RANGE | LRREL | LCREL | HCREL:
774 case RANGE | LRREL | HCREL:
775 case RANGE | LRREL | HRREL:
776 case RANGE | LRREL | HRREL | LCREL:
777 case RANGE | LRREL | HRREL | LCREL | HCREL:
778 case RANGE | LRREL | HRREL | HCREL:
779 case RANGE | HRREL:
780 case RANGE | HRREL | LCREL:
781 case RANGE | HRREL | LCREL | HCREL:
782 case RANGE | HRREL | HCREL:
783 case RANGE | LCREL:
784 case RANGE | LCREL | HCREL:
785 case RANGE | HCREL:
786 {
787 struct rng rng;
788
789 GET_RNG (refloc + 1, &rng);
790 flush_range_ref (&rng, cur_row, cur_col);
791 }
792 break;
793
794 case VAR:
795 bcopy (&refloc[1], &varp, sizeof (struct var *));
796 flush_ref_fm (&(varp->var_ref_fm), cur_row, cur_col);
797 if (varp->var_flags == VAR_CELL)
798 {
799 other_cell = find_cell (varp->v_rng.lr, varp->v_rng.lc);
800 if (other_cell)
801 flush_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
802 }
803 else if (varp->var_flags == VAR_RANGE)
804 flush_range_ref (&(varp->v_rng), cur_row, cur_col);
805 #ifdef TEST
806 else if (varp->var_flags != VAR_UNDEF)
807 panic ("Unknown var type %d", varp->var_flags);
808 #endif
809 break;
810
811 default:
812 {
813 struct function *fun;
814
815 if (byte < USR1)
816 fun = &the_funs[byte];
817 #ifdef TEST
818 else if (byte >= SKIP)
819 fun = 0, panic ("SKIP? in flush_old_value()");
820 #endif
821 else
822 fun = &usr_funs[byte - USR1][refloc[1]];
823
824 if (fun->fn_comptype & C_T)
825 {
826 #ifdef TEST
827 if (!timer_cells || !timer_cells->refs_used)
828 panic ("No timer cells in flush_timer_cell");
829 #endif
830 flush_ref_fm (&timer_cells, cur_row, cur_col);
831 --timer_active;
832 break;
833 }
834 else
835 io_error_msg ("Bad ref_to of %d.%x ignored", ref->to_refs[n], byte);
836 }
837 break;
838 }
839 }
840 flush_ref_to (&(my_cell->cell_refs_to));
841 }
842 if (my_cell->cell_formula)
843 {
844 byte_free (my_cell->cell_formula);
845 my_cell->cell_formula = 0;
846 }
847 if (GET_TYP (my_cell) == TYP_STR)
848 free (my_cell->cell_str);
849 SET_TYP (my_cell, 0);
850 }
851
852 /* --------- Routines for dealing with cell references to other cells ------ */
853
854
855 /* Record in the argument cell that cur_row/col depends on it. */
856
857 void
add_ref(CELLREF row,CELLREF col)858 add_ref (CELLREF row, CELLREF col)
859 {
860 CELL *other_cell;
861
862 other_cell = find_or_make_cell (row, col);
863 add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
864 }
865
866 /* like add_ref, except over a range of arguments and with memory
867 * management weirdness.
868 */
869 void
add_range_ref(struct rng * rng)870 add_range_ref (struct rng *rng)
871 {
872 CELL *other_cell;
873 struct ref_fm *oldref, *newref;
874 struct ref_fm nonref;
875
876
877 make_cells_in_range (rng);
878
879 /* Be efficient: If cells in the range currently have the same
880 * references, they'll have the same references afterward, so just
881 * adjust the refcounts
882 */
883 nonref.refs_refcnt = 1;
884 other_cell = next_cell_in_range ();
885 oldref = other_cell->cell_refs_from;
886 if (oldref && oldref->refs_refcnt == 1)
887 oldref = &nonref;
888
889 add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
890 newref = other_cell->cell_refs_from;
891 while ((other_cell = next_cell_in_range ()))
892 {
893 if (other_cell->cell_refs_from == oldref)
894 {
895 if (oldref)
896 {
897 if (oldref->refs_refcnt == 1)
898 {
899 flush_fm_ref (oldref);
900 oldref = &nonref;
901 }
902 else
903 oldref->refs_refcnt--;
904 }
905 other_cell->cell_refs_from = newref;
906 newref->refs_refcnt++;
907 }
908 else if (oldref == &nonref && (!other_cell->cell_refs_from || other_cell->cell_refs_from->refs_refcnt > 1))
909 {
910 oldref = other_cell->cell_refs_from;
911 add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
912 newref = other_cell->cell_refs_from;
913 }
914 else
915 add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
916 }
917 /* if(oldref && oldref->refs_refcnt==0) {
918 oldref->refs_refcnt=1;
919 flush_fm_ref(oldref);
920 } */
921 }
922
923 static void
flush_range_ref(struct rng * rng,CELLREF rr,CELLREF cc)924 flush_range_ref (struct rng *rng, CELLREF rr, CELLREF cc)
925 {
926 CELL *other_cell;
927 struct ref_fm *oldref, *newref;
928 struct ref_fm nonref;
929 /* This is horribly inefficient: Simply referencing a cell makes
930 it appear. On the other hand, there is no other easy way to deal
931 with the references to the cells (That I know of, anyway) */
932 find_cells_in_range (rng);
933 /* Be efficient: If cells in the range currently have the same
934 references, they'll have the same references afterward, so just
935 adjust the refcounts */
936 nonref.refs_refcnt = 1;
937 other_cell = next_cell_in_range ();
938 if (!other_cell)
939 return;
940 oldref = other_cell->cell_refs_from;
941 if (oldref && oldref->refs_refcnt == 1)
942 oldref = &nonref;
943
944 flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
945 newref = other_cell->cell_refs_from;
946 while ((other_cell = next_cell_in_range ()))
947 {
948 if (other_cell->cell_refs_from == oldref)
949 {
950 if (oldref)
951 {
952 if (oldref->refs_refcnt == 1)
953 {
954 flush_fm_ref (oldref);
955 oldref = &nonref;
956 }
957 else
958 oldref->refs_refcnt--;
959 }
960 other_cell->cell_refs_from = newref;
961 if (newref)
962 newref->refs_refcnt++;
963 }
964 else if (oldref == &nonref && (!other_cell->cell_refs_from || other_cell->cell_refs_from->refs_refcnt > 1))
965 {
966 oldref = other_cell->cell_refs_from;
967 flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
968 newref = other_cell->cell_refs_from;
969 }
970 else
971 flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
972 }
973 }
974
975 #ifdef __TURBOC__
976 #define FM_HASH_NUM 51
977 #define TO_HASH_NUM 13
978 #else
979 #define FM_HASH_NUM 503
980 #define TO_HASH_NUM 29
981 #endif
982 #ifdef TEST
983 static int fm_misses = 0;
984 static int to_misses = 0;
985 #endif
986
987 static struct ref_fm *fm_list[FM_HASH_NUM];
988 static struct ref_fm *fm_tmp_ref;
989 static unsigned fm_tmp_ref_alloc;
990
991 static struct ref_to *to_list[TO_HASH_NUM];
992 static struct ref_to *to_tmp_ref;
993 static unsigned to_tmp_ref_alloc;
994
995 void
flush_refs(void)996 flush_refs (void)
997 {
998 int n;
999 struct ref_fm *ftmp, *oftmp;
1000 struct ref_to *ttmp, *ottmp;
1001
1002 for (n = 0; n < FM_HASH_NUM; n++)
1003 {
1004 for (ftmp = fm_list[n]; ftmp; ftmp = oftmp)
1005 {
1006 oftmp = ftmp->refs_next;
1007 free (ftmp);
1008 }
1009 fm_list[n] = 0;
1010 }
1011 for (n = 0; n < TO_HASH_NUM; n++)
1012 {
1013 for (ttmp = to_list[n]; ttmp; ttmp = ottmp)
1014 {
1015 ottmp = ttmp->refs_next;
1016 free (ttmp);
1017 }
1018 to_list[n] = 0;
1019 }
1020 }
1021
1022 static struct ref_fm *
find_fm_ref(void)1023 find_fm_ref (void)
1024 {
1025 struct ref_fm *tmp;
1026 int n;
1027 unsigned long hash;
1028
1029 #if 1
1030 for (hash = 0, n = 0; n < fm_tmp_ref->refs_used; n++)
1031 {
1032 hash += (n + 1) * (((fm_tmp_ref->fm_refs[n].ref_row) << BITS_PER_CELLREF) +
1033 fm_tmp_ref->fm_refs[n].ref_col);
1034 }
1035 hash %= FM_HASH_NUM;
1036 #else
1037 hash = fm_tmp_ref->refs_used;
1038 #endif
1039 for (tmp = fm_list[hash]; tmp; tmp = tmp->refs_next)
1040 {
1041 if (tmp->refs_used != fm_tmp_ref->refs_used)
1042 continue;
1043 if (!bcmp (tmp->fm_refs, fm_tmp_ref->fm_refs, fm_tmp_ref->refs_used * sizeof (struct ref_array)))
1044 {
1045 tmp->refs_refcnt++;
1046 return tmp;
1047 }
1048 #ifdef TEST
1049 else
1050 fm_misses++;
1051 #endif
1052 }
1053
1054 tmp = ck_malloc (sizeof (struct ref_fm) + (fm_tmp_ref->refs_used - 1) * sizeof (struct ref_array));
1055 tmp->refs_next = fm_list[hash];
1056 fm_list[hash] = tmp;
1057 tmp->refs_refcnt = 1;
1058 tmp->refs_used = fm_tmp_ref->refs_used;
1059 if (tmp->refs_used)
1060 bcopy (fm_tmp_ref->fm_refs, tmp->fm_refs,
1061 tmp->refs_used * sizeof (struct ref_array));
1062
1063 return tmp;
1064 }
1065
1066 static void
flush_fm_ref(struct ref_fm * old)1067 flush_fm_ref (struct ref_fm *old)
1068 {
1069 struct ref_fm *tmp;
1070 int n;
1071 unsigned long hash;
1072
1073 --(old->refs_refcnt);
1074
1075 #ifdef DEFER_FREE
1076 return;
1077 #endif
1078 if (!old->refs_refcnt)
1079 {
1080 #if 1
1081 for (hash = 0, n = 0; n < old->refs_used; n++)
1082 {
1083 hash += (n + 1) * (((old->fm_refs[n].ref_row) << BITS_PER_CELLREF) +
1084 old->fm_refs[n].ref_col);
1085 }
1086 hash %= FM_HASH_NUM;
1087 #else
1088 hash = old->refs_used;
1089 #endif
1090 if (fm_list[hash] == old)
1091 fm_list[hash] = old->refs_next;
1092 else
1093 {
1094 for (tmp = fm_list[hash];
1095 tmp && tmp->refs_next != old;
1096 tmp = tmp->refs_next)
1097 ;
1098 #ifdef TEST
1099 if (!tmp)
1100 {
1101 io_error_msg ("Old not in refs_list in flush_fm_ref(%p)", old);
1102 return;
1103 }
1104 #endif
1105 if (tmp)
1106 tmp->refs_next = old->refs_next;
1107 }
1108 free (old);
1109 }
1110 }
1111
1112 /* This adds a from reference to a cells reference list.
1113 * Note that the ref_fm structures themselves are hash-consed.
1114 */
1115 static void
add_ref_fm(struct ref_fm ** where,CELLREF r,CELLREF c)1116 add_ref_fm (struct ref_fm **where, CELLREF r, CELLREF c)
1117 {
1118 struct ref_fm *from;
1119 int n;
1120
1121 from = *where;
1122 if (!from)
1123 {
1124 if (!fm_tmp_ref)
1125 {
1126 fm_tmp_ref = ck_malloc (sizeof (struct ref_fm));
1127 fm_tmp_ref_alloc = 1;
1128 }
1129 fm_tmp_ref->refs_used = 1;
1130 fm_tmp_ref->fm_refs[0].ref_row = r;
1131 fm_tmp_ref->fm_refs[0].ref_col = c;
1132 }
1133 else
1134 {
1135 if (fm_tmp_ref_alloc <= from->refs_used)
1136 {
1137 fm_tmp_ref =
1138 ck_realloc (fm_tmp_ref, sizeof (struct ref_fm)
1139 + from->refs_used * sizeof (struct ref_array)) ;
1140 fm_tmp_ref_alloc = from->refs_used + 1;
1141 }
1142 fm_tmp_ref->refs_used = from->refs_used + 1;
1143 n = 0;
1144 while (n < from->refs_used
1145 && (from->fm_refs[n].ref_row < r
1146 || (from->fm_refs[n].ref_row == r && from->fm_refs[n].ref_col <= c)))
1147 {
1148 fm_tmp_ref->fm_refs[n] = from->fm_refs[n];
1149 n++;
1150 }
1151 fm_tmp_ref->fm_refs[n].ref_row = r;
1152 fm_tmp_ref->fm_refs[n].ref_col = c;
1153 while (n < from->refs_used)
1154 {
1155 fm_tmp_ref->fm_refs[n + 1] = from->fm_refs[n];
1156 n++;
1157 }
1158 }
1159 *where = find_fm_ref ();
1160 if (from)
1161 flush_fm_ref (from);
1162 }
1163
1164 static void
flush_ref_fm(struct ref_fm ** where,CELLREF r,CELLREF c)1165 flush_ref_fm (struct ref_fm **where, CELLREF r, CELLREF c)
1166 {
1167 struct ref_fm *from;
1168 int n;
1169
1170 from = *where;
1171 #ifdef TEST
1172 if (!from)
1173 {
1174 io_error_msg ("No refs in flush_ref_fm(%p,%u,%u)", where, r, c);
1175 return;
1176 }
1177 #endif
1178 if (!from)
1179 return;
1180 if (from->refs_used == 1)
1181 {
1182 *where = 0;
1183 flush_fm_ref (from);
1184 return;
1185 }
1186 fm_tmp_ref->refs_used = from->refs_used - 1;
1187 n = 0;
1188 while (n < from->refs_used
1189 && (from->fm_refs[n].ref_row < r
1190 || (from->fm_refs[n].ref_row == r && from->fm_refs[n].ref_col < c)))
1191 {
1192 fm_tmp_ref->fm_refs[n] = from->fm_refs[n];
1193 n++;
1194 }
1195 #ifdef TEST
1196 if (n == from->refs_used)
1197 {
1198 io_error_msg ("No refs from %u,%u in %p in flush_refs_fm", r, c, where);
1199 return;
1200 }
1201 #endif
1202 while (n < fm_tmp_ref->refs_used)
1203 {
1204 fm_tmp_ref->fm_refs[n] = from->fm_refs[n + 1];
1205 n++;
1206 }
1207 *where = find_fm_ref ();
1208 flush_fm_ref (from);
1209 }
1210
1211 #ifdef TEST
1212
1213 void
dbg_print_ref_fm(rf)1214 dbg_print_ref_fm (rf)
1215 struct ref_fm *rf;
1216 {
1217 int nr;
1218 char *bufp;
1219 extern char *print_buf;
1220
1221 if (rf)
1222 {
1223 io_text_line ("fm %p: refcnt %u next %p used %u",
1224 rf, rf->refs_refcnt, rf->refs_next, rf->refs_used);
1225 for (nr = 0, bufp = print_buf; nr < rf->refs_used; nr++)
1226 {
1227 (void) sprintf (bufp, " %s", cell_name (rf->fm_refs[nr].ref_row, rf->fm_refs[nr].ref_col));
1228 if (nr % 10 == 9)
1229 {
1230 io_text_line (print_buf);
1231 bufp = print_buf;
1232 }
1233 else
1234 bufp += strlen (bufp);
1235 }
1236 if (nr % 10)
1237 io_text_line (print_buf);
1238 }
1239 }
1240
1241 #endif
1242
1243 static struct ref_to *
find_to_ref(void)1244 find_to_ref (void)
1245 {
1246 struct ref_to *tmp;
1247 int n;
1248 unsigned long hash;
1249
1250 /* io_error_msg("find_to_ref %u %u",to_tmp_ref->refs_used,to_tmp_ref->to_refs[0]); */
1251 #if 1
1252 for (hash = 0, n = 0; n < to_tmp_ref->refs_used; n++)
1253 hash += (n + 1) * to_tmp_ref->to_refs[n];
1254
1255 hash %= TO_HASH_NUM;
1256 #else
1257 hash = to_tmp_ref->refs_used;
1258 #endif
1259 for (tmp = to_list[hash]; tmp; tmp = tmp->refs_next)
1260 {
1261 /* io_error_msg("%p(%u)->%p %u %u",tmp,tmp->refs_refcnt,
1262 tmp->refs_next,tmp->refs_used,tmp->to_refs[0]); */
1263 if (tmp->refs_used != to_tmp_ref->refs_used)
1264 continue;
1265 if (!bcmp (tmp->to_refs, to_tmp_ref->to_refs, to_tmp_ref->refs_used))
1266 {
1267 /* io_error_msg("Hit!"); */
1268 tmp->refs_refcnt++;
1269 return tmp;
1270 }
1271 #ifdef TEST
1272 else
1273 to_misses++;
1274 #endif
1275 }
1276
1277 /* io_error_msg("Miss. .."); */
1278 tmp = ck_malloc (sizeof (struct ref_to) + to_tmp_ref->refs_used - 1);
1279 tmp->refs_next = to_list[hash];
1280 to_list[hash] = tmp;
1281 tmp->refs_refcnt = 1;
1282 tmp->refs_used = to_tmp_ref->refs_used;
1283 if (tmp->refs_used)
1284 bcopy (to_tmp_ref->to_refs, tmp->to_refs, tmp->refs_used);
1285
1286 return tmp;
1287 }
1288
1289 void
add_ref_to(int whereto)1290 add_ref_to (int whereto)
1291 {
1292 struct ref_to *from;
1293 int n;
1294
1295 from = my_cell->cell_refs_to;
1296 if (!from)
1297 {
1298 if (!to_tmp_ref)
1299 {
1300 to_tmp_ref = ck_malloc (sizeof (struct ref_to));
1301 to_tmp_ref_alloc = 1;
1302 }
1303 to_tmp_ref->refs_used = 1;
1304 to_tmp_ref->to_refs[0] = whereto;
1305 }
1306 else
1307 {
1308 if (to_tmp_ref_alloc <= from->refs_used)
1309 {
1310 to_tmp_ref = ck_realloc (to_tmp_ref, sizeof (struct ref_to) + from->refs_used);
1311 to_tmp_ref_alloc = from->refs_used + 1;
1312 }
1313 to_tmp_ref->refs_used = from->refs_used + 1;
1314 n = 0;
1315 while (n < from->refs_used && from->to_refs[n] < whereto)
1316 {
1317 to_tmp_ref->to_refs[n] = from->to_refs[n];
1318 n++;
1319 }
1320 to_tmp_ref->to_refs[n] = whereto;
1321 while (n < from->refs_used)
1322 {
1323 to_tmp_ref->to_refs[n + 1] = from->to_refs[n];
1324 n++;
1325 }
1326 flush_ref_to (&(my_cell->cell_refs_to));
1327 }
1328 my_cell->cell_refs_to = find_to_ref ();
1329 }
1330
1331 static void
flush_ref_to(struct ref_to ** where)1332 flush_ref_to (struct ref_to **where)
1333 {
1334 struct ref_to *tmp;
1335 struct ref_to *old;
1336 int n;
1337 unsigned long hash;
1338
1339 #ifdef TEST
1340 if (!where || !*where)
1341 {
1342 io_error_msg ("null flush_ref_to(%p)", where);
1343 return;
1344 }
1345 #endif
1346 old = *where;
1347 *where = 0;
1348 --(old->refs_refcnt);
1349
1350 #ifdef DEFER_FREE
1351 return;
1352 #endif
1353 if (!old->refs_refcnt)
1354 {
1355 #if 1
1356 for (hash = 0, n = 0; n < old->refs_used; n++)
1357 hash += (n + 1) * old->to_refs[n];
1358
1359 hash %= TO_HASH_NUM;
1360 #else
1361 hash = old->refs_used;
1362 #endif
1363 if (to_list[hash] == old)
1364 to_list[hash] = old->refs_next;
1365 else
1366 {
1367 for (tmp = to_list[hash]; tmp && tmp->refs_next != old; tmp = tmp->refs_next)
1368 ;
1369 #ifdef TEST
1370 if (!tmp)
1371 {
1372 io_error_msg ("Old not in refs_list in flush_to_ref(%p)", old);
1373 return;
1374 }
1375 #endif
1376 tmp->refs_next = old->refs_next;
1377 }
1378 free (old);
1379 }
1380 }
1381
1382 #ifdef TEST
1383 void
dbg_print_ref_to(rt,form)1384 dbg_print_ref_to (rt, form)
1385 struct ref_to *rt;
1386 unsigned char *form;
1387 {
1388 int nr;
1389 char *bufp;
1390 extern char *print_buf;
1391
1392 if (rt)
1393 {
1394 io_text_line ("to %p: refcnt %u next %p used %u",
1395 rt, rt->refs_refcnt, rt->refs_next, rt->refs_used);
1396 for (nr = 0, bufp = print_buf; nr < rt->refs_used; nr++)
1397 {
1398 (void) sprintf (bufp, " %3d (%#4x)", rt->to_refs[nr], form[rt->to_refs[nr]]);
1399 if (nr % 7 == 6)
1400 {
1401 io_text_line (print_buf);
1402 bufp = print_buf;
1403 }
1404 else
1405 bufp += strlen (bufp);
1406 }
1407 if (nr % 7)
1408 io_text_line (print_buf);
1409 }
1410 }
1411
1412 void
ref_stats()1413 ref_stats ()
1414 {
1415 int n;
1416 int cur;
1417 struct ref_fm *rf;
1418 struct ref_to *rt;
1419
1420 int rf_max = 0;
1421 int rf_num = 0;
1422 int rf_shared = 0;
1423 int rf_saved = 0;
1424 int rf_zero = 0;
1425
1426 int rt_max = 0;
1427 int rt_num = 0;
1428 int rt_shared = 0;
1429 int rt_saved = 0;
1430 int rt_zero = 0;
1431
1432 for (n = 0; n < FM_HASH_NUM; n++)
1433 {
1434 cur = 0;
1435 for (rf = fm_list[n]; rf; rf = rf->refs_next)
1436 {
1437 if (rf->refs_refcnt == 0)
1438 rf_zero++;
1439 if (rf->refs_refcnt > 1)
1440 {
1441 rf_shared++;
1442 rf_saved += rf->refs_refcnt - 1;
1443 }
1444 rf_num++;
1445 cur++;
1446 }
1447 if (cur > rf_max)
1448 rf_max = cur;
1449 }
1450 for (n = 0; n < TO_HASH_NUM; n++)
1451 {
1452 cur = 0;
1453 for (rt = to_list[n]; rt; rt = rt->refs_next)
1454 {
1455 if (rt->refs_refcnt == 0)
1456 rt_zero++;
1457 if (rt->refs_refcnt > 1)
1458 {
1459 rt_shared++;
1460 rt_saved += rt->refs_refcnt - 1;
1461 }
1462 rt_num++;
1463 cur++;
1464 }
1465 if (cur > rt_max)
1466 rt_max = cur;
1467 }
1468 io_text_line ("from: %d refs, max_length %d, shared %d, saved %d, zero_ref %d, missed %d\n", rf_num, rf_max, rf_shared, rf_saved, rf_zero, fm_misses);
1469 io_text_line ("to: %d refs, max_length %d, shared %d, saved %d, zero_ref %d, missed %d\n", rt_num, rt_max, rt_shared, rt_saved, rt_zero, to_misses);
1470 }
1471
1472 #endif
1473
1474 /* ------------- Routines for dealing with moving cells -------------------- */
1475
1476 static struct rng *shift_fm;
1477 static int shift_ov;
1478 static int shift_dn;
1479
1480 /* This removes all the CELL_REF_FM links associated with a
1481 * variable, and adjusts the variables value.
1482 * After calling this function, one must also call
1483 * finish_shift_var to install the new CELL_REF_FM links.
1484 */
1485 static void
start_shift_var(char * name,struct var * v)1486 start_shift_var (char *name, struct var *v)
1487 {
1488 int n;
1489 int nn;
1490
1491
1492 n = (BETWEEN (v->v_rng.hc, shift_fm->lc, shift_fm->hc) << 3)
1493 + (BETWEEN (v->v_rng.lc, shift_fm->lc, shift_fm->hc) << 2)
1494 + (BETWEEN (v->v_rng.hr, shift_fm->lr, shift_fm->hr) << 1)
1495 + BETWEEN (v->v_rng.lr, shift_fm->lr, shift_fm->hr);
1496 switch (n)
1497 {
1498 case 0:
1499 case 1:
1500 case 2:
1501 case 3:
1502 case 4:
1503 case 8:
1504 case 12:
1505 /* Null intersection, ignore it */
1506 break;
1507
1508 case 5: /* The bottom and right */
1509 case 6: /* The bottom and left */
1510 case 9: /* The top and right */
1511 case 10: /* The top and left */
1512 /* The var sticks out of the range we're moving */
1513 /* on two sides. what should we do? */
1514 io_error_msg ("'%s' can't be adjusted", v->var_name);
1515 break;
1516
1517 case 7: /* v->hc sticks out the right */
1518 case 11: /* v->lc sticks out the left */
1519 case 13: /* v->hr sticks out the bottom */
1520 case 14: /* v->lr sticks out the top */
1521 /* It only sticks out on one side. We can
1522 (try to) adjust it */
1523
1524 case 15: /* var is completely inside the range */
1525 if (v->var_ref_fm)
1526 {
1527 for (nn = 0; nn < v->var_ref_fm->refs_used; nn++)
1528 {
1529 flush_range_ref (&(v->v_rng),
1530 v->var_ref_fm->fm_refs[nn].ref_row,
1531 v->var_ref_fm->fm_refs[nn].ref_col);
1532 }
1533 }
1534 if (n != 7)
1535 v->v_rng.hc += shift_ov;
1536 if (n != 11)
1537 v->v_rng.lc += shift_ov;
1538 if (n != 13)
1539 v->v_rng.hr += shift_dn;
1540 if (n != 14)
1541 v->v_rng.lr += shift_dn;
1542 v->var_flags = VAR_DANGLING_RANGE;
1543 }
1544 }
1545
1546
1547 static void
finish_shift_var(char * name,struct var * v)1548 finish_shift_var (char *name, struct var *v)
1549 {
1550 int n;
1551 if (v->var_flags != VAR_DANGLING_RANGE)
1552 return;
1553
1554 v->var_flags = VAR_RANGE;
1555
1556 if (!v->var_ref_fm)
1557 return;
1558
1559 for (n = 0; n < v->var_ref_fm->refs_used; n++)
1560 {
1561 cur_row = v->var_ref_fm->fm_refs[n].ref_row;
1562 cur_col = v->var_ref_fm->fm_refs[n].ref_col;
1563 add_range_ref (&(v->v_rng));
1564 }
1565 }
1566
1567 #define RIGHT 8
1568 #define LEFT 4
1569 #define BOTTOM 2
1570 #define TOP 1
1571
1572 /*
1573 * This iterates over the region FM, preparing the cells there to be shifted
1574 * OV(er) and D(ow)N.
1575 *
1576 * After this, the ref_fm and ref_to lists of a cell within the region should
1577 * be appropriate to the location that cell will be shifted to.
1578 *
1579 * Variables and references to variables are also shifted.
1580 */
1581 void
shift_outside(struct rng * fm,int dn,int ov)1582 shift_outside (struct rng *fm, int dn, int ov)
1583 {
1584 CELL *cp;
1585 CELL *fcp;
1586 CELL *tcp;
1587 int n;
1588 int fn;
1589 CELLREF rr, cc;
1590 CELLREF frr, fcc;
1591 CELLREF trr, tcc;
1592 unsigned char *ffp;
1593 unsigned char *fp;
1594 struct rng orng;
1595
1596 char *ptr;
1597 unsigned long val;
1598 static char DEF_REF[] = "DEFREF";
1599 static char DEF_RNG[] = "DEFRNG";
1600
1601 /* Variables and references to variables are also shifted. */
1602 shift_fm = fm;
1603 shift_dn = dn;
1604 shift_ov = ov;
1605 for_all_vars (start_shift_var);
1606
1607 /* This stack is used to defer adjustments to references that are entirely
1608 * within FM. Intra-FM references are adjusted after references into and
1609 * out of FM.
1610 */
1611
1612 if (!moving)
1613 moving = init_stack ();
1614
1615 find_cells_in_range (fm);
1616
1617 while ((cp = next_row_col_in_range (&rr, &cc)))
1618 {
1619 /* cp/rr/cc is a cell in FM. */
1620
1621 /* First, adjust references FROM the region */
1622 if (cp->cell_refs_to)
1623 {
1624 for (n = 0; n < cp->cell_refs_to->refs_used; n++)
1625 {
1626 fp = &(cp->cell_formula[cp->cell_refs_to->to_refs[n]]);
1627 switch (*fp)
1628 {
1629 case R_CELL:
1630 case R_CELL | ROWREL:
1631 case R_CELL | COLREL:
1632 case R_CELL | ROWREL | COLREL:
1633 /* Trr/cc/cp is the cell being referenced */
1634 trr = GET_ROW (fp + 1);
1635 tcc = GET_COL (fp + 1);
1636 tcp = find_cell (trr, tcc);
1637
1638 /* Get rid of the backpointer to this reference. */
1639 flush_ref_fm (&(tcp->cell_refs_from), rr, cc);
1640
1641 /* frr/fcc is the new address of the referenced cell.
1642 * The address will change if Trr/cc happens to be
1643 * in the region that is moving, or if the reference
1644 * is a relative reference.
1645 */
1646 fn = (BETWEEN (trr, fm->lr, fm->hr)
1647 && BETWEEN (tcc, fm->lc, fm->hc));
1648 frr = (fn || (((*fp) & ROWREL))) ? trr + dn : trr;
1649 fcc = (fn || (((*fp) & COLREL))) ? tcc + ov : tcc;
1650
1651 PUT_ROW (fp + 1, frr); /* Adjust the formula byte-code. */
1652 PUT_COL (fp + 1, fcc); /* This might even be a noop. */
1653
1654 /* Reinstall the backreference, unless the new address of the
1655 * referenced cell is w/in the region being moved. (In which
1656 * case, defer making the backreference).
1657 */
1658 if (BETWEEN(frr, fm->lr, fm->hr) && BETWEEN(fcc, fm->lc, fm->hc))
1659 {
1660 push_stack (moving, (VOIDSTAR) TO_MAGIC (rr + dn, cc + ov));
1661 push_stack (moving, (VOIDSTAR) TO_MAGIC (frr, fcc));
1662 push_stack (moving, DEF_REF);
1663 }
1664 else
1665 {
1666 tcp = find_or_make_cell (frr, fcc);
1667 add_ref_fm (&(tcp->cell_refs_from), rr + dn, cc + ov);
1668 cp = find_cell (rr, cc);
1669 }
1670
1671 break;
1672
1673 case VAR:
1674 {
1675 struct var * varp;
1676 bcopy ((VOIDSTAR) (fp + 1),
1677 (VOIDSTAR)&varp, sizeof (struct var *));
1678 flush_ref_fm (&varp->var_ref_fm, rr, cc);
1679 add_ref_fm (&varp->var_ref_fm, rr + dn, cc + ov);
1680 break;
1681 }
1682
1683 case RANGE:
1684 case RANGE | LRREL:
1685 case RANGE | HRREL:
1686 case RANGE | LCREL:
1687 case RANGE | HCREL:
1688 case RANGE | LRREL | HRREL:
1689 case RANGE | LRREL | LCREL:
1690 case RANGE | LRREL | HCREL:
1691 case RANGE | HRREL | LCREL:
1692 case RANGE | HRREL | HCREL:
1693 case RANGE | LCREL | HCREL:
1694 case RANGE | LRREL | LCREL | HCREL:
1695 case RANGE | LRREL | HRREL | LCREL:
1696 case RANGE | LRREL | HRREL | HCREL:
1697 case RANGE | HRREL | LCREL | HCREL:
1698 case RANGE | LRREL | HRREL | LCREL | HCREL:
1699 /* orng is the range being referenced. */
1700 GET_RNG (fp + 1, &orng);
1701
1702 /* Get rid of backpointers to this reference. */
1703 flush_range_ref (&orng, rr, cc);
1704
1705 /* This asks -- does the referenced region
1706 * intersect the region being moved at the:
1707 */
1708 fn = ((BETWEEN (orng.hc, fm->lc, fm->hc) << 3) /* right? 8 */
1709 | (BETWEEN (orng.lc, fm->lc, fm->hc) << 2) /* left? 4 */
1710 | (BETWEEN (orng.hr, fm->lr, fm->hr) << 1) /* bottom? 2 */
1711 | BETWEEN (orng.lr, fm->lr, fm->hr)); /* top? 1 */
1712
1713 /* In this switch, a union of masks represents a conjunction
1714 * of intersections. So, LEFT | TOP means `interects at left
1715 * and top'.
1716 */
1717 switch (fn)
1718 {
1719 /* Most of the time, the referenced region is moved only
1720 * if the reference is relative.
1721 */
1722 case LEFT | TOP:
1723 case LEFT | BOTTOM:
1724 case RIGHT | TOP:
1725 case RIGHT | BOTTOM:
1726
1727 /* There used to be a warning given to the user here, but
1728 * that seems silly, no?
1729 */
1730
1731 case 0:
1732 case TOP:
1733 case BOTTOM:
1734 case TOP | BOTTOM:
1735 case LEFT:
1736 case RIGHT:
1737 case LEFT | RIGHT:
1738 if ((*fp) & LRREL)
1739 orng.lr += dn;
1740 if ((*fp) & HRREL)
1741 orng.hr += dn;
1742 if ((*fp) & LCREL)
1743 orng.lc += ov;
1744 if ((*fp) & HCREL)
1745 orng.hc += ov;
1746 break;
1747
1748 /* If the referenced range contains rows or columns that
1749 * are entirely within the region being moved, then
1750 * the region is moved, shrunk or stretched.
1751 */
1752 case LEFT | BOTTOM | TOP:
1753 case RIGHT | BOTTOM | TOP:
1754 case RIGHT | LEFT | TOP:
1755 case RIGHT | LEFT | BOTTOM:
1756 case RIGHT | LEFT | BOTTOM | TOP:
1757 if (fn != (LEFT | BOTTOM | TOP))
1758 orng.hc += ov;
1759 if (fn != (RIGHT | BOTTOM | TOP))
1760 orng.lc += ov;
1761 if (fn != (RIGHT | LEFT | TOP))
1762 orng.hr += dn;
1763 if (fn != (RIGHT | LEFT | BOTTOM))
1764 orng.lr += dn;
1765 break;
1766 }
1767 PUT_RNG (fp + 1, &orng); /* Patch the bytecode. */
1768
1769 push_stack (moving, (VOIDSTAR) fp);
1770 push_stack (moving, (VOIDSTAR) TO_MAGIC (rr + dn, cc + ov));
1771 push_stack (moving, DEF_RNG);
1772 break;
1773
1774 default:
1775 {
1776 struct function *fun;
1777
1778 if (*fp < USR1)
1779 fun = &the_funs[*fp];
1780 else
1781 fun = &usr_funs[*fp - USR1][fp[1]];
1782
1783 if (fun->fn_comptype & C_T)
1784 {
1785 flush_ref_fm (&timer_cells, rr, cc);
1786 add_ref_fm (&timer_cells, rr + dn, cc + ov);
1787 }
1788 }
1789 break;
1790 }
1791
1792 }
1793 }
1794
1795 /* Next, adjust references TO the region */
1796 for (n = 0; cp->cell_refs_from && n < cp->cell_refs_from->refs_used; n++)
1797 {
1798 /* The second enclosed loop over the bytecode will fix all of the
1799 * references to this cell. This loop is here because a
1800 * refs_fm structure may contain more than one occurence of the
1801 * referencing cell. We don't want to adjust the same bytecode
1802 * twice.
1803 */
1804 while ((n < cp->cell_refs_from->refs_used - 1)
1805 && (cp->cell_refs_from->fm_refs[n].ref_row ==
1806 cp->cell_refs_from->fm_refs[n + 1].ref_row)
1807 && (cp->cell_refs_from->fm_refs[n].ref_col ==
1808 cp->cell_refs_from->fm_refs[n + 1].ref_col))
1809 ++n;
1810
1811 /* For each cell that referenced this one, look
1812 * at the type of reference involved
1813 */
1814 frr = cp->cell_refs_from->fm_refs[n].ref_row;
1815 fcc = cp->cell_refs_from->fm_refs[n].ref_col;
1816
1817 /* Unless the reference is from inside the region we're moving, in
1818 * which case, it has already been adjusted.
1819 *
1820 * (This test seems unnecessary but harmless. -tl)
1821 */
1822 if (BETWEEN (frr, fm->lr, fm->hr) && BETWEEN (fcc, fm->lc, fm->hc))
1823 continue;
1824
1825 /* Find the cell that references cp. */
1826 fcp = find_cell (frr, fcc);
1827
1828 /* Search the byte-code for the reference. */
1829 for (fn = 0; fcp->cell_refs_to && fn < fcp->cell_refs_to->refs_used; fn++)
1830 {
1831
1832 ffp = &(fcp->cell_formula[fcp->cell_refs_to->to_refs[fn]]);
1833 switch (*ffp)
1834 {
1835 case R_CELL:
1836 case R_CELL | ROWREL:
1837 case R_CELL | COLREL:
1838 case R_CELL | ROWREL | COLREL:
1839
1840 trr = GET_ROW (ffp + 1);
1841 tcc = GET_COL (ffp + 1);
1842
1843 if (trr != rr || tcc != cc)
1844 continue;
1845
1846 {
1847 CELLREF old_tr = trr;
1848 CELLREF old_tc = tcc;
1849 /* Find the cell that fcp should reference now. */
1850 if (!((*ffp) & ROWREL))
1851 {
1852 trr += dn;
1853 PUT_ROW (ffp + 1, trr);
1854 }
1855 if (!((*ffp) & COLREL))
1856 {
1857 tcc += ov;
1858 PUT_COL (ffp + 1, tcc);
1859 }
1860 else
1861 /* If this is an abs reference, it doesn't change. */
1862 continue;
1863 /* Get rid of the now-invalid backpointer */
1864 {
1865 CELL * old_reffed = find_cell (old_tr, old_tc);
1866 flush_ref_fm (&(old_reffed->cell_refs_from), frr, fcc);
1867 }
1868 }
1869
1870 if (BETWEEN (trr, fm->lr, fm->hr) && BETWEEN (tcc, fm->lc, fm->hc))
1871 {
1872 push_stack (moving, (VOIDSTAR) TO_MAGIC (frr, fcc));
1873 push_stack (moving, (VOIDSTAR) TO_MAGIC (trr, tcc));
1874 push_stack (moving, DEF_REF);
1875 }
1876 else
1877 {
1878 cp = find_or_make_cell (trr, tcc);
1879 add_ref_fm (&(cp->cell_refs_from), frr, fcc);
1880 }
1881
1882
1883 case VAR:
1884 /* This case is taken care of by {start,finish}_shift_vars */
1885 continue;
1886
1887 case RANGE:
1888 case RANGE | LRREL:
1889 case RANGE | LRREL | LCREL:
1890 case RANGE | LRREL | LCREL | HCREL:
1891 case RANGE | LRREL | HCREL:
1892 case RANGE | LRREL | HRREL:
1893 case RANGE | LRREL | HRREL | LCREL:
1894 case RANGE | LRREL | HRREL | LCREL | HCREL:
1895 case RANGE | LRREL | HRREL | HCREL:
1896 case RANGE | HRREL:
1897 case RANGE | HRREL | LCREL:
1898 case RANGE | HRREL | LCREL | HCREL:
1899 case RANGE | HRREL | HCREL:
1900 case RANGE | LCREL:
1901 case RANGE | LCREL | HCREL:
1902 case RANGE | HCREL:
1903 GET_RNG (ffp + 1, &orng);
1904
1905 if (!BETWEEN (rr, orng.lr, orng.hr) || !BETWEEN (cc, orng.lc, orng.hc))
1906 break;
1907
1908 val = ((BETWEEN (orng.hc, fm->lc, fm->hc) << 3) /* right */
1909 + (BETWEEN (orng.lc, fm->lc, fm->hc) << 2) /* left */
1910 + (BETWEEN (orng.hr, fm->lr, fm->hr) << 1) /* bottom */
1911 + BETWEEN (orng.lr, fm->lr, fm->hr)); /* top */
1912
1913 /* If the reference is absolute, or relative only in directions
1914 * that aren't changing, there's nothing to do.
1915 */
1916 if (!(*ffp == RANGE
1917 || (!dn && ((*ffp) | LRREL | HRREL) == (RANGE | LRREL | HRREL))
1918 || (!ov && ((*ffp) | LCREL | HCREL) == (RANGE | LCREL | HCREL))))
1919 continue;
1920
1921 /* If it's a case we don't know how to adjust, there's
1922 * nothing to do. If there is no overlap, there's nothing to
1923 * do.
1924 */
1925 if ((val != (LEFT | BOTTOM | TOP))
1926 && (val != (RIGHT | BOTTOM | TOP))
1927 && (val != (RIGHT | LEFT | TOP))
1928 && (val != (RIGHT | LEFT | BOTTOM))
1929 && (val != (RIGHT | LEFT | BOTTOM | TOP)))
1930 continue;
1931
1932 flush_range_ref (&orng, frr, fcc);
1933
1934 if (val != (RIGHT | LEFT | BOTTOM))
1935 orng.lr += dn;
1936 if (val != (RIGHT | LEFT | TOP))
1937 orng.hr += dn;
1938 if (val != (RIGHT | BOTTOM | TOP))
1939 orng.lc += ov;
1940 if (val != (LEFT | BOTTOM | TOP))
1941 orng.hc += ov;
1942 PUT_RNG (ffp + 1, &orng);
1943 push_stack (moving, (VOIDSTAR) ffp);
1944 push_stack (moving, (VOIDSTAR) TO_MAGIC (frr, fcc));
1945 push_stack (moving, DEF_RNG);
1946 continue;
1947 #ifdef TEST
1948 default:
1949 { struct function *fun; if (*ffp < USR1) fun =
1950 &the_funs[*ffp]; else if (*ffp >= SKIP) fun = 0, panic
1951 ("SKIP? in shift_outside()"); else fun =
1952 &usr_funs[*ffp][ffp[1]];
1953 if ((fun->fn_comptype & C_T) == 0) io_error_msg
1954 ("Unknown byte (%d) for reference_to #%d %d",
1955 *ffp, fn, fcp->cell_refs_to->to_refs[fn]);
1956 }
1957 break;
1958 #endif
1959 }
1960 }
1961 }
1962 }
1963
1964 while ((ptr = pop_stack (moving)))
1965 {
1966 if (ptr == DEF_REF)
1967 {
1968 val = (unsigned long) pop_stack (moving);
1969 trr = MAGIC_ROW (val);
1970 tcc = MAGIC_COL (val);
1971 val = (unsigned long) pop_stack (moving);
1972 cp = find_or_make_cell (trr, tcc);
1973 add_ref_fm (&(cp->cell_refs_from), MAGIC_ROW (val), MAGIC_COL (val));
1974 }
1975 else if (ptr == DEF_RNG)
1976 {
1977 val = (unsigned long) pop_stack (moving);
1978 cur_row = MAGIC_ROW (val);
1979 cur_col = MAGIC_COL (val);
1980 ffp = (unsigned char *) pop_stack (moving);
1981
1982 GET_RNG (ffp + 1, &orng);
1983 add_range_ref (&orng);
1984 if (my_cell)
1985 panic ("shift_outside: my_cell lost.");
1986 /* If this panic occurs, the caller should be recomputing
1987 * my_cell after shift_outside returns (and this useful panic
1988 * will have to be removed or my_cell set temporarily to 0).
1989 */
1990 }
1991 #ifdef TEST
1992 else
1993 panic ("Now what (%p)?", ptr);
1994 #endif
1995 }
1996 for_all_vars (finish_shift_var);
1997 /* flush_stack(moving); */
1998 }
1999
2000 /* The formula in cell my_cell has moved by DN down and OV over, adjust
2001 everything so it'll still work */
2002 void
shift_formula(int r,int c,int dn,int ov)2003 shift_formula (int r, int c, int dn, int ov)
2004 {
2005 int n;
2006 unsigned char *fp;
2007
2008 for (n = 0; n < my_cell->cell_refs_to->refs_used; n++)
2009 {
2010 fp = &(my_cell->cell_formula[my_cell->cell_refs_to->to_refs[n]]);
2011 switch (*fp)
2012 {
2013 case F_ROW:
2014 case F_COL:
2015 push_cell (cur_row, cur_col);
2016 break;
2017
2018 case R_CELL:
2019 case R_CELL | ROWREL:
2020 case R_CELL | COLREL:
2021 case R_CELL | ROWREL | COLREL:
2022 {
2023 CELLREF trr, tcc;
2024 CELL *tcp;
2025
2026 /* These are more difficult */
2027 trr = GET_ROW (fp + 1);
2028 tcc = GET_COL (fp + 1);
2029 tcp = find_cell (trr, tcc);
2030 #ifdef TEST
2031 if (!tcp)
2032 panic ("Can't find_cell(%s) in shift_formula", cell_name (trr, tcc));
2033 #endif
2034 flush_ref_fm (&(tcp->cell_refs_from), cur_row - dn, cur_col - ov);
2035
2036 if (((*fp) & ROWREL) && dn)
2037 {
2038 trr += dn;
2039 PUT_ROW (fp + 1, trr);
2040 }
2041 if (((*fp) & COLREL) && ov)
2042 {
2043 tcc += ov;
2044 PUT_COL (fp + 1, tcc);
2045 }
2046 tcp = find_or_make_cell (trr, tcc);
2047 add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
2048 }
2049 break;
2050
2051 case RANGE:
2052 case RANGE | LRREL:
2053 case RANGE | LRREL | LCREL:
2054 case RANGE | LRREL | LCREL | HCREL:
2055 case RANGE | LRREL | HCREL:
2056 case RANGE | LRREL | HRREL:
2057 case RANGE | LRREL | HRREL | LCREL:
2058 case RANGE | LRREL | HRREL | LCREL | HCREL:
2059 case RANGE | LRREL | HRREL | HCREL:
2060 case RANGE | HRREL:
2061 case RANGE | HRREL | LCREL:
2062 case RANGE | HRREL | LCREL | HCREL:
2063 case RANGE | HRREL | HCREL:
2064 case RANGE | LCREL:
2065 case RANGE | LCREL | HCREL:
2066 case RANGE | HCREL:
2067 {
2068 struct rng orng;
2069 GET_RNG (fp + 1, &orng);
2070
2071 flush_range_ref (&orng, cur_row - dn, cur_col - ov);
2072
2073 if ((*fp) & LRREL)
2074 orng.lr += dn;
2075 if ((*fp) & HRREL)
2076 orng.hr += dn;
2077 if ((*fp) & LCREL)
2078 orng.lc += ov;
2079 if ((*fp) & HCREL)
2080 orng.hc += ov;
2081 PUT_RNG (fp + 1, &orng);
2082 add_range_ref (&orng);
2083 /* sparse array bug fixed here */
2084 my_cell = find_cell (r, c);
2085 }
2086 break;
2087
2088 case VAR:
2089 {
2090 struct var *v;
2091 struct cell *tcp;
2092
2093 bcopy (&fp[1], &v, sizeof (struct var *));
2094 flush_ref_fm (&(v->var_ref_fm), cur_row - dn, cur_col - ov);
2095 add_ref_fm (&(v->var_ref_fm), cur_row, cur_col);
2096 switch (v->var_flags)
2097 {
2098 case VAR_UNDEF:
2099 break;
2100
2101 case VAR_CELL:
2102 tcp = find_cell (v->v_rng.lr, v->v_rng.lc);
2103 #ifdef TEST
2104 if (!tcp)
2105 panic ("Can't find_cell(%s) in shift_formula", cell_name (v->v_rng.lr, v->v_rng.lc));
2106 #endif
2107 flush_ref_fm (&(tcp->cell_refs_from), cur_row - dn, cur_col - ov);
2108 add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
2109 break;
2110
2111 case VAR_RANGE:
2112 flush_range_ref (&(v->v_rng), cur_row - dn, cur_col - ov);
2113 add_range_ref (&(v->v_rng));
2114 /* sparse array bug fixed here */
2115 my_cell = find_cell (r, c);
2116 break;
2117
2118 #ifdef TEST
2119 default:
2120 panic ("Unknown var type %d", v->var_flags);
2121 #endif
2122 }
2123 }
2124 break;
2125
2126 default:
2127 {
2128 struct function *fun;
2129
2130 if (*fp < USR1)
2131 fun = &the_funs[*fp];
2132 #ifdef TEST
2133 else if (*fp >= SKIP)
2134 fun = 0, panic ("SKIP? in shift_formula?");
2135 #endif
2136 else
2137 fun = &usr_funs[*fp][fp[1]];
2138 /* These are easy */
2139 if (fun->fn_comptype & C_T)
2140 {
2141 flush_ref_fm (&timer_cells, cur_row - dn, cur_col - ov);
2142 add_ref_fm (&timer_cells, cur_row, cur_col);
2143 }
2144 #ifdef TEST
2145 else
2146 panic ("How do I deal with byte %d in shift_formula()?", *fp);
2147 #endif
2148 }
2149 break;
2150 }
2151 }
2152 }
2153
2154
2155 /* ---------------- Routines for dealing with async functions -------------- */
2156
2157
2158 /* This function is called when the alarm has gone off (but not from inside
2159 * the signal handler!). It schedules timer_cells->fm_refs for recalc.
2160 */
2161 void
cell_alarm(void)2162 cell_alarm (void)
2163 {
2164 int n;
2165 static time_t last_time = 0;
2166 if (timer_active)
2167 {
2168 time_t this_time = time(0);
2169 if ((this_time - last_time) < cell_timer_seconds)
2170 return;
2171 last_time = this_time;
2172 current_cycle++;
2173 for (n = 0; n < timer_cells->refs_used; n++)
2174 push_cell (timer_cells->fm_refs[n].ref_row,
2175 timer_cells->fm_refs[n].ref_col);
2176 }
2177 }
2178
2179 /* All the timer_cells are going away, 'cuz everything is going away. . . */
2180 void
flush_all_timers(void)2181 flush_all_timers (void)
2182 {
2183 if (timer_active)
2184 {
2185 flush_fm_ref (timer_cells);
2186 timer_cells = 0;
2187 timer_active = 0;
2188 }
2189 }
2190
2191 /* Add CUR_ROW, CUR_COL to the list of active timer-cells, turning on
2192 the timer_active, if it isn't already */
2193 void
add_timer_ref(int whereto)2194 add_timer_ref (int whereto)
2195 {
2196 add_ref_to (whereto);
2197 add_ref_fm (&timer_cells, cur_row, cur_col);
2198 ++timer_active;
2199 }
2200
2201 /* ---------- Routines and vars for dealing with the eval FIFO ------------ */
2202 static struct cell_buf cell_buffer;
2203
2204 /* Start up the FIFO of cells to update */
2205 void
init_refs(void)2206 init_refs (void)
2207 {
2208 cell_buffer.size = FIFO_START;
2209 cell_buffer.buf = (struct pos *) ck_malloc (cell_buffer.size * sizeof (struct pos));
2210 bzero (cell_buffer.buf, cell_buffer.size * sizeof (struct pos));
2211 cell_buffer.push_to_here = cell_buffer.buf;
2212 cell_buffer.pop_frm_here = cell_buffer.buf;
2213 the_vars = hash_new ();
2214 }
2215
2216 /* Push the cells in REF onto the FIFO. This calls push_cell to do the
2217 actual work. . . */
2218 void
push_refs(struct ref_fm * ref)2219 push_refs (struct ref_fm *ref)
2220 {
2221 int n;
2222
2223 if (!ref || !ref->refs_used)
2224 return;
2225 n = ref->refs_used;
2226 while (n--)
2227 {
2228 #if 0
2229 CELL *cp;
2230
2231 fprintf (stderr, "Push %s\n", cell_name (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col));
2232 cp = find_cell (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col);
2233 if (cp->cell_cycle == current_cycle)
2234 {
2235 fprintf (stderr, "Cycle detected from %s to %s\n",
2236 cell_name (cur_row, cur_col),
2237 cell_name (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col));
2238 push_cell (ref->fm_refs[n].ref_row,
2239 ref->fm_refs[n].ref_col);
2240 }
2241 else
2242 #endif
2243 push_cell (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col);
2244 }
2245 }
2246
2247 /* Push a cell onto the FIFO of cells to evaluate, checking for cells
2248 that are already on the FIFO, etc.
2249
2250 This does not implement best-order recalculation, since there may be
2251 intersecting branches in the dependency tree, however, it's close enough
2252 for most people.
2253 */
2254 static void cell_buffer_contents (FILE *fp);
2255
2256 void
push_cell(CELLREF row,CELLREF col)2257 push_cell (CELLREF row, CELLREF col)
2258 {
2259 struct pos *dup;
2260 CELL *cp;
2261 struct ref_fm *rf;
2262
2263 /* printf("push_cell entry %d %d\n", row, col); cell_buffer_contents(stdout); */
2264 if (cell_buffer.push_to_here + 1 == cell_buffer.pop_frm_here
2265 || (cell_buffer.pop_frm_here == cell_buffer.buf
2266 && cell_buffer.push_to_here == cell_buffer.buf + (cell_buffer.size - 1)))
2267 {
2268 int f, t, from_num;
2269
2270 f = cell_buffer.pop_frm_here - cell_buffer.buf;
2271 t = cell_buffer.push_to_here - cell_buffer.buf;
2272 from_num = cell_buffer.size - f;
2273
2274 cell_buffer.size FIFO_INC;
2275 cell_buffer.buf = (struct pos *) ck_realloc((VOIDSTAR) cell_buffer.buf,
2276 cell_buffer.size * sizeof (struct pos));
2277 if (t == 0)
2278 {
2279 cell_buffer.push_to_here = cell_buffer.buf + f + from_num;
2280 cell_buffer.pop_frm_here = cell_buffer.buf + f;
2281 }
2282 else if (t > f)
2283 {
2284 cell_buffer.push_to_here = cell_buffer.buf + t;
2285 cell_buffer.pop_frm_here = cell_buffer.buf + f;
2286 }
2287 else
2288 {
2289 cell_buffer.push_to_here = cell_buffer.buf + t;
2290 cell_buffer.pop_frm_here = cell_buffer.buf + (cell_buffer.size - from_num);
2291 if (from_num)
2292 bcopy (cell_buffer.buf + f,
2293 cell_buffer.pop_frm_here,
2294 from_num * sizeof (struct pos));
2295 }
2296 }
2297
2298 #if 1
2299 if (cell_buffer.pop_frm_here != cell_buffer.push_to_here)
2300 {
2301 dup = cell_buffer.pop_frm_here;
2302
2303 cp = find_cell (row, col);
2304 if (!cp)
2305 {
2306 return;
2307 }
2308 rf = cp->cell_refs_from;
2309 for (; dup != cell_buffer.push_to_here;)
2310 {
2311 if (dup->row == row && dup->col == col)
2312 {
2313 #ifdef TEST
2314 if (debug & 010)
2315 io_error_msg ("Flushed dup ref to %s", cell_name (row, col));
2316 #endif
2317 *dup = *(cell_buffer.pop_frm_here);
2318 cell_buffer.pop_frm_here++;
2319 if (cell_buffer.pop_frm_here == cell_buffer.buf + cell_buffer.size)
2320 cell_buffer.pop_frm_here = cell_buffer.buf;
2321 break;
2322 }
2323 #if 0
2324 if (rf)
2325 {
2326 for (n = 0; n < rf->refs_used; n++)
2327 if (rf->fm_refs[n].ref_row == dup->row && rf->fm_refs[n].ref_col == dup->col)
2328 {
2329 #ifdef TEST
2330 if (debug & 01)
2331 io_error_msg ("Swapped %s and %s", cell_name (row, col), cell_name (dup->row, dup->col));
2332 #endif
2333 dup->row = row;
2334 dup->col = col;
2335 row = rf->fm_refs[n].ref_row;
2336 col - rf->fm_refs[n].ref_col;
2337 goto breakout;
2338 }
2339 }
2340 #endif
2341
2342 if (++dup == cell_buffer.buf + cell_buffer.size)
2343 dup = cell_buffer.buf;
2344 }
2345 }
2346 #endif
2347
2348 cell_buffer.push_to_here->row = row;
2349 cell_buffer.push_to_here->col = col;
2350 cell_buffer.push_to_here++;
2351 if (cell_buffer.push_to_here == cell_buffer.buf + cell_buffer.size)
2352 cell_buffer.push_to_here = cell_buffer.buf;
2353 /* printf("push_cell exit %d %d\n", row, col); cell_buffer_contents(stdout); */
2354 }
2355
2356 /* Pop a cell off CELL_BUFFER, and evaluate it, displaying the result. . .
2357 This returns 0 if there are no more cells to update, or if it gets
2358 an error. */
2359
2360 int
eval_next_cell(void)2361 eval_next_cell (void)
2362 {
2363 CELL *cp;
2364 static int loop_counter = 40;
2365
2366 if (cell_buffer.pop_frm_here == cell_buffer.push_to_here)
2367 return 0;
2368
2369 cur_row = cell_buffer.pop_frm_here->row;
2370 cur_col = cell_buffer.pop_frm_here->col;
2371 /* printf("eval_next_cell %d %d\n", cur_row, cur_col); */
2372 cell_buffer.pop_frm_here++;
2373 if (cell_buffer.pop_frm_here == cell_buffer.buf + cell_buffer.size)
2374 cell_buffer.pop_frm_here = cell_buffer.buf;
2375
2376 if (!(cp = find_cell(cur_row, cur_col)))
2377 return 0;
2378
2379 if (cp->cell_cycle == current_cycle)
2380 --loop_counter;
2381 else
2382 loop_counter = 40;
2383
2384 #if 0
2385 fprintf(stderr, "eval_next_cell: cp->cell_cycle = %d, current_cycle = %d, loop_counter = %d\n", cp->cell_cycle, current_cycle, loop_counter);
2386 cell_buffer_contents(stderr);
2387 #endif
2388 update_cell (cp);
2389 io_pr_cell (cur_row, cur_col, cp);
2390 #if 0
2391 if (!loop_counter)
2392 printf("eval_next_cell: returning 0 due to loop_counter\n");
2393 #endif
2394 return loop_counter;
2395 }
2396
2397 #if 1
2398 static void
cell_buffer_contents(FILE * fp)2399 cell_buffer_contents (FILE *fp)
2400 {
2401 struct pos *ptr;
2402
2403 if (!fp)
2404 fp = stdout;
2405 if (cell_buffer.pop_frm_here != cell_buffer.push_to_here)
2406 {
2407 ptr = cell_buffer.pop_frm_here;
2408 for (;;)
2409 {
2410 /* fprintf (fp, "Ref to %s\r\n", cell_name (ptr->row, ptr->col)); */
2411 fprintf (fp, " -> %d %d\n", ptr->row, ptr->col);
2412 if (++ptr == cell_buffer.buf + cell_buffer.size)
2413 ptr = cell_buffer.buf;
2414 if (ptr == cell_buffer.push_to_here)
2415 break;
2416 }
2417 }
2418 /* fprintf (fp, "End of buffer\r\n"); */
2419 }
2420
2421 #endif
2422
2423 /* ----------------- Routines for dealing with variables ------------------ */
2424
2425 /* Either this needs to be redone as a wrapper for the new new_var_value,
2426 * or the invocations of it in oleofile.c, sc.c and sylk.c need to be
2427 * adjusted so it can be deleted altogether. The new version has
2428 * been introduced to improve the interface of new set-var. The
2429 * only cost has been the need to introduce and unset-var command,
2430 * since the '@' argument type now required by set-var will
2431 * only recognize a valid region.
2432 */
2433 char *
old_new_var_value(char * v_name,int v_namelen,char * v_newval)2434 old_new_var_value (char *v_name, int v_namelen, char *v_newval)
2435 {
2436 struct var *var;
2437 int n;
2438 int newflag;
2439 struct rng tmp_rng;
2440
2441 cur_row = MIN_ROW;
2442 cur_col = MIN_COL;
2443 if (v_newval && *v_newval)
2444 {
2445 n = parse_cell_or_range (&v_newval, &tmp_rng);
2446 if (!n)
2447 return "Can't parse cell or range";
2448 if (*v_newval)
2449 return "Junk after cell or range";
2450 newflag = ((n | ROWREL | COLREL) == (R_CELL | ROWREL | COLREL)) ? VAR_CELL : VAR_RANGE;
2451 }
2452 else
2453 {
2454 tmp_rng.lr = tmp_rng.hr = NON_ROW;
2455 tmp_rng.lc = tmp_rng.hc = NON_COL;
2456 newflag = VAR_UNDEF;
2457 }
2458
2459 var = find_or_make_var (v_name, v_namelen);
2460
2461 if (var->var_ref_fm)
2462 {
2463 if (var->var_flags != VAR_UNDEF)
2464 {
2465 for (n = 0; n < var->var_ref_fm->refs_used; n++)
2466 {
2467 flush_range_ref (&(var->v_rng),
2468 var->var_ref_fm->fm_refs[n].ref_row,
2469 var->var_ref_fm->fm_refs[n].ref_col);
2470 }
2471 }
2472 var->v_rng = tmp_rng;
2473
2474 if (var->v_rng.lr != NON_ROW)
2475 {
2476 for (n = 0; n < var->var_ref_fm->refs_used; n++)
2477 {
2478 cur_row = var->var_ref_fm->fm_refs[n].ref_row;
2479 cur_col = var->var_ref_fm->fm_refs[n].ref_col;
2480 add_range_ref (&(var->v_rng));
2481 }
2482 }
2483 for (n = 0; n < var->var_ref_fm->refs_used; n++)
2484 push_cell (var->var_ref_fm->fm_refs[n].ref_row,
2485 var->var_ref_fm->fm_refs[n].ref_col);
2486 }
2487 else
2488 var->v_rng = tmp_rng;
2489
2490 var->var_flags = newflag;
2491
2492 return 0;
2493 }
2494
2495 /* This sets the variable V_NAME to V_NEWVAL
2496 * It returns error msg, or 0 on success.
2497 * all the appropriate cells have their ref_fm arrays adjusted appropriately
2498 * This could be smarter; when changing a range var, only the cells that
2499 * were in the old value but not in the new one need their references flushed,
2500 * and only the cells that are new need references added.
2501 * This might also be changed to use add_range_ref()?
2502 */
2503
2504 char *
new_var_value(char * v_name,int v_namelen,struct rng * rng)2505 new_var_value (char *v_name, int v_namelen, struct rng *rng)
2506 {
2507 struct var *var;
2508 int n = 0;
2509 int newflag = 0;
2510
2511 cur_row = MIN_ROW;
2512 cur_col = MIN_COL;
2513
2514 newflag = ((ROWREL | COLREL) == (R_CELL | ROWREL | COLREL)) ? VAR_CELL : VAR_RANGE;
2515
2516 var = find_or_make_var (v_name, v_namelen);
2517
2518 if (var->var_ref_fm)
2519 {
2520 if (var->var_flags != VAR_UNDEF)
2521 {
2522 for (n = 0; n < var->var_ref_fm->refs_used; n++)
2523 {
2524 flush_range_ref (&(var->v_rng),
2525 var->var_ref_fm->fm_refs[n].ref_row,
2526 var->var_ref_fm->fm_refs[n].ref_col);
2527 }
2528 }
2529 var->v_rng = *rng;
2530
2531 if (var->v_rng.lr != NON_ROW)
2532 {
2533 for (n = 0; n < var->var_ref_fm->refs_used; n++)
2534 {
2535 cur_row = var->var_ref_fm->fm_refs[n].ref_row;
2536 cur_col = var->var_ref_fm->fm_refs[n].ref_col;
2537 add_range_ref (&(var->v_rng));
2538 }
2539 }
2540 for (n = 0; n < var->var_ref_fm->refs_used; n++)
2541 push_cell (var->var_ref_fm->fm_refs[n].ref_row,
2542 var->var_ref_fm->fm_refs[n].ref_col);
2543 }
2544 else
2545 var->v_rng = *rng;
2546
2547 var->var_flags = newflag;
2548
2549 return 0;
2550 }
2551
2552 void
for_all_vars(void (* func)(char *,struct var *))2553 for_all_vars (void (*func) (char *, struct var *))
2554 {
2555 hash_apply (the_vars, func);
2556 }
2557
2558 /* Find a variable in the list of variables, or create it if it doesn't
2559 exist. Takes a name and a length so the name doesn't have to be
2560 null-terminated
2561 */
2562 struct var *
find_or_make_var(char * string,int len)2563 find_or_make_var (char *string, int len)
2564 {
2565 struct var *ret;
2566 int ch;
2567
2568 ch = string[len];
2569 string[len] = '\0';
2570
2571 ret = (struct var *) hash_find (the_vars, string);
2572 if (ret)
2573 {
2574 string[len] = ch;
2575 return ret;
2576 }
2577
2578 ret = (struct var *) ck_malloc (sizeof (struct var) + len);
2579 bcopy (string, ret->var_name, len + 1);
2580 ret->var_flags = VAR_UNDEF;
2581 ret->v_rng.lr = 0;
2582 ret->v_rng.lc = 0;
2583 ret->v_rng.hr = 0;
2584 ret->v_rng.hc = 0;
2585 ret->var_ref_fm = 0;
2586 hash_insert (the_vars, ret->var_name, ret);
2587 string[len] = ch;
2588 return ret;
2589 }
2590
2591 /* Like find-or-make-var except returns 0 if it doesn't exist */
2592 struct var *
find_var(char * string,int len)2593 find_var (char *string, int len)
2594 {
2595 int ch;
2596 struct var *ret;
2597
2598 ch = string[len];
2599 string[len] = '\0';
2600 ret = (struct var *) hash_find (the_vars, string);
2601 string[len] = ch;
2602 return ret;
2603 }
2604
2605 /* This adds a reference from CUR_ROW,CUR_COL to the variable VAR
2606 It calls add_ref or add_range_ref to have the cell(s) in VAR be
2607 referenced by CUR_ROW,CUR_COL
2608 */
2609 void
add_var_ref(void * vvar)2610 add_var_ref (void * vvar)
2611 {
2612 struct var *var = (struct var *)vvar;
2613 add_ref_fm (&(var->var_ref_fm), cur_row, cur_col);
2614 switch (var->var_flags)
2615 {
2616 case VAR_UNDEF:
2617 break;
2618 case VAR_CELL:
2619 add_ref (var->v_rng.lr, var->v_rng.lc);
2620 break;
2621 case VAR_RANGE:
2622 add_range_ref (&(var->v_rng));
2623 break;
2624 #ifdef TEST
2625 default:
2626 panic ("Unknown var type %d in add_var_ref", var->var_flags);
2627 #endif
2628 }
2629 }
2630
2631 static void
flush_var(char * name,struct var * var)2632 flush_var (char *name, struct var *var)
2633 {
2634 free (var);
2635 }
2636
2637
2638 /* Free up all the variables, and (if SPLIT_REFS) the ref_fm structure
2639 associated with each variable. Note that this does not get rid of
2640 the struct var *s in cell expressions, so it can only be used when all
2641 the cells are being freed also
2642 */
2643 void
flush_variables(void)2644 flush_variables (void)
2645 {
2646 for_all_vars (flush_var);
2647 hash_die (the_vars);
2648 the_vars = hash_new ();
2649 }
2650