MFC: An off-by-one malloc size was corrupting the installer's memory,
[dragonfly.git] / contrib / texinfo-4 / makeinfo / macro.c
blob65ac0dac8f83d5236f40225b447800c1e6be0e64
1 /* macro.c -- user-defined macros for Texinfo.
2 $Id: macro.c,v 1.6 2004/04/11 17:56:47 karl Exp $
4 Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
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.
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.
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. */
20 #include "system.h"
21 #include "cmds.h"
22 #include "files.h"
23 #include "macro.h"
24 #include "makeinfo.h"
25 #include "insertion.h"
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;
33 /* Output file for -E. */
34 char *macro_expansion_filename;
36 /* Nonzero means a macro string is in execution, as opposed to a file. */
37 int me_executing_string = 0;
39 /* Nonzero means we want only to expand macros and
40 leave everything else intact. */
41 int only_macro_expansion = 0;
43 static ITEXT **itext_info = NULL;
44 static int itext_size = 0;
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;
50 /* Array of macros and definitions. */
51 MACRO_DEF **macro_list = NULL;
53 int macro_list_len = 0; /* Number of elements. */
54 int macro_list_size = 0; /* Number of slots in total. */
56 /* Return the length of the array in ARRAY. */
57 int
58 array_len (char **array)
60 int i = 0;
62 if (array)
63 for (i = 0; array[i]; i++);
65 return i;
68 void
69 free_array (char **array)
71 if (array)
73 int i;
74 for (i = 0; array[i]; i++)
75 free (array[i]);
77 free (array);
81 /* Return the macro definition of NAME or NULL if NAME is not defined. */
82 MACRO_DEF *
83 find_macro (char *name)
85 int i;
86 MACRO_DEF *def;
88 def = NULL;
89 for (i = 0; macro_list && (def = macro_list[i]); i++)
91 if ((!def->inhibited) && (strcmp (def->name, name) == 0))
92 break;
94 return def;
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
103 add_macro (char *name, char **arglist, char *body, char *source_file,
104 int source_lineno, int flags)
106 MACRO_DEF *def;
108 def = find_macro (name);
110 if (!def)
112 if (macro_list_len + 2 >= macro_list_size)
113 macro_list = xrealloc
114 (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
116 macro_list[macro_list_len] = xmalloc (sizeof (MACRO_DEF));
117 macro_list[macro_list_len + 1] = NULL;
119 def = macro_list[macro_list_len];
120 macro_list_len += 1;
121 def->name = name;
123 else
125 char *temp_filename = input_filename;
126 int temp_line = line_number;
128 warning (_("macro `%s' previously defined"), name);
130 input_filename = def->source_file;
131 line_number = def->source_lineno;
132 warning (_("here is the previous definition of `%s'"), name);
134 input_filename = temp_filename;
135 line_number = temp_line;
137 if (def->arglist)
139 int i;
141 for (i = 0; def->arglist[i]; i++)
142 free (def->arglist[i]);
144 free (def->arglist);
146 free (def->source_file);
147 free (def->body);
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;
159 char **
160 get_brace_args (int quote_single)
162 char **arglist, *word;
163 int arglist_index, arglist_size;
164 int character, escape_seen, start;
165 int depth = 1;
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;
173 get_arg:
174 skip_whitespace_and_newlines ();
175 start = input_text_offset;
176 escape_seen = 0;
178 while ((character = curchar ()))
180 if (character == '\\')
182 input_text_offset += 2;
183 escape_seen = 1;
185 else if (character == '{')
187 depth++;
188 input_text_offset++;
190 else if ((character == ',' && !quote_single) ||
191 ((character == '}') && depth == 1))
193 int len = input_text_offset - start;
195 if (len || (character != '}'))
197 word = xmalloc (1 + len);
198 memcpy (word, input_text + start, len);
199 word[len] = 0;
201 /* Clean up escaped characters. */
202 if (escape_seen)
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));
211 if (arglist_index + 2 >= arglist_size)
212 arglist = xrealloc
213 (arglist, (arglist_size += 10) * sizeof (char *));
215 arglist[arglist_index++] = word;
216 arglist[arglist_index] = NULL;
219 input_text_offset++;
220 if (character == '}')
221 break;
222 else
223 goto get_arg;
225 else if (character == '}')
227 depth--;
228 input_text_offset++;
230 else
232 input_text_offset++;
233 if (character == '\n') line_number++;
236 return arglist;
239 static char **
240 get_macro_args (MACRO_DEF *def)
242 int i;
243 char *word;
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;
251 if (input_text[i] != '{')
253 if (braces_required_for_macro_args)
255 return NULL;
257 else
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])
264 char **arglist;
266 get_rest_of_line (0, &word);
267 if (input_text[input_text_offset - 1] == '\n')
269 input_text_offset--;
270 line_number--;
272 /* canon_white (word); */
273 arglist = xmalloc (2 * sizeof (char *));
274 arglist[0] = word;
275 arglist[1] = NULL;
276 return arglist;
278 else
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;
287 return get_brace_args (def->flags & ME_QUOTE_ARG);
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 *
294 apply (char **named, char **actuals, char *body)
296 int i;
297 int new_body_index, new_body_size;
298 char *new_body, *text;
299 int length_of_actuals;
301 length_of_actuals = array_len (actuals);
302 new_body_size = strlen (body);
303 new_body = xmalloc (1 + new_body_size);
305 /* Copy chars from BODY into NEW_BODY. */
306 i = 0;
307 new_body_index = 0;
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;
318 param_start = ++i;
319 while (body[i] && body[i] != '\\')
320 i++;
322 len = i - param_start;
323 param = xmalloc (1 + len);
324 memcpy (param, body + param_start, len);
325 param[len] = 0;
327 if (body[i]) /* move past \ */
328 i++;
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);
336 else
338 int which;
340 /* Check against named parameters. */
341 for (which = 0; named && named[which]; which++)
342 if (STREQ (named[which], param))
343 break;
345 if (named && named[which])
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 */
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);
363 if (strlen (param) + 2 < len)
365 new_body_size += len + 1;
366 new_body = xrealloc (new_body, new_body_size);
369 free (param);
371 strcpy (new_body + new_body_index, text);
372 new_body_index += len;
374 free (text);
378 new_body[new_body_index] = 0;
379 return new_body;
382 /* Expand macro passed in DEF, a pointer to a MACRO_DEF, and
383 return its expansion as a string. */
384 char *
385 expand_macro (MACRO_DEF *def)
387 char **arglist;
388 int num_args;
389 char *execution_string = NULL;
390 int start_line = line_number;
392 /* Find out how many arguments this macro definition takes. */
393 num_args = array_len (def->arglist);
395 /* Gather the arguments present on the line if there are any. */
396 arglist = get_macro_args (def);
398 if (num_args < array_len (arglist))
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;
406 if (def->body)
407 execution_string = apply (def->arglist, arglist, def->body);
409 free_array (arglist);
410 return execution_string;
413 /* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */
414 void
415 execute_macro (MACRO_DEF *def)
417 char *execution_string;
418 int start_line = line_number, end_line;
420 if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
421 me_append_before_this_command ();
423 execution_string = expand_macro (def);
424 if (!execution_string)
425 return;
427 if (def->body)
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;
436 if (macro_expansion_output_stream
437 && !executing_string && !me_inhibit_expansion)
439 remember_itext (input_text, input_text_offset);
440 me_execute_string (execution_string);
442 else
443 execute_string ("%s", execution_string);
445 free (execution_string);
446 line_number = end_line;
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
455 define_macro (char *mactype, int recursive)
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;
467 if (macro_expansion_output_stream && !executing_string)
468 me_append_before_this_command ();
470 skip_whitespace ();
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;
476 int len;
478 for (i = start; i < input_text_length && input_text[i] != '{'
479 && !cr_or_whitespace (input_text[i]);
480 i++) ;
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;
489 skip_whitespace ();
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 () == '{')
495 int character;
496 int arglist_index = 0, arglist_size = 0;
497 int gathering_words = 1;
498 char *word = NULL;
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. */
504 input_text_offset++;
505 skip_whitespace_and_newlines ();
507 while (gathering_words)
509 int len;
511 for (i = input_text_offset;
512 (character = input_text[i]);
513 i++)
515 switch (character)
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;
530 /* Advance to the comma or close-brace that signified
531 the end of the argument. */
532 while ((character = curchar ())
533 && character != ','
534 && character != '}')
536 input_text_offset++;
537 if (character == '\n')
538 line_number++;
541 /* Add the word to our list of words. */
542 if (arglist_index + 2 >= arglist_size)
544 arglist_size += 10;
545 arglist = xrealloc (arglist,
546 arglist_size * sizeof (char *));
549 arglist[arglist_index++] = word;
550 arglist[arglist_index] = NULL;
551 break;
554 if (character == '}')
556 input_text_offset++;
557 gathering_words = 0;
558 break;
561 if (character == ',')
563 input_text_offset++;
564 skip_whitespace_and_newlines ();
565 i = input_text_offset - 1;
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;
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 ();
581 while (depth)
583 if ((input_text_offset + 9) > input_text_length)
585 file_line_error (input_filename, defining_line,
586 _("%cend macro not found"), COMMAND_PREFIX);
587 return;
590 get_rest_of_line (0, &line);
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])))
597 for (i = 16; whitespace (line[i]); i++);
598 strcpy (line, line + i);
599 flags |= ME_RECURSE;
600 if (!*line)
602 free (line);
603 continue;
607 if ((*line == COMMAND_PREFIX) && (depth == 1) &&
608 (strncmp (line + 1, "quote-arg", 9) == 0) &&
609 (line[10] == 0 || whitespace (line[10])))
611 for (i = 10; whitespace (line[i]); i++);
612 strcpy (line, line + i);
614 if (arglist && arglist[0] && !arglist[1])
616 flags |= ME_QUOTE_ARG;
617 if (!*line)
619 free (line);
620 continue;
623 else
624 line_error (_("@quote-arg only useful for single-argument macros"));
627 if (*line == COMMAND_PREFIX
628 && (strncmp (line + 1, "macro ", 6) == 0
629 || strncmp (line + 1, "rmacro ", 7) == 0))
630 depth++;
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)
637 depth--;
638 last_end = "macro";
640 if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 10) == 0)
642 depth--;
643 last_end = "rmacro";
646 if (depth)
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;
655 free (line);
658 /* Check that @end matched the macro command. */
659 if (!STREQ (last_end, mactype))
660 warning (_("mismatched @end %s with @%s"), last_end, mactype);
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)
668 body = (char *)malloc(1);
669 *body = 0;
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;
678 if (recursive)
679 flags |= ME_RECURSE;
681 add_macro (name, arglist, body, input_filename, defining_line, flags);
683 if (macro_expansion_output_stream && !executing_string)
685 /* Remember text for future expansions. */
686 remember_itext (input_text, input_text_offset);
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);
702 void
703 cm_macro (void)
705 define_macro ("macro", 0);
708 void
709 cm_rmacro (void)
711 define_macro ("rmacro", 1);
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. */
718 static MACRO_DEF *
719 delete_macro (char *name)
721 int i;
722 MACRO_DEF *def;
724 def = NULL;
726 for (i = 0; macro_list && (def = macro_list[i]); i++)
727 if (strcmp (def->name, name) == 0)
729 memmove (macro_list + i, macro_list + i + 1,
730 ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
731 macro_list_len--;
732 break;
734 return def;
737 void
738 cm_unmacro (void)
740 int i;
741 char *line, *name;
742 MACRO_DEF *def;
744 if (macro_expansion_output_stream && !executing_string)
745 me_append_before_this_command ();
747 get_rest_of_line (0, &line);
749 for (i = 0; line[i] && !whitespace (line[i]); i++);
750 name = xmalloc (i + 1);
751 memcpy (name, line, i);
752 name[i] = 0;
754 def = delete_macro (name);
756 if (def)
758 free (def->source_file);
759 free (def->name);
760 free (def->body);
762 if (def->arglist)
764 int i;
766 for (i = 0; def->arglist[i]; i++)
767 free (def->arglist[i]);
769 free (def->arglist);
772 free (def);
775 free (line);
776 free (name);
778 if (macro_expansion_output_stream && !executing_string)
779 remember_itext (input_text, input_text_offset);
782 /* How to output sections of the input file verbatim. */
784 /* Set the value of POINTER's offset to OFFSET. */
785 ITEXT *
786 remember_itext (char *pointer, int offset)
788 int i;
789 ITEXT *itext = NULL;
791 /* If we have no info, initialize a blank list. */
792 if (!itext_info)
794 itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *));
795 for (i = 0; i < itext_size; i++)
796 itext_info[i] = NULL;
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))
804 itext = itext_info[i];
805 itext_info[i]->offset = offset;
806 break;
809 if (i == itext_size)
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;
817 /* If not found, then add some slots. */
818 if (i == itext_size)
820 int j;
822 itext_info = xrealloc
823 (itext_info, (itext_size += 10) * sizeof (ITEXT *));
825 for (j = i; j < itext_size; j++)
826 itext_info[j] = NULL;
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];
835 return itext;
838 /* Forget the input text associated with POINTER. */
839 void
840 forget_itext (char *pointer)
842 int i;
844 for (i = 0; i < itext_size; i++)
845 if (itext_info[i] && (itext_info[i]->pointer == pointer))
847 free (itext_info[i]);
848 itext_info[i] = NULL;
849 break;
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
856 me_append_before_this_command (void)
858 int i;
860 for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--)
862 maybe_write_itext (input_text, i);
865 /* Similar to execute_string, but only takes a single string argument,
866 and remembers the input text location, etc. */
867 void
868 me_execute_string (char *execution_string)
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;
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);
882 remember_itext (input_text, 0);
884 me_executing_string++;
885 reader_loop ();
886 free (input_text);
887 free (input_filename);
888 popfile ();
889 me_executing_string--;
891 in_paragraph = saved_in_paragraph;
892 escape_html = saved_escape_html;
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
900 me_execute_string_keep_state (char *execution_string, char *append_string)
902 int op_orig, opcol_orig, popen_orig;
903 int fill_orig, newline_orig, indent_orig, meta_pos_orig;
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;
927 /* Append the text which appears in input_text from the last offset to
928 the current OFFSET. */
929 void
930 append_to_expansion_output (int offset)
932 int i;
933 ITEXT *itext = NULL;
935 for (i = 0; i < itext_size; i++)
936 if (itext_info[i] && itext_info[i]->pointer == input_text)
938 itext = itext_info[i];
939 break;
942 if (!itext)
943 return;
945 if (offset > itext->offset)
947 write_region_to_macro_output (input_text, itext->offset, offset);
948 remember_itext (input_text, offset);
952 /* Only write this input text iff it appears in our itext list. */
953 void
954 maybe_write_itext (char *pointer, int offset)
956 int i;
957 ITEXT *itext = NULL;
959 for (i = 0; i < itext_size; i++)
960 if (itext_info[i] && (itext_info[i]->pointer == pointer))
962 itext = itext_info[i];
963 break;
966 if (itext && (itext->offset < offset))
968 write_region_to_macro_output (itext->pointer, itext->offset, offset);
969 remember_itext (pointer, offset);
973 void
974 write_region_to_macro_output (char *string, int start, int end)
976 if (macro_expansion_output_stream)
977 fwrite (string + start, 1, end - start, macro_expansion_output_stream);
980 /* Aliases. */
982 typedef struct alias_struct
984 char *alias;
985 char *mapto;
986 struct alias_struct *next;
987 } alias_type;
989 static alias_type *aliases;
991 /* @alias aname = cmdname */
993 void
994 cm_alias (void)
996 alias_type *a = xmalloc (sizeof (alias_type));
998 skip_whitespace ();
999 get_until_in_line (0, "=", &(a->alias));
1000 canon_white (a->alias);
1002 discard_until ("=");
1003 skip_whitespace ();
1004 get_until_in_line (0, " ", &(a->mapto));
1006 a->next = aliases;
1007 aliases = a;
1010 /* Perform an alias expansion. Called from read_command. */
1011 char *
1012 alias_expand (char *tok)
1014 alias_type *findit = aliases;
1016 while (findit)
1017 if (strcmp (findit->alias, tok) == 0)
1019 free (tok);
1020 return alias_expand (xstrdup (findit->mapto));
1022 else
1023 findit = findit->next;
1025 return tok;
1028 /* definfoenclose implementation. */
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
1035 char *enclose;
1036 char *before;
1037 char *after;
1038 struct enclose_struct *next;
1039 } enclosure_type;
1041 static enclosure_type *enclosures;
1043 typedef struct enclosure_stack_struct
1045 enclosure_type *current;
1046 struct enclosure_stack_struct *next;
1047 } enclosure_stack_type;
1049 static enclosure_stack_type *enclosure_stack;
1051 /* @definfoenclose */
1052 void
1053 cm_definfoenclose (void)
1055 enclosure_type *e = xmalloc (sizeof (enclosure_type));
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));
1064 e->next = enclosures;
1065 enclosures = e;
1068 /* If TOK is an enclosure command, push it on the enclosure stack and
1069 return 1. Else return 0. */
1072 enclosure_command (char *tok)
1074 enclosure_type *findit = enclosures;
1076 while (findit)
1077 if (strcmp (findit->enclose, tok) == 0)
1079 enclosure_stack_type *new = xmalloc (sizeof (enclosure_stack_type));
1080 new->current = findit;
1081 new->next = enclosure_stack;
1082 enclosure_stack = new;
1084 return 1;
1086 else
1087 findit = findit->next;
1089 return 0;
1092 /* actually perform the enclosure expansion */
1093 void
1094 enclosure_expand (int arg, int start, int end)
1096 if (arg == START)
1097 add_word (enclosure_stack->current->before);
1098 else
1100 enclosure_stack_type *temp;
1102 add_word (enclosure_stack->current->after);
1104 temp = enclosure_stack;
1105 enclosure_stack = enclosure_stack->next;
1106 free (temp);