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