1 /*
2 Copyright (c) 1991-1999 Thomas T. Wetmore IV
3
4 Permission is hereby granted, free of charge, to any person
5 obtaining a copy of this software and associated documentation
6 files (the "Software"), to deal in the Software without
7 restriction, including without limitation the rights to use, copy,
8 modify, merge, publish, distribute, sublicense, and/or sell copies
9 of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 /*=============================================================
25 * alloc.c -- Allocate nodes for report generator
26 * pnodes are parse nodes in the parse tree built by yacc.c
27 * Copyright(c) 1991-95 by T.T. Wetmore IV; all rights reserved
28 *===========================================================*/
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 #include "sys_inc.h"
34 #ifdef HAVE_LOCALE_H
35 #include <locale.h>
36 #endif
37 #include "llstdlib.h"
38 #include "table.h"
39 #include "translat.h"
40 #include "gedcom.h"
41 #include "cache.h"
42 #include "interpi.h"
43 #include "feedback.h"
44 #include "liflines.h"
45 #include "codesets.h"
46 #include "zstr.h"
47 #include "vtable.h"
48
49 /*********************************************
50 * global/exported variables
51 *********************************************/
52
53 /* reused report language error strings */
54 STRING nonint1 = 0;
55 STRING nonintx = 0;
56 STRING nonboo1 = 0;
57 STRING nonboox = 0;
58 STRING nonflo1 = 0;
59 STRING nonflox = 0;
60 STRING nonstr1 = 0;
61 STRING nonstrx = 0;
62 STRING nullarg1 = 0;
63 STRING nonfname1 = 0;
64 STRING nonnodstr1 = 0;
65 STRING nonind1 = 0;
66 STRING nonindx = 0;
67 STRING nonfam1 = 0;
68 STRING nonfamx = 0;
69 STRING nonif1 = 0;
70 STRING nonrecx = 0;
71 STRING nonnod1 = 0;
72 STRING nonnodx = 0;
73 STRING nonvar1 = 0;
74 STRING nonvarx = 0;
75 STRING nonlst1 = 0;
76 STRING nonlstx = 0;
77 STRING nontabx = 0;
78 STRING nonset1 = 0;
79 STRING nonsetx = 0;
80 STRING nonlstarrx = 0;
81 STRING badargs = 0;
82 STRING badarg1 = 0;
83 STRING badargx = 0;
84 STRING badtrig = 0;
85
86 /*********************************************
87 * external/imported variables
88 *********************************************/
89
90
91
92 /*********************************************
93 * local types
94 *********************************************/
95
96 struct tag_pn_block
97 {
98 struct tag_pn_block * next;
99 struct tag_pnode nodes[100]; /* arbitrary size may be adjusted */
100 };
101 typedef struct tag_pn_block *PN_BLOCK;
102 #define BLOCK_NODES (sizeof(((PN_BLOCK)0)->nodes)/sizeof(((PN_BLOCK)0)->nodes[0]))
103
104 /*********************************************
105 * local function prototypes
106 *********************************************/
107
108 /* alphabetical */
109 static PNODE alloc_pnode_memory(void);
110 static void clear_error_strings(void);
111 static void clear_call_node(PNODE node);
112 static void clear_icons_node(PNODE node);
113 static void clear_iden_node(PNODE node);
114 static void clear_fcons_node(PNODE node);
115 static void clear_pnode(PNODE node);
116 static void clear_proc_node(PNODE node);
117 static void clear_string_node(PNODE node);
118 static PNODE create_pnode(PACTX pactx, INT type);
119 static void delete_pnode(PNODE node);
120 static void describe_pnodes(PNODE node, ZSTR zstr, INT max);
121 static void free_pnode_memory(PNODE node);
122 static void rptinfo_destructor(VTABLE *obj);
123 static void set_parents(PNODE body, PNODE node);
124 static void verify_builtins(void);
125
126 /*********************************************
127 * local variables
128 *********************************************/
129
130 static PN_BLOCK block_list = 0;
131 static PNODE free_list = 0;
132 static STRING interp_locale = 0;
133 static INT live_pnodes = 0;
134 static TABLE f_rptinfos=0;
135
136 static struct tag_vtable vtable_for_rptinfo = {
137 VTABLE_MAGIC
138 , "rptinfo"
139 , &rptinfo_destructor
140 , &refcountable_isref
141 , &refcountable_addref
142 , &refcountable_release
143 , 0 /* copy_fnc */
144 , &generic_get_type_name
145 };
146
147 /*********************************************
148 * local & exported function definitions
149 * body of module
150 *********************************************/
151
152 /*========================================
153 * alloc_pnode_memory -- return new pnode memory
154 * We use a custom allocator, which lowers our overhead
155 * (no heap overhead per pnode, only per block)
156 * and also allows us to clean them all up after the
157 * report.
158 * NB: This is not traditional garbage collection - we're
159 * not doing any live/dead analysis; we depend entirely
160 * on carnal knowledge of the program.
161 * As far as I know, no pnodes were ever being freed before.
162 * Perry Rapp, 2001/01/20
163 *======================================*/
164 static PNODE
alloc_pnode_memory(void)165 alloc_pnode_memory (void)
166 {
167 PNODE node;
168
169 /*
170 This assumes that all pnodes are scoped
171 within report processing. If this ceases to
172 be true, this breaks.
173 */
174 if (!free_list) {
175 PN_BLOCK new_block = stdalloc(sizeof(*new_block));
176 INT i;
177 new_block->next = block_list;
178 block_list = new_block;
179 for (i=0; i<(INT)BLOCK_NODES; i++) {
180 PNODE node1 = &new_block->nodes[i];
181 itype(node1) = IFREED;
182 inext(node1) = free_list;
183 free_list = node1;
184 }
185 }
186 node = free_list;
187 free_list = inext(node);
188 live_pnodes++;
189 return node;
190 }
191 /*========================================
192 * free_pnode_memory -- return pnode to free-list
193 * (see alloc_pnode_memory comments)
194 * Created: 2001/01/21, Perry Rapp
195 *======================================*/
196 static void
free_pnode_memory(PNODE node)197 free_pnode_memory (PNODE node)
198 {
199 /* put on free list */
200 inext(node) = free_list;
201 free_list = node;
202 live_pnodes--;
203 ASSERT(live_pnodes>=0);
204 }
205 /*======================================
206 * free_all_pnodes -- Free every pnode
207 * Created: 2001/01/21, Perry Rapp
208 *====================================*/
209 void
free_all_pnodes(void)210 free_all_pnodes (void)
211 {
212 PN_BLOCK block;
213 while ((block = block_list)) {
214 PN_BLOCK next = block->next;
215 free_list = 0;
216 if (live_pnodes) {
217 INT i;
218 for (i=0; i<(INT)BLOCK_NODES; i++) {
219 PNODE node1=&block->nodes[i];
220 if (itype(node1) != IFREED) {
221 delete_pnode(node1);
222 }
223 }
224 }
225 stdfree(block);
226 block_list = next;
227 }
228 free_list = 0;
229 }
230 /*==================================
231 * create_pnode -- Create PNODE node
232 * 2001/01/21 changed to block allocator
233 *================================*/
234 static PNODE
create_pnode(PACTX pactx,INT type)235 create_pnode (PACTX pactx, INT type)
236 {
237 PNODE node = alloc_pnode_memory();
238 itype(node) = type;
239 iprnt(node) = NULL;
240 inext(node) = NULL;
241 iline(node) = pactx->lineno;
242 /* Assumption -- pactx->fullpath stays live longer than all pnodes */
243 irptinfo(node) = get_rptinfo(pactx->fullpath);
244 node->i_word1 = node->i_word2 = node->i_word3 = NULL;
245 node->i_word4 = node->i_word5 = NULL;
246 return node;
247 }
248 /*========================================
249 * clear_pnode -- Empty contents of pvalue
250 * Created: 2001/01/20, Perry Rapp
251 *======================================*/
252 static void
clear_pnode(PNODE node)253 clear_pnode (PNODE node)
254 {
255 switch (itype(node)) {
256 case IICONS: clear_icons_node(node); return;
257 case IFCONS: clear_fcons_node(node); return;
258 case ISCONS: clear_string_node(node); return;
259 case IIDENT: clear_iden_node(node); return;
260 case IPCALL: clear_call_node(node); return;
261 case IPDEFN: clear_proc_node(node); return;
262 }
263 if (node->i_flags & PN_INAME_HSTR) {
264 STRING str = iname(node);
265 if (str) {
266 stdfree(str);
267 iname(node) = 0;
268 }
269 }
270 if (node->i_flags & PN_ICHILD_HPTR) {
271 STRING str = ichild(node);
272 if (str) {
273 stdfree(str);
274 ichild(node) = 0;
275 }
276 }
277 if (node->i_flags & PN_INUM_HPTR) {
278 STRING str = inum(node);
279 if (str) {
280 stdfree(str);
281 inum(node) = 0;
282 }
283 }
284 if (node->i_flags & PN_ISPOUSE_HPTR) {
285 STRING str = ispouse(node);
286 if (str) {
287 stdfree(str);
288 ispouse(node) = 0;
289 }
290 }
291 if (node->i_flags & PN_IFAMILY_HPTR) {
292 STRING str = ifamily(node);
293 if (str) {
294 stdfree(str);
295 ifamily(node) = 0;
296 }
297 }
298 if (node->i_flags & PN_IELEMENT_HPTR) {
299 STRING str = ielement(node);
300 if (str) {
301 stdfree(str);
302 ielement(node) = 0;
303 }
304 }
305 if (node->i_flags & PN_IPARENT_HPTR) {
306 STRING str = iiparent(node);
307 if (str) {
308 stdfree(str);
309 iiparent(node) = 0;
310 }
311 }
312 if (node->i_flags & PN_IVALVAR_HPTR) {
313 STRING str = ivalvar(node);
314 if (str) {
315 stdfree(str);
316 ivalvar(node) = 0;
317 }
318 }
319 }
320 /*==================================
321 * delete_pnode -- Create PNODE node
322 * Created: 2001/01/21, Perry Rapp
323 *================================*/
324 static void
delete_pnode(PNODE node)325 delete_pnode (PNODE node)
326 {
327 if (!node) return;
328 clear_pnode(node);
329 free_pnode_memory(node);
330 }
331 /*==================================
332 * create_string_node -- Create string node
333 * We copy the string memory.
334 *================================*/
335 PNODE
create_string_node(PACTX pactx,STRING str)336 create_string_node (PACTX pactx, STRING str)
337 {
338 PNODE node = create_pnode(pactx, ISCONS);
339 ASSERT(str); /* we're not converting NULL to "" because nobody passes us NULL */
340 node->vars.iscons.value = create_pvalue_from_string(str);
341 return node;
342 }
343 /*===================================
344 * get_internal_string_node_value --
345 * Return string value from string constant node
346 * node: IN] node
347 *=================================*/
348 CNSTRING
get_internal_string_node_value(PNODE node)349 get_internal_string_node_value (PNODE node)
350 {
351 PVALUE pval=0;
352 ASSERT(itype(node) == ISCONS);
353 pval = node->vars.iscons.value;
354 ASSERT(pval);
355 ASSERT(ptype(pval) == PSTRING);
356 return pvalue_to_string(pval);
357 }
358 /*===================================
359 * clear_string_node -- Free memory stored inside node
360 * node: [I/O] node
361 *=================================*/
362 static void
clear_string_node(PNODE node)363 clear_string_node (PNODE node)
364 {
365 PVALUE val=0;
366 ASSERT(itype(node) == ISCONS);
367 val = node->vars.iscons.value;
368 if (val) {
369 delete_pvalue(val);
370 node->vars.iscons.value = 0;
371 }
372
373 }
374 /*========================================
375 * children_node -- Create child loop node
376 * pactx: [I/O] pointer to parseinfo structure (parse globals)
377 * fexpr: [IN] expr
378 * cvar: [IN] child
379 * nvar: [IN] counter
380 * body: [IN] loop body statements
381 *======================================*/
382 PNODE
children_node(PACTX pactx,PNODE fexpr,STRING cvar,STRING nvar,PNODE body)383 children_node (PACTX pactx, PNODE fexpr, STRING cvar, STRING nvar, PNODE body)
384 {
385 PNODE node = create_pnode(pactx, ICHILDREN);
386 iloopexp(node) = (VPTR) fexpr;
387 ichild(node) = (VPTR) cvar;
388 inum(node) = (VPTR) nvar;
389 ibody(node) = (VPTR) body;
390 node->i_flags = PN_ICHILD_HPTR + PN_INUM_HPTR;
391 set_parents(body, node);
392 return node;
393 }
394 /*========================================
395 * familyspouses_node -- Create parent loop node
396 * pactx: [I/O] pointer to parseinfo structure (parse globals)
397 * fexpr: [IN] expr
398 * cvar: [IN] child
399 * nvar: [IN] counter
400 * body: [IN] loop body statements
401 *======================================*/
402 PNODE
familyspouses_node(PACTX pactx,PNODE fexpr,STRING cvar,STRING nvar,PNODE body)403 familyspouses_node (PACTX pactx, PNODE fexpr, STRING cvar, STRING nvar, PNODE body)
404 {
405 PNODE node = create_pnode(pactx, IFAMILYSPOUSES);
406 iloopexp(node) = (VPTR) fexpr;
407 iiparent(node) = (VPTR) cvar;
408 inum(node) = (VPTR) nvar;
409 ibody(node) = (VPTR) body;
410 node->i_flags = PN_IPARENT_HPTR + PN_INUM_HPTR;
411 set_parents(body, node);
412 return node;
413 }
414 /*========================================
415 * spouses_node -- Create spouse loop node
416 * pactx: [IN] pointer to parseinfo structure (parse globals)
417 * pexpr: [IN] expr
418 * svar: [IN] spouse
419 * fvar: [IN] family
420 * nvar: [IN] counter
421 * body: [IN] loop body statements
422 *======================================*/
423 PNODE
spouses_node(PACTX pactx,PNODE pexpr,STRING svar,STRING fvar,STRING nvar,PNODE body)424 spouses_node (PACTX pactx, PNODE pexpr, STRING svar, STRING fvar, STRING nvar, PNODE body)
425 {
426 PNODE node = create_pnode(pactx, ISPOUSES);
427 iloopexp(node) = (VPTR) pexpr;
428 ispouse(node) = (VPTR) svar;
429 ifamily(node) = (VPTR) fvar;
430 inum(node) = (VPTR) nvar;
431 ibody(node) = (VPTR) body;
432 node->i_flags = PN_ISPOUSE_HPTR + PN_IFAMILY_HPTR + PN_INUM_HPTR;
433 set_parents(body, node);
434 return node;
435 }
436 /*=========================================
437 * families_node -- Create family loop node
438 * pactx: [IN] pointer to parseinfo structure (parse globals)
439 * pexpr: [IN] expr
440 * fvar: [IN] family
441 * svar: [IN] spouse
442 * nvar: [IN] counter
443 * body: [IN] loop body statements
444 *=======================================*/
445 PNODE
families_node(PACTX pactx,PNODE pexpr,STRING fvar,STRING svar,STRING nvar,PNODE body)446 families_node (PACTX pactx, PNODE pexpr, STRING fvar, STRING svar, STRING nvar, PNODE body)
447 {
448 PNODE node = create_pnode(pactx, IFAMILIES);
449 iloopexp(node) = (VPTR) pexpr;
450 ifamily(node) = (VPTR) fvar;
451 ispouse(node) = (VPTR) svar;
452 inum(node) = (VPTR) nvar;
453 ibody(node) = (VPTR) body;
454 node->i_flags = PN_IFAMILY_HPTR + PN_ISPOUSE_HPTR + PN_INUM_HPTR;
455 set_parents(body, node);
456 return node;
457 }
458 /*=========================================
459 * fathers_node -- Create fathers loop node
460 * pactx: [IN] pointer to parseinfo structure (parse globals)
461 * pexpr, [IN] expression
462 * pvar: [IN] father
463 * fvar: [IN] family
464 * nvar: [IN] counter
465 * body: [IN] loop body statements
466 *=======================================*/
467 PNODE
fathers_node(PACTX pactx,PNODE pexpr,STRING pvar,STRING fvar,STRING nvar,PNODE body)468 fathers_node (PACTX pactx, PNODE pexpr, STRING pvar, STRING fvar, STRING nvar, PNODE body)
469 {
470 PNODE node = create_pnode(pactx, IFATHS);
471 iloopexp(node) = (VPTR) pexpr;
472 iiparent(node) = (VPTR) pvar;
473 ifamily(node) = (VPTR) fvar;
474 inum(node) = (VPTR) nvar;
475 ibody(node) = (VPTR) body;
476 node->i_flags = PN_IPARENT_HPTR + PN_IFAMILY_HPTR + PN_INUM_HPTR;
477 set_parents(body, node);
478 return node;
479 }
480 /*=========================================
481 * mothers_node -- Create mothers loop node
482 * pactx: [IN] pointer to parseinfo structure (parse globals)
483 * pexpr, [IN] expression
484 * pvar: [IN] mother
485 * fvar: [IN] family
486 * nvar: [IN] counter
487 * body: [IN] loop body statements
488 *=======================================*/
489 PNODE
mothers_node(PACTX pactx,PNODE pexpr,STRING pvar,STRING fvar,STRING nvar,PNODE body)490 mothers_node (PACTX pactx, PNODE pexpr, STRING pvar, STRING fvar, STRING nvar, PNODE body)
491 {
492 PNODE node = create_pnode(pactx, IMOTHS);
493 iloopexp(node) = (VPTR) pexpr;
494 iiparent(node) = (VPTR) pvar;
495 ifamily(node) = (VPTR) fvar;
496 inum(node) = (VPTR) nvar;
497 ibody(node) = (VPTR) body;
498 node->i_flags = PN_IPARENT_HPTR + PN_IFAMILY_HPTR + PN_INUM_HPTR;
499 set_parents(body, node);
500 return node;
501 }
502 /*=========================================
503 * parents_node -- Create parents loop node
504 * pactx: [IN] pointer to parseinfo structure (parse globals)
505 * pexpr, [IN] expression
506 * fvar: [IN] family
507 * nvar: [IN] counter
508 * body: [IN] loop body statements
509 *=======================================*/
510 PNODE
parents_node(PACTX pactx,PNODE pexpr,STRING fvar,STRING nvar,PNODE body)511 parents_node (PACTX pactx, PNODE pexpr, STRING fvar, STRING nvar, PNODE body)
512 {
513 PNODE node = create_pnode(pactx, IFAMCS);
514 iloopexp(node) = (VPTR) pexpr;
515 ifamily(node) = (VPTR) fvar;
516 inum(node) = (VPTR) nvar;
517 ibody(node) = (VPTR) body;
518 node->i_flags = PN_IFAMILY_HPTR + PN_INUM_HPTR;
519 set_parents(body, node);
520 return node;
521 }
522 /*========================================
523 * forindiset_node -- Create set loop node
524 * pactx: [IN] pointer to parseinfo structure (parse globals)
525 * iexpr, [IN] expression
526 * ivar: [IN] person
527 * vvar: [IN] value
528 * nvar: [IN] counter
529 * body: [IN] loop body statements
530 *======================================*/
531 PNODE
forindiset_node(PACTX pactx,PNODE iexpr,STRING ivar,STRING vvar,STRING nvar,PNODE body)532 forindiset_node (PACTX pactx, PNODE iexpr, STRING ivar, STRING vvar, STRING nvar, PNODE body)
533 {
534 PNODE node = create_pnode(pactx, ISET);
535 iloopexp(node) = (VPTR) iexpr;
536 ielement(node) = (VPTR) ivar;
537 ivalvar(node) = (VPTR) vvar;
538 inum(node) = (VPTR) nvar;
539 ibody(node) = (VPTR) body;
540 node->i_flags = PN_IELEMENT_HPTR + PN_IVALVAR_HPTR + PN_INUM_HPTR;
541 set_parents(body, node);
542 return node;
543 }
544 /*======================================
545 * forlist_node -- Create list loop node
546 * pactx: [IN] pointer to parseinfo structure (parse globals)
547 * iexpr, [IN] expression
548 * evar: [IN] element
549 * nvar: [IN] counter
550 * body: [IN] loop body statements
551 *====================================*/
552 PNODE
forlist_node(PACTX pactx,PNODE iexpr,STRING evar,STRING nvar,PNODE body)553 forlist_node (PACTX pactx, PNODE iexpr, STRING evar, STRING nvar, PNODE body)
554 {
555 PNODE node = create_pnode(pactx, ILIST);
556 iloopexp(node) = (VPTR) iexpr;
557 ielement(node) = (VPTR) evar;
558 inum(node) = (VPTR) nvar;
559 ibody(node) = (VPTR) body;
560 node->i_flags = PN_IELEMENT_HPTR + PN_INUM_HPTR;
561 set_parents(body, node);
562 return node;
563 }
564 /*=========================================
565 * forindi_node -- Create forindi loop node
566 * pactx: [IN] pointer to parseinfo structure (parse globals)
567 * ivar, [IN] person
568 * nvar: [IN] counter
569 * body: [IN] loop body statements
570 *=======================================*/
571 PNODE
forindi_node(PACTX pactx,STRING ivar,STRING nvar,PNODE body)572 forindi_node (PACTX pactx, STRING ivar, STRING nvar, PNODE body)
573 {
574 PNODE node = create_pnode(pactx, IINDI);
575 ielement(node) = (VPTR) ivar;
576 inum(node) = (VPTR) nvar;
577 ibody(node) = (VPTR) body;
578 node->i_flags = PN_IELEMENT_HPTR + PN_INUM_HPTR;
579 set_parents(body, node);
580 return node;
581 }
582 /*=========================================
583 * forsour_node -- Create forsour loop node
584 * pactx: [IN] pointer to parseinfo structure (parse globals)
585 * svar, [IN] source
586 * nvar: [IN] counter
587 * body: [IN] loop body statements
588 *=======================================*/
589 PNODE
forsour_node(PACTX pactx,STRING svar,STRING nvar,PNODE body)590 forsour_node (PACTX pactx, STRING svar, STRING nvar, PNODE body)
591 {
592 PNODE node = create_pnode(pactx, ISOUR);
593 ielement(node) = (VPTR) svar;
594 inum(node) = (VPTR) nvar;
595 ibody(node) = (VPTR) body;
596 node->i_flags = PN_IELEMENT_HPTR + PN_INUM_HPTR;
597 set_parents(body, node);
598 return node;
599 }
600 /*=========================================
601 * foreven_node -- Create foreven loop node
602 * pactx: [IN] pointer to parseinfo structure (parse globals)
603 * evar, [IN] event
604 * nvar: [IN] counter
605 * body: [IN] loop body statements
606 *=======================================*/
607 PNODE
foreven_node(PACTX pactx,STRING evar,STRING nvar,PNODE body)608 foreven_node (PACTX pactx, STRING evar, STRING nvar, PNODE body)
609 {
610 PNODE node = create_pnode(pactx, IEVEN);
611 ielement(node) = (VPTR) evar;
612 inum(node) = (VPTR) nvar;
613 ibody(node) = (VPTR) body;
614 node->i_flags = PN_IELEMENT_HPTR + PN_INUM_HPTR;
615 set_parents(body, node);
616 return node;
617 }
618 /*=========================================
619 * forothr_node -- Create forothr loop node
620 * pactx: [IN] pointer to parseinfo structure (parse globals)
621 * ovar, [IN] other record
622 * nvar: [IN] counter
623 * body: [IN] loop body statements
624 *=======================================*/
625 PNODE
forothr_node(PACTX pactx,STRING ovar,STRING nvar,PNODE body)626 forothr_node (PACTX pactx, STRING ovar, STRING nvar, PNODE body)
627 {
628 PNODE node = create_pnode(pactx, IOTHR);
629 ielement(node) = (VPTR) ovar;
630 inum(node) = (VPTR) nvar;
631 ibody(node) = (VPTR) body;
632 node->i_flags = PN_IELEMENT_HPTR + PN_INUM_HPTR;
633 set_parents(body, node);
634 return node;
635 }
636 /*=======================================
637 * forfam_node -- Create forfam loop node
638 * pactx: [IN] pointer to parseinfo structure (parse globals)
639 * fvar, [IN] family
640 * nvar: [IN] counter
641 * body: [IN] loop body statements
642 *=====================================*/
643 PNODE
forfam_node(PACTX pactx,STRING fvar,STRING nvar,PNODE body)644 forfam_node (PACTX pactx, STRING fvar, STRING nvar, PNODE body)
645 {
646 PNODE node = create_pnode(pactx, IFAM);
647 ielement(node) = (VPTR) fvar;
648 inum(node) = (VPTR) nvar;
649 ibody(node) = (VPTR) body;
650 node->i_flags = PN_IELEMENT_HPTR + PN_INUM_HPTR;
651 set_parents(body, node);
652 return node;
653 }
654 /*===========================================
655 * fornotes_node -- Create fornotes loop node
656 * pactx: [IN] pointer to parseinfo structure (parse globals)
657 * nexpr: [IN] expression
658 * vvar: [IN] value
659 * body: [IN] loop body statements
660 *=========================================*/
661 PNODE
fornotes_node(PACTX pactx,PNODE nexpr,STRING vvar,PNODE body)662 fornotes_node (PACTX pactx, PNODE nexpr, STRING vvar, PNODE body)
663 {
664 PNODE node = create_pnode(pactx, INOTES);
665 iloopexp(node) = (VPTR) nexpr;
666 ielement(node) = (VPTR) vvar;
667 ibody(node) = (VPTR) body;
668 node->i_flags = PN_IELEMENT_HPTR;
669 set_parents(body, node);
670 return node;
671 }
672 /*===========================================
673 * fornodes_node -- Create fornodes loop node
674 * pactx: [IN] pointer to parseinfo structure (parse globals)
675 * nexpr: [IN] expression
676 * vvar: [IN] node (next level)
677 * body: [IN] loop body statements
678 *=========================================*/
679 PNODE
fornodes_node(PACTX pactx,PNODE nexpr,STRING nvar,PNODE body)680 fornodes_node (PACTX pactx, PNODE nexpr, STRING nvar, PNODE body)
681 {
682 PNODE node = create_pnode(pactx, INODES);
683 iloopexp(node) = (VPTR) nexpr;
684 ielement(node) = (VPTR) nvar;
685 ibody(node) = (VPTR) body;
686 node->i_flags = PN_IELEMENT_HPTR;
687 set_parents(body, node);
688 return node;
689 }
690 /*===========================================
691 * traverse_node -- Create traverse loop node
692 * pactx: [IN] pointer to parseinfo structure (parse globals)
693 * nexpr: [IN] node
694 * snode: [IN] subnode
695 * levv: [IN] level
696 * body: [IN] loop body statements
697 *=========================================*/
698 PNODE
traverse_node(PACTX pactx,PNODE nexpr,STRING snode,STRING levv,PNODE body)699 traverse_node (PACTX pactx, PNODE nexpr, STRING snode, STRING levv, PNODE body)
700 {
701 PNODE node = create_pnode(pactx, ITRAV);
702 iloopexp(node) = (VPTR) nexpr;
703 ielement(node) = (VPTR) snode;
704 ilev(node) = (VPTR) levv;
705 ibody(node) = (VPTR) body;
706 node->i_flags = PN_IELEMENT_HPTR;
707 set_parents(body, node);
708 return node;
709 }
710 /*====================================
711 * iden_node -- Create identifier node
712 *==================================*/
713 PNODE
create_iden_node(PACTX pactx,STRING iden)714 create_iden_node (PACTX pactx, STRING iden)
715 {
716 PNODE node = create_pnode(pactx, IIDENT);
717 node->vars.iident.name = iden;
718 return node;
719 }
720 CNSTRING
iident_name(PNODE node)721 iident_name (PNODE node)
722 {
723 ASSERT(itype(node) == IIDENT);
724 return node->vars.iident.name;
725 }
726 /*====================================
727 * builtin_args -- Return args node of a call to built-in function
728 * This are the instance (runtime) values
729 *==================================*/
730 PNODE
builtin_args(PNODE node)731 builtin_args (PNODE node)
732 {
733 ASSERT(itype(node) == IBCALL);
734 return (PNODE)iargs(node);
735 /* TODO: */
736 /* return node->vars.ibcall.fargs; */
737 }
738 /*====================================
739 * ipdefn_args -- Return args node of a proc declaration
740 * This are the variables used in the proc declaration
741 *==================================*/
742 PNODE
ipdefn_args(PNODE node)743 ipdefn_args (PNODE node)
744 {
745 ASSERT(itype(node) == IPDEFN);
746 return (PNODE)iargs(node);
747 /* TODO: */
748 /* return node->vars.ipdefn.args; */
749 }
750 /*====================================
751 * ipcall_args -- Return args node of a proc call
752 * This are the instance values passed in the call
753 *==================================*/
754 PNODE
ipcall_args(PNODE node)755 ipcall_args (PNODE node)
756 {
757 ASSERT(itype(node) == IPCALL);
758 return (PNODE)iargs(node);
759 /* TODO: */
760 /* return node->vars.ipcall.args; */
761 }
762 /*====================================
763 * ifdefn_args -- Return args node of a func declaration
764 * This are the variables used in the func declaration
765 *==================================*/
766 PNODE
ifdefn_args(PNODE node)767 ifdefn_args (PNODE node)
768 {
769 ASSERT(itype(node) == IFDEFN);
770 return (PNODE)iargs(node);
771 /* TODO: */
772 /* return node->vars.ipdefn.args; */
773 }
774 /*====================================
775 * ifcall_args -- Return args node of a func call
776 * This are the instance values passed in the call
777 *==================================*/
778 PNODE
ifcall_args(PNODE node)779 ifcall_args (PNODE node)
780 {
781 ASSERT(itype(node) == IFCALL);
782 return (PNODE)iargs(node);
783 /* TODO: */
784 /* return node->vars.ipcall.args; */
785 }
786 /*===================================
787 * clear_iden_node -- Free memory stored inside node
788 * node: [I/O] node
789 *=================================*/
790 static void
clear_iden_node(PNODE node)791 clear_iden_node (PNODE node)
792 {
793 CNSTRING str=0;
794 ASSERT(itype(node) == IIDENT);
795 str = iident_name(node);
796 if (str) {
797 stdfree(str);
798 node->vars.iident.name = 0;
799 }
800 }
801 /*==================================
802 * create_icons_node -- Create integer node
803 *================================*/
804 PNODE
create_icons_node(PACTX pactx,INT ival)805 create_icons_node (PACTX pactx, INT ival)
806 {
807 PNODE node = create_pnode(pactx, IICONS);
808 node->vars.iicons.value = create_pvalue_from_int(ival);
809 return node;
810 }
811 /*===================================
812 * clear_icons_node -- Free memory stored inside node
813 * node: [I/O] node
814 *=================================*/
815 static void
clear_icons_node(PNODE node)816 clear_icons_node (PNODE node)
817 {
818 PVALUE val=0;
819 ASSERT(itype(node) == IICONS);
820 val = node->vars.iicons.value;
821 if (val) {
822 delete_pvalue(val);
823 node->vars.iicons.value = 0;
824 }
825
826 }
827 /*===================================
828 * fcons_node -- Create floating node
829 *=================================*/
830 PNODE
create_fcons_node(PACTX pactx,FLOAT fval)831 create_fcons_node (PACTX pactx, FLOAT fval)
832 {
833 PNODE node = create_pnode(pactx, IFCONS);
834 node->vars.ifcons.value = create_pvalue_from_float(fval);
835 return node;
836 }
837 /*===================================
838 * clear_fcons_node -- Free memory stored inside node
839 * node: [I/O] node
840 *=================================*/
841 static void
clear_fcons_node(PNODE node)842 clear_fcons_node (PNODE node)
843 {
844 PVALUE val=0;
845 ASSERT(itype(node) == IFCONS);
846 val = node->vars.ifcons.value;
847 if (val) {
848 delete_pvalue(val);
849 node->vars.ifcons.value = 0;
850 }
851
852 }
853 /*===================================
854 * create_proc_node -- Create procedure node
855 * pactx: [I/O] pointer to parseinfo structure (parse globals)
856 * name: [IN] proc name (from IDEN token)
857 * parms: [IN] param/s
858 * body: [IN] body
859 *=================================*/
860 PNODE
create_proc_node(PACTX pactx,CNSTRING name,PNODE parms,PNODE body)861 create_proc_node (PACTX pactx, CNSTRING name, PNODE parms, PNODE body)
862 {
863 PNODE node = create_pnode(pactx, IPDEFN);
864 iname(node) = (VPTR) name;
865 iargs(node) = (VPTR) parms;
866 ibody(node) = (VPTR) body;
867 node->i_flags = PN_INAME_HSTR;
868 set_parents(body, node);
869 return node;
870 }
871 /*===================================
872 * clear_proc_node -- Free memory stored inside node
873 * node: [I/O] node
874 *=================================*/
875 static void
clear_proc_node(PNODE node)876 clear_proc_node (PNODE node)
877 {
878 STRING str=0;
879 ASSERT(itype(node) == IPDEFN);
880 str = iname(node);
881 if (str) {
882 stdfree(str);
883 iname(node) = 0;
884 }
885 }
886 /*==================================================
887 * fdef_node -- Create user function definition node
888 * pactx: [I/O] pointer to parseinfo structure (parse globals)
889 * name: [IN] proc name
890 * parms: [IN] param/s
891 * body: [IN] body
892 *================================================*/
893 PNODE
fdef_node(PACTX pactx,CNSTRING name,PNODE parms,PNODE body)894 fdef_node (PACTX pactx, CNSTRING name, PNODE parms, PNODE body)
895 {
896 PNODE node = create_pnode(pactx, IFDEFN);
897 iname(node) = (VPTR) name;
898 iargs(node) = (VPTR) parms;
899 ibody(node) = (VPTR) body;
900 node->i_flags = PN_INAME_HSTR;
901 set_parents(body, node);
902 return node;
903 }
904 /*=======================================================
905 * func_node -- Create builtin or user function call node
906 * pactx: [I/O] pointer to parseinfo structure (parse globals)
907 * name: [IN] function name
908 * elist: [IN] param(s)
909 * consumes name heap pointer
910 *=====================================================*/
911 PNODE
func_node(PACTX pactx,STRING name,PNODE elist)912 func_node (PACTX pactx, STRING name, PNODE elist)
913 {
914 PNODE node, func;
915 INT lo, hi, md=0, n, r;
916 BOOLEAN found = FALSE;
917 INT count;
918
919 /* See if the function is user defined */
920 /* find func in local or global table */
921 func = get_proc_node(name, get_rptinfo(pactx->fullpath)->functab, gfunctab, &count);
922 if (func) {
923 node = create_pnode(pactx, IFCALL);
924 iname(node) = (VPTR) name;
925 iargs(node) = (VPTR) elist;
926 node->i_flags = PN_INAME_HSTR;
927 ifunc(node) = func;
928 return node;
929 } else if (count) {
930 /* ambiguous call */
931 goto func_node_bad;
932 }
933
934 /*
935 See if the function is builtin
936 Assume that builtins[] is in alphabetic order
937 and do binary search on it
938 */
939
940 lo = 0;
941 hi = nobuiltins - 1;
942 while (lo <= hi) {
943 md = (lo + hi) >> 1;
944 if ((r = cmpstr(name, builtins[md].ft_name)) < 0)
945 hi = md - 1;
946 else if (r > 0)
947 lo = md + 1;
948 else {
949 found = TRUE;
950 break;
951 }
952 }
953 if (found) {
954 if ((n = num_params(elist)) < builtins[md].ft_nparms_min
955 || n > builtins[md].ft_nparms_max) {
956 llwprintf(_("Error: file \"%s\": line %d: "), pactx->ifile, pactx->lineno);
957 llwprintf("%s: must have %d to %d parameters (found with %d).\n"
958 , name, builtins[md].ft_nparms_min, builtins[md].ft_nparms_max
959 , n);
960 Perrors++;
961 }
962 node = create_pnode(pactx, IBCALL);
963 iname(node) = (VPTR) name;
964 iargs(node) = (VPTR) elist;
965 ifunc(node) = (VPTR) builtins[md].ft_eval;
966 node->i_flags = PN_INAME_HSTR;
967 return node;
968
969 }
970
971 /* If neither make it a user call to undefined function */
972 func_node_bad:
973 node = create_pnode(pactx, IFCALL);
974 iname(node) = (VPTR) name;
975 iargs(node) = (VPTR) elist;
976 ifunc(node) = NULL;
977 return node;
978 }
979 /*=============================
980 * init_interpreter -- any initialization needed by
981 * interpreter at program startup
982 * Created: 2001/06/10, Perry Rapp
983 *===========================*/
984 void
init_interpreter(void)985 init_interpreter (void)
986 {
987 verify_builtins();
988 }
989 /*=============================
990 * clear_error_strings -- Free all error strings
991 * Used at end, and also if language change needed
992 *===========================*/
993 static void
clear_error_strings(void)994 clear_error_strings (void)
995 {
996 strfree(&nonint1);
997 strfree(&nonintx);
998 strfree(&nonboo1);
999 strfree(&nonboox);
1000 strfree(&nonflo1);
1001 strfree(&nonflox);
1002 strfree(&nonstr1);
1003 strfree(&nonstrx);
1004 strfree(&nullarg1);
1005 strfree(&nonfname1);
1006 strfree(&nonnodstr1);
1007 strfree(&nonind1);
1008 strfree(&nonindx);
1009 strfree(&nonfam1);
1010 strfree(&nonfamx);
1011 strfree(&nonif1);
1012 strfree(&nonrecx);
1013 strfree(&nonnod1);
1014 strfree(&nonnodx);
1015 strfree(&nonvar1);
1016 strfree(&nonvarx);
1017 strfree(&nonlst1);
1018 strfree(&nonlstx);
1019 strfree(&nontabx);
1020 strfree(&nonset1);
1021 strfree(&nonsetx);
1022 strfree(&nonlstarrx);
1023 strfree(&badargs);
1024 strfree(&badarg1);
1025 strfree(&badargx);
1026 strfree(&badtrig);
1027 strfree(&interp_locale);
1028 }
1029 /*=============================
1030 * shutdown_interpreter -- shutdown code for
1031 * interpreter at program end
1032 * Created: 2002/02/16, Perry Rapp
1033 *===========================*/
1034 void
shutdown_interpreter(void)1035 shutdown_interpreter (void)
1036 {
1037 clear_error_strings();
1038 }
1039 /*=============================
1040 * interp_load_lang -- Load the common
1041 * error msgs for current locale
1042 * These are used by many report functions.
1043 * This avoids having to localize dozens of strings
1044 * just like these.
1045 * Examples:
1046 * nonfam1 is for a function taking a single argument
1047 * which should be a FAM
1048 * nonfamx is for a function taking multiple arguments
1049 * with error in one which should be a FAM
1050 * Created: 2002/02/16, Perry Rapp
1051 *===========================*/
1052 void
interp_load_lang(void)1053 interp_load_lang (void)
1054 {
1055 #ifdef HAVE_SETLOCALE
1056 STRING cur_locale = setlocale(LC_COLLATE, NULL);
1057 if (interp_locale) {
1058 /* using LC_COLLATE because Win32 lacks LC_MESSAGES */
1059 if (eqstr(interp_locale, cur_locale))
1060 return;
1061 stdfree(interp_locale);
1062 }
1063 interp_locale = strsave(cur_locale);
1064 #else
1065 if (interp_locale)
1066 return;
1067 interp_locale = strsave("C");
1068 #endif
1069 clear_error_strings();
1070 nonint1 = strsave(_("%s: the arg must be an integer."));
1071 nonintx = strsave(_("%s: the arg #%s must be an integer."));
1072 nonboo1 = strsave(_("%s: the arg must be a boolean."));
1073 nonboox = strsave(_("%s: the arg #%s must be a boolean."));
1074 nonflo1 = strsave(_("%s: the arg must be a float."));
1075 nonflox = strsave(_("%s: the arg #%s must be a float."));
1076 nonstr1 = strsave(_("%s: the arg must be a string."));
1077 nonstrx = strsave(_("%s: the arg #%s must be a string."));
1078 nullarg1 = strsave(_("%s: null arg not permissible."));
1079 nonfname1 = strsave(_("%s: the arg must be a filename."));
1080 nonnodstr1 = strsave(_("%s: the arg must be a node or string."));
1081 nonind1 = strsave(_("%s: the arg must be a person."));
1082 nonindx = strsave(_("%s: the arg #%s must be a person."));
1083 nonfam1 = strsave(_("%s: the arg must be a family."));
1084 nonfamx = strsave(_("%s: the arg #%s must be a family."));
1085 nonif1 = strsave(_("%s: the arg must be a person or family."));
1086 nonrecx = strsave(_("%s: the arg #%s must be a record."));
1087 nonnod1 = strsave(_("%s: the arg must be a node."));
1088 nonnodx = strsave(_("%s: the arg #%s must be a node."));
1089 nonvar1 = strsave(_("%s: the arg must be a variable."));
1090 nonvarx = strsave(_("%s: the arg #%s must be a variable."));
1091 nonlst1 = strsave(_("%s: the arg must be a list."));
1092 nonlstx = strsave(_("%s: the arg #%s must be a list."));
1093 nontabx = strsave(_("%s: the arg #%s must be a table."));
1094 nonset1 = strsave(_("%s: the arg must be a set."));
1095 nonsetx = strsave(_("%s: the arg #%s must be a set."));
1096 nonlstarrx = strsave(_("%s: the arg #%s must be a list or array."));
1097 badargs = strsave(_("%s: Bad arguments"));
1098 badarg1 = strsave(_("%s: the arg had a major error."));
1099 badargx = strsave(_("%s: the arg #%s had a major error."));
1100 badtrig = strsave(_("%s: the arg #%s would cause an arithmetic exception."));
1101 }
1102
1103 /*=============================
1104 * verify_builtins -- check that builtins are in order
1105 * Created: 2001/06/10, Perry Rapp
1106 *===========================*/
1107 static void
verify_builtins(void)1108 verify_builtins (void)
1109 {
1110 INT i;
1111 for (i=0; i<nobuiltins-1; ++i) {
1112 if (strcmp(builtins[i].ft_name, builtins[i+1].ft_name)>0) {
1113 char msg[64];
1114 sprintf(msg, "builtins array out of order ! (entries %ld,%ld)"
1115 , i, i+1);
1116 FATAL2(msg);
1117 }
1118 if (builtins[i].ft_nparms_min > builtins[i].ft_nparms_max) {
1119 char msg[64];
1120 sprintf(msg, "builtins array bad min,max (%ld,%ld, entry %ld)"
1121 , builtins[i].ft_nparms_min, builtins[i].ft_nparms_max
1122 , i);
1123 FATAL2(msg);
1124 }
1125 }
1126 }
1127 /*=============================
1128 * if_node -- Create an if node
1129 * pactx: [I/O] pointer to parseinfo structure (parse globals)
1130 * cond: [IN] conditional expression governing if
1131 * tnode: [IN] then statements
1132 * enode: [IN] else statements
1133 *===========================*/
1134 PNODE
if_node(PACTX pactx,PNODE cond,PNODE tnode,PNODE enode)1135 if_node (PACTX pactx, PNODE cond, PNODE tnode, PNODE enode)
1136 {
1137 PNODE node = create_pnode(pactx, IIF);
1138 node->vars.iif.icond = cond;
1139 node->vars.iif.ithen = tnode;
1140 node->vars.iif.ielse = enode;
1141 set_parents(tnode, node);
1142 set_parents(enode, node);
1143 return node;
1144 }
1145 /*================================
1146 * while_node -- Create while node
1147 * pactx: [I/O] pointer to parseinfo structure (parse globals)
1148 * cond: [IN] conditional expression governing while loop
1149 * body: [IN] body statements of while loop
1150 *==============================*/
1151 PNODE
while_node(PACTX pactx,PNODE cond,PNODE body)1152 while_node (PACTX pactx, PNODE cond, PNODE body)
1153 {
1154 PNODE node = create_pnode(pactx, IWHILE);
1155 node->vars.iwhile.icond = cond;
1156 node->vars.iwhile.ibody = body;
1157 set_parents(body, node);
1158 return node;
1159 }
1160 /*===================================
1161 * create_call_node -- Create proc call node
1162 * pactx: [I/O] pointer to parseinfo structure (parse globals)
1163 * name: [IN] procedure name (from IDEN value)
1164 * args: [IN] argument(s)
1165 *=================================*/
1166 PNODE
create_call_node(PACTX pactx,STRING name,PNODE args)1167 create_call_node (PACTX pactx, STRING name, PNODE args)
1168 {
1169 PNODE node = create_pnode(pactx, IPCALL);
1170 node->vars.ipcall.fname = name;
1171 node->vars.ipcall.fargs = args;
1172 return node;
1173 }
1174 /*===================================
1175 * clear_call_node -- Free memory stored inside node
1176 * node: [I/O] node
1177 *=================================*/
1178 static void
clear_call_node(PNODE node)1179 clear_call_node (PNODE node)
1180 {
1181 CNSTRING str=0;
1182 ASSERT(itype(node) == IPCALL);
1183 str = node->vars.ipcall.fname;
1184 if (str) {
1185 stdfree(str);
1186 }
1187 }
1188 /*================================
1189 * break_node -- Create break node
1190 *==============================*/
break_node(PACTX pactx)1191 PNODE break_node (PACTX pactx)
1192 {
1193 PNODE node = create_pnode(pactx, IBREAK);
1194 return node;
1195 }
1196 /*======================================
1197 * continue_node -- Create continue node
1198 *====================================*/
continue_node(PACTX pactx)1199 PNODE continue_node (PACTX pactx)
1200 {
1201 PNODE node = create_pnode(pactx, ICONTINUE);
1202 return node;
1203 }
1204 /*==================================
1205 * return_node -- Create return node
1206 *================================*/
1207 PNODE
return_node(PACTX pactx,PNODE args)1208 return_node (PACTX pactx, PNODE args)
1209 {
1210 PNODE node = create_pnode(pactx, IRETURN);
1211 iargs(node) = (VPTR) args;
1212 return node;
1213 }
1214 /*==============================================
1215 * set_parents -- Link body nodes to parent node
1216 *============================================*/
1217 void
set_parents(PNODE body,PNODE node)1218 set_parents (PNODE body,
1219 PNODE node)
1220 {
1221 while (body) {
1222 iprnt(body) = node;
1223 body = inext(body);
1224 }
1225 }
1226 /*=========================================================
1227 * show_pnode -- DEBUG routine that shows a PNODE structure
1228 *=======================================================*/
1229 void
show_pnode(PNODE node)1230 show_pnode (PNODE node)
1231 {
1232 while (node) {
1233 debug_show_one_pnode(node);
1234 node = inext(node);
1235 }
1236 }
1237 /*==========================================================
1238 * show_pnodes -- DEBUG routine that shows expression PNODEs
1239 *========================================================*/
1240 void
show_pnodes(PNODE node)1241 show_pnodes (PNODE node)
1242 {
1243
1244 while (node) {
1245 debug_show_one_pnode(node);
1246 node = inext(node);
1247 if (node) llwprintf(",");
1248 }
1249 }
1250 /*==========================================================
1251 * describe_pnodes -- DEBUG routine that describes expression PNODE chain
1252 * into zstring
1253 *========================================================*/
1254 static void
describe_pnodes(PNODE node,ZSTR zstr,INT max)1255 describe_pnodes (PNODE node, ZSTR zstr, INT max)
1256 {
1257 while (node) {
1258 describe_pnode(node, zstr, max);
1259 node = inext(node);
1260 if (node)
1261 zs_appc(zstr, ',');
1262 }
1263 }
1264 /*====================================================
1265 * debug_show_one_pnode -- DEBUG routine that show one PNODE
1266 *==================================================*/
1267 void
debug_show_one_pnode(PNODE node)1268 debug_show_one_pnode (PNODE node) /* node to print */
1269 {
1270 ZSTR zstr = zs_newn(512);
1271 INT max = 512;
1272 describe_pnode(node, zstr, max);
1273 llwprintf(zs_str(zstr));
1274 }
1275 /*====================================================
1276 * debug_show_one_pnode -- DEBUG routine to describe one node
1277 * appending description into zstring
1278 * but not more than max chars
1279 *==================================================*/
1280 void
describe_pnode(PNODE node,ZSTR zstr,INT max)1281 describe_pnode (PNODE node, ZSTR zstr, INT max)
1282 {
1283 if ((INT)zs_len(zstr) >= max-2)
1284 return;
1285 if ((INT)zs_len(zstr) >= max-7) {
1286 if (zs_str(zstr)[zs_len(zstr)-1] != '.')
1287 zs_apps(zstr, "...");
1288 return;
1289 }
1290
1291 switch (itype(node)) {
1292
1293 case IICONS:
1294 zs_appf(zstr, "%d", pvalue_to_int(node->vars.iicons.value));
1295 break;
1296 case IFCONS:
1297 zs_appf(zstr, "%f", pvalue_to_float(node->vars.ifcons.value));
1298 break;
1299 case ISCONS:
1300 zs_appf(zstr, "^^%s^^", pvalue_to_string(node->vars.iscons.value));
1301 break;
1302 case IIDENT:
1303 zs_appf(zstr, "%s", iident_name(node));
1304 break;
1305 case IIF:
1306 zs_apps(zstr, "if(");
1307 describe_pnodes(node->vars.iif.icond, zstr, max);
1308 zs_apps(zstr, "){");
1309 describe_pnodes(node->vars.iif.ithen, zstr, max);
1310 zs_apps(zstr, "}");
1311 if (node->vars.iif.ielse) {
1312 zs_apps(zstr, "else{");
1313 describe_pnodes(node->vars.iif.ielse, zstr, max);
1314 zs_apps(zstr, "}");
1315 }
1316 break;
1317 case IWHILE:
1318 zs_apps(zstr, "while(");
1319 describe_pnodes(node->vars.iwhile.icond, zstr, max);
1320 zs_apps(zstr, "){");
1321 describe_pnodes(node->vars.iwhile.ibody, zstr, max);
1322 zs_apps(zstr, "}");
1323 break;
1324 case IBREAK:
1325 zs_apps(zstr, "break ");
1326 break;
1327 case ICONTINUE:
1328 zs_apps(zstr, "continue ");
1329 break;
1330 case IRETURN:
1331 zs_apps(zstr, "return(");
1332 describe_pnodes(iargs(node), zstr, max);
1333 zs_apps(zstr, ")");
1334 break;
1335 case IPDEFN:
1336 zs_apps(zstr, "*PDefn *");
1337 break;
1338 case IPCALL:
1339 zs_appf(zstr, "%s(", iname(node));
1340 describe_pnodes(iargs(node), zstr, max);
1341 zs_apps(zstr, ")");
1342 break;
1343 case IFDEFN:
1344 zs_apps(zstr, "*FDefn *");
1345 break;
1346 case IFCALL:
1347 zs_appf(zstr, "%s(", iname(node));
1348 describe_pnodes(iargs(node), zstr, max);
1349 zs_apps(zstr, ")");
1350 break;
1351 case IBCALL:
1352 zs_appf(zstr, "%s(", iname(node));
1353 describe_pnodes(iargs(node), zstr, max);
1354 zs_apps(zstr, ")");
1355 break;
1356 case ITRAV:
1357 zs_apps(zstr, "*Traverse *");
1358 break;
1359 case INODES:
1360 zs_apps(zstr, "*Fornodes *");
1361 break;
1362 case IFAMILIES:
1363 zs_apps(zstr, "*FamiliesLoop *");
1364 break;
1365 case ISPOUSES:
1366 zs_apps(zstr, "*SpousesLoop *");
1367 break;
1368 case ICHILDREN:
1369 zs_apps(zstr, "*ChildrenLoop *");
1370 break;
1371 case IFAMILYSPOUSES:
1372 zs_apps(zstr, "*FamilySpousesLoop *");
1373 break;
1374 case IINDI:
1375 zs_apps(zstr, "*PersonLoop *");
1376 break;
1377 case IFAM:
1378 zs_apps(zstr, "*FamilyLoop *");
1379 break;
1380 case ISOUR:
1381 zs_apps(zstr, "*SourceLoop *");
1382 break;
1383 case IEVEN:
1384 zs_apps(zstr, "*EventLoop *");
1385 break;
1386 case IOTHR:
1387 zs_apps(zstr, "*OtherLoop *");
1388 break;
1389 case ILIST:
1390 zs_apps(zstr, "*ListLoop *");
1391 break;
1392 case ISET:
1393 zs_apps(zstr, "*IndisetLoop *");
1394 break;
1395 case IFATHS:
1396 zs_apps(zstr, "*FathersLoop *");
1397 break;
1398 case IMOTHS:
1399 zs_apps(zstr, "*MothersLoop *");
1400 break;
1401 case IFAMCS:
1402 zs_apps(zstr, "*ParentsLoop *");
1403 break;
1404 case INOTES:
1405 zs_apps(zstr, "*NotesLoop *");
1406 break;
1407 default:
1408 break;
1409 }
1410 }
1411 /*==========================================================
1412 * create_rptinfo -- Create new empty report info object
1413 * returns addref'd rptinfo
1414 *========================================================*/
1415 static RPTINFO
create_rptinfo(void)1416 create_rptinfo (void)
1417 {
1418 RPTINFO rptinfo = (RPTINFO)stdalloc(sizeof(*rptinfo));
1419 memset(rptinfo, 0, sizeof(*rptinfo));
1420 rptinfo->vtable = &vtable_for_rptinfo;
1421 rptinfo->refcnt = 1;
1422 return rptinfo;
1423 }
1424 /*==========================================================
1425 * get_rptinfo -- Fetch info about report file
1426 * create if not yet known
1427 *========================================================*/
1428 RPTINFO
get_rptinfo(CNSTRING fullpath)1429 get_rptinfo (CNSTRING fullpath)
1430 {
1431 RPTINFO rptinfo;
1432 if (!f_rptinfos)
1433 f_rptinfos = create_table_obj();
1434 rptinfo = (RPTINFO)valueof_obj(f_rptinfos, fullpath);
1435 if (!rptinfo) {
1436 STRING filename=0;
1437 ZSTR zstr=0;
1438
1439 rptinfo = create_rptinfo();
1440 rptinfo->fullpath = strsave(fullpath);
1441 rptinfo->functab = create_table_vptr(); /* PNODES owned elsewhere */
1442 rptinfo->proctab = create_table_vptr(); /* PNODES owned elsewhere */
1443 rptinfo->codeset = strsave(report_codeset_in);
1444
1445 /* calculate localpath & localepath for report gettext */
1446 filename = lastpathname(fullpath);
1447 zstr = zs_newsubs(fullpath, strlen(fullpath)-strlen(filename)-1);
1448 rptinfo->localpath = zstr;
1449 filename = concat_path_alloc(zs_str(zstr), "locale");
1450 rptinfo->localepath = zs_news(filename);
1451 strfree(&filename);
1452 rptinfo->textdomain = zs_news("llreports"); /* for now, fixed textdomain */
1453
1454 insert_table_obj(f_rptinfos, fullpath, rptinfo);
1455 --rptinfo->refcnt; /* release our reference on rptinfo */
1456 ASSERT(rptinfo->refcnt>0);
1457 }
1458 return rptinfo;
1459 }
1460 /*==========================================================
1461 * clear_rptinfos -- Delete all allocated rptinfos
1462 *========================================================*/
1463 void
clear_rptinfos(void)1464 clear_rptinfos (void)
1465 {
1466 if (f_rptinfos) {
1467 destroy_table(f_rptinfos);
1468 f_rptinfos = 0;
1469 }
1470 }
1471 /*=================================================
1472 * rptinfo_destructor -- destructor for rptinfo
1473 * (destructor entry in vtable)
1474 *===============================================*/
1475 static void
rptinfo_destructor(VTABLE * obj)1476 rptinfo_destructor (VTABLE *obj)
1477 {
1478 RPTINFO rptinfo = (RPTINFO)obj;
1479 ASSERT(rptinfo->vtable == &vtable_for_rptinfo);
1480
1481 destroy_table(rptinfo->proctab); /* values are vptr PNODES */
1482 destroy_table(rptinfo->functab); /* values are vptr PNODES */
1483 strfree(&rptinfo->fullpath);
1484 strfree(&rptinfo->codeset);
1485 zs_free(&rptinfo->localpath);
1486 zs_free(&rptinfo->localepath);
1487 zs_free(&rptinfo->textdomain);
1488 stdfree(rptinfo);
1489 }
1490