1 /* macro.c -- user-defined macros for Texinfo.
2 $Id: macro.c,v 1.1.1.3 2006/07/17 16:03:47 espie Exp $
3
4 Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20 #include "system.h"
21 #include "cmds.h"
22 #include "files.h"
23 #include "macro.h"
24 #include "makeinfo.h"
25 #include "insertion.h"
26
27 /* If non-NULL, this is an output stream to write the full macro expansion
28 of the input text to. The result is another texinfo file, but
29 missing @include, @infoinclude, @macro, and macro invocations. Instead,
30 all of the text is placed within the file. */
31 FILE *macro_expansion_output_stream = NULL;
32
33 /* Output file for -E. */
34 char *macro_expansion_filename;
35
36 /* Nonzero means a macro string is in execution, as opposed to a file. */
37 int me_executing_string = 0;
38
39 /* Nonzero means we want only to expand macros and
40 leave everything else intact. */
41 int only_macro_expansion = 0;
42
43 static ITEXT **itext_info = NULL;
44 static int itext_size = 0;
45
46 /* Return the arglist on the current line. This can behave in two different
47 ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */
48 int braces_required_for_macro_args = 0;
49
50 /* Array of macros and definitions. */
51 MACRO_DEF **macro_list = NULL;
52
53 int macro_list_len = 0; /* Number of elements. */
54 int macro_list_size = 0; /* Number of slots in total. */
55
56 /* Return the length of the array in ARRAY. */
57 int
array_len(char ** array)58 array_len (char **array)
59 {
60 int i = 0;
61
62 if (array)
63 for (i = 0; array[i]; i++);
64
65 return i;
66 }
67
68 void
free_array(char ** array)69 free_array (char **array)
70 {
71 if (array)
72 {
73 int i;
74 for (i = 0; array[i]; i++)
75 free (array[i]);
76
77 free (array);
78 }
79 }
80
81 /* Return the macro definition of NAME or NULL if NAME is not defined. */
82 MACRO_DEF *
find_macro(char * name)83 find_macro (char *name)
84 {
85 int i;
86 MACRO_DEF *def;
87
88 def = NULL;
89 for (i = 0; macro_list && (def = macro_list[i]); i++)
90 {
91 if ((!def->inhibited) && (strcmp (def->name, name) == 0))
92 break;
93 }
94 return def;
95 }
96
97 /* Add the macro NAME with ARGLIST and BODY to the list of defined macros.
98 SOURCE_FILE is the name of the file where this definition can be found,
99 and SOURCE_LINENO is the line number within that file. If a macro already
100 exists with NAME, then a warning is produced, and that previous
101 definition is overwritten. */
102 static void
add_macro(char * name,char ** arglist,char * body,char * source_file,int source_lineno,int flags)103 add_macro (char *name, char **arglist, char *body, char *source_file,
104 int source_lineno, int flags)
105 {
106 MACRO_DEF *def;
107
108 def = find_macro (name);
109
110 if (!def)
111 {
112 if (macro_list_len + 2 >= macro_list_size)
113 macro_list = xrealloc
114 (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
115
116 macro_list[macro_list_len] = xmalloc (sizeof (MACRO_DEF));
117 macro_list[macro_list_len + 1] = NULL;
118
119 def = macro_list[macro_list_len];
120 macro_list_len += 1;
121 def->name = name;
122 }
123 else
124 {
125 char *temp_filename = input_filename;
126 int temp_line = line_number;
127
128 warning (_("macro `%s' previously defined"), name);
129
130 input_filename = def->source_file;
131 line_number = def->source_lineno;
132 warning (_("here is the previous definition of `%s'"), name);
133
134 input_filename = temp_filename;
135 line_number = temp_line;
136
137 if (def->arglist)
138 {
139 int i;
140
141 for (i = 0; def->arglist[i]; i++)
142 free (def->arglist[i]);
143
144 free (def->arglist);
145 }
146 free (def->source_file);
147 free (def->body);
148 }
149
150 def->source_file = xstrdup (source_file);
151 def->source_lineno = source_lineno;
152 def->body = body;
153 def->arglist = arglist;
154 def->inhibited = 0;
155 def->flags = flags;
156 }
157
158
159 char **
get_brace_args(int quote_single)160 get_brace_args (int quote_single)
161 {
162 char **arglist, *word;
163 int arglist_index, arglist_size;
164 int character, escape_seen, start;
165 int depth = 1;
166
167 /* There is an arglist in braces here, so gather the args inside of it. */
168 skip_whitespace_and_newlines ();
169 input_text_offset++;
170 arglist = NULL;
171 arglist_index = arglist_size = 0;
172
173 get_arg:
174 skip_whitespace_and_newlines ();
175 start = input_text_offset;
176 escape_seen = 0;
177
178 while ((character = curchar ()))
179 {
180 if (character == '\\')
181 {
182 input_text_offset += 2;
183 escape_seen = 1;
184 }
185 else if (character == '{')
186 {
187 depth++;
188 input_text_offset++;
189 }
190 else if ((character == ',' && !quote_single) ||
191 ((character == '}') && depth == 1))
192 {
193 int len = input_text_offset - start;
194
195 if (len || (character != '}'))
196 {
197 word = xmalloc (1 + len);
198 memcpy (word, input_text + start, len);
199 word[len] = 0;
200
201 /* Clean up escaped characters. */
202 if (escape_seen)
203 {
204 int i;
205 for (i = 0; word[i]; i++)
206 if (word[i] == '\\')
207 memmove (word + i, word + i + 1,
208 1 + strlen (word + i + 1));
209 }
210
211 if (arglist_index + 2 >= arglist_size)
212 arglist = xrealloc
213 (arglist, (arglist_size += 10) * sizeof (char *));
214
215 arglist[arglist_index++] = word;
216 arglist[arglist_index] = NULL;
217 }
218
219 input_text_offset++;
220 if (character == '}')
221 break;
222 else
223 goto get_arg;
224 }
225 else if (character == '}')
226 {
227 depth--;
228 input_text_offset++;
229 }
230 else
231 {
232 input_text_offset++;
233 if (character == '\n') line_number++;
234 }
235 }
236 return arglist;
237 }
238
239 static char **
get_macro_args(MACRO_DEF * def)240 get_macro_args (MACRO_DEF *def)
241 {
242 int i;
243 char *word;
244
245 /* Quickly check to see if this macro has been invoked with any arguments.
246 If not, then don't skip any of the following whitespace. */
247 for (i = input_text_offset; i < input_text_length; i++)
248 if (!cr_or_whitespace (input_text[i]))
249 break;
250
251 if (input_text[i] != '{')
252 {
253 if (braces_required_for_macro_args)
254 {
255 return NULL;
256 }
257 else
258 {
259 /* Braces are not required to fill out the macro arguments. If
260 this macro takes one argument, it is considered to be the
261 remainder of the line, sans whitespace. */
262 if (def->arglist && def->arglist[0] && !def->arglist[1])
263 {
264 char **arglist;
265
266 get_rest_of_line (0, &word);
267 if (input_text[input_text_offset - 1] == '\n')
268 {
269 input_text_offset--;
270 line_number--;
271 }
272 /* canon_white (word); */
273 arglist = xmalloc (2 * sizeof (char *));
274 arglist[0] = word;
275 arglist[1] = NULL;
276 return arglist;
277 }
278 else
279 {
280 /* The macro either took no arguments, or took more than
281 one argument. In that case, it must be invoked with
282 arguments surrounded by braces. */
283 return NULL;
284 }
285 }
286 }
287 return get_brace_args (def->flags & ME_QUOTE_ARG);
288 }
289
290 /* Substitute actual parameters for named parameters in body.
291 The named parameters which appear in BODY must by surrounded
292 reverse slashes, as in \foo\. */
293 static char *
apply(char ** named,char ** actuals,char * body)294 apply (char **named, char **actuals, char *body)
295 {
296 int i;
297 int new_body_index, new_body_size;
298 char *new_body, *text;
299 int length_of_actuals;
300
301 length_of_actuals = array_len (actuals);
302 new_body_size = strlen (body);
303 new_body = xmalloc (1 + new_body_size);
304
305 /* Copy chars from BODY into NEW_BODY. */
306 i = 0;
307 new_body_index = 0;
308
309 while (body[i])
310 { /* Anything but a \ is easy. */
311 if (body[i] != '\\')
312 new_body[new_body_index++] = body[i++];
313 else
314 { /* Snarf parameter name, check against named parameters. */
315 char *param;
316 int param_start, len;
317
318 param_start = ++i;
319 while (body[i] && body[i] != '\\')
320 i++;
321
322 len = i - param_start;
323 param = xmalloc (1 + len);
324 memcpy (param, body + param_start, len);
325 param[len] = 0;
326
327 if (body[i]) /* move past \ */
328 i++;
329
330 if (len == 0)
331 { /* \\ always means \, even if macro has no args. */
332 len++;
333 text = xmalloc (1 + len);
334 sprintf (text, "\\%s", param);
335 }
336 else
337 {
338 int which;
339
340 /* Check against named parameters. */
341 for (which = 0; named && named[which]; which++)
342 if (STREQ (named[which], param))
343 break;
344
345 if (named && named[which])
346 {
347 text = which < length_of_actuals ? actuals[which] : NULL;
348 if (!text)
349 text = "";
350 len = strlen (text);
351 text = xstrdup (text); /* so we can free it */
352 }
353 else
354 { /* not a parameter, so it's an error. */
355 warning (_("\\ in macro expansion followed by `%s' instead of parameter name"),
356 param);
357 len++;
358 text = xmalloc (1 + len);
359 sprintf (text, "\\%s", param);
360 }
361 }
362
363 if (strlen (param) + 2 < len)
364 {
365 new_body_size += len + 1;
366 new_body = xrealloc (new_body, new_body_size);
367 }
368
369 free (param);
370
371 strcpy (new_body + new_body_index, text);
372 new_body_index += len;
373
374 free (text);
375 }
376 }
377
378 new_body[new_body_index] = 0;
379 return new_body;
380 }
381
382 /* Expand macro passed in DEF, a pointer to a MACRO_DEF, and
383 return its expansion as a string. */
384 char *
expand_macro(MACRO_DEF * def)385 expand_macro (MACRO_DEF *def)
386 {
387 char **arglist;
388 int num_args;
389 char *execution_string = NULL;
390 int start_line = line_number;
391
392 /* Find out how many arguments this macro definition takes. */
393 num_args = array_len (def->arglist);
394
395 /* Gather the arguments present on the line if there are any. */
396 arglist = get_macro_args (def);
397
398 if (num_args < array_len (arglist))
399 {
400 free_array (arglist);
401 line_error (_("Macro `%s' called on line %d with too many args"),
402 def->name, start_line);
403 return execution_string;
404 }
405
406 if (def->body)
407 execution_string = apply (def->arglist, arglist, def->body);
408
409 free_array (arglist);
410 return execution_string;
411 }
412
413 /* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */
414 void
execute_macro(MACRO_DEF * def)415 execute_macro (MACRO_DEF *def)
416 {
417 char *execution_string;
418 int start_line = line_number, end_line;
419
420 if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
421 me_append_before_this_command ();
422
423 execution_string = expand_macro (def);
424 if (!execution_string)
425 return;
426
427 if (def->body)
428 {
429 /* Reset the line number to where the macro arguments began.
430 This makes line numbers reported in error messages correct in
431 case the macro arguments span several lines and the expanded
432 arguments invoke other commands. */
433 end_line = line_number;
434 line_number = start_line;
435
436 if (macro_expansion_output_stream
437 && !executing_string && !me_inhibit_expansion)
438 {
439 remember_itext (input_text, input_text_offset);
440 me_execute_string (execution_string);
441 }
442 else
443 execute_string ("%s", execution_string);
444
445 free (execution_string);
446 line_number = end_line;
447 }
448 }
449
450
451 /* Read and remember the definition of a macro. If RECURSIVE is set,
452 set the ME_RECURSE flag. MACTYPE is either "macro" or "rmacro", and
453 tells us what the matching @end should be. */
454 static void
define_macro(char * mactype,int recursive)455 define_macro (char *mactype, int recursive)
456 {
457 int i, start;
458 char *name, *line;
459 char *last_end = NULL;
460 char *body = NULL;
461 char **arglist = NULL;
462 int body_size = 0, body_index = 0;
463 int depth = 1;
464 int flags = 0;
465 int defining_line = line_number;
466
467 if (macro_expansion_output_stream && !executing_string)
468 me_append_before_this_command ();
469
470 skip_whitespace ();
471
472 /* Get the name of the macro. This is the set of characters which are
473 not whitespace and are not `{' immediately following the @macro. */
474 start = input_text_offset;
475 {
476 int len;
477
478 for (i = start; i < input_text_length && input_text[i] != '{'
479 && !cr_or_whitespace (input_text[i]);
480 i++) ;
481
482 len = i - start;
483 name = xmalloc (1 + len);
484 memcpy (name, input_text + start, len);
485 name[len] = 0;
486 input_text_offset = i;
487 }
488
489 skip_whitespace ();
490
491 /* It is not required that the definition of a macro includes an arglist.
492 If not, don't try to get the named parameters, just use a null list. */
493 if (curchar () == '{')
494 {
495 int character;
496 int arglist_index = 0, arglist_size = 0;
497 int gathering_words = 1;
498 char *word = NULL;
499
500 /* Read the words inside of the braces which determine the arglist.
501 These words will be replaced within the body of the macro at
502 execution time. */
503
504 input_text_offset++;
505 skip_whitespace_and_newlines ();
506
507 while (gathering_words)
508 {
509 int len;
510
511 for (i = input_text_offset;
512 (character = input_text[i]);
513 i++)
514 {
515 switch (character)
516 {
517 case '\n':
518 line_number++;
519 case ' ':
520 case '\t':
521 case ',':
522 case '}':
523 /* Found the end of the current arglist word. Save it. */
524 len = i - input_text_offset;
525 word = xmalloc (1 + len);
526 memcpy (word, input_text + input_text_offset, len);
527 word[len] = 0;
528 input_text_offset = i;
529
530 /* Advance to the comma or close-brace that signified
531 the end of the argument. */
532 while ((character = curchar ())
533 && character != ','
534 && character != '}')
535 {
536 input_text_offset++;
537 if (character == '\n')
538 line_number++;
539 }
540
541 /* Add the word to our list of words. */
542 if (arglist_index + 2 >= arglist_size)
543 {
544 arglist_size += 10;
545 arglist = xrealloc (arglist,
546 arglist_size * sizeof (char *));
547 }
548
549 arglist[arglist_index++] = word;
550 arglist[arglist_index] = NULL;
551 break;
552 }
553
554 if (character == '}')
555 {
556 input_text_offset++;
557 gathering_words = 0;
558 break;
559 }
560
561 if (character == ',')
562 {
563 input_text_offset++;
564 skip_whitespace_and_newlines ();
565 i = input_text_offset - 1;
566 }
567 }
568 }
569
570 /* If we have exactly one argument, do @quote-arg implicitly. Not
571 only does this match TeX's behavior (which can't feasibly be
572 changed), but it's a good idea. */
573 if (arglist_index == 1)
574 flags |= ME_QUOTE_ARG;
575 }
576
577 /* Read the text carefully until we find an "@end macro" which
578 matches this one. The text in between is the body of the macro. */
579 skip_whitespace_and_newlines ();
580
581 while (depth)
582 {
583 if ((input_text_offset + 9) > input_text_length)
584 {
585 file_line_error (input_filename, defining_line,
586 _("%cend macro not found"), COMMAND_PREFIX);
587 return;
588 }
589
590 get_rest_of_line (0, &line);
591
592 /* Handle commands only meaningful within a macro. */
593 if ((*line == COMMAND_PREFIX) && (depth == 1) &&
594 (strncmp (line + 1, "allow-recursion", 15) == 0) &&
595 (line[16] == 0 || whitespace (line[16])))
596 {
597 for (i = 16; whitespace (line[i]); i++);
598 strcpy (line, line + i);
599 flags |= ME_RECURSE;
600 if (!*line)
601 {
602 free (line);
603 continue;
604 }
605 }
606
607 if ((*line == COMMAND_PREFIX) && (depth == 1) &&
608 (strncmp (line + 1, "quote-arg", 9) == 0) &&
609 (line[10] == 0 || whitespace (line[10])))
610 {
611 for (i = 10; whitespace (line[i]); i++);
612 strcpy (line, line + i);
613
614 if (arglist && arglist[0] && !arglist[1])
615 {
616 flags |= ME_QUOTE_ARG;
617 if (!*line)
618 {
619 free (line);
620 continue;
621 }
622 }
623 else
624 line_error (_("@quote-arg only useful for single-argument macros"));
625 }
626
627 if (*line == COMMAND_PREFIX
628 && (strncmp (line + 1, "macro ", 6) == 0
629 || strncmp (line + 1, "rmacro ", 7) == 0))
630 depth++;
631
632 /* Incorrect implementation of nesting -- just check that the last
633 @end matches what we started with. Since nested macros don't
634 work in TeX anyway, this isn't worth the trouble to get right. */
635 if (*line == COMMAND_PREFIX && strncmp (line + 1, "end macro", 9) == 0)
636 {
637 depth--;
638 last_end = "macro";
639 }
640 if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 10) == 0)
641 {
642 depth--;
643 last_end = "rmacro";
644 }
645
646 if (depth)
647 {
648 if ((body_index + strlen (line) + 3) >= body_size)
649 body = xrealloc (body, body_size += 3 + strlen (line));
650 strcpy (body + body_index, line);
651 body_index += strlen (line);
652 body[body_index++] = '\n';
653 body[body_index] = 0;
654 }
655 free (line);
656 }
657
658 /* Check that @end matched the macro command. */
659 if (!STREQ (last_end, mactype))
660 warning (_("mismatched @end %s with @%s"), last_end, mactype);
661
662 /* If it was an empty macro like
663 @macro foo
664 @end macro
665 create an empty body. (Otherwise, the macro is not expanded.) */
666 if (!body)
667 {
668 body = (char *)malloc(1);
669 *body = 0;
670 }
671
672 /* We now have the name, the arglist, and the body. However, BODY
673 includes the final newline which preceded the `@end macro' text.
674 Delete it. */
675 if (body && strlen (body))
676 body[strlen (body) - 1] = 0;
677
678 if (recursive)
679 flags |= ME_RECURSE;
680
681 add_macro (name, arglist, body, input_filename, defining_line, flags);
682
683 if (macro_expansion_output_stream && !executing_string)
684 {
685 /* Remember text for future expansions. */
686 remember_itext (input_text, input_text_offset);
687
688 /* Bizarrely, output the @macro itself. This is so texinfo.tex
689 will have a chance to read it when texi2dvi calls makeinfo -E.
690 The problem is that we don't really expand macros in all
691 contexts; a @table's @item is one. And a fix is not obvious to
692 me, since it appears virtually identical to any other internal
693 expansion. Just setting a variable in cm_item caused other
694 strange expansion problems. */
695 write_region_to_macro_output ("@", 0, 1);
696 write_region_to_macro_output (mactype, 0, strlen (mactype));
697 write_region_to_macro_output (" ", 0, 1);
698 write_region_to_macro_output (input_text, start, input_text_offset);
699 }
700 }
701
702 void
cm_macro(void)703 cm_macro (void)
704 {
705 define_macro ("macro", 0);
706 }
707
708 void
cm_rmacro(void)709 cm_rmacro (void)
710 {
711 define_macro ("rmacro", 1);
712 }
713
714 /* Delete the macro with name NAME. The macro is deleted from the list,
715 but it is also returned. If there was no macro defined, NULL is
716 returned. */
717
718 static MACRO_DEF *
delete_macro(char * name)719 delete_macro (char *name)
720 {
721 int i;
722 MACRO_DEF *def;
723
724 def = NULL;
725
726 for (i = 0; macro_list && (def = macro_list[i]); i++)
727 if (strcmp (def->name, name) == 0)
728 {
729 memmove (macro_list + i, macro_list + i + 1,
730 ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
731 macro_list_len--;
732 break;
733 }
734 return def;
735 }
736
737 void
cm_unmacro(void)738 cm_unmacro (void)
739 {
740 int i;
741 char *line, *name;
742 MACRO_DEF *def;
743
744 if (macro_expansion_output_stream && !executing_string)
745 me_append_before_this_command ();
746
747 get_rest_of_line (0, &line);
748
749 for (i = 0; line[i] && !whitespace (line[i]); i++);
750 name = xmalloc (i + 1);
751 memcpy (name, line, i);
752 name[i] = 0;
753
754 def = delete_macro (name);
755
756 if (def)
757 {
758 free (def->source_file);
759 free (def->name);
760 free (def->body);
761
762 if (def->arglist)
763 {
764 int i;
765
766 for (i = 0; def->arglist[i]; i++)
767 free (def->arglist[i]);
768
769 free (def->arglist);
770 }
771
772 free (def);
773 }
774
775 free (line);
776 free (name);
777
778 if (macro_expansion_output_stream && !executing_string)
779 remember_itext (input_text, input_text_offset);
780 }
781
782 /* How to output sections of the input file verbatim. */
783
784 /* Set the value of POINTER's offset to OFFSET. */
785 ITEXT *
remember_itext(char * pointer,int offset)786 remember_itext (char *pointer, int offset)
787 {
788 int i;
789 ITEXT *itext = NULL;
790
791 /* If we have no info, initialize a blank list. */
792 if (!itext_info)
793 {
794 itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *));
795 for (i = 0; i < itext_size; i++)
796 itext_info[i] = NULL;
797 }
798
799 /* If the pointer is already present in the list, then set the offset. */
800 for (i = 0; i < itext_size; i++)
801 if ((itext_info[i]) &&
802 (itext_info[i]->pointer == pointer))
803 {
804 itext = itext_info[i];
805 itext_info[i]->offset = offset;
806 break;
807 }
808
809 if (i == itext_size)
810 {
811 /* Find a blank slot (or create a new one), and remember the
812 pointer and offset. */
813 for (i = 0; i < itext_size; i++)
814 if (itext_info[i] == NULL)
815 break;
816
817 /* If not found, then add some slots. */
818 if (i == itext_size)
819 {
820 int j;
821
822 itext_info = xrealloc
823 (itext_info, (itext_size += 10) * sizeof (ITEXT *));
824
825 for (j = i; j < itext_size; j++)
826 itext_info[j] = NULL;
827 }
828
829 /* Now add the pointer and the offset. */
830 itext_info[i] = xmalloc (sizeof (ITEXT));
831 itext_info[i]->pointer = pointer;
832 itext_info[i]->offset = offset;
833 itext = itext_info[i];
834 }
835 return itext;
836 }
837
838 /* Forget the input text associated with POINTER. */
839 void
forget_itext(char * pointer)840 forget_itext (char *pointer)
841 {
842 int i;
843
844 for (i = 0; i < itext_size; i++)
845 if (itext_info[i] && (itext_info[i]->pointer == pointer))
846 {
847 free (itext_info[i]);
848 itext_info[i] = NULL;
849 break;
850 }
851 }
852
853 /* Append the text which appeared in input_text from the last offset to
854 the character just before the command that we are currently executing. */
855 void
me_append_before_this_command(void)856 me_append_before_this_command (void)
857 {
858 int i;
859
860 for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--)
861 ;
862 maybe_write_itext (input_text, i);
863 }
864
865 /* Similar to execute_string, but only takes a single string argument,
866 and remembers the input text location, etc. */
867 void
me_execute_string(char * execution_string)868 me_execute_string (char *execution_string)
869 {
870 int saved_escape_html = escape_html;
871 int saved_in_paragraph = in_paragraph;
872 escape_html = me_executing_string == 0;
873 in_paragraph = 0;
874
875 pushfile ();
876 input_text_offset = 0;
877 /* The following xstrdup is so we can relocate input_text at will. */
878 input_text = xstrdup (execution_string);
879 input_filename = xstrdup (input_filename);
880 input_text_length = strlen (execution_string);
881
882 remember_itext (input_text, 0);
883
884 me_executing_string++;
885 reader_loop ();
886 free (input_text);
887 free (input_filename);
888 popfile ();
889 me_executing_string--;
890
891 in_paragraph = saved_in_paragraph;
892 escape_html = saved_escape_html;
893 }
894
895 /* A wrapper around me_execute_string which saves and restores
896 variables important for output generation. This is called
897 when we need to produce macro-expanded output for input which
898 leaves no traces in the Info output. */
899 void
me_execute_string_keep_state(char * execution_string,char * append_string)900 me_execute_string_keep_state (char *execution_string, char *append_string)
901 {
902 int op_orig, opcol_orig, popen_orig;
903 int fill_orig, newline_orig, indent_orig, meta_pos_orig;
904
905 remember_itext (input_text, input_text_offset);
906 op_orig = output_paragraph_offset;
907 meta_pos_orig = meta_char_pos;
908 opcol_orig = output_column;
909 popen_orig = paragraph_is_open;
910 fill_orig = filling_enabled;
911 newline_orig = last_char_was_newline;
912 filling_enabled = 0;
913 indent_orig = no_indent;
914 no_indent = 1;
915 me_execute_string (execution_string);
916 if (append_string)
917 write_region_to_macro_output (append_string, 0, strlen (append_string));
918 output_paragraph_offset = op_orig;
919 meta_char_pos = meta_pos_orig;
920 output_column = opcol_orig;
921 paragraph_is_open = popen_orig;
922 filling_enabled = fill_orig;
923 last_char_was_newline = newline_orig;
924 no_indent = indent_orig;
925 }
926
927 /* Append the text which appears in input_text from the last offset to
928 the current OFFSET. */
929 void
append_to_expansion_output(int offset)930 append_to_expansion_output (int offset)
931 {
932 int i;
933 ITEXT *itext = NULL;
934
935 for (i = 0; i < itext_size; i++)
936 if (itext_info[i] && itext_info[i]->pointer == input_text)
937 {
938 itext = itext_info[i];
939 break;
940 }
941
942 if (!itext)
943 return;
944
945 if (offset > itext->offset)
946 {
947 write_region_to_macro_output (input_text, itext->offset, offset);
948 remember_itext (input_text, offset);
949 }
950 }
951
952 /* Only write this input text iff it appears in our itext list. */
953 void
maybe_write_itext(char * pointer,int offset)954 maybe_write_itext (char *pointer, int offset)
955 {
956 int i;
957 ITEXT *itext = NULL;
958
959 for (i = 0; i < itext_size; i++)
960 if (itext_info[i] && (itext_info[i]->pointer == pointer))
961 {
962 itext = itext_info[i];
963 break;
964 }
965
966 if (itext && (itext->offset < offset))
967 {
968 write_region_to_macro_output (itext->pointer, itext->offset, offset);
969 remember_itext (pointer, offset);
970 }
971 }
972
973 void
write_region_to_macro_output(char * string,int start,int end)974 write_region_to_macro_output (char *string, int start, int end)
975 {
976 if (macro_expansion_output_stream)
977 fwrite (string + start, 1, end - start, macro_expansion_output_stream);
978 }
979
980 /* Aliases. */
981
982 typedef struct alias_struct
983 {
984 char *alias;
985 char *mapto;
986 struct alias_struct *next;
987 } alias_type;
988
989 static alias_type *aliases;
990
991 /* @alias aname = cmdname */
992
993 void
cm_alias(void)994 cm_alias (void)
995 {
996 alias_type *a = xmalloc (sizeof (alias_type));
997
998 skip_whitespace ();
999 get_until_in_line (0, "=", &(a->alias));
1000 canon_white (a->alias);
1001
1002 discard_until ("=");
1003 skip_whitespace ();
1004 get_until_in_line (0, " ", &(a->mapto));
1005
1006 a->next = aliases;
1007 aliases = a;
1008 }
1009
1010 /* Perform an alias expansion. Called from read_command. */
1011 char *
alias_expand(char * tok)1012 alias_expand (char *tok)
1013 {
1014 alias_type *findit = aliases;
1015
1016 while (findit)
1017 if (strcmp (findit->alias, tok) == 0)
1018 {
1019 free (tok);
1020 return alias_expand (xstrdup (findit->mapto));
1021 }
1022 else
1023 findit = findit->next;
1024
1025 return tok;
1026 }
1027
1028 /* definfoenclose implementation. */
1029
1030 /* This structure is used to track enclosure macros. When an enclosure
1031 macro is recognized, a pointer to the enclosure block corresponding
1032 to its name is saved in the brace element for its argument. */
1033 typedef struct enclose_struct
1034 {
1035 char *enclose;
1036 char *before;
1037 char *after;
1038 struct enclose_struct *next;
1039 } enclosure_type;
1040
1041 static enclosure_type *enclosures;
1042
1043 typedef struct enclosure_stack_struct
1044 {
1045 enclosure_type *current;
1046 struct enclosure_stack_struct *next;
1047 } enclosure_stack_type;
1048
1049 static enclosure_stack_type *enclosure_stack;
1050
1051 /* @definfoenclose */
1052 void
cm_definfoenclose(void)1053 cm_definfoenclose (void)
1054 {
1055 enclosure_type *e = xmalloc (sizeof (enclosure_type));
1056
1057 skip_whitespace ();
1058 get_until_in_line (1, ",", &(e->enclose));
1059 discard_until (",");
1060 get_until_in_line (0, ",", &(e->before));
1061 discard_until (",");
1062 get_until_in_line (0, "\n", &(e->after));
1063
1064 e->next = enclosures;
1065 enclosures = e;
1066 }
1067
1068 /* If TOK is an enclosure command, push it on the enclosure stack and
1069 return 1. Else return 0. */
1070
1071 int
enclosure_command(char * tok)1072 enclosure_command (char *tok)
1073 {
1074 enclosure_type *findit = enclosures;
1075
1076 while (findit)
1077 if (strcmp (findit->enclose, tok) == 0)
1078 {
1079 enclosure_stack_type *new = xmalloc (sizeof (enclosure_stack_type));
1080 new->current = findit;
1081 new->next = enclosure_stack;
1082 enclosure_stack = new;
1083
1084 return 1;
1085 }
1086 else
1087 findit = findit->next;
1088
1089 return 0;
1090 }
1091
1092 /* actually perform the enclosure expansion */
1093 void
enclosure_expand(int arg,int start,int end)1094 enclosure_expand (int arg, int start, int end)
1095 {
1096 if (arg == START)
1097 add_word (enclosure_stack->current->before);
1098 else
1099 {
1100 enclosure_stack_type *temp;
1101
1102 add_word (enclosure_stack->current->after);
1103
1104 temp = enclosure_stack;
1105 enclosure_stack = enclosure_stack->next;
1106 free (temp);
1107 }
1108 }
1109