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