1
2 /**
3 * @file funcDef.c
4 *
5 * This module implements the DEFINE text function.
6 *
7 * @addtogroup autogen
8 * @{
9 */
10 /*
11 * This file is part of AutoGen.
12 * AutoGen Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
13 *
14 * AutoGen is free software: you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * AutoGen is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 * See the GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28 typedef int (tCmpProc)(const void *, const void *);
29
30 typedef struct def_list def_list_t;
31 struct def_list {
32 def_ent_t de;
33 char * pzExpr;
34 };
35
36 /*
37 * Procedure local forwards
38 */
39 MOD_LOCAL int
40 order_def_list(const void * p1, const void * p2);
41 MOD_LOCAL def_list_t *
42 link_twins(def_list_t * pDL, def_list_t * pNext, int * pCt);
43 MOD_LOCAL uint_t
44 count_named_values(templ_t * pT, macro_t * mac);
45 MOD_LOCAL char *
46 gather_assigned_value(char * pzScan, def_list_t * pDL);
47 MOD_LOCAL void
48 fill_in_values(def_list_t * pDL, char * pzScan, templ_t * pT, macro_t * mac);
49 MOD_LOCAL void
50 build_defs(int def_ct, def_list_t * def_list);
51 MOD_LOCAL void
52 prep_invoke_args(macro_t * mac);
53
54 /**
55 * comparison function for reordering a definitions list.
56 */
57 MOD_LOCAL int
order_def_list(const void * p1,const void * p2)58 order_def_list(const void * p1, const void * p2)
59 {
60 def_ent_t * pDL1 = (def_ent_t *)p1;
61 def_ent_t * pDL2 = (def_ent_t *)p2;
62 int cmp = streqvcmp(pDL1->de_name, pDL2->de_name);
63
64 /*
65 * IF the names are the same, then we order them based on which name
66 * appears first. Do not reorder entries with the same name.
67 */
68 if (cmp == 0)
69 cmp = (int)(pDL1->de_name - pDL2->de_name);
70 return cmp;
71 }
72
73 MOD_LOCAL def_list_t *
link_twins(def_list_t * pDL,def_list_t * pNext,int * pCt)74 link_twins(def_list_t * pDL, def_list_t * pNext, int * pCt)
75 {
76 def_list_t * pN;
77 int ct = *pCt;
78 int idx = 1;
79
80 pDL->de.de_twin = &(pNext->de);
81 pNext->de.de_ptwin = &(pDL->de);
82
83 for (;;) {
84 pNext->de.de_index = idx++;
85 pN = pNext + 1; /* We return this, valid or not */
86 if (--ct <= 0) /* count each successive twin */
87 break;
88 if (streqvcmp(pNext->de.de_name, pN->de.de_name) != 0)
89 break;
90
91 /*
92 * We have found another twin. Link it in and advance
93 */
94 pNext->de.de_twin = &(pN->de);
95 pN->de.de_ptwin = &(pNext->de);
96 pNext = pN;
97 }
98
99 pDL->de.de_etwin = &(pNext->de);
100 pNext->de.de_twin = NULL; /* NULL terminated list */
101 pDL->de.de_ptwin = NULL; /* NULL terminated list */
102 *pCt = ct;
103 pDL->de.de_next = NULL; /* in case ct == 0 */
104 return pN; /* If ct is zero, then this is invalid */
105 }
106
107 MOD_LOCAL uint_t
count_named_values(templ_t * pT,macro_t * mac)108 count_named_values(templ_t * pT, macro_t * mac)
109 {
110 char * pzScan = pT->td_text + mac->md_txt_off;
111 uint_t ct = 0;
112
113 while (*pzScan != NUL) {
114 ct++;
115 if (! IS_VAR_FIRST_CHAR(*pzScan)) {
116 fprintf(stderr, NAMED_VALUES_WHERE, ct, pzScan);
117 AG_ABEND_IN(pT, mac, NAMED_VALUES_NO_NAME);
118 }
119
120 pzScan = SPN_VALUE_NAME_CHARS(pzScan);
121 pzScan = SPN_WHITESPACE_CHARS(pzScan);
122 if (*pzScan != '=')
123 continue;
124 pzScan = SPN_WHITESPACE_CHARS(pzScan+1);
125 pzScan = (char *)skip_expr(pzScan, strlen(pzScan));
126 pzScan = SPN_WHITESPACE_CHARS(pzScan);
127 }
128
129 return ct;
130 }
131
132
133 MOD_LOCAL char *
gather_assigned_value(char * pzScan,def_list_t * pDL)134 gather_assigned_value(char * pzScan, def_list_t * pDL)
135 {
136 pzScan = SPN_WHITESPACE_CHARS(pzScan);
137 strtransform(pDL->de.de_name, pDL->de.de_name);
138 pDL->pzExpr = pzScan;
139 pDL->de.de_type = VALTYP_TEXT;
140 pzScan = (char *)skip_expr(pzScan, strlen(pzScan));
141
142 /*
143 * Figure out what kind of expression we have
144 */
145 switch (*pDL->pzExpr) {
146 case ';':
147 case '(':
148 /*
149 * These expressions will need evaluation
150 */
151 break;
152
153 case '`':
154 {
155 char * pz;
156 /*
157 * Process the quoted string, but leave a '`' marker, too
158 */
159 AGDUPSTR(pz, pDL->pzExpr, "macro arg expr");
160 span_quote(pz);
161 strcpy(pDL->pzExpr+1, pz);
162 AGFREE(pz);
163 break;
164 }
165 case '"':
166 case '\'':
167 /*
168 * Process the quoted strings now
169 */
170 if ((pzScan - pDL->pzExpr) < 24) {
171 char * pz = (char *)AGALOC(24, "quoted string");
172 memcpy(VOIDP(pz), pDL->pzExpr, (size_t)(pzScan - pDL->pzExpr));
173 pDL->pzExpr = pz;
174 }
175 span_quote(pDL->pzExpr);
176 /* FALLTHROUGH */
177
178 default:
179 /*
180 * Default: the raw sequence of characters is the value
181 */
182 pDL->de.de_val.dvu_text = pDL->pzExpr;
183 pDL->pzExpr = NULL;
184 }
185
186 return pzScan;
187 }
188
189 MOD_LOCAL void
fill_in_values(def_list_t * pDL,char * pzScan,templ_t * pT,macro_t * mac)190 fill_in_values(def_list_t * pDL, char * pzScan, templ_t * pT, macro_t * mac)
191 {
192 for (;; pDL++ ) {
193 pDL->de.de_name = pzScan;
194 pzScan = SPN_VALUE_NAME_CHARS(pzScan);
195
196 switch (*pzScan) {
197 case NUL:
198 pDL->de.de_val.dvu_text = (char *)zNil;
199 return;
200
201 default:
202 AG_ABEND_IN(pT, mac, FILL_IN_VAL_NO_ASSIGN);
203
204 case ' ': case TAB: case NL: case '\f':
205 *(pzScan++) = NUL;
206 pzScan = SPN_WHITESPACE_CHARS(pzScan);
207
208 /*
209 * The name was separated by space, but has no value
210 */
211 if (*pzScan != '=') {
212 pDL->de.de_val.dvu_text = (char *)zNil;
213 if (*pzScan == NUL)
214 return;
215 continue;
216 }
217 /* FALLTHROUGH */
218
219 case '=':
220 *(pzScan++) = NUL;
221 }
222
223 /*
224 * When we arrive here, we have just clobbered a '=' char.
225 * Now we have gather up the assigned value.
226 */
227 pzScan = gather_assigned_value(pzScan, pDL);
228
229 /*
230 * IF the next char is NUL, we are done.
231 * OTHERWISE, the next character must be a space
232 */
233 if (*pzScan == NUL)
234 break;
235
236 if (! IS_WHITESPACE_CHAR(*pzScan))
237 AG_ABEND_IN(pT, mac, FILL_IN_VAL_NO_SEP);
238
239 /*
240 * Terminate the string value and skip over any additional space
241 */
242 *(pzScan++) = NUL;
243 pzScan = SPN_WHITESPACE_CHARS(pzScan);
244 }
245 }
246
247 /**
248 * parse_mac_args
249 *
250 * This routine is called just before the first call to mFunc_Define
251 * for a particular macro invocation. It scans the text of the invocation
252 * for name-value assignments that are only to live for the duration
253 * of the processing of the user defined macro.
254 */
255 static void
parse_mac_args(templ_t * pT,macro_t * mac)256 parse_mac_args(templ_t * pT, macro_t * mac)
257 {
258 char * pzScan = pT->td_text + mac->md_txt_off;
259 uint_t ct;
260 def_list_t * pDL;
261 def_list_t * pN;
262
263 /*
264 * If there is no argument text, then the arg count is zero.
265 */
266 if (mac->md_txt_off == 0) {
267 mac->md_res = 0;
268 return;
269 }
270
271 ct = count_named_values(pT, mac);
272
273 /*
274 * The result is zero if we don't have any
275 */
276 mac->md_sib_idx = (int)ct;
277 if (ct == 0) {
278 mac->md_txt_off = 0;
279 mac->md_res = 0;
280 return;
281 }
282
283 /*
284 * Allocate the array of definition descriptors
285 */
286 pzScan = pT->td_text + mac->md_txt_off;
287 pDL = (def_list_t *)AGALOC(ct * sizeof(def_list_t), "array of def desc");
288 memset(VOIDP(pDL), 0, ct * sizeof(def_list_t));
289 mac->md_res = (uintptr_t)pDL;
290
291 /*
292 * Fill in the array of value assignments
293 */
294 fill_in_values(pDL, pzScan, pT, mac);
295
296 if (ct > 1) {
297 /*
298 * There was more than one value assignment.
299 * Sort them just so we know the siblings are together.
300 * Order is preserved by comparing string addresses,
301 * if the strings compare equal.
302 */
303 pDL = (def_list_t *)mac->md_res;
304 qsort(VOIDP(pDL), (size_t)ct, sizeof(def_list_t), order_def_list);
305
306 /*
307 * Now, link them all together. Singly linked list.
308 */
309 for (;;) {
310 if (--ct == 0) {
311 pDL->de.de_next = NULL;
312 break;
313 }
314
315 pN = pDL + 1;
316
317 /*
318 * IF the next entry has the same name,
319 * THEN it is a "twin". Link twins on the twin list.
320 */
321 if (streqvcmp(pDL->de.de_name, pN->de.de_name) == 0) {
322 pN = link_twins(pDL, pN, (int *)&ct);
323 if (ct <= 0)
324 break; /* pN is now invalid */
325 }
326
327 pDL->de.de_next = &(pN->de);
328 pDL = pN;
329 }
330 }
331 }
332
333 /**
334 * prepare the args for INVOKE macro.
335 * See if there's any text following the name of the DEFINE macro to invoke.
336 * If there is, then set up the arguments now so it's easy to deal with
337 * next time around. The name of the macro to invoke may be dynamic.
338 * "skip_expr" skips over either a name or a scheme expression that
339 * is supposed to yield a name.
340 *
341 * @param mac the macro structure describing the invocation
342 */
343 MOD_LOCAL void
prep_invoke_args(macro_t * mac)344 prep_invoke_args(macro_t * mac)
345 {
346 char * pzText;
347 templ_t * pT = current_tpl;
348
349 if (mac->md_txt_off == 0)
350 AG_ABEND_IN(pT, mac, PREP_INVOKE_NO_NAME);
351 mac->md_name_off = mac->md_txt_off;
352 pzText = pT->td_text + mac->md_txt_off;
353 pzText = (char *)skip_expr(pzText, strlen(pzText));
354
355 /*
356 * IF there is no more text,
357 * THEN there are no arguments
358 */
359 if (*pzText == NUL) {
360 mac->md_txt_off = 0;
361 mac->md_res = 0;
362 }
363
364 /*
365 * OTHERWISE, skip to the start of the text and process
366 * the arguments to the macro
367 */
368 else {
369 if (! IS_WHITESPACE_CHAR(*pzText))
370 AG_ABEND_IN(pT, mac, PREP_INVOKE_NO_SEP);
371 *pzText = NUL;
372 pzText = SPN_WHITESPACE_CHARS(pzText + 1);
373 mac->md_txt_off = (uintptr_t)(pzText - pT->td_text);
374 parse_mac_args(pT, mac);
375 current_tpl = pT;
376 }
377 }
378
379 /*=macfunc DEBUG
380 *
381 * handler-proc:
382 * load-proc:
383 *
384 * what: Print debug message to trace output
385 * desc:
386 *
387 * If the tracing level is at "debug-message" or above
388 * (@pxref{autogen trace}), this macro prints a debug message to trace
389 * output. This message is not evaluated. This macro can also be used to
390 * set useful debugger breakpoints. By inserting [+DEBUG n+] into your
391 * template, you can set a debugger breakpoint on the #n case element
392 * below (in the AutoGen source) and step through the processing of
393 * interesting parts of your template.
394 *
395 * To be useful, you have to have access to the source tree where autogen
396 * was built and the template being processed. The definitions are also
397 * helpful, but not crucial. Please contact the author if you think you
398 * might actually want to use this.
399 =*/
400 macro_t *
mFunc_Debug(templ_t * pT,macro_t * mac)401 mFunc_Debug(templ_t * pT, macro_t * mac)
402 {
403 static int dummy = 0;
404 char const * pz = pT->td_text + mac->md_txt_off;
405 int for_index = (curr_ivk_info->ii_for_depth <= 0)
406 ? -1
407 : curr_ivk_info->ii_for_data[ curr_ivk_info->ii_for_depth-1].for_index;
408
409 fprintf(trace_fp, FN_DEBUG, pz, for_index);
410
411 /*
412 * The case element values were chosen to thwart most
413 * optimizers that might be too bright for its own good.
414 * (`dummy' is write-only and could be ignored)
415 */
416 do {
417 if (IS_DEC_DIGIT_CHAR(*pz)) {
418 for_index = atoi(pz);
419 break;
420 }
421 } while (*(pz++) != NUL);
422
423 if (for_index < 0)
424 for_index = -1;
425
426 switch (for_index) {
427 case -1: dummy = 'X'; break;
428 case 0: dummy = 'A'; break;
429 case 1: dummy = 'u'; break;
430 case 2: dummy = 't'; break;
431 case 3: dummy = 'o'; break;
432 case 4: dummy = 'G'; break;
433 case 5: dummy = 'e'; break;
434 case 6: dummy = 'n'; break;
435 case 7: dummy = 'N'; break;
436 case 8: dummy = 'U'; break;
437 case 9: dummy = 'T'; break;
438 case 10: dummy = '.'; break;
439 default: dummy++;
440 }
441 if (IS_GRAPHIC_CHAR(dummy))
442 fprintf(trace_fp, FN_DEBUG_GRAPHIC, dummy);
443 putc(NL, trace_fp);
444 return mac+1;
445 }
446
447 /**
448 * Build up a definition context.
449 * It is created by passed-in macro arguments.
450 *
451 * @param def_ct number of definitions
452 * @param def_list list of definitions
453 */
454 MOD_LOCAL void
build_defs(int def_ct,def_list_t * def_list)455 build_defs(int def_ct, def_list_t * def_list)
456 {
457 curr_def_ctx.dcx_defent = &(def_list->de);
458
459 /*
460 * FOR each definition, evaluate the associated expression
461 * and set the text value to it.
462 */
463 do {
464 if (def_list->pzExpr == NULL)
465 continue;
466
467 retryExpression:
468 switch (*(def_list->pzExpr)) {
469 case ';':
470 {
471 char * pz = strchr(def_list->pzExpr, NL);
472 if (pz != NULL) {
473 pz = SPN_WHITESPACE_CHARS(pz + 1);
474 def_list->pzExpr = pz;
475 goto retryExpression;
476 }
477 /* FALLTHROUGH */
478 }
479 case NUL:
480 def_list->pzExpr = NULL;
481 def_list->de.de_val.dvu_text = (char *)zNil;
482 break;
483
484 case '(':
485 {
486 SCM res;
487
488 /*
489 * It is a scheme expression. Accept only string
490 * and number results.
491 */
492 if (OPT_VALUE_TRACE >= TRACE_EXPRESSIONS) {
493 fprintf(trace_fp, TRACE_BUILD_DEFS,
494 cur_macro->md_sib_idx - def_ct, def_list->pzExpr);
495 }
496
497 res = ag_eval(def_list->pzExpr);
498 if (scm_is_string(res)) {
499 AGDUPSTR(def_list->de.de_val.dvu_text,
500 ag_scm2zchars(res, "res"), "ev res");
501 }
502 else if (scm_is_number(res)) {
503 def_list->de.de_val.dvu_text = AGALOC(16, "num buf");
504 snprintf(def_list->de.de_val.dvu_text, (size_t)16,
505 ULONG_FMT, AG_SCM_TO_ULONG(res));
506 }
507 else
508 AGDUPSTR(def_list->de.de_val.dvu_text, zNil, "nil str");
509 break;
510 }
511
512 case '`':
513 if (OPT_VALUE_TRACE >= TRACE_EXPRESSIONS) {
514 fprintf(trace_fp, TRACE_BUILD_DEFS,
515 cur_macro->md_sib_idx - def_ct, def_list->pzExpr+1);
516 }
517 def_list->de.de_val.dvu_text = shell_cmd(def_list->pzExpr+1);
518 break;
519 }
520 } while (def_list++, --def_ct > 0);
521 }
522
523 /*=macfunc DEFINE
524 *
525 * what: Define a user AutoGen macro
526 * cindex: define macro
527 * handler_proc:
528 * load_proc:
529 * unload-proc:
530 *
531 * desc:
532 *
533 * This function will define a new macro. You must provide a name for the
534 * macro. You do not specify any arguments, though the invocation may
535 * specify a set of name/value pairs that are to be active during the
536 * processing of the macro.
537 *
538 * @example
539 * [+ define foo +]
540 * ... macro body with macro functions ...
541 * [+ enddef +]
542 * ... [+ foo bar='raw text' baz=<<text expression>> +]
543 * @end example
544 *
545 * Once the macro has been defined, this new macro can be invoked by
546 * specifying the macro name as the first token after the start macro marker.
547 * Alternatively, you may make the invocation explicitly invoke a defined
548 * macro by specifying @code{INVOKE} (@pxref{INVOKE}) in the macro
549 * invocation. If you do that, the macro name can be computed with an
550 * expression that gets evaluated every time the INVOKE macro is encountered.
551 *
552 * Any remaining text in the macro invocation will be used to create new
553 * name/value pairs that only persist for the duration of the processing of
554 * the macro. The expressions are evaluated the same way basic
555 * expressions are evaluated. @xref{expression syntax}.
556 *
557 * The resulting definitions are handled much like regular
558 * definitions, except:
559 *
560 * @enumerate
561 * @item
562 * The values may not be compound. That is, they may not contain
563 * nested name/value pairs.
564 * @item
565 * The bindings go away when the macro is complete.
566 * @item
567 * The name/value pairs are separated by whitespace instead of
568 * semi-colons.
569 * @item
570 * Sequences of strings are not concatenated.
571 * @end enumerate
572 *
573 * @quotation
574 * @strong{NB:} The macro is extracted from the template as the template is
575 * scanned. You cannot conditionally define a macro by enclosing it in an
576 * @code{IF}/@code{ENDIF} (@pxref{IF}) macro pair. If you need to dynamically
577 * select the format of a @code{DEFINE}d macro, then put the flavors into
578 * separate template files that simply define macros. @code{INCLUDE}
579 * (@pxref{INCLUDE}) the appropriate template when you have computed which
580 * you need.
581 * @end quotation
582 *
583 * Due to this, it is acceptable and even a good idea to place all the
584 * @code{DEFINE} macros at the end of the template. That puts the main
585 * body of the template at the beginning of the file.
586 =*/
587 /*=macfunc ENDDEF
588 *
589 * what: Ends a macro definition.
590 * in-context:
591 *
592 * desc:
593 * This macro ends the @code{DEFINE} function template block.
594 * For a complete description @xref{DEFINE}.
595 =*/
596 /**
597 * This routine runs the invocation of a defined macro.
598 *
599 * @param tpl not used
600 * @param[in] mac the macro that holds the data for the defined macro
601 */
602 macro_t *
mFunc_Define(templ_t * tpl,macro_t * mac)603 mFunc_Define(templ_t * tpl, macro_t * mac)
604 {
605 def_list_t * pList = (def_list_t *)mac->md_res;
606 int defCt = mac->md_sib_idx;
607 def_ctx_t ctx;
608
609 if (OPT_VALUE_TRACE > TRACE_NOTHING) {
610 tpl = (templ_t *)mac->md_pvt;
611
612 fprintf(trace_fp, TPL_INVOKED, tpl->td_name, defCt);
613 if (OPT_VALUE_TRACE == TRACE_EVERYTHING)
614 fprintf(trace_fp, TAB_FILE_LINE_FMT,
615 current_tpl->td_file, mac->md_line);
616 }
617
618 /*
619 * IF we have no special definitions, then do not nest definitions
620 */
621 if (defCt != 0) {
622 ctx = curr_def_ctx;
623 curr_def_ctx.dcx_prev = &ctx;
624 build_defs(defCt, pList);
625 }
626
627 gen_new_block((templ_t *)mac->md_pvt);
628
629 if (defCt != 0)
630 curr_def_ctx = ctx;
631
632 if ((defCt = mac->md_sib_idx) > 0) {
633 pList = (def_list_t *)mac->md_res;
634 while (defCt-- > 0) {
635 if (pList->pzExpr != NULL) {
636 AGFREE(pList->de.de_val.dvu_text);
637 pList->de.de_val.dvu_text = NULL;
638 }
639 pList++;
640 }
641 }
642
643 return mac+1;
644 }
645
646 /**
647 * unload a defined macro
648 *
649 * @param[in,out] mac macro containing the data to unload
650 */
651 void
mUnload_Define(macro_t * mac)652 mUnload_Define(macro_t * mac)
653 {
654 void * p = VOIDP(mac->md_res);
655 if (p != NULL)
656 AGFREE(p);
657 }
658
659 /*=macfunc INVOKE
660 *
661 * handler_proc:
662 * what: Invoke a User Defined Macro
663 *
664 * desc:
665 *
666 * User defined macros may be invoked explicitly or implicitly.
667 * If you invoke one implicitly, the macro must begin with the
668 * name of the defined macro. Consequently, this may @strong{not}
669 * be a computed value. If you explicitly invoke a user defined macro,
670 * the macro begins with the macro name @code{INVOKE} followed by
671 * a @i{basic expression} that must yield a known user defined macro.
672 * A macro name _must_ be found, or AutoGen will issue a diagnostic
673 * and exit.
674 *
675 * Arguments are passed to the invoked macro by name.
676 * The text following the macro name must consist of a series of
677 * names each of which is followed by an equal sign (@code{=}) and
678 * a @i{basic expression} that yields a string.
679 *
680 * The string values may contain template macros that are parsed
681 * the first time the macro is processed and evaluated again every
682 * time the macro is evaluated.
683 =*/
684 macro_t *
mFunc_Invoke(templ_t * tpl,macro_t * mac)685 mFunc_Invoke(templ_t * tpl, macro_t * mac)
686 {
687 /*
688 * IF this is the first time through,
689 * THEN separate the name from the rest of the arguments.
690 */
691 if (mac->md_name_off == 0) {
692 prep_invoke_args(mac);
693
694 /*
695 * IF the name is constant and not an expression,
696 * THEN go find the template now and bind the macro call
697 * to a particular template macro
698 */
699 if (IS_VAR_FIRST_CHAR(tpl->td_text[ mac->md_name_off ])) {
700 mac->md_code = FTYP_DEFINE;
701 mac->md_pvt = VOIDP(find_tpl(tpl->td_text + mac->md_name_off));
702
703 if (mac->md_pvt == NULL) {
704 char const * p = tpl->td_text + mac->md_name_off;
705 AG_ABEND_IN(tpl, mac, aprf(BAD_MAC_NM_FMT, p));
706 /* NOTREACHED */
707 }
708
709 return mFunc_Define(tpl, mac);
710 }
711 }
712
713 /*
714 * Call `eval' to determine the macro name. Every invocation
715 * may be different!!
716 */
717 {
718 SCM macName = eval(tpl->td_text + mac->md_name_off);
719 char * pz = ag_scm2zchars(macName, "mac name");
720 templ_t * ntpl = find_tpl(pz);
721 if (ntpl == NULL) {
722 pz = aprf(BAD_MAC_NM_FMT, pz);
723 AG_ABEND_IN(tpl, mac, pz);
724 /* NOTREACHED */
725 }
726
727 mac->md_pvt = VOIDP(ntpl);
728 }
729 return mFunc_Define(tpl, mac);
730 }
731
732 /**
733 * Loads the debug function for load time breakpoints.
734 * @param pT containing template
735 * @param pMac the debug macro data
736 * @param ppzSan pointer to scanning pointer
737 * @returns the next open macro slot
738 */
739 macro_t *
mLoad_Debug(templ_t * pT,macro_t * pMac,char const ** ppzScan)740 mLoad_Debug(templ_t * pT, macro_t * pMac, char const ** ppzScan)
741 {
742 if (OPT_VALUE_TRACE >= TRACE_DEBUG_MESSAGE)
743 return mLoad_Unknown(pT, pMac, ppzScan);
744 return mLoad_Comment(pT, pMac, ppzScan);
745 }
746
747 static templ_t *
new_template(templ_t * base_tpl,macro_t * mac,char const * scan)748 new_template(templ_t * base_tpl, macro_t * mac, char const * scan)
749 {
750 templ_t * ntpl;
751 char * copy;
752 char const * src = (char const *)mac->md_txt_off;
753 int ct = (int)(base_tpl->td_mac_ct - (mac - base_tpl->td_macros));
754 size_t aloc_sz = sizeof(*ntpl)
755 + ((uint32_t)ct * sizeof(macro_t)) + strlen(scan) + 0x100;
756 aloc_sz &= (size_t)~0x0F;
757
758 /*
759 * Allocate a new template block that is much larger than needed.
760 */
761 ntpl = (templ_t *)AGALOC(aloc_sz, "new tpl");
762 memset(VOIDP(ntpl), 0, aloc_sz);
763 ntpl->td_magic = base_tpl->td_magic;
764 ntpl->td_size = aloc_sz;
765 ntpl->td_mac_ct = ct;
766 ntpl->td_file = strdup(base_tpl->td_file);
767
768 copy = ntpl->td_name = VOIDP(ntpl->td_macros + ct);
769 if (! IS_VAR_FIRST_CHAR(*src))
770 AG_ABEND_IN(base_tpl, mac, LD_DEF_NEED_NAME);
771
772 while (IS_VALUE_NAME_CHAR(*src))
773 *(copy++) = *(src++);
774
775 *(copy++) = NUL;
776
777 if (OPT_VALUE_TRACE >= TRACE_BLOCK_MACROS)
778 fprintf(trace_fp, TRACE_MACRO_DEF, ntpl->td_name, ntpl->td_file);
779
780 ntpl->td_text = copy;
781 ntpl->td_scan = copy+1;
782 strcpy(ntpl->td_start_mac, base_tpl->td_start_mac);
783 strcpy(ntpl->td_end_mac, base_tpl->td_end_mac);
784 current_tpl = ntpl;
785
786 return ntpl;
787 }
788
789 static void
load_define_tpl(templ_t * tpl,char const ** ppzScan)790 load_define_tpl(templ_t * tpl, char const ** ppzScan)
791 {
792 macro_t * last_mac = parse_tpl(tpl->td_macros, ppzScan);
793 int ct;
794
795 /*
796 * Make sure all of the input string was *NOT* scanned.
797 */
798 if (*ppzScan == NULL)
799 AG_ABEND_IN(tpl, tpl->td_macros, LD_DEF_WOOPS);
800
801 ct = (int)(last_mac - tpl->td_macros);
802
803 /*
804 * IF there are empty macro slots,
805 * THEN pack the text
806 */
807 if (ct < tpl->td_mac_ct) {
808 int delta = (int)sizeof(macro_t) * (int)(tpl->td_mac_ct - ct);
809 void * data = (tpl->td_name == NULL) ? tpl->td_text : tpl->td_name;
810 size_t size = (size_t)(tpl->td_scan - (char *)data);
811 memmove(VOIDP(last_mac), data, size);
812
813 tpl->td_text -= delta;
814 tpl->td_scan -= delta;
815 tpl->td_name -= delta;
816 tpl->td_mac_ct = ct;
817 }
818 }
819
820 macro_t *
mLoad_Define(templ_t * ori_tpl,macro_t * mac,char const ** p_scan)821 mLoad_Define(templ_t * ori_tpl, macro_t * mac, char const ** p_scan)
822 {
823 static load_proc_p_t apDefineLoad[ FUNC_CT ] = { NULL };
824
825 templ_t * new_tpl;
826
827 /**
828 * Save the global macro loading mode
829 */
830 load_proc_p_t const * save_load_procs = load_proc_table;
831
832 if (mac->md_txt_off == 0)
833 AG_ABEND_IN(ori_tpl, mac, LD_DEF_NEED_NAME);
834
835 /*
836 * IF this is the first time here, THEN set up the "DEFINE" block
837 * callout table. It is the standard table, except entries are
838 * inserted for functions that are enabled only while processing
839 * a DEFINE block (viz. "ENDDEF" and removing "DEFINE").
840 */
841 if (apDefineLoad[0] == NULL) {
842 memcpy(VOIDP(apDefineLoad), base_load_table, sizeof(base_load_table));
843 apDefineLoad[ FTYP_ENDDEF ] = &mLoad_Ending;
844 apDefineLoad[ FTYP_DEFINE ] = &mLoad_Bogus;
845 }
846
847 load_proc_table = apDefineLoad;
848 defining_macro = true;
849 new_tpl = new_template(ori_tpl, mac, *p_scan);
850 load_define_tpl(new_tpl, p_scan);
851 defining_macro = false;
852
853 /*
854 * Adjust the sizes. Remove absolute pointers. Reallocate to the correct
855 * size. Restore the offsets to pointer values.
856 */
857 {
858 size_t sz = (size_t)(new_tpl->td_scan - (char *)new_tpl);
859 if (sz < new_tpl->td_size) {
860 new_tpl->td_size = sz;
861 new_tpl->td_name -= (long)new_tpl;
862 new_tpl->td_text -= (long)new_tpl;
863 new_tpl = AGREALOC(VOIDP(new_tpl), new_tpl->td_size, "resize mac");
864 new_tpl->td_name += (long)new_tpl;
865 new_tpl->td_text += (long)new_tpl;
866 }
867 }
868
869 #if defined(DEBUG_ENABLED)
870 if (HAVE_OPT(SHOW_DEFS)) {
871 static char const zSum[] = "loaded %d macros from %s\n"
872 "\tBinary template size: 0x%X\n\n";
873 fprintf(trace_fp, zSum, new_tpl->td_mac_ct, new_tpl->td_file,
874 (unsigned int)new_tpl->td_size);
875 }
876 #endif
877
878 new_tpl->td_scan = (char *)named_tpls;
879 named_tpls = new_tpl;
880 load_proc_table = save_load_procs;
881 memset(VOIDP(mac), 0, sizeof(*mac));
882 current_tpl = ori_tpl;
883 return mac;
884 }
885 /**
886 * @}
887 *
888 * Local Variables:
889 * mode: C
890 * c-file-style: "stroustrup"
891 * indent-tabs-mode: nil
892 * End:
893 * end of agen5/funcDef.c */
894