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