1 /*
2  * $Id: cells.c,v 1.12 2000/08/10 21:02:50 danny Exp $
3  *
4  * Copyright � 1990, 1992, 1993 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 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #ifdef	WITH_DMALLOC
28 #include <dmalloc.h>
29 #endif
30 
31 #define obstack_chunk_alloc ck_malloc
32 #define obstack_chunk_free free
33 #include "obstack.h"
34 #include "funcdef.h"
35 #include "sysdef.h"
36 
37 #include "global.h"
38 #include "cell.h"
39 #include "eval.h"
40 #include "errors.h"
41 #include "lists.h"
42 #include "format.h"
43 #include "io-abstract.h"
44 #include "io-generic.h"
45 #include "io-term.h"
46 #include "cmd.h"
47 #include "ref.h"
48 
49 #ifdef	HAVE_MOTIF
50 #include "io-motif.h"
51 #endif
52 
53 struct value
54   {
55     int type;
56     union vals x;
57   };
58 
59 #define Float	x.c_d
60 #define String	x.c_s
61 #define Int	x.c_l
62 #define Value	x.c_i
63 #define Rng	x.c_r
64 
65 #define ERROR(x)	\
66  {			\
67 	p->Value=x;	\
68 	p->type=TYP_ERR;\
69 	return;		\
70  }
71 
72 
73 static int
cell(row,col,dowhat,p)74 cell (row, col, dowhat, p)
75      long row;
76      long col;
77      char *dowhat;
78      struct value *p;
79 {
80   struct func
81     {
82       char *name;
83       int typ;
84     };
85 
86   static struct func cell_funs[] =
87   {
88     {"row", TYP_INT},		/* 1 */
89     {"column", TYP_INT},	/* 2 */
90     {"width", TYP_INT},		/* 3 */
91     {"lock", TYP_STR},		/* 4 */
92     {"protection", TYP_STR},	/* 5 */
93     {"justify", TYP_STR},	/* 6 */
94     {"alignment", TYP_STR},	/* 7 */
95     {"fmt", TYP_STR},		/* 8 */
96     {"format", TYP_STR},	/* 9 */
97     {"type", TYP_STR},		/* 10 */
98     {"formula", TYP_STR},	/* 11 */
99     {"value", 0},		/* 12 */
100     {0, 0}
101   };
102 
103   CELL *cell_ptr;
104   char *strptr;
105   struct func *func;
106   struct func *f1;
107   int n;
108 
109   n = strlen (dowhat) - 1;
110   f1 = 0;
111   for (func = cell_funs; func->name; func++)
112     if (func->name[0] == dowhat[0]
113 	&& (n == 0 || !strincmp (&(func->name[1]), &dowhat[1], n)))
114       {
115 	if (f1)
116 	  return BAD_INPUT;
117 	f1 = func;
118       }
119   if (!f1)
120     return BAD_INPUT;
121   p->type = f1->typ;
122   switch (f1 - cell_funs)
123     {
124     case 0:
125       p->Int = row;
126       break;
127     case 1:
128       p->Int = col;
129       break;
130     case 2:
131       p->Int = get_width (col);
132       break;
133     case 3:
134     case 4:
135       cell_ptr = find_cell (row, col);
136       p->String = ( (cell_ptr ? GET_LCK (cell_ptr) : default_lock)
137 		   ? "locked"
138 		   : "unlocked");
139       break;
140     case 5:
141     case 6:
142       cell_ptr = find_cell (row, col);
143       p->String = jst_to_str (cell_ptr ?  GET_JST (cell_ptr) : default_jst);
144       break;
145     case 7:
146     case 8:
147       p->String = cell_format_string(find_cell(row, col));
148       break;
149     case 9:
150       cell_ptr = find_cell (row, col);
151       if (cell_ptr)
152 	switch (GET_TYP (cell_ptr))
153 	  {
154 	  case TYP_FLT:
155 	    p->String = "float";
156 	    break;
157 	  case TYP_INT:
158 	    p->String = "integer";
159 	    break;
160 	  case TYP_STR:
161 	    p->String = "string";
162 	    break;
163 	  case TYP_BOL:
164 	    p->String = "boolean";
165 	    break;
166 	  case TYP_ERR:
167 	    p->String = "error";
168 	    break;
169 	  default:
170 	    p->String = "unknown";
171 	  }
172       else
173 	p->String = "null";
174       break;
175     case 10:
176       cell_ptr = find_cell (row, col);
177       if (cell_ptr && (GET_TYP (cell_ptr) || cell_ptr->cell_formula))
178 	{
179 	  strptr = decomp (row, col, cell_ptr);
180 	  p->String = obstack_alloc (&tmp_mem, strlen (strptr) + 1);
181 	  strcpy (p->String, strptr);
182 	  decomp_free ();
183 	}
184       else
185 	p->String = "";
186       break;
187     case 11:
188       cell_ptr = find_cell (row, col);
189       if (cell_ptr)
190 	{
191 	  p->type = GET_TYP (cell_ptr);
192 	  p->x = cell_ptr->c_z;
193 	}
194       else
195 	p->type = 0;
196       break;
197     default:
198       return BAD_INPUT;
199     }
200   return 0;
201 }
202 
203 
204 static void
do_curcell(p)205 do_curcell (p)
206      struct value *p;
207 {
208   int tmp;
209 
210   tmp = cell (curow, cucol, p->String, p);
211   if (tmp)
212     ERROR (tmp);
213 }
214 
215 static void
do_my(p)216 do_my (p)
217      struct value *p;
218 {
219   int tmp;
220 
221   tmp = cell (cur_row, cur_col, p->String, p);
222   if (tmp)
223     ERROR (tmp);
224 }
225 
226 /* Note that the second argument may be *anything* including ERROR.  If it is
227    error, we find the first occurence of that ERROR in the range */
228 
229 static void
do_member(p)230 do_member (p)
231      struct value *p;
232 {
233   CELLREF crow;
234   CELLREF ccol;
235   int foundit;
236   CELL *cell_ptr;
237 
238   find_cells_in_range (&(p->Rng));
239   while ((cell_ptr = next_row_col_in_range (&crow, &ccol)))
240     {
241       if (GET_TYP (cell_ptr) != (p + 1)->type)
242 	continue;
243       switch ((p + 1)->type)
244 	{
245 	case 0:
246 	  foundit = 1;
247 	  break;
248 	case TYP_FLT:
249 	  foundit = cell_ptr->cell_flt == (p + 1)->Float;
250 	  break;
251 	case TYP_INT:
252 	  foundit = cell_ptr->cell_int == (p + 1)->Int;
253 	  break;
254 	case TYP_STR:
255 	  foundit = !strcmp (cell_ptr->cell_str, (p + 1)->String);
256 	  break;
257 	case TYP_BOL:
258 	  foundit = cell_ptr->cell_bol == (p + 1)->Value;
259 	  break;
260 	case TYP_ERR:
261 	  foundit = cell_ptr->cell_err == (p + 1)->Value;
262 	  break;
263 	default:
264 	  foundit = 0;
265 #ifdef TEST
266 	  panic ("Unknown type (%d) in member", (p + 1)->type);
267 #endif
268 	}
269       if (foundit)
270 	{
271 	  no_more_cells ();
272 	  p->Int = 1 + crow - p->Rng.lr + (ccol - p->Rng.lc) * (1 + p->Rng.hr - p->Rng.lr);
273 	  p->type = TYP_INT;
274 	  return;
275 	}
276     }
277   p->Int = 0L;
278   p->type = TYP_INT;
279 }
280 
281 static void
do_smember(p)282 do_smember (p)
283      struct value *p;
284 {
285   CELLREF crow;
286   CELLREF ccol;
287   CELL *cell_ptr;
288   char *string;
289 
290   string = (p + 1)->String;
291   find_cells_in_range (&(p->Rng));
292   while ((cell_ptr = next_row_col_in_range (&crow, &ccol)))
293     {
294       if (((GET_TYP (cell_ptr) == 0) && (string[0] == '\0'))
295 	  || (cell_ptr && (GET_TYP (cell_ptr) == TYP_STR)
296 	      && strstr (string, cell_ptr->cell_str)))
297 	{
298 	  no_more_cells ();
299 	  p->Int = 1 + (crow - p->Rng.lr)
300 	    + (ccol - p->Rng.lc) * (1 + (p->Rng.hr - p->Rng.lr));
301 	  p->type = TYP_INT;
302 	  return;
303 	}
304     }
305   p->Int = 0L;
306   p->type = TYP_INT;
307 }
308 
309 static void
do_members(p)310 do_members (p)
311      struct value *p;
312 {
313   CELLREF crow;
314   CELLREF ccol;
315   CELL *cell_ptr;
316   char *string;
317 
318   string = (p + 1)->String;
319   find_cells_in_range (&(p->Rng));
320   while ((cell_ptr = next_row_col_in_range (&crow, &ccol)))
321     {
322       if (GET_TYP (cell_ptr) != TYP_STR)
323 	continue;
324       if (strstr (cell_ptr->cell_str, string))
325 	{
326 	  no_more_cells ();
327 	  p->Int = 1 + (crow - p->Rng.lr)
328 	    + (ccol - p->Rng.lc) * (1 + (p->Rng.hr - p->Rng.lr));
329 	  p->type = TYP_INT;
330 	  return;
331 	}
332     }
333   p->Int = 0L;
334   p->type = TYP_INT;
335 }
336 
337 static void
do_pmember(p)338 do_pmember (p)
339      struct value *p;
340 {
341   CELLREF crow;
342   CELLREF ccol;
343   CELL *cell_ptr;
344   char *string;
345 
346   string = (p + 1)->String;
347   find_cells_in_range (&(p->Rng));
348   while ((cell_ptr = next_row_col_in_range (&crow, &ccol)))
349     {
350       if ((GET_TYP (cell_ptr) == 0 && string[0] == '\0')
351 	  || (cell_ptr && GET_TYP (cell_ptr) == TYP_STR && !strncmp (string, cell_ptr->cell_str, strlen (cell_ptr->cell_str))))
352 	{
353 	  no_more_cells ();
354 	  p->Int = 1 + (crow - p->Rng.lr)
355 	    + (ccol - p->Rng.lc) * (1 + (p->Rng.hr - p->Rng.lr));
356 	  p->type = TYP_INT;
357 	  return;
358 	}
359     }
360   p->Int = 0L;
361   p->type = TYP_INT;
362 }
363 
364 static void
do_memberp(p)365 do_memberp (p)
366      struct value *p;
367 {
368   CELLREF crow;
369   CELLREF ccol;
370   CELL *cell_ptr;
371   int tmp;
372   char *string;
373 
374   string = (p + 1)->String;
375   find_cells_in_range (&(p->Rng));
376   tmp = strlen (string);
377   while ((cell_ptr = next_row_col_in_range (&crow, &ccol)))
378     {
379       if (GET_TYP (cell_ptr) != TYP_STR)
380 	continue;
381       if (!strncmp (cell_ptr->cell_str, string, tmp))
382 	{
383 	  no_more_cells ();
384 	  p->Int = 1 + (crow - p->Rng.lr)
385 	    + (ccol - p->Rng.lc) * (1 + (p->Rng.hr - p->Rng.lr));
386 	  p->type = TYP_INT;
387 	  return;
388 	}
389     }
390   p->Int = 0L;
391   p->type = TYP_INT;
392 }
393 
394 static void
do_hlookup(p)395 do_hlookup (p)
396      struct value *p;
397 {
398 
399   struct rng *rng = &((p)->Rng);
400   double fltval = (p + 1)->Float;
401   long offset = (p + 2)->Int;
402 
403   CELL *cell_ptr;
404   double f;
405   CELLREF col;
406   CELLREF row;
407   char *strptr;
408 
409   row = rng->lr;
410   for (col = rng->lc; col <= rng->hc; col++)
411     {
412       if (!(cell_ptr = find_cell (row, col)))
413 	ERROR (NON_NUMBER);
414       switch (GET_TYP (cell_ptr))
415 	{
416 	case TYP_FLT:
417 	  if (fltval < cell_ptr->cell_flt)
418 	    goto out;
419 	  break;
420 	case TYP_INT:
421 	  if (fltval < cell_ptr->cell_int)
422 	    goto out;
423 	  break;
424 	case TYP_STR:
425 	  strptr = cell_ptr->cell_str;
426 	  f = astof (&strptr);
427 	  if (!*strptr && fltval > f)
428 	    goto out;
429 	  else
430 	    ERROR (NON_NUMBER);
431 	case 0:
432 	case TYP_BOL:
433 	case TYP_ERR:
434 	default:
435 	  ERROR (NON_NUMBER);
436 	}
437     }
438 out:
439   if (col == rng->lc)
440     ERROR (OUT_OF_RANGE);
441   --col;
442   row = rng->lr + offset;
443   if (row > rng->hr)
444     ERROR (OUT_OF_RANGE);
445   cell_ptr = find_cell (row, col);
446   if (!cell_ptr)
447     {
448       p->type = 0;
449       p->Int = 0;
450     }
451   else
452     {
453       p->type = GET_TYP (cell_ptr);
454       p->x = cell_ptr->c_z;
455     }
456 }
457 
458 static void
do_vlookup(p)459 do_vlookup (p)
460      struct value *p;
461 {
462 
463   struct rng *rng = &((p)->Rng);
464   double fltval = (p + 1)->Float;
465   long offset = (p + 2)->Int;
466 
467   CELL *cell_ptr;
468   double f;
469   CELLREF col;
470   CELLREF row;
471   char *strptr;
472 
473   col = rng->lc;
474   for (row = rng->lr; row <= rng->hr; row++)
475     {
476       if (!(cell_ptr = find_cell (row, col)))
477 	ERROR (NON_NUMBER);
478       switch (GET_TYP (cell_ptr))
479 	{
480 	case TYP_FLT:
481 	  if (fltval < cell_ptr->cell_flt)
482 	    goto out;
483 	  break;
484 	case TYP_INT:
485 	  if (fltval < cell_ptr->cell_int)
486 	    goto out;
487 	  break;
488 	case TYP_STR:
489 	  strptr = cell_ptr->cell_str;
490 	  f = astof (&strptr);
491 	  if (!*strptr && fltval > f)
492 	    goto out;
493 	  else
494 	    ERROR (NON_NUMBER);
495 	case 0:
496 	case TYP_BOL:
497 	case TYP_ERR:
498 	default:
499 	  ERROR (NON_NUMBER);
500 	}
501     }
502 out:
503   if (row == rng->lr)
504     ERROR (OUT_OF_RANGE);
505   --row;
506   col = rng->lc + offset;
507   if (col > rng->hc)
508     ERROR (OUT_OF_RANGE);
509 
510   cell_ptr = find_cell (row, col);
511   if (!cell_ptr)
512     {
513       p->type = 0;
514       p->Int = 0;
515     }
516   else
517     {
518       p->type = GET_TYP (cell_ptr);
519       p->x = cell_ptr->c_z;
520     }
521 }
522 
523 static void
do_vlookup_str(p)524 do_vlookup_str (p)
525      struct value *p;
526 {
527 
528   struct rng *rng = &((p)->Rng);
529   char * key = (p + 1)->String;
530   long offset = (p + 2)->Int;
531 
532   CELL *cell_ptr;
533   CELLREF col;
534   CELLREF row;
535 
536   col = rng->lc;
537   for (row = rng->lr; row <= rng->hr; row++)
538     {
539       if (!(cell_ptr = find_cell (row, col)))
540 	ERROR (NON_NUMBER);
541       switch (GET_TYP (cell_ptr))
542 	{
543 	case TYP_STR:
544 	  if (!strcmp (key, cell_ptr->cell_str))
545 	    goto out;
546 	  break;
547 	case 0:
548 	case TYP_FLT:
549 	case TYP_INT:
550 	case TYP_BOL:
551 	case TYP_ERR:
552 	default:
553 	  ERROR (NON_NUMBER);
554 	}
555     }
556 out:
557   if (row > rng->hr)
558     ERROR (OUT_OF_RANGE);
559   col = rng->lc + offset;
560   if (col > rng->hc)
561     ERROR (OUT_OF_RANGE);
562 
563   cell_ptr = find_cell (row, col);
564   if (!cell_ptr)
565     {
566       p->type = 0;
567       p->Int = 0;
568     }
569   else
570     {
571       p->type = GET_TYP (cell_ptr);
572       p->x = cell_ptr->c_z;
573     }
574 }
575 
576 
577 static void
do_cell(p)578 do_cell (p)
579      struct value *p;
580 {
581   int tmp;
582 
583   tmp = cell (p->Int, (p + 1)->Int, (p + 2)->String, p);
584   if (tmp)
585     ERROR (tmp);
586 }
587 
588 /* While writing the macro loader, I found a need for a function
589  * that could report back on whether or not a variable was defined.
590  * The function below does that and more.  It accepts an integer
591  * and two strings as arguments.  The integer specifies a corner;
592  * 0 for NW, 1 for NE, 2 for SE and 3 for SW.  The first string
593  * argument should specify a variable name.  The second should
594  * specify one of the elements accepted by cell().  If the
595  * variable has not been defined, this reports back its bare
596  * name as a string.
597  */
598 
599 static void
do_varval(struct value * p)600 do_varval (struct value *p)
601 {
602   int tmp;
603   int vr;
604   int vc;
605   struct var * v;
606 
607   v = find_var ((p+1)->String, strlen((p+1)->String));
608 
609   if (!v || v->var_flags == VAR_UNDEF) {
610     p->type = TYP_STR;
611     p->String = (p+1)->String;
612   } else {
613     switch(p->Int) {
614       case 0:
615         vr = v->v_rng.lr;
616         vc = v->v_rng.lc;
617         break;
618       case 1:
619         vr = v->v_rng.lr;
620         vc = v->v_rng.hc;
621         break;
622       case 2:
623         vr = v->v_rng.hr;
624         vc = v->v_rng.hc;
625         break;
626       case 3:
627         vr = v->v_rng.hr;
628         vc = v->v_rng.lc;
629         break;
630       default:
631         ERROR(OUT_OF_RANGE);
632         return;
633     }
634     p->String = (p+2)->String;
635     tmp = cell (vr, vc, p->String, p);
636     if (tmp)
637       ERROR (tmp);
638   }
639 }
640 
641 static void
do_button(struct value * p)642 do_button(struct value *p)
643 {
644 #ifdef	HAVE_MOTIF
645   MotifButton(cur_row, cur_col, p->String, (p+1)->String);
646 #endif
647 
648   p->type = TYP_STR;
649   p->String = (p+1)->String;
650 }
651 
652 struct function cells_funs[] =
653 {
654   {C_FN1 | C_T, X_A1, "S", do_curcell, "curcell"},
655   {C_FN1 | C_T, X_A1, "S", do_my, "my"},
656   {C_FN3 | C_T, X_A3, "IIS", do_cell, "cell"},
657   {C_FN3 | C_T, X_A3, "ISS", do_varval, "varval"},
658 
659   {C_FN2, X_A2, "RA", do_member, "member"},
660   {C_FN2, X_A2, "RS", do_smember, "smember"},
661   {C_FN2, X_A2, "RS", do_members, "members"},
662   {C_FN2, X_A2, "RS", do_pmember, "pmember"},
663   {C_FN2, X_A2, "RS", do_memberp, "memberp"},
664 
665   {C_FN3, X_A3, "RFI", do_hlookup, "hlookup"},
666   {C_FN3, X_A3, "RFI", do_vlookup, "vlookup"},
667   {C_FN3, X_A3, "RSI", do_vlookup_str, "vlookup_str"},
668 
669   {C_FN2,	X_A2,	"SS",	do_button,	"button" },
670 
671   {0, 0, "", 0, 0},
672 };
673 
init_cells_function_count(void)674 int init_cells_function_count(void)
675 {
676         return sizeof(cells_funs) / sizeof(struct function) - 1;
677 }
678