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