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