1 /* handle_commands.c -- what to do when a command name is first read */
2 /* Copyright 2010-2020 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "parser.h"
22 #include "input.h"
23 #include "text.h"
24
25 /* Return a containing @itemize or @enumerate if inside it. */
26 ELEMENT *
item_container_parent(ELEMENT * current)27 item_container_parent (ELEMENT *current)
28 {
29 if ((current->cmd == CM_item
30 || current->type == ET_before_item)
31 && current->parent
32 && ((current->parent->cmd == CM_itemize
33 || current->parent->cmd == CM_enumerate)))
34 {
35 return current->parent;
36 }
37 return 0;
38 }
39
40 /* Check that there are no text holding environments (currently
41 checking only paragraphs and preformatted) in contents. */
42 int
check_no_text(ELEMENT * current)43 check_no_text (ELEMENT *current)
44 {
45 int after_paragraph = 0;
46 int i, j;
47 for (i = 0; i < current->contents.number; i++)
48 {
49 enum element_type t;
50 ELEMENT *f;
51 f = current->contents.list[i];
52 t = f->type;
53 if (t == ET_paragraph)
54 {
55 after_paragraph = 1;
56 break;
57 }
58 else if (t == ET_preformatted
59 || t == ET_rawpreformatted)
60 {
61 for (j = 0; j < f->contents.number; j++)
62 {
63 ELEMENT *g = f->contents.list[j];
64 if ((g->text.end > 0
65 && g->text.text[strspn (g->text.text, whitespace_chars)])
66 || (g->cmd && g->cmd != CM_c
67 && g->cmd != CM_comment
68 && g->type != ET_index_entry_command))
69 {
70 after_paragraph = 1;
71 break;
72 }
73 }
74 if (after_paragraph)
75 break;
76 }
77 }
78 return after_paragraph;
79 }
80
81 /* noarg skipspace */
82 ELEMENT *
handle_other_command(ELEMENT * current,char ** line_inout,enum command_id cmd,int * status)83 handle_other_command (ELEMENT *current, char **line_inout,
84 enum command_id cmd, int *status)
85 {
86 ELEMENT *misc = 0;
87 char *line = *line_inout;
88 int arg_spec;
89
90 *status = STILL_MORE_TO_PROCESS;
91
92 arg_spec = command_data(cmd).data;
93 if (arg_spec == OTHER_noarg)
94 {
95 if (command_data(cmd).flags & CF_in_heading)
96 {
97 line_error ("@%s should only appear in heading or footing",
98 command_name(cmd));
99 }
100
101 misc = new_element (ET_NONE);
102 misc->cmd = cmd;
103 add_to_element_contents (current, misc);
104 register_global_command (misc);
105 if (close_preformatted_command(cmd))
106 current = begin_preformatted (current);
107 }
108 else
109 {
110 /* @item can occur in several contents: in an @itemize, a @table, or
111 a @multitable. */
112 if (cmd == CM_item || cmd == CM_headitem || cmd == CM_tab)
113 {
114 ELEMENT *parent;
115
116 /* @itemize or @enumerate */
117 if ((parent = item_container_parent (current)))
118 {
119 if (cmd == CM_item)
120 {
121 debug ("ITEM CONTAINER");
122 counter_inc (&count_items);
123 misc = new_element (ET_NONE);
124 misc->cmd = CM_item;
125
126 add_extra_integer (misc, "item_number",
127 counter_value (&count_items, parent));
128
129 add_to_element_contents (parent, misc);
130 current = misc;
131 }
132 else
133 {
134 line_error ("@%s not meaningful inside `@%s' block",
135 command_name(cmd),
136 command_name(parent->cmd));
137 }
138 current = begin_preformatted (current);
139 }
140 /* @table, @vtable, @ftable */
141 else if ((parent = item_line_parent (current)))
142 {
143 line_error ("@%s not meaningful inside `@%s' block",
144 command_name(cmd),
145 command_name(parent->cmd));
146 current = begin_preformatted (current);
147 }
148 /* In a @multitable */
149 else if ((parent = item_multitable_parent (current)))
150 {
151 if (cmd != CM_item && cmd != CM_headitem
152 && cmd != CM_tab)
153 {
154 line_error ("@%s not meaningful inside @%s block",
155 command_name(cmd),
156 command_name(parent->cmd));
157 }
158 else
159 {
160 int max_columns = 0;
161 KEY_PAIR *prototypes;
162
163 prototypes = lookup_extra (parent, "prototypes");
164 if (prototypes)
165 max_columns = prototypes->value->contents.number;
166 else
167 {
168 prototypes = lookup_extra(parent, "columnfractions");
169 if (prototypes)
170 {
171 prototypes = lookup_extra((ELEMENT *) prototypes->value,
172 "misc_args");
173 if (prototypes)
174 max_columns = prototypes->value->contents.number;
175 }
176 }
177
178 if (max_columns == 0)
179 {
180 line_warn ("@%s in empty multitable",
181 command_name(cmd));
182 }
183 else if (cmd == CM_tab)
184 {
185 ELEMENT *row;
186 row = last_contents_child (parent);
187 if (row->type == ET_before_item)
188 line_error ("@tab before @item");
189 else if (counter_value (&count_cells, row)
190 >= max_columns)
191 {
192 line_error ("too many columns in multitable item"
193 " (max %d)", max_columns);
194 }
195 else
196 {
197 counter_inc (&count_cells);
198 misc = new_element (ET_NONE);
199 misc->cmd = cmd;
200 add_to_element_contents (row, misc);
201 current = misc;
202 debug ("TAB");
203
204 add_extra_integer (current, "cell_number",
205 counter_value (&count_cells, row));
206 }
207 }
208 else /* @item or @headitem */
209 {
210 ELEMENT *row;
211
212 debug ("ROW");
213 row = new_element (ET_row);
214 add_to_element_contents (parent, row);
215
216 /* Note that the "row_number" extra value,
217 isn't actually used anywhere at present. */
218 add_extra_integer (row, "row_number",
219 parent->contents.number - 1);
220
221 misc = new_element (ET_NONE);
222 misc->cmd = cmd;
223 add_to_element_contents (row, misc);
224 current = misc;
225
226 if (counter_value (&count_cells, parent) != -1)
227 counter_pop (&count_cells);
228 counter_push (&count_cells, row, 1);
229 add_extra_integer (current, "cell_number",
230 counter_value (&count_cells, row));
231 }
232 }
233 current = begin_preformatted (current);
234 } /* In @multitable */
235 else if (cmd == CM_tab)
236 {
237 line_error ("ignoring @tab outside of multitable");
238 current = begin_preformatted (current);
239 }
240 else
241 {
242 line_error ("@%s outside of table or list",
243 command_name(cmd));
244 current = begin_preformatted (current);
245 }
246 if (misc)
247 misc->line_nr = line_nr;
248 }
249 else
250 {
251 misc = new_element (ET_NONE);
252 misc->cmd = cmd;
253 misc->line_nr = line_nr;
254 add_to_element_contents (current, misc);
255 }
256 start_empty_line_after_command (current, &line, misc);
257 if (cmd == CM_indent || cmd == CM_noindent)
258 {
259 /* Start a new paragraph if not in one already. */
260 int spaces;
261 ELEMENT *paragraph;
262
263 /* Check if if we should change an ET_empty_line_after_command
264 element to ET_empty_spaces_after_command by looking ahead
265 to see what comes next. */
266 if (!strchr (line, '\n'))
267 {
268 char *line2;
269 input_push_text (strdup (line), 0);
270 line2 = new_line ();
271 if (line2)
272 line = line2;
273 }
274 spaces = strspn (line, whitespace_chars);
275 if (spaces > 0)
276 {
277 char saved = line[spaces];
278 line[spaces] = '\0';
279 current = merge_text (current, line);
280 line[spaces] = saved;
281 line += spaces;
282 }
283 if (*line
284 && last_contents_child(current)->type
285 == ET_empty_line_after_command)
286 {
287 last_contents_child(current)->type
288 = ET_empty_spaces_after_command;
289 }
290 paragraph = begin_paragraph (current);
291 if (paragraph)
292 current = paragraph;
293 if (!*line)
294 {
295 *status = GET_A_NEW_LINE;
296 goto funexit;
297 }
298 }
299 }
300
301 funexit:
302 *line_inout = line;
303 return current;
304 }
305
306 /* STATUS is set to GET_A_NEW_LINE if we should get a new line after this,
307 to FINISHED_TOTALLY if we should stop processing completely. */
308 ELEMENT *
handle_line_command(ELEMENT * current,char ** line_inout,enum command_id cmd,int * status)309 handle_line_command (ELEMENT *current, char **line_inout,
310 enum command_id cmd, int *status)
311 {
312 ELEMENT *misc = 0;
313 char *line = *line_inout;
314 int arg_spec;
315
316 *status = STILL_MORE_TO_PROCESS;
317
318 /* Root commands (like @node) and @bye */
319 if (command_data(cmd).flags & CF_root || cmd == CM_bye)
320 {
321 ELEMENT *closed_elt; /* Not used */
322 current = close_commands (current, 0, &closed_elt, cmd);
323 if (current->type == ET_text_root)
324 {
325 if (cmd != CM_bye)
326 {
327 /* Use document_root when we have nodes or sections. */
328 ELEMENT *new_root = new_element (ET_document_root);
329 add_to_element_contents (new_root, current);
330 current = new_root;
331 }
332 }
333 else
334 {
335 current = current->parent;
336 if (!current)
337 fatal ("no parent element");
338 }
339 }
340
341 /* Look up information about this command ( skipline text
342 line lineraw (a number) ). */
343 arg_spec = command_data(cmd).data;
344
345 /* All the cases using the raw line.
346 TODO: I don't understand what the difference is between these.
347 LINE_skipline is used where the command takes no argument at all. */
348 if (arg_spec == LINE_skipline || arg_spec == LINE_lineraw
349 || arg_spec == LINE_special)
350 {
351 ELEMENT *args = 0;
352 enum command_id equivalent_cmd = 0;
353 int has_comment = 0;
354 int ignored = 0;
355
356 if (cmd == CM_insertcopying)
357 {
358 ELEMENT *p = current;
359 while (p)
360 {
361 if (p->cmd == CM_copying)
362 {
363 line_error ("@%s not allowed inside `@copying' block",
364 command_name(cmd));
365 ignored = 1;
366 break;
367 }
368 p = p->parent;
369 }
370 }
371
372 /* If the current input is the result of a macro expansion,
373 it may not be a complete line. Check for this and acquire the rest
374 of the line if necessary. */
375 if (!strchr (line, '\n'))
376 {
377 char *line2;
378 LINE_NR save_ln;
379
380 input_push_text (strdup (line), 0);
381
382 save_ln = line_nr;
383 line2 = new_line ();
384 if (line2)
385 {
386 line = line2;
387 line_nr = save_ln;
388 }
389 }
390
391 misc = new_element (ET_NONE);
392 misc->cmd = cmd;
393
394 if (arg_spec == LINE_skipline || arg_spec == LINE_lineraw)
395 {
396 ELEMENT *arg;
397 args = new_element (ET_NONE);
398 arg = new_element (ET_NONE);
399 add_to_element_contents (args, arg);
400 text_append (&arg->text, line);
401 }
402 else /* arg_spec == LINE_special */
403 {
404 args = parse_special_misc_command (line, cmd, &has_comment);
405 add_extra_string (misc, "arg_line", strdup (line));
406 }
407
408 /* Handle @set txicodequoteundirected as an
409 alternative to @codequoteundirected. */
410 if (cmd == CM_set || cmd == CM_clear)
411 {
412 if (args->contents.number > 0
413 && args->contents.list[0]->text.end > 0)
414 {
415 if (!strcmp (args->contents.list[0]->text.text,
416 "txicodequoteundirected"))
417 equivalent_cmd = CM_codequoteundirected;
418 else if (!strcmp (args->contents.list[0]->text.text,
419 "txicodequotebacktick"))
420 equivalent_cmd = CM_codequotebacktick;
421 }
422 }
423 if (equivalent_cmd)
424 {
425 char *arg = 0;
426 ELEMENT *line_args;
427 ELEMENT *e;
428
429 if (cmd == CM_set)
430 arg = "on";
431 else
432 arg = "off";
433
434 /* Now manufacture the parse tree for the equivalent
435 command and add it to the tree. */
436
437 destroy_element_and_children (args);
438 args = new_element (ET_NONE);
439 e = new_element (ET_NONE);
440 text_append (&e->text, arg);
441 add_to_element_contents (args, e);
442
443 destroy_element_and_children (misc);
444 misc = new_element (ET_NONE);
445 misc->cmd = equivalent_cmd;
446 misc->line_nr = line_nr;
447
448 line_args = new_element (ET_line_arg);
449 add_to_element_args (misc, line_args);
450 add_extra_misc_args (misc, "misc_args", args);
451
452 add_extra_string_dup (misc, "spaces_before_argument", " ");
453
454 e = new_element (ET_NONE);
455 text_append (&e->text, arg);
456 add_to_element_contents (line_args, e);
457
458 e = new_element (ET_spaces_at_end);
459 text_append_n (&e->text, "\n", 1);
460 add_to_element_contents (line_args, e);
461
462 add_to_element_contents (current, misc);
463 }
464 else
465 {
466 int i;
467 if (!ignored)
468 {
469 add_to_element_contents (current, misc);
470
471 for (i = 0; i < args->contents.number; i++)
472 {
473 ELEMENT *misc_arg = new_element (ET_misc_arg);
474 text_append_n (&misc_arg->text,
475 args->contents.list[i]->text.text,
476 args->contents.list[i]->text.end);
477 add_to_element_args (misc, misc_arg);
478 }
479 /* TODO: Could we have just set misc->args directly as args? */
480 if (args->contents.number > 0 && arg_spec != LINE_skipline)
481 add_extra_misc_args (misc, "misc_args", args);
482 else
483 destroy_element_and_children (args);
484 }
485 else
486 {
487 destroy_element_and_children (misc);
488 destroy_element_and_children (args);
489 misc = 0;
490 }
491 }
492
493 if (cmd == CM_raisesections)
494 {
495 global_info.sections_level++;
496 }
497 else if (cmd == CM_lowersections)
498 {
499 global_info.sections_level--;
500 }
501 else if (cmd == CM_novalidate)
502 {
503 global_info.novalidate = 1;
504 }
505
506 if (misc)
507 register_global_command (misc);
508
509 if (arg_spec != LINE_special || !has_comment)
510 current = end_line (current);
511
512 if (cmd == CM_bye)
513 {
514 *status = FINISHED_TOTALLY;
515 goto funexit;
516 }
517
518 if (close_preformatted_command(cmd))
519 current = begin_preformatted (current);
520
521 *status = GET_A_NEW_LINE;
522 goto funexit;
523 }
524 else
525 {
526 ELEMENT *arg;
527
528 /* text, line, or a number.
529 (This includes handling of "@end", which is LINE_text.) */
530 if (cmd == CM_item_LINE || cmd == CM_itemx)
531 {
532 ELEMENT *parent;
533 if ((parent = item_line_parent (current)))
534 {
535 debug ("ITEM_LINE");
536 current = parent;
537 gather_previous_item (current, cmd);
538 }
539 else
540 {
541 line_error ("@%s outside of table or list",
542 cmd == CM_item_LINE ? "item" : "itemx");
543 current = begin_preformatted (current);
544 }
545 misc = new_element (ET_NONE);
546 misc->cmd = (cmd == CM_item_LINE) ? CM_item : CM_itemx;
547 misc->line_nr = line_nr;
548 add_to_element_contents (current, misc);
549 }
550 else
551 {
552 /* Add to contents */
553 misc = new_element (ET_NONE);
554 misc->cmd = cmd;
555 misc->line_nr = line_nr;
556
557 if (cmd == CM_subentry)
558 {
559 long level = 1;
560 ELEMENT *parent = current->parent;
561
562 if (!(command_flags(parent) & CF_index_entry_command)
563 && parent->cmd != CM_subentry)
564 {
565 line_warn ("@subentry should only occur in an index entry");
566 }
567
568 add_extra_element (parent, "subentry", misc);
569
570 if (parent->cmd == CM_subentry)
571 {
572 KEY_PAIR *k = lookup_extra (parent, "level");
573 if (k && k->value)
574 level = (long) k->value + 1;
575 }
576 add_extra_integer (misc, "level", level);
577 if (level > 2)
578 {
579 line_error
580 ("no more than two levels of index subentry are allowed");
581 }
582
583 /* Do not make the @subentry element a child of the index
584 command. This means that spaces are preserved properly
585 when converting back to Texinfo. */
586 current = end_line (current);
587 }
588
589 add_to_element_contents (current, misc);
590
591 if (command_data(cmd).flags & CF_sectioning)
592 {
593 if (global_info.sections_level)
594 {
595 add_extra_integer (misc, "sections_level",
596 global_info.sections_level);
597 }
598 }
599
600 /* @def*x */
601 if (command_data(cmd).flags & CF_def)
602 {
603 enum command_id base_command;
604 char *base_name;
605 int base_len;
606 int after_paragraph;
607
608 /* Find the command with "x" stripped from the end, e.g.
609 deffnx -> deffn. */
610 base_name = command_name(cmd);
611 add_extra_string_dup (misc, "original_def_cmdname", base_name);
612
613 base_name = strdup (base_name);
614 base_len = strlen (base_name);
615 if (base_name[base_len - 1] != 'x')
616 fatal ("no x at end of def command name");
617 base_name[base_len - 1] = '\0';
618 base_command = lookup_command (base_name);
619 if (base_command == CM_NONE)
620 fatal ("no def base command");
621 add_extra_string (misc, "def_command", base_name);
622
623 after_paragraph = check_no_text (current);
624 push_context (ct_def);
625 misc->type = ET_def_line;
626 if (current->cmd == base_command)
627 {
628 ELEMENT *e = pop_element_from_contents (current);
629 /* e should be the same as misc */
630 /* Gather an "inter_def_item" element. */
631 gather_def_item (current, cmd);
632 add_to_element_contents (current, e);
633 }
634 if (current->cmd != base_command || after_paragraph)
635 {
636 // error - deffnx not after deffn
637 line_error ("must be after `@%s' to use `@%s'",
638 command_name(base_command),
639 command_name(cmd));
640 add_extra_integer (misc, "not_after_command", 1);
641 }
642 }
643 }
644
645 /* change 'current' to its last child. This is ELEMENT *misc above. */
646 current = last_contents_child (current);
647 arg = new_element (ET_line_arg);
648 add_to_element_args (current, arg);
649
650 if (cmd == CM_node)
651 {
652 /* At most three comma-separated arguments to @node. This
653 is the only (non-block) line command taking comma-separated
654 arguments. Its arguments will be gathered the same as
655 those of some block line commands and brace commands. */
656 counter_push (&count_remaining_args, current, 3);
657 }
658 else if (cmd == CM_author)
659 {
660 ELEMENT *parent = current;
661 int found = 0;
662 while (parent->parent)
663 {
664 parent = parent->parent;
665 if (parent->type == ET_brace_command_context)
666 break;
667 if (parent->cmd == CM_titlepage)
668 {
669 add_extra_element (current, "titlepage", parent);
670 found = 1; break;
671 }
672 else if (parent->cmd == CM_quotation
673 || parent->cmd == CM_smallquotation)
674 {
675 KEY_PAIR *k; ELEMENT *e;
676 k = lookup_extra (parent, "authors");
677 if (k)
678 e = k->value;
679 else
680 {
681 e = new_element (ET_NONE);
682 add_extra_contents (parent, "authors", e);
683 }
684 add_to_contents_as_array (e, current);
685 add_extra_element (current, "quotation", parent);
686 found = 1; break;
687 }
688 }
689 if (!found)
690 line_warn ("@author not meaningful outside "
691 "`@titlepage' and `@quotation' environments");
692 }
693 else if (cmd == CM_dircategory && current_node)
694 line_warn ("@dircategory after first node");
695 else if (cmd == CM_printindex && current_node)
696 add_extra_integer (current_node, "isindex", 1);
697
698 current = last_args_child (current);
699
700 /* add 'line' to context_stack. This will be the
701 case while we read the argument on this line. */
702 if (!(command_data(cmd).flags & CF_def))
703 push_context (ct_line);
704 start_empty_line_after_command (current, &line, misc);
705 }
706
707 if (misc)
708 register_global_command (misc);
709 if (cmd == CM_dircategory)
710 add_to_contents_as_array (&global_info.dircategory_direntry, misc);
711
712 funexit:
713 *line_inout = line;
714 return current;
715 }
716
717
718 struct expanded_format {
719 char *format;
720 int expandedp;
721 };
722 static struct expanded_format expanded_formats[] = {
723 "html", 0,
724 "docbook", 0,
725 "plaintext", 1,
726 "tex", 0,
727 "xml", 0,
728 "info", 1,
729 };
730
731 void
clear_expanded_formats(void)732 clear_expanded_formats (void)
733 {
734 int i;
735 for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
736 i++)
737 {
738 expanded_formats[i].expandedp = 0;
739 }
740 }
741
742 void
add_expanded_format(char * format)743 add_expanded_format (char *format)
744 {
745 int i;
746 for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
747 i++)
748 {
749 if (!strcmp (format, expanded_formats[i].format))
750 {
751 expanded_formats[i].expandedp = 1;
752 break;
753 }
754 }
755 if (!strcmp (format, "plaintext"))
756 add_expanded_format ("info");
757 }
758
759 int
format_expanded_p(char * format)760 format_expanded_p (char *format)
761 {
762 int i;
763 for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
764 i++)
765 {
766 if (!strcmp (format, expanded_formats[i].format))
767 return expanded_formats[i].expandedp;
768 }
769 return 0;
770 }
771
772 /* A command name has been read that starts a multiline block, which should
773 end in @end <command name>. The block will be processed until
774 "end_line_misc_line" in end_line.c processes the @end command. */
775 ELEMENT *
handle_block_command(ELEMENT * current,char ** line_inout,enum command_id cmd,int * get_new_line)776 handle_block_command (ELEMENT *current, char **line_inout,
777 enum command_id cmd, int *get_new_line)
778 {
779 char *line = *line_inout;
780 unsigned long flags = command_data(cmd).flags;
781
782 /* New macro being defined. */
783 if (cmd == CM_macro || cmd == CM_rmacro)
784 {
785 ELEMENT *macro;
786 macro = parse_macro_command_line (cmd, &line, current);
787 add_to_element_contents (current, macro);
788 current = macro;
789
790 /* A new line should be read immediately after this. */
791 line = strchr (line, '\0');
792 *get_new_line = 1;
793 goto funexit;
794 }
795 else if (command_data(cmd).data == BLOCK_conditional)
796 {
797 int iftrue = 0; /* Whether the conditional is true. */
798 if (cmd == CM_ifclear || cmd == CM_ifset
799 || cmd == CM_ifcommanddefined || cmd == CM_ifcommandnotdefined)
800 {
801 char *p = line;
802 p = line + strspn (line, whitespace_chars);
803 if (!*p)
804 line_error ("@%s requires a name", command_name(cmd));
805 else
806 {
807 char *flag = read_flag_name (&p);
808 if (!flag)
809 goto bad_value;
810 else
811 {
812 p += strspn (p, whitespace_chars);
813 /* Check for a comment at the end of the line. */
814 if (memcmp (p, "@c", 2) == 0)
815 {
816 p += 2;
817 if (memcmp (p, "omment", 6) == 0)
818 p += 7;
819 if (*p && *p != '@' && !strchr (whitespace_chars, *p))
820 goto bad_value; /* @c or @comment not terminated. */
821 }
822 else if (*p)
823 goto bad_value; /* Trailing characters on line. */
824 }
825 if (1)
826 {
827 if (cmd == CM_ifclear || cmd == CM_ifset)
828 {
829 char *val = fetch_value (flag);
830 if (val)
831 iftrue = 1;
832 if (cmd == CM_ifclear)
833 iftrue = !iftrue;
834 }
835 else /* cmd == CM_ifcommanddefined
836 || cmd == CM_ifcommandnotdefined */
837 {
838 enum command_id c = lookup_command (flag);
839 if (c)
840 iftrue = 1;
841 if (cmd == CM_ifcommandnotdefined)
842 iftrue = !iftrue;
843 }
844 }
845 else if (0)
846 {
847 bad_value:
848 line_error ("bad name for @%s", command_name(cmd));
849 }
850 free (flag);
851 }
852 }
853 else if (!memcmp (command_name(cmd), "if", 2)) /* e.g. @ifhtml */
854 {
855 int i; char *p;
856 /* Handle @if* and @ifnot* */
857
858 p = command_name(cmd) + 2; /* After "if". */
859 if (!memcmp (p, "not", 3))
860 p += 3; /* After "not". */
861 for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
862 i++)
863 {
864 if (!strcmp (p, expanded_formats[i].format))
865 {
866 iftrue = expanded_formats[i].expandedp;
867 break;
868 }
869 }
870 if (!memcmp (command_name(cmd), "ifnot", 5))
871 iftrue = !iftrue;
872 }
873 else
874 bug_message ("unknown conditional command @%s", command_name(cmd));
875
876
877 /* If conditional true, push onto conditional stack. Otherwise
878 open a new element (which we shall later remove, in
879 process_remaining_on_line ("CLOSED conditional")). */
880
881 debug ("CONDITIONAL %s %d", command_name(cmd), iftrue);
882 if (iftrue)
883 push_conditional_stack (cmd);
884 else
885 {
886 /* Ignored. */
887 ELEMENT *e;
888 e = new_element (ET_NONE);
889 e->cmd = cmd;
890 add_to_element_contents (current, e);
891 current = e;
892 }
893 line = strchr (line, '\0');
894 *get_new_line = 1;
895 goto funexit;
896 }
897 else
898 {
899 ELEMENT *block = 0;
900 if (flags & CF_menu
901 && (current->type == ET_menu_comment
902 || current->type == ET_menu_entry_description))
903 {
904 /* This is for @detailmenu within @menu */
905 ELEMENT *menu = current->parent;
906 if (current->contents.number == 0)
907 destroy_element (pop_element_from_contents (menu));
908
909 if (pop_context () != ct_preformatted)
910 fatal ("preformatted context expected");
911 if (menu->type == ET_menu_entry)
912 menu = menu->parent;
913 current = menu;
914 }
915
916 if (flags & CF_def)
917 {
918 ELEMENT *def_line;
919 push_context (ct_def);
920 block = new_element (ET_NONE);
921 block->cmd = cmd;
922 block->line_nr = line_nr;
923 add_to_element_contents (current, block);
924 current = block;
925 def_line = new_element (ET_def_line);
926 def_line->line_nr = line_nr;
927 add_to_element_contents (current, def_line);
928 current = def_line;
929 add_extra_string_dup (current, "def_command", command_name(cmd));
930 add_extra_string_dup (current, "original_def_cmdname",
931 command_name(cmd));
932 }
933 else
934 {
935 block = new_element (ET_NONE);
936
937 block->cmd = cmd;
938 add_to_element_contents (current, block);
939 current = block;
940 }
941
942 /* Check if 'block args command' */
943 if (command_data(cmd).data != BLOCK_raw)
944 {
945 if (command_data(cmd).flags & CF_preformatted)
946 push_context (ct_preformatted);
947 else if (cmd == CM_displaymath)
948 push_context (ct_math);
949 else if (command_data(cmd).flags & CF_format_raw)
950 {
951 push_context (ct_rawpreformatted);
952 if (!format_expanded_p (command_name(cmd)))
953 {
954 ELEMENT *e;
955 enum command_id dummy;
956 char *line_dummy;
957
958 e = new_element (ET_elided_block);
959 add_to_element_contents (current, e);
960 line_dummy = line;
961 while (!is_end_current_command (current,
962 &line_dummy, &dummy))
963 {
964 line = new_line ();
965 if (!line)
966 {
967 line = "";
968 break;
969 }
970 line_dummy = line;
971 }
972 e = new_element (ET_empty_line_after_command);
973 text_append_n (&e->text, "\n", 1);
974 add_to_element_contents (current, e);
975
976 e = new_element (ET_empty_line);
977 text_append (&e->text, "");
978 add_to_element_contents (current, e);
979 goto funexit;
980 }
981 }
982 else if (command_data(cmd).data == BLOCK_region)
983 {
984 if (current_region_cmd ())
985 {
986 line_error ("region %s inside region %s is not allowed",
987 command_name(cmd),
988 command_name(current_region_cmd ()));
989 }
990 push_region (block);
991 }
992
993 if (command_data(cmd).flags & CF_menu)
994 {
995 if (current_context () == ct_preformatted)
996 push_context (ct_preformatted);
997 else
998 push_context (ct_menu);
999
1000 if (cmd == CM_direntry)
1001 add_to_contents_as_array (&global_info.dircategory_direntry,
1002 block);
1003
1004 if (current_node)
1005 {
1006 if (cmd == CM_direntry && conf.show_menu)
1007 {
1008 line_warn ("@direntry after first node");
1009 }
1010 else if (cmd == CM_menu)
1011 {
1012 if (!(command_flags(current->parent) & CF_root))
1013 line_warn ("@menu in invalid context");
1014 /* Add to array of menus for current node. Currently
1015 done in Perl code. */
1016 }
1017 }
1018 }
1019
1020 if (cmd == CM_itemize || cmd == CM_enumerate)
1021 counter_push (&count_items, current, 0);
1022 /* Note that no equivalent thing is done in the Perl code, because
1023 'item_count' is assumed to start at 0. */
1024
1025 {
1026 ELEMENT *bla = new_element (ET_block_line_arg);
1027 add_to_element_args (current, bla);
1028
1029 if (command_data (current->cmd).data > 1)
1030 {
1031 counter_push (&count_remaining_args,
1032 current,
1033 command_data (current->cmd).data - 1);
1034 }
1035 else if (command_data (current->cmd).data == BLOCK_variadic)
1036 {
1037 /* Unlimited args */
1038 counter_push (&count_remaining_args, current,
1039 COUNTER_VARIADIC);
1040 }
1041
1042 current = bla;
1043 if (!(command_data(cmd).flags & CF_def))
1044 push_context (ct_line);
1045
1046 /* Note that an ET_empty_line_after_command gets reparented in the
1047 contents in 'end_line'. */
1048
1049 }
1050 }
1051 block->line_nr = line_nr;
1052 register_global_command (block);
1053 start_empty_line_after_command (current, &line, block);
1054 }
1055
1056 funexit:
1057 *line_inout = line;
1058 return current;
1059 }
1060
1061 ELEMENT *
handle_brace_command(ELEMENT * current,char ** line_inout,enum command_id cmd)1062 handle_brace_command (ELEMENT *current, char **line_inout, enum command_id cmd)
1063 {
1064 char *line = *line_inout;
1065 ELEMENT *e;
1066
1067 e = new_element (ET_NONE);
1068 e->cmd = cmd;
1069
1070 /* The line number information is only ever used for brace commands
1071 if the command is given with braces, but it's easier just to always
1072 store the information. */
1073 e->line_nr = line_nr;
1074
1075 add_to_element_contents (current, e);
1076
1077 if (cmd == CM_sortas)
1078 {
1079 if (!(command_flags(current->parent) & CF_index_entry_command)
1080 && current->parent->cmd != CM_subentry)
1081 {
1082 line_warn ("@%s should only appear in an index entry",
1083 command_name(cmd));
1084 }
1085 }
1086
1087 current = e;
1088
1089 if (cmd == CM_click)
1090 {
1091 add_extra_string_dup (e, "clickstyle", global_clickstyle);
1092 }
1093 else if (cmd == CM_kbd)
1094 {
1095 if (current_context () == ct_preformatted
1096 && global_kbdinputstyle != kbd_distinct
1097 || global_kbdinputstyle == kbd_code)
1098 {
1099 add_extra_integer (e, "code", 1);
1100 }
1101 else if (global_kbdinputstyle == kbd_example)
1102 {
1103 /* TODO: Understand what is going on here. */
1104 ELEMENT *tmp = current->parent;
1105 while (tmp->parent
1106 && (command_flags(tmp->parent) & CF_brace)
1107 && command_data(tmp->parent->cmd).data != BRACE_context)
1108 {
1109 if (command_flags(tmp->parent) & CF_code_style)
1110 {
1111 add_extra_integer (e, "code", 1);
1112 break;
1113 }
1114 tmp = tmp->parent->parent;
1115 }
1116 }
1117 }
1118 else if (command_data(cmd).flags & CF_INFOENCLOSE)
1119 {
1120 INFO_ENCLOSE *ie = lookup_infoenclose (cmd);
1121 if (ie)
1122 {
1123 add_extra_string_dup (e, "begin", ie->begin);
1124 add_extra_string_dup (e, "end", ie->end);
1125 }
1126 e->type = ET_definfoenclose_command;
1127 }
1128
1129 *line_inout = line;
1130 return current;
1131 }
1132