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. */
|
---|
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 |
|
---|
57 | /* Return the length of the array in ARRAY. */
|
---|
58 | int
|
---|
59 | array_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 |
|
---|
69 | void
|
---|
70 | free_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. */
|
---|
84 | MACRO_DEF *
|
---|
85 | find_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. */
|
---|
104 | static void
|
---|
105 | add_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 |
|
---|
161 | char **
|
---|
162 | get_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 |
|
---|
241 | static char **
|
---|
242 | get_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\. */
|
---|
295 | static char *
|
---|
296 | apply (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. */
|
---|
386 | char *
|
---|
387 | expand_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. */
|
---|
416 | void
|
---|
417 | execute_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. */
|
---|
457 | static void
|
---|
458 | define_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 |
|
---|
705 | void
|
---|
706 | cm_macro (void)
|
---|
707 | {
|
---|
708 | define_macro ("macro", 0);
|
---|
709 | }
|
---|
710 |
|
---|
711 | void
|
---|
712 | cm_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 |
|
---|
722 | static MACRO_DEF *
|
---|
723 | delete_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 |
|
---|
741 | void
|
---|
742 | cm_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. */
|
---|
790 | ITEXT *
|
---|
791 | remember_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. */
|
---|
844 | void
|
---|
845 | forget_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. */
|
---|
860 | void
|
---|
861 | me_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. */
|
---|
872 | void
|
---|
873 | me_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. */
|
---|
904 | void
|
---|
905 | me_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. */
|
---|
934 | void
|
---|
935 | append_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. */
|
---|
958 | void
|
---|
959 | maybe_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 |
|
---|
978 | void
|
---|
979 | write_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 |
|
---|
988 | typedef struct alias_struct
|
---|
989 | {
|
---|
990 | char *alias;
|
---|
991 | char *mapto;
|
---|
992 | struct alias_struct *next;
|
---|
993 | } alias_type;
|
---|
994 |
|
---|
995 | static alias_type *aliases;
|
---|
996 |
|
---|
997 | /* @alias aname = cmdname */
|
---|
998 |
|
---|
999 | void
|
---|
1000 | cm_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. */
|
---|
1017 | char *
|
---|
1018 | alias_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. */
|
---|
1040 | typedef struct enclose_struct
|
---|
1041 | {
|
---|
1042 | char *enclose;
|
---|
1043 | char *before;
|
---|
1044 | char *after;
|
---|
1045 | struct enclose_struct *next;
|
---|
1046 | } enclosure_type;
|
---|
1047 |
|
---|
1048 | static enclosure_type *enclosures;
|
---|
1049 |
|
---|
1050 | typedef struct enclosure_stack_struct
|
---|
1051 | {
|
---|
1052 | enclosure_type *current;
|
---|
1053 | struct enclosure_stack_struct *next;
|
---|
1054 | } enclosure_stack_type;
|
---|
1055 |
|
---|
1056 | static enclosure_stack_type *enclosure_stack;
|
---|
1057 |
|
---|
1058 | /* @definfoenclose */
|
---|
1059 | void
|
---|
1060 | cm_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 |
|
---|
1078 | int
|
---|
1079 | enclosure_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 */
|
---|
1100 | void
|
---|
1101 | enclosure_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 | }
|
---|