xref: /openbsd-src/gnu/usr.bin/texinfo/makeinfo/insertion.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /* insertion.c -- insertions for Texinfo.
2    $Id: insertion.c,v 1.1.1.1 2000/02/09 01:25:19 espie Exp $
3 
4    Copyright (C) 1998, 99 Free Software Foundation, Inc.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19 
20 #include "system.h"
21 #include "cmds.h"
22 #include "defun.h"
23 #include "insertion.h"
24 #include "macro.h"
25 #include "makeinfo.h"
26 
27 /* Must match list in insertion.h.  */
28 static char *insertion_type_names[] =
29 {
30   "cartouche", "defcv", "deffn", "defivar", "defmac", "defmethod",
31   "defop", "defopt", "defspec", "deftp", "deftypefn", "deftypefun",
32   "deftypeivar", "deftypemethod", "deftypeop", "deftypevar",
33   "deftypevr", "defun", "defvar", "defvr", "detailmenu", "direntry",
34   "display", "enumerate", "example", "flushleft", "flushright",
35   "format", "ftable", "group", "ifclear", "ifhtml", "ifinfo",
36   "ifnothtml", "ifnotinfo", "ifnottex", "ifset", "iftex", "itemize",
37   "lisp", "menu", "multitable", "quotation", "rawhtml", "rawtex",
38   "smalldisplay", "smallexample", "smallformat", "smalllisp", "table",
39   "tex", "vtable", "bad_type"
40 };
41 
42 /* All nested environments.  */
43 INSERTION_ELT *insertion_stack = NULL;
44 
45 /* How deeply we're nested.  */
46 int insertion_level = 0;
47 
48 /* Whether to examine menu lines.  */
49 int in_menu = 0;
50 
51 /* How to examine menu lines.  */
52 int in_detailmenu = 0;
53 
54 /* Set to 1 if we've processed (commentary) text in a @menu that
55    wasn't part of a menu item.  */
56 int had_menu_commentary;
57 
58 /* Set to 1 if <p> is written in normal context.
59    Used for menu and itemize. */
60 int in_paragraph = 0;
61 
62 static const char dl_tag[] = "<dl>\n";
63 
64 void
65 init_insertion_stack ()
66 {
67   insertion_stack = NULL;
68 }
69 
70 /* Return the type of the current insertion. */
71 static enum insertion_type
72 current_insertion_type ()
73 {
74   return insertion_level ? insertion_stack->insertion : bad_type;
75 }
76 
77 /* Return the string which is the function to wrap around items, or NULL
78    if we're not in an environment where @item is ok.  */
79 static char *
80 current_item_function ()
81 {
82   int done = 0;
83   INSERTION_ELT *elt = insertion_stack;
84 
85   /* Skip down through the stack until we find an insertion with an
86      itemize function defined, i.e., skip conditionals, @cartouche, etc.  */
87   while (!done && elt)
88     {
89       switch (elt->insertion)
90         {
91         /* This list should match the one in cm_item.  */
92         case ifclear:
93         case ifhtml:
94         case ifinfo:
95         case ifnothtml:
96         case ifnotinfo:
97         case ifnottex:
98         case ifset:
99         case iftex:
100         case rawhtml:
101         case rawtex:
102         case tex:
103         case cartouche:
104 	  elt = elt->next;
105 	  break;
106 
107         default:
108           done = 1;
109         }
110     }
111 
112   /* item_function usually gets assigned the empty string.  */
113   return done && (*elt->item_function) ? elt->item_function : NULL;
114 }
115 
116 /* Parse the item marker function off the input.  If result is just "@",
117    change it to "@ ", since "@" by itself is not a command.  This makes
118    "@ ", "@\t", and "@\n" all the same, but their default meanings are
119    the same anyway, and let's not worry about supporting redefining them.  */
120 char *
121 get_item_function ()
122 {
123   char *item_function;
124   get_rest_of_line (0, &item_function);
125 
126   /* If we hit the end of text in get_rest_of_line, backing up
127      input pointer will cause the last character of the last line
128      be pushed back onto the input, which is wrong.  */
129   if (input_text_offset < input_text_length)
130     backup_input_pointer ();
131 
132   if (STREQ (item_function, "@"))
133     {
134       free (item_function);
135       item_function = xstrdup ("@ ");
136     }
137 
138   return item_function;
139 }
140 
141  /* Push the state of the current insertion on the stack. */
142 void
143 push_insertion (type, item_function)
144      enum insertion_type type;
145      char *item_function;
146 {
147   INSERTION_ELT *new = xmalloc (sizeof (INSERTION_ELT));
148 
149   new->item_function = item_function;
150   new->filling_enabled = filling_enabled;
151   new->indented_fill = indented_fill;
152   new->insertion = type;
153   new->line_number = line_number;
154   new->filename = xstrdup (input_filename);
155   new->inhibited = inhibit_paragraph_indentation;
156   new->in_fixed_width_font = in_fixed_width_font;
157   new->next = insertion_stack;
158   insertion_stack = new;
159   insertion_level++;
160 }
161 
162  /* Pop the value on top of the insertion stack into the
163     global variables. */
164 void
165 pop_insertion ()
166 {
167   INSERTION_ELT *temp = insertion_stack;
168 
169   if (temp == NULL)
170     return;
171 
172   in_fixed_width_font = temp->in_fixed_width_font;
173   inhibit_paragraph_indentation = temp->inhibited;
174   filling_enabled = temp->filling_enabled;
175   indented_fill = temp->indented_fill;
176   free_and_clear (&(temp->item_function));
177   free_and_clear (&(temp->filename));
178   insertion_stack = insertion_stack->next;
179   free (temp);
180   insertion_level--;
181 }
182 
183  /* Return a pointer to the print name of this
184     enumerated type. */
185 char *
186 insertion_type_pname (type)
187      enum insertion_type type;
188 {
189   if ((int) type < (int) bad_type)
190     return insertion_type_names[(int) type];
191   else
192     return _("Broken-Type in insertion_type_pname");
193 }
194 
195 /* Return the insertion_type associated with NAME.
196    If the type is not one of the known ones, return BAD_TYPE. */
197 enum insertion_type
198 find_type_from_name (name)
199      char *name;
200 {
201   int index = 0;
202   while (index < (int) bad_type)
203     {
204       if (STREQ (name, insertion_type_names[index]))
205         return (enum insertion_type) index;
206       if (index == rawhtml && STREQ (name, "html"))
207         return rawhtml;
208       if (index == rawtex && STREQ (name, "tex"))
209         return rawtex;
210       index++;
211     }
212   return bad_type;
213 }
214 
215 int
216 defun_insertion (type)
217      enum insertion_type type;
218 {
219   return 0
220      || (type == defcv)
221      || (type == deffn)
222      || (type == defivar)
223      || (type == defmac)
224      || (type == defmethod)
225      || (type == defop)
226      || (type == defopt)
227      || (type == defspec)
228      || (type == deftp)
229      || (type == deftypefn)
230      || (type == deftypefun)
231      || (type == deftypeivar)
232      || (type == deftypemethod)
233      || (type == deftypeop)
234      || (type == deftypevar)
235      || (type == deftypevr)
236      || (type == defun)
237      || (type == defvar)
238      || (type == defvr)
239   ;
240 }
241 
242 /* MAX_NS is the maximum nesting level for enumerations.  I picked 100
243    which seemed reasonable.  This doesn't control the number of items,
244    just the number of nested lists. */
245 #define max_stack_depth 100
246 #define ENUM_DIGITS 1
247 #define ENUM_ALPHA  2
248 typedef struct {
249   int enumtype;
250   int enumval;
251 } DIGIT_ALPHA;
252 
253 DIGIT_ALPHA enumstack[max_stack_depth];
254 int enumstack_offset = 0;
255 int current_enumval = 1;
256 int current_enumtype = ENUM_DIGITS;
257 char *enumeration_arg = NULL;
258 
259 void
260 start_enumerating (at, type)
261      int at, type;
262 {
263   if ((enumstack_offset + 1) == max_stack_depth)
264     {
265       line_error (_("Enumeration stack overflow"));
266       return;
267     }
268   enumstack[enumstack_offset].enumtype = current_enumtype;
269   enumstack[enumstack_offset].enumval = current_enumval;
270   enumstack_offset++;
271   current_enumval = at;
272   current_enumtype = type;
273 }
274 
275 void
276 stop_enumerating ()
277 {
278   --enumstack_offset;
279   if (enumstack_offset < 0)
280     enumstack_offset = 0;
281 
282   current_enumval = enumstack[enumstack_offset].enumval;
283   current_enumtype = enumstack[enumstack_offset].enumtype;
284 }
285 
286 /* Place a letter or digits into the output stream. */
287 void
288 enumerate_item ()
289 {
290   char temp[10];
291 
292   if (current_enumtype == ENUM_ALPHA)
293     {
294       if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
295         {
296           current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
297           warning (_("lettering overflow, restarting at %c"), current_enumval);
298         }
299       sprintf (temp, "%c. ", current_enumval);
300     }
301   else
302     sprintf (temp, "%d. ", current_enumval);
303 
304   indent (output_column += (current_indent - strlen (temp)));
305   add_word (temp);
306   current_enumval++;
307 }
308 
309 static void
310 enum_html ()
311 {
312   char type;
313   int start;
314 
315   if (isdigit (*enumeration_arg))
316     {
317       type = '1';
318       start = atoi (enumeration_arg);
319     }
320   else if (isupper (*enumeration_arg))
321     {
322       type = 'A';
323       start = *enumeration_arg - 'A' + 1;
324     }
325   else
326     {
327       type = 'a';
328       start = *enumeration_arg - 'a' + 1;
329     }
330 
331   add_word_args ("<ol type=%c start=%d>\n", type, start);
332 }
333 
334 /* Conditionally parse based on the current command name. */
335 void
336 command_name_condition ()
337 {
338   char *discarder = xmalloc (8 + strlen (command));
339 
340   sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
341   discard_until (discarder);
342   discard_until ("\n");
343 
344   free (discarder);
345 }
346 
347 /* This is where the work for all the "insertion" style
348    commands is done.  A huge switch statement handles the
349    various setups, and generic code is on both sides. */
350 void
351 begin_insertion (type)
352      enum insertion_type type;
353 {
354   int no_discard = 0;
355 
356   if (defun_insertion (type))
357     {
358       push_insertion (type, xstrdup (""));
359       no_discard++;
360     }
361   else
362     push_insertion (type, get_item_function ());
363 
364   switch (type)
365     {
366     case menu:
367       if (!no_headers)
368         close_paragraph ();
369 
370       filling_enabled = no_indent = 0;
371       inhibit_paragraph_indentation = 1;
372 
373       if (html)
374         {
375           had_menu_commentary = 1;
376         }
377       else if (!no_headers)
378         add_word ("* Menu:\n");
379 
380       in_menu++;
381       in_fixed_width_font++;
382       no_discard++;
383       break;
384 
385     case detailmenu:
386       if (!in_menu)
387         {
388           if (!no_headers)
389             close_paragraph ();
390 
391           filling_enabled = no_indent = 0;
392           inhibit_paragraph_indentation = 1;
393 
394           no_discard++;
395         }
396 
397       in_fixed_width_font++;
398       in_detailmenu++;
399       break;
400 
401     case direntry:
402       if (html)
403         command_name_condition ();
404       else
405         {
406           close_single_paragraph ();
407           filling_enabled = no_indent = 0;
408           inhibit_paragraph_indentation = 1;
409           insert_string ("START-INFO-DIR-ENTRY\n");
410         }
411       break;
412 
413     case quotation:
414       /* @quotation does filling (@display doesn't).  */
415       if (html)
416         add_word ("<blockquote>\n");
417       else
418         {
419           close_single_paragraph ();
420           last_char_was_newline = no_indent = 0;
421           indented_fill = filling_enabled = 1;
422           inhibit_paragraph_indentation = 1;
423         }
424       current_indent += default_indentation_increment;
425       break;
426 
427     case display:
428     case smalldisplay:
429     case example:
430     case smallexample:
431     case lisp:
432     case smalllisp:
433       /* Like @display but without indentation. */
434     case smallformat:
435     case format:
436       close_single_paragraph ();
437       inhibit_paragraph_indentation = 1;
438       in_fixed_width_font++;
439       filling_enabled = 0;
440       last_char_was_newline = 0;
441 
442       if (html)
443         /* Kludge alert: if <pre> is followed by a newline, IE3
444            renders an extra blank line before the pre-formatted block.
445            Other browsers seem to not mind one way or the other.  */
446         add_word ("<pre>");
447 
448       if (type != format && type != smallformat)
449         current_indent += default_indentation_increment;
450       break;
451 
452     case multitable:
453       do_multitable ();
454       break;
455 
456     case table:
457     case ftable:
458     case vtable:
459     case itemize:
460       close_single_paragraph ();
461       current_indent += default_indentation_increment;
462       filling_enabled = indented_fill = 1;
463 #if defined (INDENT_PARAGRAPHS_IN_TABLE)
464       inhibit_paragraph_indentation = 0;
465 #else
466       inhibit_paragraph_indentation = 1;
467 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */
468 
469       /* Make things work for losers who forget the itemize syntax. */
470       if (type == itemize)
471         {
472           if (!(*insertion_stack->item_function))
473             {
474               free (insertion_stack->item_function);
475               insertion_stack->item_function = xstrdup ("@bullet");
476             }
477         }
478 
479       if (!*insertion_stack->item_function)
480         {
481           line_error (_("%s requires an argument: the formatter for %citem"),
482                       insertion_type_pname (type), COMMAND_PREFIX);
483         }
484 
485       if (html)
486         {
487           if (type == itemize)
488 	    {
489 	      add_word ("<ul>\n");
490 	      in_paragraph = 0;
491 	    }
492           else
493             add_word (dl_tag);
494         }
495       break;
496 
497     case enumerate:
498       close_single_paragraph ();
499       no_indent = 0;
500 #if defined (INDENT_PARAGRAPHS_IN_TABLE)
501       inhibit_paragraph_indentation = 0;
502 #else
503       inhibit_paragraph_indentation = 1;
504 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */
505 
506       current_indent += default_indentation_increment;
507       filling_enabled = indented_fill = 1;
508 
509       if (html)
510         enum_html ();
511 
512       if (isdigit (*enumeration_arg))
513         start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
514       else
515         start_enumerating (*enumeration_arg, ENUM_ALPHA);
516       break;
517 
518       /* @group does nothing special in makeinfo. */
519     case group:
520       /* Only close the paragraph if we are not inside of an
521          @example-like environment. */
522       if (!insertion_stack->next
523           || (insertion_stack->next->insertion != display
524               && insertion_stack->next->insertion != smalldisplay
525               && insertion_stack->next->insertion != example
526               && insertion_stack->next->insertion != smallexample
527               && insertion_stack->next->insertion != lisp
528               && insertion_stack->next->insertion != smalllisp
529               && insertion_stack->next->insertion != format
530               && insertion_stack->next->insertion != smallformat
531               && insertion_stack->next->insertion != flushleft
532               && insertion_stack->next->insertion != flushright))
533         close_single_paragraph ();
534       break;
535 
536       /* Insertions that are no-ops in info, but do something in TeX. */
537     case cartouche:
538     case ifclear:
539     case ifhtml:
540     case ifinfo:
541     case ifnothtml:
542     case ifnotinfo:
543     case ifnottex:
544     case ifset:
545     case iftex:
546     case rawtex:
547       if (in_menu)
548         no_discard++;
549       break;
550 
551     case rawhtml:
552       escape_html = 0;
553       break;
554 
555     case defcv:
556     case deffn:
557     case defivar:
558     case defmac:
559     case defmethod:
560     case defop:
561     case defopt:
562     case defspec:
563     case deftp:
564     case deftypefn:
565     case deftypefun:
566     case deftypeivar:
567     case deftypemethod:
568     case deftypeop:
569     case deftypevar:
570     case deftypevr:
571     case defun:
572     case defvar:
573     case defvr:
574       inhibit_paragraph_indentation = 1;
575       filling_enabled = indented_fill = 1;
576       current_indent += default_indentation_increment;
577       no_indent = 0;
578       break;
579 
580     case flushleft:
581       close_single_paragraph ();
582       inhibit_paragraph_indentation = 1;
583       filling_enabled = indented_fill = no_indent = 0;
584       break;
585 
586     case flushright:
587       close_single_paragraph ();
588       filling_enabled = indented_fill = no_indent = 0;
589       inhibit_paragraph_indentation = 1;
590       force_flush_right++;
591       break;
592 
593     default:
594       line_error ("begin_insertion internal error: type=%d", type);
595 
596     }
597 
598   if (!no_discard)
599     discard_until ("\n");
600 }
601 
602 /* Try to end the insertion with the specified TYPE.  With a value of
603    `bad_type', TYPE gets translated to match the value currently on top
604    of the stack.  Otherwise, if TYPE doesn't match the top of the
605    insertion stack, give error. */
606 void
607 end_insertion (type)
608      enum insertion_type type;
609 {
610   enum insertion_type temp_type;
611 
612   if (!insertion_level)
613     return;
614 
615   temp_type = current_insertion_type ();
616 
617   if (type == bad_type)
618     type = temp_type;
619 
620   if (type != temp_type)
621     {
622       line_error
623         (_("`@end' expected `%s', but saw `%s'"),
624          insertion_type_pname (temp_type), insertion_type_pname (type));
625       return;
626     }
627 
628   pop_insertion ();
629 
630   switch (type)
631     {
632       /* Insertions which have no effect on paragraph formatting. */
633     case ifclear:
634     case ifhtml:
635     case ifinfo:
636     case ifnothtml:
637     case ifnotinfo:
638     case ifnottex:
639     case ifset:
640     case iftex:
641     case rawtex:
642       break;
643 
644     case rawhtml:
645       escape_html = 1;
646       break;
647 
648     case direntry:              /* Eaten if html. */
649       insert_string ("END-INFO-DIR-ENTRY\n\n");
650       close_insertion_paragraph ();
651       break;
652 
653     case detailmenu:
654       in_detailmenu--;          /* No longer hacking menus. */
655       if (!in_menu)
656         {
657           if (!no_headers)
658             close_insertion_paragraph ();
659         }
660       break;
661 
662     case menu:
663       in_menu--;                /* No longer hacking menus. */
664       if (html)
665         add_word ("</ul>\n");
666       else if (!no_headers)
667         close_insertion_paragraph ();
668       break;
669 
670     case multitable:
671       end_multitable ();
672       break;
673 
674     case enumerate:
675       stop_enumerating ();
676       close_insertion_paragraph ();
677       current_indent -= default_indentation_increment;
678       if (html)
679         add_word ("</ol>\n");
680       break;
681 
682     case flushleft:
683     case group:
684     case cartouche:
685       close_insertion_paragraph ();
686       break;
687 
688     case format:
689     case smallformat:
690     case display:
691     case smalldisplay:
692     case example:
693     case smallexample:
694     case lisp:
695     case smalllisp:
696     case quotation:
697       /* @format and @smallformat are the only fixed_width insertion
698          without a change in indentation. */
699       if (type != format && type != smallformat)
700         current_indent -= default_indentation_increment;
701 
702       if (html)
703         add_word (type == quotation ? "</blockquote>\n" : "</pre>\n");
704 
705       /* The ending of one of these insertions always marks the
706          start of a new paragraph. */
707       close_insertion_paragraph ();
708       break;
709 
710     case table:
711     case ftable:
712     case vtable:
713       current_indent -= default_indentation_increment;
714       if (html)
715         add_word ("</dl>\n");
716       break;
717 
718     case itemize:
719       current_indent -= default_indentation_increment;
720       if (html)
721         add_word ("</ul>\n");
722       close_insertion_paragraph ();
723       break;
724 
725     case flushright:
726       force_flush_right--;
727       close_insertion_paragraph ();
728       break;
729 
730     /* Handle the @defun insertions with this default clause. */
731     default:
732       {
733 	enum insertion_type base_type;
734 
735         if (type < defcv || type > defvr)
736           line_error ("end_insertion internal error: type=%d", type);
737 
738         base_type = get_base_type (type);
739         switch (base_type)
740           {
741           case deffn:
742           case defvr:
743           case deftp:
744           case deftypefn:
745           case deftypevr:
746           case defcv:
747           case defop:
748 	  case deftypemethod:
749 	  case deftypeop:
750 	  case deftypeivar:
751 	    if (html)
752 	      /* close the tables which has been opened in defun.c */
753               add_word ("</TD></TR>\n</TABLE>\n");
754             break;
755           } /* switch (base_type)... */
756 
757         current_indent -= default_indentation_increment;
758         close_insertion_paragraph ();
759       }
760       break;
761 
762     }
763 
764   if (current_indent < 0)
765     line_error ("end_insertion internal error: current indent=%d",
766                 current_indent);
767 }
768 
769 /* Insertions cannot cross certain boundaries, such as node beginnings.  In
770    code that creates such boundaries, you should call `discard_insertions'
771    before doing anything else.  It prints the errors for you, and cleans up
772    the insertion stack.
773 
774    With nonzero SPECIALS_OK argument, allows unmatched
775    @if... conditionals, otherwise not.  This is because conditionals can
776    cross node boundaries.  Always happens with the @top node, for example.  */
777 void
778 discard_insertions (specials_ok)
779     int specials_ok;
780 {
781   int real_line_number = line_number;
782   while (insertion_stack)
783     {
784       if (specials_ok
785           && ((ifclear <= insertion_stack->insertion
786                && insertion_stack->insertion <= iftex)
787               || insertion_stack->insertion == rawhtml
788               || insertion_stack->insertion == rawtex))
789         break;
790       else
791         {
792           char *offender = insertion_type_pname (insertion_stack->insertion);
793           char *current_filename = input_filename;
794 
795           input_filename = insertion_stack->filename;
796           line_number = insertion_stack->line_number;
797           line_error (_("No matching `%cend %s'"), COMMAND_PREFIX, offender);
798           input_filename = current_filename;
799           pop_insertion ();
800         }
801     }
802   line_number = real_line_number;
803 }
804 
805 /* Insertion (environment) commands.  */
806 
807 void
808 cm_quotation ()
809 {
810   begin_insertion (quotation);
811 }
812 
813 void
814 cm_example ()
815 {
816   begin_insertion (example);
817 }
818 
819 void
820 cm_smallexample ()
821 {
822   begin_insertion (smallexample);
823 }
824 
825 void
826 cm_lisp ()
827 {
828   begin_insertion (lisp);
829 }
830 
831 void
832 cm_smalllisp ()
833 {
834   begin_insertion (smalllisp);
835 }
836 
837 /* @cartouche/@end cartouche draws box with rounded corners in
838    TeX output.  Right now, just a no-op insertion. */
839 void
840 cm_cartouche ()
841 {
842   begin_insertion (cartouche);
843 }
844 
845 void
846 cm_format ()
847 {
848   begin_insertion (format);
849 }
850 
851 void
852 cm_smallformat ()
853 {
854   begin_insertion (smallformat);
855 }
856 
857 void
858 cm_display ()
859 {
860   begin_insertion (display);
861 }
862 
863 void
864 cm_smalldisplay ()
865 {
866   begin_insertion (smalldisplay);
867 }
868 
869 void
870 cm_direntry ()
871 {
872   if (no_headers || html)
873     command_name_condition ();
874   else
875     begin_insertion (direntry);
876 }
877 
878 void
879 cm_itemize ()
880 {
881   begin_insertion (itemize);
882 }
883 
884 /* Start an enumeration insertion of type TYPE.  If the user supplied
885    no argument on the line, then use DEFAULT_STRING as the initial string. */
886 static void
887 do_enumeration (type, default_string)
888      int type;
889      char *default_string;
890 {
891   get_until_in_line (0, ".", &enumeration_arg);
892   canon_white (enumeration_arg);
893 
894   if (!*enumeration_arg)
895     {
896       free (enumeration_arg);
897       enumeration_arg = xstrdup (default_string);
898     }
899 
900   if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
901     {
902       warning (_("%s requires letter or digit"), insertion_type_pname (type));
903 
904       switch (type)
905         {
906         case enumerate:
907           default_string = "1";
908           break;
909         }
910       enumeration_arg = xstrdup (default_string);
911     }
912   begin_insertion (type);
913 }
914 
915 void
916 cm_enumerate ()
917 {
918   do_enumeration (enumerate, "1");
919 }
920 
921 void
922 cm_table ()
923 {
924   begin_insertion (table);
925 }
926 
927 void
928 cm_multitable ()
929 {
930   begin_insertion (multitable); /* @@ */
931 }
932 
933 void
934 cm_ftable ()
935 {
936   begin_insertion (ftable);
937 }
938 
939 void
940 cm_vtable ()
941 {
942   begin_insertion (vtable);
943 }
944 
945 void
946 cm_group ()
947 {
948   begin_insertion (group);
949 }
950 
951 void
952 cm_ifinfo ()
953 {
954   if (process_info)
955     begin_insertion (ifinfo);
956   else
957     command_name_condition ();
958 }
959 
960 void
961 cm_ifnotinfo ()
962 {
963   if (!process_info)
964     begin_insertion (ifnotinfo);
965   else
966     command_name_condition ();
967 }
968 
969 
970 /* Insert raw HTML (no escaping of `<' etc.). */
971 void
972 cm_html ()
973 {
974   if (process_html)
975     begin_insertion (rawhtml);
976   else
977     command_name_condition ();
978 }
979 
980 void
981 cm_ifhtml ()
982 {
983   if (process_html)
984     begin_insertion (ifhtml);
985   else
986     command_name_condition ();
987 }
988 
989 void
990 cm_ifnothtml ()
991 {
992   if (!process_html)
993     begin_insertion (ifnothtml);
994   else
995     command_name_condition ();
996 }
997 
998 
999 void
1000 cm_tex ()
1001 {
1002   if (process_tex)
1003     begin_insertion (rawtex);
1004   else
1005     command_name_condition ();
1006 }
1007 
1008 void
1009 cm_iftex ()
1010 {
1011   if (process_tex)
1012     begin_insertion (iftex);
1013   else
1014     command_name_condition ();
1015 }
1016 
1017 void
1018 cm_ifnottex ()
1019 {
1020   if (!process_tex)
1021     begin_insertion (ifnottex);
1022   else
1023     command_name_condition ();
1024 }
1025 
1026 /* Begin an insertion where the lines are not filled or indented. */
1027 void
1028 cm_flushleft ()
1029 {
1030   begin_insertion (flushleft);
1031 }
1032 
1033 /* Begin an insertion where the lines are not filled, and each line is
1034    forced to the right-hand side of the page. */
1035 void
1036 cm_flushright ()
1037 {
1038   begin_insertion (flushright);
1039 }
1040 
1041 void
1042 cm_menu ()
1043 {
1044   if (current_node == NULL)
1045     {
1046       warning (_("@menu seen before first @node, creating `Top' node"));
1047       warning (_("perhaps your @top node should be wrapped in @ifnottex rather than @ifinfo?"));
1048       /* Include @top command so we can construct the implicit node tree.  */
1049       execute_string ("@node top\n@top Top\n");
1050     }
1051   begin_insertion (menu);
1052 }
1053 
1054 void
1055 cm_detailmenu ()
1056 {
1057   if (current_node == NULL)
1058     { /* Problems anyway, @detailmenu should always be inside @menu.  */
1059       warning (_("@detailmenu seen before first node, creating `Top' node"));
1060       execute_string ("@node top\n@top Top\n");
1061     }
1062   begin_insertion (detailmenu);
1063 }
1064 
1065 /* End existing insertion block. */
1066 void
1067 cm_end ()
1068 {
1069   char *temp;
1070   enum insertion_type type;
1071 
1072   if (!insertion_level)
1073     {
1074       line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command);
1075       return;
1076     }
1077 
1078   get_rest_of_line (0, &temp);
1079 
1080   if (temp[0] == 0)
1081     line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command);
1082 
1083   type = find_type_from_name (temp);
1084 
1085   if (type == bad_type)
1086     {
1087       line_error (_("Bad argument to `%s', `%s', using `%s'"),
1088            command, temp, insertion_type_pname (current_insertion_type ()));
1089     }
1090   end_insertion (type);
1091   free (temp);
1092 }
1093 
1094 /* @itemx, @item. */
1095 
1096 static int itemx_flag = 0;
1097 
1098 /* Return whether CMD takes a brace-delimited {arg}.  */
1099 static int
1100 command_needs_braces (cmd)
1101      char *cmd;
1102 {
1103   int i;
1104   for (i = 0; command_table[i].name; i++)
1105     {
1106       if (STREQ (command_table[i].name, cmd))
1107         return command_table[i].argument_in_braces == BRACE_ARGS;
1108     }
1109 
1110   return 0; /* macro or alias */
1111 }
1112 
1113 
1114 void
1115 cm_item ()
1116 {
1117   char *rest_of_line, *item_func;
1118 
1119   /* Can only hack "@item" while inside of an insertion. */
1120   if (insertion_level)
1121     {
1122       INSERTION_ELT *stack = insertion_stack;
1123       int original_input_text_offset;
1124 
1125       skip_whitespace ();
1126       original_input_text_offset = input_text_offset;
1127 
1128       get_rest_of_line (0, &rest_of_line);
1129       item_func = current_item_function ();
1130 
1131     /* Do the right thing depending on which insertion function is active. */
1132     switch_top:
1133       switch (stack->insertion)
1134         {
1135         case multitable:
1136           multitable_item ();
1137           /* Support text directly after the @item.  */
1138           if (*rest_of_line)
1139             {
1140               line_number--;
1141               input_text_offset = original_input_text_offset;
1142             }
1143           break;
1144 
1145         case ifclear:
1146         case ifhtml:
1147         case ifinfo:
1148         case ifnothtml:
1149         case ifnotinfo:
1150         case ifnottex:
1151         case ifset:
1152         case iftex:
1153         case rawhtml:
1154         case rawtex:
1155         case tex:
1156         case cartouche:
1157           stack = stack->next;
1158           if (!stack)
1159             goto no_insertion;
1160           else
1161             goto switch_top;
1162           break;
1163 
1164         case menu:
1165         case quotation:
1166         case example:
1167         case smallexample:
1168         case lisp:
1169         case smalllisp:
1170         case format:
1171         case smallformat:
1172         case display:
1173         case smalldisplay:
1174         case group:
1175           line_error (_("@%s not meaningful inside `@%s' block"),
1176                       command,
1177                       insertion_type_pname (current_insertion_type ()));
1178           break;
1179 
1180         case itemize:
1181         case enumerate:
1182           if (itemx_flag)
1183             {
1184               line_error (_("@itemx not meaningful inside `%s' block"),
1185                           insertion_type_pname (current_insertion_type ()));
1186             }
1187           else
1188             {
1189               if (html)
1190 		{
1191 		  if (in_paragraph)
1192 		    {
1193 		      add_word ("</p>");
1194 		      in_paragraph = 0;
1195 		    }
1196 		  add_word ("<li>");
1197 		}
1198               else
1199                 {
1200                   start_paragraph ();
1201                   kill_self_indent (-1);
1202                   filling_enabled = indented_fill = 1;
1203 
1204                   if (current_item_function ())
1205                     {
1206                       output_column = current_indent - 2;
1207                       indent (output_column);
1208 
1209                       /* The item marker can be given with or without
1210                          braces -- @bullet and @bullet{} are both ok.
1211                          Or it might be something that doesn't take
1212                          braces at all, such as "o" or "#" or "@ ".
1213                          Thus, only supply braces if the item marker is
1214                          a command, they haven't supplied braces
1215                          themselves, and we know it needs them.  */
1216                       if (item_func && *item_func)
1217                         {
1218                           if (*item_func == COMMAND_PREFIX
1219                               && item_func[strlen (item_func) - 1] != '}'
1220                               && command_needs_braces (item_func + 1))
1221                             execute_string ("%s{}", item_func);
1222                           else
1223                             execute_string ("%s", item_func);
1224                         }
1225                       insert (' ');
1226                       output_column++;
1227                     }
1228                   else
1229                     enumerate_item ();
1230 
1231                   /* Special hack.  This makes `close_paragraph' a no-op until
1232                      `start_paragraph' has been called. */
1233                   must_start_paragraph = 1;
1234                 }
1235 
1236 	      /* Handle text directly after the @item.  */
1237 	      if (*rest_of_line)
1238 		{
1239 		  line_number--;
1240 		  input_text_offset = original_input_text_offset;
1241 		}
1242             }
1243           break;
1244 
1245         case table:
1246         case ftable:
1247         case vtable:
1248           if (html)
1249             {
1250               static int last_html_output_position = 0;
1251 
1252               /* If nothing has been output since the last <dd>,
1253                  remove the empty <dd> element.  Some browsers render
1254                  an extra empty line for <dd><dt>, which makes @itemx
1255                  conversion look ugly.  */
1256               if (last_html_output_position == output_position
1257                   && strncmp ((char *) output_paragraph, "<dd>",
1258                                 output_paragraph_offset) == 0)
1259                 output_paragraph_offset = 0;
1260 
1261               /* Force the browser to render one blank line before
1262                  each new @item in a table.  But don't do that unless
1263                  this is the first <dt> after the <dl>, or if we are
1264                  converting @itemx.
1265 
1266                  Note that there are some browsers which ignore <br>
1267                  in this context, but I cannot find any way to force
1268                  them all render exactly one blank line.  */
1269               if (!itemx_flag
1270                   && strncmp ((char *) output_paragraph
1271                               + output_paragraph_offset - sizeof (dl_tag) + 1,
1272                               dl_tag, sizeof (dl_tag) - 1) != 0)
1273                 add_word ("<br>");
1274 
1275               add_word ("<dt>");
1276               if (item_func && *item_func)
1277                 execute_string ("%s{%s}", item_func, rest_of_line);
1278               else
1279                 execute_string ("%s", rest_of_line);
1280 
1281               if (current_insertion_type () == ftable)
1282                 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
1283 
1284               if (current_insertion_type () == vtable)
1285                 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
1286               /* Make sure output_position is updated, so we could
1287                  remember it.  */
1288               close_single_paragraph ();
1289               last_html_output_position = output_position;
1290               add_word ("<dd>");
1291             }
1292           else
1293             {
1294               /* We need this to determine if we have two @item's in a row
1295                  (see test just below).  */
1296               static int last_item_output_position = 0;
1297 
1298               /* Get rid of extra characters. */
1299               kill_self_indent (-1);
1300 
1301               /* If we have one @item followed directly by another @item,
1302                  we need to insert a blank line.  This is not true for
1303                  @itemx, though.  */
1304               if (!itemx_flag && last_item_output_position == output_position)
1305                 insert ('\n');
1306 
1307               /* `close_paragraph' almost does what we want.  The problem
1308                  is when paragraph_is_open, and last_char_was_newline, and
1309                  the last newline has been turned into a space, because
1310                  filling_enabled. I handle it here. */
1311               if (last_char_was_newline && filling_enabled &&
1312                   paragraph_is_open)
1313                 insert ('\n');
1314               close_paragraph ();
1315 
1316 #if defined (INDENT_PARAGRAPHS_IN_TABLE)
1317               /* Indent on a new line, but back up one indentation level. */
1318               {
1319                 int save = inhibit_paragraph_indentation;
1320                 inhibit_paragraph_indentation = 1;
1321                 /* At this point, inserting any non-whitespace character will
1322                    force the existing indentation to be output. */
1323                 add_char ('i');
1324                 inhibit_paragraph_indentation = save;
1325               }
1326 #else /* !INDENT_PARAGRAPHS_IN_TABLE */
1327               add_char ('i');
1328 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */
1329 
1330               output_paragraph_offset--;
1331               kill_self_indent (default_indentation_increment + 1);
1332 
1333               /* Add item's argument to the line. */
1334               filling_enabled = 0;
1335               if (item_func && *item_func)
1336                 execute_string ("%s{%s}", item_func, rest_of_line);
1337               else
1338                 execute_string ("%s", rest_of_line);
1339 
1340               if (current_insertion_type () == ftable)
1341                 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
1342               else if (current_insertion_type () == vtable)
1343                 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
1344 
1345               /* Start a new line, and let start_paragraph ()
1346                  do the indenting of it for you. */
1347               close_single_paragraph ();
1348               indented_fill = filling_enabled = 1;
1349               last_item_output_position = output_position;
1350             }
1351         }
1352       free (rest_of_line);
1353     }
1354   else
1355     {
1356     no_insertion:
1357       line_error (_("%c%s found outside of an insertion block"),
1358                   COMMAND_PREFIX, command);
1359     }
1360 }
1361 
1362 void
1363 cm_itemx ()
1364 {
1365   itemx_flag++;
1366   cm_item ();
1367   itemx_flag--;
1368 }
1369