source: trunk/essentials/sys-apps/texinfo/makeinfo/macro.c

Last change on this file was 2617, checked in by bird, 19 years ago

GNU Texinfo 4.8

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