1 /* end_line.c -- what to do at the end of a whole line of input */
2 /* Copyright 2010-2019 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 #include <ctype.h>
21 
22 #include "parser.h"
23 #include "text.h"
24 #include "input.h"
25 #include "convert.h"
26 #include "labels.h"
27 #include "indices.h"
28 
29 void
check_internal_node(NODE_SPEC_EXTRA * nse)30 check_internal_node (NODE_SPEC_EXTRA *nse)
31 {
32   if (nse && nse->manual_content
33       && nse->manual_content->contents.number > 0)
34     {
35       char *texi = node_extra_to_texi (nse);
36       line_error ("syntax for an external node used for `%s'", texi);
37       free (texi);
38     }
39 }
40 
41 int
check_empty_node(NODE_SPEC_EXTRA * nse,enum command_id cmd)42 check_empty_node (NODE_SPEC_EXTRA *nse,
43                   enum command_id cmd)
44 {
45   if (!nse || !nse->node_content || nse->node_content->contents.number == 0)
46     {
47       line_error ("empty argument in @%s", command_name(cmd));
48       return 0;
49     }
50   else
51     return 1;
52 }
53 
54 int
check_node_label(NODE_SPEC_EXTRA * nse,enum command_id cmd)55 check_node_label (NODE_SPEC_EXTRA *nse,
56                   enum command_id cmd)
57 {
58   check_internal_node (nse);
59   return check_empty_node (nse, cmd);
60 }
61 
62 static int
is_decimal_number(char * string)63 is_decimal_number (char *string)
64 {
65   char *p = string;
66   char *first_digits = 0;
67   char *second_digits = 0;
68 
69   if (string[0] == '\0')
70     return 0;
71 
72   if (strchr (digit_chars, *p))
73     p = first_digits = string + strspn (string, digit_chars);
74 
75   if (*p == '.')
76     {
77       p++;
78       if (strchr (digit_chars, *p))
79         p = second_digits = p + strspn (p, digit_chars);
80     }
81 
82   if (*p /* Bytes remaining at end of argument. */
83       || (!first_digits && !second_digits)) /* Need digits either
84                                                before or after the
85                                                decimal point. */
86     {
87       return 0;
88     }
89 
90   return 1;
91 }
92 
93 static int
is_whole_number(char * string)94 is_whole_number (char *string)
95 {
96   if (string[strspn (string, digit_chars)] == '\0')
97     return 1;
98   return 0;
99 }
100 
101 /* Return end of argument before comment and whitespace. */
102 char *
skip_comment(char * q,int * has_comment)103 skip_comment (char *q, int *has_comment)
104 {
105   char *q1;
106   while (1)
107     {
108       q1 = strstr (q, "@c");
109       if (!q1)
110         {
111           q = q + strlen (q);
112           break;
113         }
114       q = q1 + 2;
115       if (!memcmp (q, "omment", 6))
116         q += 6;
117 
118       /* TeX control sequence name ends at an escape character or
119          whitespace. */
120       if (*q == '@' || strchr (whitespace_chars, *q))
121         {
122           q = q1;
123           *has_comment = 1;
124           break;
125         }
126     }
127 
128   /* q is now either at the end of the string, or at the start of a comment.
129      Find the start of any trailing whitespace. */
130   while (strchr (whitespace_chars, q[-1]))
131     q--;
132 
133   return q;
134 }
135 
136 /* Process argument to special line command. */
137 ELEMENT *
parse_special_misc_command(char * line,enum command_id cmd,int * has_comment)138 parse_special_misc_command (char *line, enum command_id cmd, int *has_comment)
139 {
140 #define ADD_ARG(string, len) do { \
141   ELEMENT *E = new_element (ET_NONE); \
142   text_append_n (&E->text, string, len); \
143   add_to_element_contents (args, E); \
144 } while (0)
145 
146   ELEMENT *args = new_element (ET_NONE);
147   char *p = 0, *q = 0, *r = 0;
148   char *value = 0, *remaining = 0;;
149 
150   switch (cmd)
151     {
152     case CM_set:
153       {
154       p = line;
155       p += strspn (p, whitespace_chars);
156       if (!*p)
157         goto set_no_name;
158       if (!isalnum (*p) && *p != '-' && *p != '_')
159         goto set_invalid;
160       q = strpbrk (p,
161                    " \t\f\r\n"       /* whitespace */
162                    "{\\}~^+\"<>|@"); /* other bytes that aren't allowed */
163       /* see also read_flag_name function in end_line.c */
164 
165       r = skip_comment (p, has_comment);
166 
167       if (!strchr (whitespace_chars, *q) && *q != '@')
168         goto set_invalid;
169 
170       if (*q == '@')
171         {
172           /* Check for a comment, e.g. "@set flag@c comment" */
173           if (q != r)
174             goto set_invalid;
175         }
176 
177       ADD_ARG(p, q - p); /* name */
178 
179       p = q + strspn (q, whitespace_chars);
180       /* Actually, whitespace characters except form feed. */
181 
182       if (r >= p)
183         ADD_ARG(p, r - p); /* value */
184       else
185         ADD_ARG("", 0);
186 
187       store_value (args->contents.list[0]->text.text,
188                    args->contents.list[1]->text.text);
189 
190       break;
191 set_no_name:
192       line_error ("@set requires a name");
193       break;
194 set_invalid:
195       line_error ("bad name for @set");
196       break;
197       }
198     case CM_clear:
199       {
200       char *flag = 0;
201       p = line;
202       p += strspn (p, whitespace_chars);
203       if (!*p)
204         goto clear_no_name;
205       q = p;
206       flag = read_flag_name (&q);
207       if (!flag)
208         goto clear_invalid;
209       r = q + strspn (q, whitespace_chars);
210       if (*r)
211         goto clear_invalid; /* Trailing argument. */
212 
213       ADD_ARG (p, q - p);
214       clear_value (flag);
215       free (flag);
216 
217       break;
218 clear_no_name:
219       line_error ("@clear requires a name");
220       break;
221 clear_invalid:
222       free (flag);
223       line_error ("bad name for @clear");
224       break;
225       }
226     case CM_unmacro:
227       p = line;
228       p += strspn (p, whitespace_chars);
229       if (!*p)
230         goto unmacro_noname;
231       q = p;
232       value = read_command_name (&q);
233       if (!value)
234         goto unmacro_badname;
235       /* FIXME: Check comment syntax is right */
236       delete_macro (value);
237       ADD_ARG(value, q - p);
238       debug ("UNMACRO %s", value);
239       free (value);
240       break;
241 unmacro_noname:
242       line_error ("@unmacro requires a name");
243       break;
244 unmacro_badname:
245       line_error ("bad name for @unmacro");
246       break;
247     case CM_clickstyle:
248       p = line;
249       p += strspn (p, whitespace_chars);
250       if (*p++ != '@')
251         goto clickstyle_invalid;
252       q = p;
253       value = read_command_name (&q);
254       if (!value)
255         goto clickstyle_invalid;
256       ADD_ARG (p - 1, q - p + 1);
257       free (global_clickstyle); global_clickstyle = value;
258       if (!memcmp (q, "{}", 2))
259         q += 2;
260       remaining = q;
261       /* FIXME: check comment */
262       break;
263 clickstyle_invalid:
264       line_error ("@clickstyle should only accept an @-command as argument, "
265                    "not `%s'", line);
266       free (value);
267       break;
268     default:
269       fatal ("unknown special line command");
270     }
271 
272   if (remaining)
273     {
274       remaining += strspn (remaining, whitespace_chars);
275       if (*remaining)
276         {
277           line_warn ("remaining argument on @%s line: %s",
278                      command_name(cmd), remaining);
279         }
280     }
281   return args;
282 #undef ADD_ARG
283 }
284 
285 /* Parse the arguments to a line command.  Return an element whose contents
286    is an array of the arguments.  For some commands, there is further
287    processing of the arguments (for example, for an @alias, remember the
288    alias.) */
289 ELEMENT *
parse_line_command_args(ELEMENT * line_command)290 parse_line_command_args (ELEMENT *line_command)
291 {
292 #define ADD_ARG(string) do { \
293     ELEMENT *E = new_element (ET_NONE); \
294     text_append (&E->text, string); \
295     add_to_element_contents (line_args, E); \
296 } while (0)
297 
298   ELEMENT *arg = line_command->args.list[0];
299   ELEMENT *line_args;
300   enum command_id cmd;
301   char *line;
302 
303   cmd = line_command->cmd;
304   if (arg->contents.number == 0)
305    {
306      command_error (line_command, "@%s missing argument", command_name(cmd));
307      add_extra_integer (line_command, "missing_argument", 1);
308      return 0;
309    }
310 
311   if (arg->contents.number > 1 || arg->contents.list[0]->text.end == 0)
312     {
313       line_error ("superfluous argument to @%s", command_name (cmd));
314     }
315   if (arg->contents.list[0]->text.end == 0)
316     return 0;
317 
318   line_args = new_element (ET_NONE);
319   line = arg->contents.list[0]->text.text;
320 
321   switch (cmd)
322     {
323     case CM_alias:
324       {
325         /* @alias NEW = EXISTING */
326         char *new = 0, *existing = 0;
327         enum command_id new_cmd, existing_cmd;
328 
329         new = read_command_name (&line);
330         if (!new)
331           goto alias_invalid;
332 
333         line += strspn (line, whitespace_chars);
334         if (*line != '=')
335           goto alias_invalid;
336         line++;
337         line += strspn (line, whitespace_chars);
338 
339         if (!isalnum (*line))
340           goto alias_invalid;
341         existing = read_command_name (&line);
342         if (!existing)
343           goto alias_invalid;
344 
345         if (*line)
346           goto alias_invalid; /* Trailing argument. */
347 
348         ADD_ARG(new);
349         ADD_ARG(existing);
350 
351         existing_cmd = lookup_command (existing);
352         if (!existing_cmd)
353           break; /* TODO: Error message */
354         else
355           {
356             if (command_data(existing_cmd).flags & CF_block)
357               line_warn ("environment command %s as argument to @alias",
358                          command_name(existing_cmd));
359           }
360 
361         /* Remember the alias. */
362         new_cmd = add_texinfo_command (new);
363         new_cmd &= ~USER_COMMAND_BIT;
364         user_defined_command_data[new_cmd].flags |= CF_ALIAS;
365 
366         user_defined_command_data[new_cmd].data = existing_cmd;
367         /* Note the data field is an int, existing_cmd is
368            enum command_id, so would have problems if enum command_id
369            were wider than an int. */
370 
371         free (new); free (existing);
372 
373         break;
374       alias_invalid:
375         line_error ("bad argument to @alias");
376         free (new); free (existing);
377         break;
378       }
379     case CM_definfoenclose:
380       {
381         /* @definfoenclose phoo,//,\\ */
382         char *new_command = 0, *start = 0, *end = 0;
383         enum command_id new_cmd;
384         int len;
385 
386         new_command = read_command_name (&line);
387         if (!new_command)
388           goto definfoenclose_invalid;
389 
390         line += strspn (line, whitespace_chars);
391         if (*line != ',')
392           goto definfoenclose_invalid;
393         line++;
394         line += strspn (line, whitespace_chars);
395 
396         /* TODO: Can we have spaces in the delimiters? */
397         len = strcspn (line, ",");
398         start = strndup (line, len);
399         line += len;
400 
401         if (!*line)
402           goto definfoenclose_invalid; /* Not enough args. */
403         line++; /* Past ','. */
404         line += strspn (line, whitespace_chars);
405         len = strcspn (line, ",");
406         end = strndup (line, len);
407 
408         if (*line == ',')
409           goto definfoenclose_invalid; /* Too many args. */
410 
411         /* Remember it. */
412         new_cmd = add_texinfo_command (new_command);
413         add_infoenclose (new_cmd, start, end);
414         new_cmd &= ~USER_COMMAND_BIT;
415 
416         user_defined_command_data[new_cmd].flags
417           |= (CF_INFOENCLOSE | CF_brace);
418         user_defined_command_data[new_cmd].data = BRACE_style;
419 
420         ADD_ARG(new_command); free (new_command);
421         ADD_ARG(start); free (start);
422         ADD_ARG(end); free (end);
423 
424         break;
425       definfoenclose_invalid:
426         line_error ("bad argument to @definfoenclose");
427         free (new_command); free (start); free (end);
428         break;
429       }
430     case CM_columnfractions:
431       {
432         /*  @multitable @columnfractions .33 .33 .33 */
433         ELEMENT *new;
434         char *p, *q;
435 
436         if (!*line)
437           {
438             line_error ("empty @columnfractions");
439             break;
440           }
441         p = line;
442         while (1)
443           {
444             char *arg;
445 
446             p += strspn (p, whitespace_chars);
447             if (!*p)
448               break;
449             q = strpbrk (p, whitespace_chars);
450             if (!q)
451               q = p + strlen (p);
452 
453             arg = strndup (p, q - p);
454 
455             /* Check argument is valid. */
456             if (!is_decimal_number (arg))
457               {
458                 line_error ("column fraction not a number: %s", arg);
459               }
460             else
461               {
462                 new = new_element (ET_NONE);
463                 text_append_n (&new->text, p, q - p);
464                 add_to_element_contents (line_args, new);
465               }
466             free (arg);
467             p = q;
468           }
469         break;
470       }
471     case CM_sp:
472       {
473         /* Argument is at least one digit. */
474         if (strchr (digit_chars, *line)
475             && !*(line + 1 + strspn (line + 1, digit_chars)))
476           {
477             ADD_ARG(line);
478           }
479         else
480           line_error ("@sp arg must be numeric, not `%s'", line);
481         break;
482       }
483     case CM_defindex:
484     case CM_defcodeindex:
485       {
486         char *name = 0;
487         char *p = line;
488 
489         name = read_command_name (&p);
490         if (*p)
491           goto defindex_invalid; /* Trailing characters. */
492 
493         /* Disallow index names NAME where it is likely that for
494            a source file BASE.texi, there will be other files called
495            BASE.NAME in the same directory.  This is to prevent such
496            files being overwritten by the files read by texindex. */
497         {
498           static char *forbidden_index_names[] = {
499             "cp", "fn", "ky", "pg", "tp", "vr",
500             "cps", "fns", "kys", "pgs", "tps", "vrs",
501             "info", "ps", "pdf", "htm", "html",
502             "log", "aux", "dvi", "texi", "txi",
503             "texinfo", "tex", "bib", 0
504           };
505           char **ptr;
506           for (ptr = forbidden_index_names; *ptr; ptr++)
507             if (!strcmp (name, *ptr))
508               goto defindex_reserved;
509 
510           if (index_by_name (name))
511             { free (name); break; }
512         }
513 
514         add_index (name, cmd == CM_defcodeindex ? 1 : 0);
515         ADD_ARG(name);
516 
517         break;
518       defindex_invalid:
519         line_error ("bad argument to @%s: %s",
520                      command_name(cmd), line);
521         free (name);
522         break;
523       defindex_reserved:
524         line_error ("reserved index name %s", name);
525         free (name);
526         break;
527       }
528     case CM_synindex:
529     case CM_syncodeindex:
530       {
531         /* synindex FROM TO */
532         char *from = 0, *to = 0;
533         INDEX *from_index, *to_index;
534         char *p = line;
535 
536         if (!isalnum (*p))
537           goto synindex_invalid;
538         from = read_command_name (&p);
539         if (!from)
540           goto synindex_invalid;
541 
542         p += strspn (p, whitespace_chars);
543 
544         if (!isalnum (*p))
545           goto synindex_invalid;
546         to = read_command_name (&p);
547         if (!to)
548           goto synindex_invalid;
549         if (*p)
550           goto synindex_invalid; /* More at end of line. */
551 
552         from_index = index_by_name (from);
553         to_index = index_by_name (to);
554         if (!from_index)
555           line_error ("unknown source index in @%s: %s",
556                       command_name(cmd), from);
557         if (!to_index)
558           line_error ("unknown destination index in @%s: %s",
559                       command_name(cmd), to);
560 
561         if (from_index && to_index)
562           {
563             INDEX *current_to = to_index;
564             /* Find ultimate index this merges to. */
565             current_to = ultimate_index (current_to);
566 
567             if (current_to != from_index)
568               {
569                 from_index->merged_in = current_to;
570                 from_index->in_code = (cmd == CM_syncodeindex);
571                 ADD_ARG(from);
572                 ADD_ARG(to);
573                 /* Note that 'current_to' may not end up as the index
574                    'from_index' merges into if there are further @synindex
575                    commands. */
576               }
577             else
578               line_warn ("@%s leads to a merging of %s in itself, ignoring",
579                           command_name(cmd), from);
580           }
581 
582         free (from);
583         free (to);
584 
585         break;
586       synindex_invalid:
587         line_error ("bad argument to @%s: %s",
588                      command_name(cmd), line);
589         free (from); free (to);
590         break;
591       }
592     case CM_printindex:
593       {
594         char *arg;
595         char *p = line;
596         arg = read_command_name (&p);
597         if (!arg || *p)
598           line_error ("bad argument to @printindex: %s", line);
599         else
600           {
601             INDEX *idx = index_by_name (arg);
602             if (!idx)
603               line_error ("unknown index `%s' in @printindex", arg);
604             else
605               {
606                 if (idx->merged_in)
607                   {
608                     INDEX *i2;
609                     for (i2 = idx; (i2->merged_in); i2 = i2->merged_in)
610                       ;
611                     line_warn
612                       ("printing an index `%s' merged in another one, `%s'",
613                        arg, i2->name);
614                   }
615                 if (!current_node && !current_section && !current_region ())
616                   {
617                     line_warn ("printindex before document beginning: "
618                                 "@printindex %s", arg);
619                   }
620                 ADD_ARG (arg);
621               }
622           }
623         free (arg);
624         break;
625       }
626     case CM_everyheadingmarks:
627     case CM_everyfootingmarks:
628     case CM_evenheadingmarks:
629     case CM_oddheadingmarks:
630     case CM_evenfootingmarks:
631     case CM_oddfootingmarks:
632       {
633         if (!strcmp (line, "top") || !strcmp (line, "bottom"))
634           {
635             ADD_ARG (line);
636           }
637         else
638           line_error ("@%s arg must be `top' or `bottom', not `%s'",
639                        command_name(cmd), line);
640 
641         break;
642       }
643     case CM_fonttextsize:
644       {
645         if (!strcmp (line, "10") || !strcmp (line, "11"))
646           {
647             ADD_ARG (line);
648           }
649         else
650           line_error ("Only @fonttextsize 10 or 11 is supported, not "
651                        "`%s'", line);
652         break;
653       }
654     case CM_footnotestyle:
655       {
656         if (!strcmp (line, "separate") || !strcmp (line, "end"))
657           {
658             ADD_ARG(line);
659           }
660         else
661           line_error ("@footnotestyle arg must be "
662                        "`separate' or `end', not `%s'", line);
663         break;
664       }
665     case CM_setchapternewpage:
666       {
667         if (!strcmp (line, "on") || !strcmp (line, "off")
668             || !strcmp (line, "odd"))
669           {
670             ADD_ARG(line);
671           }
672         else
673           line_error ("@setchapternewpage arg must be "
674                        "`on', `off' or `odd', not `%s'", line);
675         break;
676       }
677     case CM_need:
678       {
679         /* valid: 2, 2., .2, 2.2 */
680 
681         if (is_decimal_number (line))
682           ADD_ARG(line);
683         else
684           line_error ("bad argument to @need: %s", line);
685 
686         break;
687       }
688     case CM_paragraphindent:
689       {
690         if (!strcmp (line, "none") || !strcmp (line, "asis")
691             || is_whole_number (line))
692           ADD_ARG(line);
693         else
694           line_error ("@paragraphindent arg must be "
695                        "numeric/`none'/`asis', not `%s'", line);
696         break;
697       }
698     case CM_firstparagraphindent:
699       {
700         if (!strcmp (line, "none") || !strcmp (line, "insert"))
701           {
702             ADD_ARG(line);
703           }
704         else
705           line_error ("@firstparagraph arg must be "
706                        "`none' or `insert', not `%s'", line);
707 
708         break;
709       }
710     case CM_exampleindent:
711       {
712         if (!strcmp (line, "asis") || is_whole_number (line))
713           ADD_ARG(line);
714         else
715           line_error ("@exampleindent arg must be "
716                        "numeric/`asis', not `%s'", line);
717         break;
718       }
719     case CM_frenchspacing:
720     case CM_xrefautomaticsectiontitle:
721     case CM_codequoteundirected:
722     case CM_codequotebacktick:
723     case CM_deftypefnnewline:
724       {
725         if (!strcmp (line, "on") || !strcmp (line, "off"))
726           {
727             ADD_ARG(line);
728           }
729         else
730           line_error ("expected @%s on or off, not `%s'",
731                       command_name(cmd), line);
732 
733         break;
734       }
735     case CM_kbdinputstyle:
736       {
737         if (!strcmp (line, "code"))
738           global_kbdinputstyle = kbd_code;
739         else if (!strcmp (line, "example"))
740           global_kbdinputstyle = kbd_example;
741         else if (!strcmp (line, "distinct"))
742           global_kbdinputstyle = kbd_distinct;
743         else goto kdbinputstyle_invalid;
744 
745         ADD_ARG(line);
746 
747         if (0)
748           {
749 kdbinputstyle_invalid:
750           line_error ("@kbdinputstyle arg must be "
751                        "`code'/`example'/`distinct', not `%s'", line);
752           }
753         break;
754       }
755     case CM_allowcodebreaks:
756       {
757         if (!strcmp (line, "true") || !strcmp (line, "false"))
758           {
759             ADD_ARG(line);
760           }
761         else
762           line_error ("@allowcodebreaks arg must be "
763                        "`true' or `false', not `%s'", line);
764         break;
765       }
766     case CM_urefbreakstyle:
767       {
768         if (!strcmp (line, "after") || !strcmp (line, "before")
769             || !strcmp (line, "none"))
770           {
771             ADD_ARG(line);
772           }
773         else
774           line_error ("@urefbreakstyle arg must be "
775                        "`after'/`before'/`none', not `%s'", line);
776         break;
777       }
778     case CM_headings:
779       {
780         if (!strcmp (line, "off") || !strcmp (line, "on")
781             || !strcmp (line, "double") || !strcmp (line, "singleafter")
782             || !strcmp (line, "doubleafter"))
783           {
784             ADD_ARG(line);
785           }
786         else
787           line_error ("bad argument to @headings: %s", line);
788         break;
789       }
790     default:
791       ;
792     }
793   if (line_args->contents.number == 0)
794     {
795       destroy_element (line_args);
796       return 0;
797     }
798   else
799     return line_args;
800 
801 #undef ADD_ARG
802 }
803 
804 /* NODE->contents is the Texinfo for the specification of a node.  This
805    function sets three fields on the returned object:
806 
807      manual_content - Texinfo tree for a manual name extracted from the
808                       node specification.
809      node_content - Texinfo tree for the node name on its own
810      normalized - a string with the node name after HTML node name
811                   normalization is applied
812 
813    Objects returned from this function are used as an 'extra' key in a
814    few places: the elements of a 'nodes_manuals' array (itself an extra key),
815    the 'menu_entry_node' key on a 'menu_entry' element (not to be confused
816    with an ET_menu_entry_node element, which occurs in the args of a
817    'menu_entry' element), and in the 'node_argument' key of a cross-reference
818    command (like @xref). */
819 NODE_SPEC_EXTRA *
parse_node_manual(ELEMENT * node)820 parse_node_manual (ELEMENT *node)
821 {
822   NODE_SPEC_EXTRA *result;
823   ELEMENT *new;
824   int idx = 0; /* index into node->contents */
825 
826   result = malloc (sizeof (NODE_SPEC_EXTRA));
827   result->manual_content = result->node_content = 0;
828 
829   /* If the content starts with a '(', try to get a manual name. */
830   if (node->contents.number > 0 && node->contents.list[0]->text.end > 0
831       && node->contents.list[0]->text.text[0] == '(')
832     {
833       ELEMENT *manual, *first;
834       char *opening_bracket, *closing_bracket;
835 
836       /* Handle nested parentheses in the manual name, for whatever reason. */
837       int bracket_count = 1; /* Number of ( seen minus number of ) seen. */
838 
839       manual = new_element (ET_NONE);
840 
841       /* If the first contents element is "(" followed by more text, split
842          the leading "(" into its own element. */
843       first = node->contents.list[0];
844       if (first->text.end > 1)
845         {
846           memmove (first->text.text, first->text.text + 1, first->text.end);
847           first->text.end--;
848           new = new_element (0);
849           text_append_n (&new->text, "(", 1);
850           insert_into_contents (node, new, 0);
851         }
852       idx++;
853 
854       for (; idx < node->contents.number; idx++)
855         {
856           ELEMENT *e = node->contents.list[idx];
857           char *p, *q;
858 
859           if (e->text.end == 0)
860             {
861               /* Put this element in the manual contents. */
862               add_to_contents_as_array (manual, e);
863               continue;
864             }
865           p = e->text.text;
866           while (p < e->text.text + e->text.end
867                  && bracket_count > 0)
868             {
869               opening_bracket = strchr (p, '(');
870               closing_bracket = strchr (p, ')');
871               if (!opening_bracket && !closing_bracket)
872                 {
873                   break;
874                 }
875               else if (opening_bracket && !closing_bracket)
876                 {
877                   bracket_count++;
878                   p = opening_bracket + 1;
879                 }
880               else if (!opening_bracket && closing_bracket)
881                 {
882                   bracket_count--;
883                   p = closing_bracket + 1;
884                 }
885               else if (opening_bracket < closing_bracket)
886                 {
887                   bracket_count++;
888                   p = opening_bracket + 1;
889                 }
890               else if (opening_bracket > closing_bracket)
891                 {
892                   bracket_count--;
893                   p = closing_bracket + 1;
894                 }
895             }
896 
897           if (bracket_count > 0)
898             add_to_contents_as_array (manual, e);
899           else /* end of filename component */
900             {
901               /* Split the element in two, putting the part before the ")"
902                  in the manual name, leaving the part afterwards for the
903                  node name. */
904               remove_from_contents (node, idx); /* Remove 'e'. */
905 
906               p--; /* point at ) */
907               if (p > e->text.text)
908                 {
909                   /* text before ), part of the manual name */
910                   new = new_element (ET_NONE);
911                   text_append_n (&new->text, e->text.text,
912                                  p - e->text.text);
913                   insert_into_contents (node, new, idx++);
914 
915                   add_to_contents_as_array (manual, new);
916                 }
917 
918               new = new_element (0);
919               text_append_n (&new->text, ")", 1);
920               insert_into_contents (node, new, idx++);
921 
922               /* Skip ')' and any following whitespace.
923                  Note that we don't manage to skip any multibyte
924                  UTF-8 space characters here. */
925               p++;
926               q = p + strspn (p, whitespace_chars);
927               if (q > p)
928                 {
929                   new = new_element (0);
930                   text_append_n (&new->text, p, q - p);
931                   insert_into_contents (node, new, idx++);
932                 }
933 
934               p = q;
935               if (*p)
936                 {
937                   /* text after ), part of the node name. */
938                   new = new_element (ET_NONE);
939                   text_append_n (&new->text, p,
940                                  e->text.text + e->text.end - p);
941                   insert_into_contents (node, new, idx);
942                 }
943               destroy_element (e);
944               break;
945             }
946         } /* for */
947 
948       if (bracket_count == 0)
949         result->manual_content = manual;
950       else /* unbalanced */
951         {
952           destroy_element (manual);
953           idx = 0; /* Back to the start, and consider the whole thing
954                       as a node name. */
955         }
956     }
957 
958   /* If anything left, it is the node name. */
959   if (idx < node->contents.number)
960     {
961       new = new_element (0);
962       insert_slice_into_contents (new, 0, node, idx, node->contents.number);
963       result->node_content = new;
964     }
965 
966   return result;
967 }
968 
969 /* Array of recorded @float's. */
970 FLOAT_RECORD *floats_list = 0;
971 size_t floats_number = 0;
972 size_t floats_space = 0;
973 
974 int
parse_float_type(ELEMENT * current)975 parse_float_type (ELEMENT *current)
976 {
977   EXTRA_FLOAT_TYPE *eft;
978   eft = malloc (sizeof (EXTRA_FLOAT_TYPE));
979   eft->content = 0;
980   eft->normalized = 0;
981 
982   if (current->args.number > 0)
983     {
984       if (current->args.list[0]->contents.number > 0)
985         {
986           char *normalized;
987           normalized = convert_to_texinfo (current->args.list[0]);
988           eft->content = current->args.list[0];
989           eft->normalized = normalized;
990 
991           add_extra_float_type (current, "type", eft);
992           return 1;
993         }
994     }
995   eft->normalized = strdup ("");
996   add_extra_float_type (current, "type", eft);
997   return 0;
998 }
999 
1000 /* Actions to be taken at the end of a line that started a block that
1001    has to be ended with "@end". */
1002 ELEMENT *
end_line_starting_block(ELEMENT * current)1003 end_line_starting_block (ELEMENT *current)
1004 {
1005   enum context c;
1006   c = pop_context ();
1007   if (c != ct_line)
1008     fatal ("line context expected");
1009 
1010   if (current->parent->cmd == CM_multitable)
1011     {
1012       /* Parse prototype row for a @multitable.  Handling
1013          of @columnfractions is done elsewhere. */
1014 
1015       int i;
1016       ELEMENT *prototypes = new_element (ET_NONE);
1017 
1018       for (i = 0; i < current->contents.number; i++)
1019         {
1020           ELEMENT *e = contents_child_by_index(current, i);
1021 
1022           if (e->type == ET_bracketed)
1023             {
1024               /* Copy and change the type of the element. */
1025 
1026               ELEMENT *new;
1027               new = malloc (sizeof (ELEMENT));
1028               memcpy (new, e, sizeof (ELEMENT));
1029               new->type = ET_bracketed_multitable_prototype;
1030               new->parent = 0;
1031               new->extra_number = 0;
1032               add_to_contents_as_array (prototypes, new);
1033             }
1034           else if (e->text.end > 0)
1035             {
1036               /* Split the text up by whitespace. */
1037               char *p, *p2;
1038               p = e->text.text;
1039               while (1)
1040                 {
1041                   ELEMENT *new;
1042                   p2 = p + strspn (p, whitespace_chars);
1043                   if (!*p2)
1044                     break;
1045                   p = p2 + strcspn (p2, whitespace_chars);
1046                   new = new_element (ET_row_prototype);
1047                   text_append_n (&new->text, p2, p - p2);
1048                   add_to_contents_as_array (prototypes, new);
1049                 }
1050             }
1051           else
1052             {
1053               if (e->cmd != CM_c && e->cmd != CM_comment)
1054                 {
1055                   char *texi;
1056                   texi = convert_to_texinfo (e);
1057                   command_warn (current,
1058                                 "unexpected argument on @%s line: %s",
1059                                 command_name(current->parent->cmd),
1060                                 texi);
1061                   free (texi);
1062                 }
1063             }
1064         }
1065 
1066       {
1067       int max_columns = prototypes->contents.number;
1068       add_extra_integer (current->parent, "max_columns", max_columns);
1069       if (max_columns == 0)
1070         command_warn (current->parent, "empty multitable");
1071       }
1072       add_extra_contents_oot (current->parent, "prototypes", prototypes);
1073       /* See code in destroy_element for how prototypes is deallocated. */
1074     }
1075   isolate_last_space (current);
1076 
1077   current = current->parent;
1078   if (counter_value (&count_remaining_args, current) != -1)
1079     counter_pop (&count_remaining_args);
1080 
1081   /* Don't consider empty argument of block @-command as argument,
1082      reparent them as contents. */
1083   if (current->args.list[0]->contents.number > 0
1084       && current->args.list[0]->contents.list[0]->type
1085          == ET_empty_line_after_command)
1086     {
1087       ELEMENT *e = remove_from_contents (current->args.list[0], 0);
1088       insert_into_contents (current, e, 0);
1089       destroy_element (pop_element_from_args (current));
1090     }
1091 
1092   if (current->cmd == CM_float)
1093     {
1094       char *type = "";
1095       KEY_PAIR *k;
1096       EXTRA_FLOAT_TYPE *eft;
1097       current->line_nr = line_nr;
1098       if (current->args.number >= 2)
1099         {
1100           NODE_SPEC_EXTRA *float_label;
1101           float_label = parse_node_manual (args_child_by_index (current, 1));
1102           check_internal_node (float_label);
1103 
1104           register_label (current, float_label->node_content);
1105           if (float_label->manual_content)
1106             destroy_element (float_label->manual_content);
1107           free (float_label);
1108         }
1109       parse_float_type (current);
1110       k = lookup_extra (current, "type");
1111       if (k)
1112         {
1113           eft = (EXTRA_FLOAT_TYPE *) k->value;
1114           type = eft->normalized;
1115         }
1116       /* add to global 'floats' array */
1117       if (floats_number == floats_space)
1118         {
1119           floats_list = realloc (floats_list,
1120                                  (floats_space += 5) * sizeof (FLOAT_RECORD));
1121         }
1122       floats_list[floats_number].type = type;
1123       floats_list[floats_number++].element = current;
1124       if (current_section)
1125         add_extra_element (current, "float_section", current_section);
1126     }
1127 
1128   if (command_flags(current) & CF_blockitem)
1129     {
1130       if (current->cmd == CM_enumerate)
1131         {
1132           char *spec = "1";
1133 
1134           if (current->args.number > 0
1135               && current->args.list[0]->contents.number > 0)
1136             {
1137               if (current->args.list[0]->contents.number > 1)
1138                 command_error (current, "superfluous argument to @%s",
1139                                command_name(current->cmd));
1140               ELEMENT *g = current->args.list[0]->contents.list[0];
1141               /* Check if @enumerate specification is either a single
1142                  letter or a string of digits. */
1143               if (g->text.end == 1 && isalpha (g->text.text[0])
1144                   || (g->text.end > 0
1145                       && !*(g->text.text
1146                             + strspn (g->text.text, "0123456789"))))
1147                 {
1148                   spec = g->text.text;
1149                 }
1150               else
1151                 command_error (current, "bad argument to @%s",
1152                                command_name(current->cmd));
1153             }
1154           add_extra_string_dup (current, "enumerate_specification", spec);
1155         }
1156       else if (item_line_command (current->cmd))
1157         {
1158           KEY_PAIR *k;
1159           k = lookup_extra (current, "command_as_argument");
1160           if (!k)
1161             command_error (current,
1162                            "%s requires an argument: the formatter for @item",
1163                            command_name(current->cmd));
1164           else
1165             {
1166               ELEMENT *e = k->value;
1167               if (!(command_flags(e) & CF_brace)
1168                   || (command_data(e->cmd).data == 0))
1169                 {
1170                   command_error (current,
1171                                  "command @%s not accepting argument in brace "
1172                                  "should not be on @%s line",
1173                                  command_name(e->cmd),
1174                                  command_name(current->cmd));
1175                   k->key = "";
1176                   k->type = extra_deleted;
1177                   /* FIXME: Error message for accent commands is done
1178                      elsewhere (3040). */
1179                 }
1180             }
1181         }
1182 
1183       /* check that command_as_argument of the @itemize is alone on the line,
1184          otherwise it is not a command_as_argument */
1185       if (current->cmd == CM_itemize)
1186         {
1187           KEY_PAIR *k;
1188           k = lookup_extra (current, "command_as_argument");
1189           if (k)
1190             {
1191               int i;
1192               ELEMENT *e = args_child_by_index (current, 0);
1193 
1194               for (i = 0; i < e->contents.number; i++)
1195                 {
1196                   if (contents_child_by_index (e, i) == k->value)
1197                     {
1198                       i++;
1199                       break;
1200                     }
1201                 }
1202               for (; i < e->contents.number; i++)
1203                 {
1204                   ELEMENT *f = contents_child_by_index (e, i);
1205                   if (f->cmd != CM_c
1206                       && f->cmd != CM_comment
1207                       && !(f->text.end > 0
1208                            && !*(f->text.text
1209                                  + strspn (f->text.text, whitespace_chars))))
1210                     {
1211                       k->value->type = ET_NONE;
1212                       k->key = "";
1213                       k->type = extra_deleted;
1214                       break;
1215                     }
1216                 }
1217             }
1218         }
1219 
1220       // Check if command_as_argument isn't an accent command
1221       if (current->cmd == CM_itemize || item_line_command(current->cmd))
1222         {
1223           KEY_PAIR *k = lookup_extra (current, "command_as_argument");
1224           if (k && k->value)
1225             {
1226               enum command_id cmd = k->value->cmd;
1227               if (cmd && (command_data(cmd).flags & CF_accent))
1228                 {
1229                   command_warn (current, "accent command `@%s' "
1230                                 "not allowed as @%s argument",
1231                                 command_name(cmd),
1232                                 command_name(current->cmd));
1233                   k->key = "";
1234                   k->value = 0;
1235                   k->type = extra_deleted;
1236                 }
1237             }
1238         }
1239 
1240       /* if no command_as_argument given, default to @bullet for
1241          @itemize, and @asis for @table. */
1242       if (current->cmd == CM_itemize
1243           && (current->args.number == 0
1244               || current->args.list[0]->contents.number == 0))
1245         {
1246           ELEMENT *e;
1247 
1248           e = new_element (ET_command_as_argument_inserted);
1249           e->cmd = CM_bullet;
1250           insert_into_args (current, e, 0);
1251           add_extra_element (current, "command_as_argument", e);
1252         }
1253       else if (item_line_command (current->cmd)
1254           && !lookup_extra (current, "command_as_argument"))
1255         {
1256           ELEMENT *e;
1257 
1258           e = new_element (ET_command_as_argument_inserted);
1259           e->cmd = CM_asis;
1260           insert_into_args (current, e, 0);
1261           add_extra_element (current, "command_as_argument", e);
1262         }
1263 
1264       {
1265         ELEMENT *bi = new_element (ET_before_item);
1266         add_to_element_contents (current, bi);
1267         current = bi;
1268       }
1269     } /* CF_blockitem */
1270 
1271   if (command_flags(current) & CF_menu)
1272     {
1273       /* Start reading a menu.  Processing will continue in
1274          handle_menu in menus.c. */
1275 
1276       ELEMENT *menu_comment = new_element (ET_menu_comment);
1277       add_to_element_contents (current, menu_comment);
1278       current = menu_comment;
1279       debug ("MENU_COMMENT OPEN");
1280       push_context (ct_preformatted);
1281     }
1282   current = begin_preformatted (current);
1283 
1284   return current;
1285 }
1286 
1287 /* Actions to be taken at the end of an argument to a line command
1288    not starting a block.  @end is processed in here. */
1289 static ELEMENT *
end_line_misc_line(ELEMENT * current)1290 end_line_misc_line (ELEMENT *current)
1291 {
1292   enum command_id cmd;
1293   int arg_type;
1294   enum context c;
1295   ELEMENT *misc_cmd;
1296   char *end_command = 0;
1297   enum command_id end_id;
1298   int included_file = 0;
1299 
1300   isolate_last_space (current);
1301 
1302   current = current->parent;
1303   misc_cmd = current;
1304   cmd = current->cmd;
1305   if (!cmd)
1306     fatal ("command name unknown for @end");
1307 
1308   arg_type = command_data(cmd).data;
1309 
1310   /* Check 'line' is top of the context stack */
1311   c = pop_context ();
1312   if (c != ct_line)
1313     fatal ("line context expected");
1314 
1315   debug ("MISC END %s", command_name(cmd));
1316 
1317   if (arg_type > 0)
1318     {
1319       ELEMENT *args = parse_line_command_args (current);
1320       if (args)
1321         add_extra_misc_args (current, "misc_args", args);
1322     }
1323   else if (arg_type == LINE_text)
1324     {
1325       char *text = 0;
1326       int superfluous_arg = 0;
1327 
1328       if (current->args.number > 0)
1329         text = convert_to_text (current->args.list[0], &superfluous_arg);
1330 
1331       if (!text || !strcmp (text, ""))
1332         {
1333           if (!superfluous_arg)
1334             line_warn ("@%s missing argument", command_name(cmd));
1335           add_extra_integer (current, "missing_argument", 1);
1336           free (text);
1337         }
1338       else
1339         {
1340           add_extra_string (current, "text_arg", text);
1341           if (current->cmd == CM_end)
1342             {
1343               char *line = text;
1344 
1345               /* Set end_command - used below. */
1346               end_command = read_command_name (&line);
1347               if (end_command)
1348                 {
1349                   /* Check if argument is a block Texinfo command. */
1350                   end_id = lookup_command (end_command);
1351                   if (end_id == 0 || !(command_data(end_id).flags & CF_block))
1352                     {
1353                       command_warn (current, "unknown @end %s", end_command);
1354                       free (end_command); end_command = 0;
1355                     }
1356                   else
1357                     {
1358                       debug ("END BLOCK %s", end_command);
1359                       /* Handle conditional block commands (e.g. @ifinfo) */
1360 
1361                       /* If we are in a non-ignored conditional, there is not
1362                          an element for the block in the tree; it is recorded
1363                          in the conditional stack.  Pop it and check it is the
1364                          same as the one given in the @end line. */
1365 
1366                       if (command_data(end_id).data == BLOCK_conditional)
1367                         {
1368                           enum command_id popped;
1369                           if (conditional_number == 0)
1370                             goto conditional_stack_fail;
1371                           popped = pop_conditional_stack ();
1372                           if (popped != end_id)
1373                             {
1374                               push_conditional_stack (popped);
1375                               goto conditional_stack_fail;
1376                             }
1377                           if (0)
1378                             {
1379                           conditional_stack_fail:
1380                               command_error (current, "unmatched `@end'");
1381                               free (end_command); end_command = 0;
1382                             }
1383                         }
1384                       if (end_command)
1385                         {
1386                           add_extra_string (current, "command_argument",
1387                                             end_command);
1388                         }
1389                       if (end_command
1390                           && (superfluous_arg
1391                              || line[strspn (line, whitespace_chars)] != '\0'))
1392                         {
1393                           char *line, *line2;
1394                           line = convert_to_texinfo (current->args.list[0]);
1395 
1396                           line2 = line;
1397                           line2 += strspn (line2, whitespace_chars);
1398                           free (read_command_name (&line2));
1399                           command_error (current,
1400                                          "superfluous argument to @end %s: "
1401                                          "%s", end_command, line2);
1402                           superfluous_arg = 0; /* Don't issue another error
1403                                                  message below. */
1404                           free (line);
1405                         }
1406                     }
1407                 }
1408               else
1409                 {
1410                   command_error (current, "bad argument to @end: %s", line);
1411                 }
1412             }
1413           else if (superfluous_arg)
1414             {
1415               /* An error message is issued below. */
1416             }
1417           else if (current->cmd == CM_include)
1418             {
1419               int status;
1420               char *fullpath;
1421               debug ("Include %s", text);
1422 
1423               fullpath = locate_include_file (text);
1424               if (!fullpath)
1425                 {
1426                   command_error (current,
1427                                  "@include: could not find %s", text);
1428                 }
1429               else
1430                 {
1431                   status = input_push_file (fullpath);
1432                   if (status)
1433                     {
1434                       command_error (current,
1435                                      "@include: could not open %s:",
1436                                      text,
1437                                      strerror (status));
1438                     }
1439                   else
1440                     included_file = 1;
1441                   free (fullpath);
1442                 }
1443             }
1444           else if (current->cmd == CM_verbatiminclude)
1445             {
1446               if (global_info.input_perl_encoding)
1447                 add_extra_string_dup (current, "input_perl_encoding",
1448                                       global_info.input_perl_encoding);
1449             }
1450           else if (current->cmd == CM_documentencoding)
1451             {
1452               int i; char *p, *text2;
1453               char *texinfo_encoding, *perl_encoding, *input_encoding;
1454               /* See tp/Texinfo/Encoding.pm (whole file) */
1455 
1456               /* Three concepts of encoding:
1457                  texinfo_encoding -- one of the encodings supported as an
1458                                      argument to @documentencoding, documented
1459                                      in Texinfo manual
1460                  perl_encoding -- used for charset conversion within Perl
1461                  input_encoding -- for output within an HTML file */
1462 
1463               text2 = strdup (text);
1464               for (p = text2; *p; p++)
1465                 *p = tolower (*p);
1466 
1467               /* Get texinfo_encoding from what was in the document */
1468               {
1469               static char *canonical_encodings[] = {
1470                 "us-ascii", "utf-8", "iso-8859-1",
1471                 "iso-8859-15","iso-8859-2","koi8-r", "koi8-u",
1472                 0
1473               };
1474 
1475               texinfo_encoding = 0;
1476               for (i = 0; (canonical_encodings[i]); i++)
1477                 {
1478                   if (!strcmp (text2, canonical_encodings[i]))
1479                     {
1480                       texinfo_encoding = canonical_encodings[i];
1481                       break;
1482                     }
1483                 }
1484               if (!texinfo_encoding)
1485                 {
1486                   command_warn (current, "encoding `%s' is not a "
1487                                 "canonical texinfo encoding", text);
1488                 }
1489               }
1490 
1491               /* Get perl_encoding. */
1492               perl_encoding = 0;
1493               if (texinfo_encoding)
1494                 perl_encoding = texinfo_encoding;
1495               else
1496                 {
1497                   int i;
1498                   static char *known_encodings[] = {
1499                       "shift_jis",
1500                       "latin1",
1501                       0
1502                   };
1503                   for (i = 0; (known_encodings[i]); i++)
1504                     {
1505                       if (!strcmp (text2, known_encodings[i]))
1506                         {
1507                           perl_encoding = known_encodings[i];
1508                           break;
1509                         }
1510                     }
1511                 }
1512               free (text2);
1513 
1514               if (perl_encoding)
1515                 {
1516                   struct encoding_map {
1517                       char *from; char *to;
1518                   };
1519                   static struct encoding_map map[] = {
1520                       "utf-8", "utf-8-strict",
1521                       "us-ascii", "ascii",
1522                       "shift_jis", "shiftjis",
1523                       "latin1", "iso-8859-1"
1524                   };
1525                   for (i = 0; i < sizeof map / sizeof *map; i++)
1526                     {
1527                       if (!strcmp (perl_encoding, map[i].from))
1528                         {
1529                           perl_encoding = map[i].to;
1530                           break;
1531                         }
1532                     }
1533                   add_extra_string_dup (current, "input_perl_encoding",
1534                                         perl_encoding);
1535                   free (global_info.input_perl_encoding);
1536                   global_info.input_perl_encoding = strdup (perl_encoding);
1537                 }
1538               else
1539                 {
1540                   command_warn (current, "unrecognized encoding name `%s'",
1541                                 text);
1542                   /* Texinfo::Encoding calls Encode::Alias, so knows
1543                      about more encodings than what we know about here.
1544                      TODO: Check when perl_encoding could be defined when
1545                      texinfo_encoding isn't.
1546                      Maybe we should check if an iconv conversion is possible
1547                      from this encoding to UTF-8. */
1548 
1549                 }
1550 
1551               /* Set input_encoding from perl_encoding */
1552               input_encoding = 0;
1553               if (perl_encoding)
1554                 {
1555                   struct encoding_map {
1556                       char *from; char *to;
1557                   };
1558                   static struct encoding_map map[] = {
1559                       "utf8",        "utf-8",
1560                       "utf-8-strict","utf-8",
1561                       "ascii",       "us-ascii",
1562                       "shiftjis",    "shift_jis",
1563                       "latin-1",     "iso-8859-1",
1564                       "iso-8859-1",  "iso-8859-1",
1565                       "iso-8859-2",  "iso-8859-2",
1566                       "iso-8859-15", "iso-8859-15",
1567                       "koi8-r",      "koi8",
1568                       "koi8-u",      "koi8",
1569                   };
1570                   input_encoding = perl_encoding;
1571                   for (i = 0; i < sizeof map / sizeof *map; i++)
1572                     {
1573                       /* Elements in first column map to elements in
1574                          second column.  Elements in second column map
1575                          to themselves. */
1576                       if (!strcasecmp (input_encoding, map[i].from)
1577                           || !strcasecmp (input_encoding, map[i].to))
1578                         {
1579                           input_encoding = map[i].to;
1580                           break;
1581                         }
1582                     }
1583                 }
1584               if (input_encoding)
1585                 {
1586                   add_extra_string_dup (current, "input_encoding_name",
1587                                         input_encoding);
1588 
1589                   global_info.input_encoding_name = strdup (input_encoding);
1590                   set_input_encoding (input_encoding);
1591                 }
1592             }
1593           else if (current->cmd == CM_documentlanguage)
1594             {
1595               char *p, *q;
1596 
1597               /* Texinfo::Common::warn_unknown_language checks with
1598                  tp/Texinfo/Documentlanguages.pm, which is an automatically
1599                  generated list of official IANA language codes.  For now,
1600                  just check if the language code looks right. */
1601 
1602               p = text;
1603               while (isalpha (*p))
1604                 p++;
1605               if (*p && *p != '_')
1606                 {
1607                    /* non-alphabetic char in language code */
1608                   command_warn (current, "%s is not a valid language code",
1609                                 text);
1610                 }
1611               else
1612                 {
1613                   if (p - text > 4)
1614                     {
1615                       /* looks too long */
1616                       char c = *p;
1617                       *p = 0;
1618                       command_warn (current, "%s is not a valid language code",
1619                                     text);
1620                       *p = c;
1621                     }
1622                   if (*p == '_')
1623                     {
1624                       q = p + 1;
1625                       p = q;
1626                       /* Language code should be of the form LL_CC,
1627                          language code followed by country code. */
1628                       while (isalpha (*p))
1629                         p++;
1630                       if (*p || p - q > 4)
1631                         {
1632                           /* non-alphabetic char in country code or code
1633                              is too long. */
1634                           command_warn (current,
1635                                         "%s is not a valid region code", q);
1636                         }
1637                     }
1638                 }
1639 
1640               free (global_documentlanguage);
1641               global_documentlanguage = strdup (text);
1642               /* FIXME: check customization variable */
1643             }
1644         }
1645       if (superfluous_arg)
1646         {
1647           char *texi_line, *p, *p1;
1648           p = convert_to_texinfo (args_child_by_index(current, 0));
1649 
1650           texi_line = p;
1651           while (isspace (*texi_line))
1652             texi_line++;
1653 
1654           /* Trim leading and trailing whitespace. */
1655           p1 = strchr (texi_line, '\0');
1656           if (p1 > texi_line)
1657             {
1658               while (p1 > texi_line && isspace (p1[-1]))
1659                 p1--;
1660               c = *p1;
1661               *p1 = '\0';
1662             }
1663           command_error (current, "bad argument to @%s: %s",
1664                          command_name(current->cmd), texi_line);
1665           free (p);
1666         }
1667     }
1668   else if (current->cmd == CM_node)
1669     {
1670       int i;
1671       ELEMENT *arg;
1672 
1673       NODE_SPEC_EXTRA **nodes_manuals;
1674 
1675       /* Construct 'nodes_manuals' array.  Maximum of four elements
1676          (node name, up, prev, next). */
1677       nodes_manuals = malloc (sizeof (NODE_SPEC_EXTRA *) * 5);
1678 
1679       for (i = 0; i < current->args.number && i < 4; i++)
1680         {
1681           arg = current->args.list[i];
1682           nodes_manuals[i] = parse_node_manual (arg);
1683         }
1684       nodes_manuals[i] = 0;
1685 
1686       add_extra_node_spec_array (current, "nodes_manuals", nodes_manuals);
1687 
1688       check_internal_node (nodes_manuals[0]);
1689 
1690       if (nodes_manuals[0])
1691         {
1692           ELEMENT *label = 0;
1693           if (nodes_manuals[0]->node_content)
1694             {
1695               /* Copy the first 'node_content' array, to avoid the complication
1696                  of it being referenced in two different places.
1697                  This might be better with a separate function. */
1698 
1699               label = new_element (0);
1700               int i;
1701 
1702               for (i = 0; i<nodes_manuals[0]->node_content->contents.number;
1703                    i++)
1704                 {
1705                   add_to_contents_as_array (label,
1706                    contents_child_by_index(nodes_manuals[0]->node_content, i));
1707                 }
1708             }
1709           register_label (current, label);
1710         }
1711 
1712       current_node = current;
1713     }
1714   else if (current->cmd == CM_listoffloats)
1715     {
1716       parse_float_type (current);
1717     }
1718   else
1719     {
1720       /* All the other "line" commands. Check they have an argument. Empty
1721          @top is allowed. */
1722       if (current->args.list[0]->contents.number == 0
1723           && current->cmd != CM_top)
1724         {
1725           command_warn (current, "@%s missing argument",
1726                         command_name(current->cmd));
1727           add_extra_integer (current, "missing_argument", 1);
1728         }
1729       else
1730         {
1731           if ((current->parent->cmd == CM_ftable
1732                || current->parent->cmd == CM_vtable)
1733               && (current->cmd == CM_item || current->cmd == CM_itemx))
1734             {
1735               enter_index_entry (current->parent->cmd,
1736                                  current->cmd,
1737                                  current,
1738                                  current->args.list[0]);
1739             }
1740           else
1741             {
1742               // 3273 FIXME possibly check for @def... command
1743             }
1744 
1745 
1746           /* Index commands */
1747           if (command_flags(current) & CF_index_entry_command)
1748             {
1749               enter_index_entry (current->cmd, current->cmd, current,
1750                                  current->args.list[0]);
1751               current->type = ET_index_entry_command;
1752             }
1753         }
1754     }
1755 
1756   current = current->parent;
1757   if (end_command) /* Set above */
1758     {
1759       /* More processing of @end */
1760       ELEMENT *end_elt;
1761 
1762       debug ("END COMMAND %s", end_command);
1763 
1764       /* Reparent the "@end" element to be a child of the block element. */
1765       end_elt = pop_element_from_contents (current);
1766 
1767       /* If not a conditional */
1768       if (command_data(end_id).data != BLOCK_conditional)
1769         {
1770           ELEMENT *closed_command;
1771           /* This closes tree elements (e.g. paragraphs) until we reach
1772              end_command.  It can print an error if another block command
1773              is found first. */
1774           current = close_commands (current, end_id, &closed_command, 0);
1775           if (!closed_command)
1776             destroy_element_and_children (end_elt);
1777           else
1778             {
1779               add_extra_element (closed_command, "end_command", end_elt);
1780               close_command_cleanup (closed_command);
1781 
1782               add_to_element_contents (closed_command, end_elt);
1783 
1784               if (command_flags(closed_command) & CF_menu
1785                   && current_context () == ct_menu)
1786                 {
1787                   ELEMENT *e;
1788                   debug ("CLOSE menu but still in menu context");
1789                   e = new_element (ET_menu_comment);
1790                   add_to_element_contents (current, e);
1791                   current = e;
1792                   push_context (ct_preformatted);
1793                 }
1794             }
1795           if (close_preformatted_command (end_id))
1796             current = begin_preformatted (current);
1797         }
1798       else
1799         {
1800           /* The "@end" line does not appear in the final tree for a
1801              conditional block. */
1802           destroy_element_and_children (end_elt);
1803         }
1804     }
1805   else
1806     {
1807       if (close_preformatted_command (cmd))
1808         current = begin_preformatted (current);
1809     }
1810 
1811   /* If a file was included, remove the include command completely.
1812      Also ignore @setfilename in included file, as said in the manual. */
1813   if (included_file || (cmd == CM_setfilename && top_file_index () > 0))
1814     destroy_element_and_children (pop_element_from_contents (current));
1815   else if (cmd == CM_setfilename && (current_node || current_section))
1816     command_warn (misc_cmd, "@setfilename after the first element");
1817   else if (cmd == CM_columnfractions)
1818     {
1819       ELEMENT *before_item;
1820       KEY_PAIR *misc_args;
1821 
1822       /* Check if in multitable. */
1823       if (!current->parent || current->parent->cmd != CM_multitable)
1824         {
1825           command_error (current,
1826             "@columnfractions only meaningful on a @multitable line");
1827         }
1828       else
1829         {
1830           pop_context (); /* ct_line */;
1831 
1832           current = current->parent;
1833 
1834           if ((misc_args = lookup_extra (misc_cmd, "misc_args")))
1835             {
1836               add_extra_element (current, "columnfractions", misc_cmd);
1837               add_extra_integer (current, "max_columns",
1838                                  misc_args->value->contents.number);
1839             }
1840           else
1841             add_extra_integer (current, "max_columns", 0);
1842 
1843           before_item = new_element (ET_before_item);
1844           add_to_element_contents (current, before_item);
1845           current = before_item;
1846         }
1847     }
1848   else if (command_data(cmd).flags & CF_root)
1849     {
1850       current = last_contents_child (current);
1851       if (cmd == CM_node)
1852         counter_pop (&count_remaining_args);
1853 
1854       /* Destroy all contents (TODO: check why do we do this?) */
1855       while (last_contents_child (current))
1856         destroy_element (pop_element_from_contents (current));
1857 
1858       /* Set 'associated_section' extra key for a node. */
1859       if (cmd != CM_node && cmd != CM_part)
1860         {
1861           if (current_node)
1862             {
1863               if (!lookup_extra (current_node, "associated_section"))
1864                 {
1865                   add_extra_element
1866                     (current_node, "associated_section", current);
1867                   add_extra_element
1868                     (current, "associated_node", current_node);
1869                 }
1870             }
1871 
1872           if (current_part)
1873             {
1874               add_extra_element (current, "associated_part", current_part);
1875               add_extra_element (current_part, "part_associated_section",
1876                                  current);
1877               if (current->cmd == CM_top)
1878                 {
1879                   line_error_ext (1, &current_part->line_nr,
1880                          "@part should not be associated with @top");
1881                 }
1882               current_part = 0;
1883             }
1884 
1885           current_section = current;
1886         }
1887       else if (cmd == CM_part)
1888         {
1889           current_part = current;
1890           if (current_node
1891               && !lookup_extra (current_node, "associated_section"))
1892             {
1893               line_warn ("@node precedes @part, but parts may not be "
1894                          "associated with nodes");
1895             }
1896         }
1897     }
1898 
1899   return current;
1900 }
1901 
1902 /* Actions to be taken when a whole line of input has been processed */
1903 ELEMENT *
end_line(ELEMENT * current)1904 end_line (ELEMENT *current)
1905 {
1906   ELEMENT *current_old = current; /* Used at very end of function */
1907 
1908   /* If empty line, start a new paragraph. */
1909   if (last_contents_child (current)
1910       && last_contents_child (current)->type == ET_empty_line)
1911     {
1912       debug ("END EMPTY LINE");
1913       if (current->type == ET_paragraph)
1914         {
1915           ELEMENT *e;
1916           /* Remove empty_line element. */
1917           e = pop_element_from_contents (current);
1918 
1919           current = end_paragraph (current, 0, 0);
1920 
1921           /* Add empty_line to higher-level element. */
1922           add_to_element_contents (current, e);
1923         }
1924       else if (current->type == ET_preformatted
1925                && current->parent->type == ET_menu_entry_description)
1926         {
1927           ELEMENT *empty_line, *e;
1928           empty_line = pop_element_from_contents (current);
1929           if (current->contents.number == 0)
1930             {
1931               current = current->parent;
1932               destroy_element (pop_element_from_contents (current));
1933             }
1934           else
1935             current = current->parent;
1936 
1937           pop_context (); //ct_preformatted
1938 
1939           current = current->parent->parent;
1940           e = new_element (ET_menu_comment);
1941           add_to_element_contents (current, e);
1942 
1943           current = e;
1944           e = new_element (ET_preformatted);
1945           add_to_element_contents (current, e);
1946 
1947           current = e;
1948           e = new_element (ET_after_description_line);
1949           text_append (&e->text, empty_line->text.text);
1950           destroy_element (empty_line);
1951           add_to_element_contents (current, e);
1952 
1953           push_context (ct_preformatted);
1954           debug ("MENU: END DESCRIPTION, OPEN COMMENT");
1955         }
1956       else if (in_paragraph_context (current_context ()))
1957         {
1958           current = end_paragraph (current, 0, 0);
1959         }
1960     }
1961   /* The end of the line of a menu. */
1962   else if (current->type == ET_menu_entry_name
1963            || current->type == ET_menu_entry_node)
1964     {
1965       ELEMENT *end_comment = 0;
1966       int empty_menu_entry_node = 0;
1967 
1968       if (current->type == ET_menu_entry_node)
1969         {
1970           ELEMENT *last = last_contents_child (current);
1971 
1972           if (current->contents.number > 0
1973               && (last->cmd == CM_c || last->cmd == CM_comment))
1974             {
1975               end_comment = pop_element_from_contents (current);
1976             }
1977 
1978           /* If contents empty or is all whitespace. */
1979           if (current->contents.number == 0
1980               || (current->contents.number == 1
1981                   && last->text.end > 0
1982                   && !last->text.text[strspn (last->text.text,
1983                                               whitespace_chars)]))
1984             {
1985               empty_menu_entry_node = 1;
1986               if (end_comment)
1987                 add_to_element_contents (current, end_comment);
1988             }
1989         }
1990 
1991       /* Abort the menu entry if there is no destination node given. */
1992       if (empty_menu_entry_node || current->type == ET_menu_entry_name)
1993         {
1994           ELEMENT *menu, *menu_entry, *description_or_menu_comment = 0;
1995           debug ("FINALLY NOT MENU ENTRY");
1996           menu = current->parent->parent;
1997           menu_entry = pop_element_from_contents (menu);
1998           if (menu->contents.number > 0
1999               && last_contents_child(menu)->type == ET_menu_entry)
2000             {
2001               ELEMENT *entry, *description = 0;
2002               int j;
2003 
2004               entry = last_contents_child(menu);
2005               for (j = entry->args.number - 1; j >= 0; j--)
2006                 {
2007                   ELEMENT *e = args_child_by_index (entry, j);
2008                   if (e->type == ET_menu_entry_description)
2009                     {
2010                       description = e;
2011                       break;
2012                     }
2013                 }
2014               if (description)
2015                 description_or_menu_comment = description;
2016               else
2017                 {
2018                   ELEMENT *e;
2019                   /* "Normally this cannot happen." */
2020                   bug ("no description in menu entry");
2021                   e = new_element (ET_menu_entry_description);
2022                   add_to_element_args (entry, e);
2023                   description_or_menu_comment = e;
2024                 }
2025             }
2026           else if (menu->contents.number > 0
2027                    && last_contents_child(menu)->type == ET_menu_comment)
2028             {
2029               description_or_menu_comment = last_contents_child(menu);
2030             }
2031           if (description_or_menu_comment)
2032             {
2033               current = description_or_menu_comment;
2034               if (current->contents.number > 0
2035                   && last_contents_child(current)->type == ET_preformatted)
2036                 current = last_contents_child(current);
2037               else
2038                 {
2039                   /* This should not happen */
2040                   bug ("description or menu comment not in preformatted");
2041                   ELEMENT *e;
2042                   e = new_element (ET_preformatted);
2043                   add_to_element_contents (current, e);
2044                   current = e;
2045                 }
2046               push_context (ct_preformatted);
2047             }
2048           else
2049             {
2050               ELEMENT *e;
2051               e = new_element (ET_menu_comment);
2052               add_to_element_contents (menu, e);
2053               current = e;
2054               e = new_element (ET_preformatted);
2055               add_to_element_contents (current, e);
2056               current = e;
2057               push_context (ct_preformatted);
2058               debug ("THEN MENU_COMMENT OPEN");
2059             }
2060           {
2061           int i, j;
2062           for (i = 0; i < menu_entry->args.number; i++)
2063             {
2064               ELEMENT *arg = args_child_by_index(menu_entry, i);
2065               if (arg->text.end > 0)
2066                 current = merge_text (current, arg->text.text);
2067               else
2068                 {
2069                   ELEMENT *e;
2070                   for (j = 0; j < arg->contents.number; j++)
2071                     {
2072                       e = contents_child_by_index (arg, j);
2073                       if (e->text.end > 0)
2074                         {
2075                           current = merge_text (current, e->text.text);
2076                           destroy_element (e);
2077                         }
2078                       else
2079                         {
2080                           add_to_element_contents (current, e);
2081                         }
2082                     }
2083                 }
2084               destroy_element (arg);
2085             }
2086           destroy_element (menu_entry);
2087           }
2088         }
2089       else
2090         {
2091           debug ("MENU ENTRY END LINE");
2092           current = current->parent;
2093           current = enter_menu_entry_node (current);
2094           if (end_comment)
2095             add_to_element_contents (current, end_comment);
2096         }
2097     }
2098 
2099   /* End of a definition line, like @deffn */
2100   else if (current->parent && current->parent->type == ET_def_line)
2101     {
2102       enum command_id def_command, original_def_command;
2103       DEF_INFO *def_info = 0;
2104       static DEF_INFO zero_def_info; /* always stays zeroed */
2105       KEY_PAIR *k;
2106 
2107       if (pop_context () != ct_def)
2108         fatal ("def context expected");
2109 
2110       k = lookup_extra (current->parent, "original_def_cmdname");
2111       if (k)
2112         original_def_command = lookup_command ((char *) k->value);
2113       else
2114         original_def_command = current->parent->parent->cmd;
2115 
2116       def_command = original_def_command;
2117       /* Strip an trailing x from the command, e.g. @deffnx -> @deffn */
2118       if (command_data(def_command).flags & CF_line)
2119         {
2120           char *stripped = strdup (command_name(def_command));
2121           stripped[strlen (stripped) - 1] = '\0';
2122           def_command = lookup_command (stripped);
2123           free (stripped);
2124         }
2125 
2126       def_info = parse_def (def_command, current);
2127 
2128       /* Record the index entry if def_info is not empty. */
2129       if (!memcmp(def_info, &zero_def_info, sizeof (DEF_INFO)))
2130         {
2131           free (def_info);
2132           command_warn (current->parent, "missing category for @%s",
2133                         command_name (original_def_command));
2134         }
2135       else
2136         {
2137           ELEMENT *index_entry = 0; /* Index entry text. */
2138 
2139           add_extra_def_info (current->parent, "def_parsed_hash", def_info);
2140 
2141           if (def_info->name)
2142             {
2143               char *t;
2144               /* Set index_entry unless an empty ET_bracketed_def_content. */
2145               if (def_info->name->type == ET_bracketed_def_content
2146                   && (def_info->name->contents.number == 0
2147                       || (def_info->name->contents.number == 1
2148                           && (t = def_info->name->contents.list[0]->text.text)
2149                           && t[strspn (t, whitespace_chars)] == '\0')))
2150                 {
2151                 }
2152               else
2153                 index_entry = def_info->name;
2154             }
2155 
2156           if (index_entry)
2157             {
2158               ELEMENT *index_contents = 0;
2159 
2160               if (def_info->class &&
2161                   (def_command == CM_defop
2162                       || def_command == CM_deftypeop
2163                       || def_command == CM_defmethod
2164                       || def_command == CM_deftypemethod
2165                       || def_command == CM_defivar
2166                       || def_command == CM_deftypeivar
2167                       || def_command == CM_deftypecv))
2168                 {
2169                   add_extra_string_dup (current->parent, "documentlanguage",
2170                                         global_documentlanguage);
2171                 }
2172               else
2173                 {
2174                   index_contents = new_element (ET_NONE);
2175                   if (index_contents->contents.number == 0)
2176                     add_to_contents_as_array (index_contents, index_entry);
2177                 }
2178 
2179               enter_index_entry (def_command,
2180                                  original_def_command,
2181                                  current->parent,
2182                                  index_contents);
2183             }
2184           else
2185             {
2186               command_warn (current->parent, "missing name for @%s",
2187                             command_name (original_def_command));
2188             }
2189         }
2190 
2191       current = current->parent->parent;
2192       current = begin_preformatted (current);
2193     }
2194   /* End of a line starting a block. */
2195   else if (current->type == ET_block_line_arg)
2196     {
2197       current = end_line_starting_block (current);
2198     }
2199 
2200   /* after an "@end verbatim" */
2201   else if (current->contents.number
2202            && last_contents_child(current)->type == ET_empty_line_after_command
2203            && contents_child_by_index(current, -2)
2204            && contents_child_by_index(current, -2)->cmd == CM_verbatim)
2205     {
2206       /*
2207      if we are after a @end verbatim, we must restart a preformatted if needed,
2208      since there is no @end command explicitly associated to raw commands
2209      it won't be done elsewhere.
2210       */
2211 
2212       current = begin_preformatted (current);
2213     }
2214   else if (current->type == ET_line_arg)
2215     {
2216       current = end_line_misc_line (current);
2217     }
2218   else if (current->contents.number == 1
2219            && current->contents.list[0]->type == ET_empty_line_after_command
2220            || current->contents.number == 2
2221            && current->contents.list[0]->type == ET_empty_line_after_command
2222            && (current->contents.list[1]->cmd == CM_c
2223                || current->contents.list[1]->cmd == CM_comment))
2224     {
2225       if (current->type == ET_preformatted
2226           || current->type == ET_rawpreformatted)
2227         {
2228           /* Empty line after a @menu, or before a preformatted.  Reparent
2229              to the menu or other format. */
2230           ELEMENT *parent, *to_reparent;
2231 
2232           parent = current->parent;
2233           if (parent->type == ET_menu_comment
2234               && parent->contents.number == 1)
2235             {
2236               parent = parent->parent;
2237             }
2238           to_reparent = pop_element_from_contents (parent);
2239           debug ("LINE AFTER COMMAND IN PREFORMATTED");
2240           while (current->contents.number > 0)
2241             {
2242               ELEMENT *e;
2243               e = remove_from_contents (current, 0);
2244               add_to_element_contents (parent, e);
2245             }
2246           add_to_element_contents (parent, to_reparent);
2247         }
2248     }
2249 
2250   /* 'line' or 'def' at top of "context stack" - this happens when
2251      line commands are nested (always incorrectly?) */
2252   if (current_context () == ct_line || current_context () == ct_def)
2253     {
2254       debug ("Still opened line command");
2255       if (current_context () == ct_def)
2256         {
2257           while (current->parent
2258                  && current->parent->type != ET_def_line)
2259             {
2260               current = close_current (current, 0, 0);
2261             }
2262         }
2263       else
2264         {
2265           while (current->parent
2266                  && current->type != ET_line_arg
2267                  && current->type != ET_block_line_arg)
2268             {
2269               current = close_current (current, 0, 0);
2270             }
2271         }
2272 
2273       if (current == current_old)
2274         fatal ("infinite loop when closing commands");
2275 
2276       current = end_line (current);
2277     }
2278   return current;
2279 }
2280 
2281