fdl.texi is needed.
[dragonfly.git] / contrib / texinfo-4 / makeinfo / insertion.c
1 /* insertion.c -- insertions for Texinfo.
2    $Id: insertion.c,v 1.55 2004/11/11 18:34:28 karl Exp $
3
4    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
5    Foundation, Inc.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "system.h"
22 #include "cmds.h"
23 #include "defun.h"
24 #include "float.h"
25 #include "html.h"
26 #include "insertion.h"
27 #include "macro.h"
28 #include "makeinfo.h"
29 #include "multi.h"
30 #include "xml.h"
31
32 /* Must match list in insertion.h.  */
33 static char *insertion_type_names[] =
34
35   "cartouche", "copying", "defcv", "deffn", "defivar", "defmac",
36   "defmethod", "defop", "defopt", "defspec", "deftp", "deftypecv",
37   "deftypefn", "deftypefun", "deftypeivar", "deftypemethod",
38   "deftypeop", "deftypevar", "deftypevr", "defun", "defvar", "defvr",
39   "detailmenu", "direntry", "display", "documentdescription",
40   "enumerate", "example", "float", "flushleft", "flushright", "format",
41   "ftable", "group", "ifclear", "ifdocbook", "ifhtml", "ifinfo",
42   "ifnotdocbook", "ifnothtml", "ifnotinfo", "ifnotplaintext", "ifnottex",
43   "ifnotxml", "ifplaintext", "ifset", "iftex", "ifxml", "itemize", "lisp",
44   "menu", "multitable", "quotation", "rawdocbook", "rawhtml", "rawtex",
45   "rawxml", "smalldisplay", "smallexample", "smallformat", "smalllisp",
46   "verbatim", "table", "tex", "vtable", "titlepage", "bad_type"
47 };
48
49 /* All nested environments.  */
50 INSERTION_ELT *insertion_stack = NULL;
51
52 /* How deeply we're nested.  */
53 int insertion_level = 0;
54
55 /* Set to 1 if we've processed (commentary) text in a @menu that
56    wasn't part of a menu item.  */
57 int had_menu_commentary;
58
59 /* How to examine menu lines.  */
60 int in_detailmenu = 0;
61
62 /* Whether to examine menu lines.  */
63 int in_menu = 0;
64
65 /* Set to 1 if <p> is written in normal context. 
66    Used for menu and itemize. */
67 int in_paragraph = 0;
68
69 /* Since an insertion is already in the stack before we reach the switch
70    statement, we cannot use is_in_insertion_of_type (always returns true.) Also
71    making it return the level found, and comparing it with the current level is
72    no use, due to the order of stack.  */
73 static int float_active = 0;
74
75 /* Unsetting escape_html blindly causes text inside @html/etc. to be escaped if
76    used within a rmacro.  */
77 static int raw_output_block = 0;
78
79 /* Non-zero if a <dl> element has a <dt> element in it.  We use this when
80    deciding whether to insert a <br> or not.  */
81 static int html_deflist_has_term = 0;
82 \f
83 void
84 init_insertion_stack (void)
85 {
86   insertion_stack = NULL;
87 }
88
89 /* Return the type of the current insertion. */
90 static enum insertion_type
91 current_insertion_type (void)
92 {
93   return insertion_level ? insertion_stack->insertion : bad_type;
94 }
95
96 /* Return the string which is the function to wrap around items, or NULL
97    if we're not in an environment where @item is ok.  */
98 static char *
99 current_item_function (void)
100 {
101   int done = 0;
102   INSERTION_ELT *elt = insertion_stack;
103
104   /* Skip down through the stack until we find an insertion with an
105      itemize function defined, i.e., skip conditionals, @cartouche, etc.  */
106   while (!done && elt)
107     {
108       switch (elt->insertion)
109         {
110         /* This list should match the one in cm_item.  */
111         case ifclear:
112         case ifhtml:
113         case ifinfo:
114         case ifnothtml:
115         case ifnotinfo:
116         case ifnotplaintext:
117         case ifnottex:
118         case ifnotxml:
119         case ifplaintext:
120         case ifset:
121         case iftex:
122         case ifxml:
123         case rawdocbook:
124         case rawhtml:
125         case rawxml:
126         case rawtex:
127         case tex:
128         case cartouche:
129           elt = elt->next;
130           break;
131       
132         default:
133           done = 1;
134         }
135     }
136
137   /* item_function usually gets assigned the empty string.  */
138   return done && (*elt->item_function) ? elt->item_function : NULL;
139 }
140
141 /* Parse the item marker function off the input.  If result is just "@",
142    change it to "@ ", since "@" by itself is not a command.  This makes
143    "@ ", "@\t", and "@\n" all the same, but their default meanings are
144    the same anyway, and let's not worry about supporting redefining them.  */
145 static char *
146 get_item_function (void)
147 {
148   char *item_function;
149   char *item_loc;
150   
151   get_rest_of_line (0, &item_function);
152
153   /* If the document erroneously says
154        @itemize @bullet @item foobar
155      it's nicer to give an error up front than repeat `@bullet expected
156      braces' until we get a segmentation fault.  */
157   item_loc = strstr (item_function, "@item");
158   if (item_loc)
159     {
160       line_error (_("@item not allowed in argument to @itemize"));
161       *item_loc = 0;
162     }
163
164   /* If we hit the end of text in get_rest_of_line, backing up
165      input pointer will cause the last character of the last line
166      be pushed back onto the input, which is wrong.  */
167   if (input_text_offset < input_text_length)
168     backup_input_pointer ();
169
170   if (STREQ (item_function, "@"))
171     {
172       free (item_function);
173       item_function = xstrdup ("@ ");
174     }
175
176   return item_function;
177 }
178
179  /* Push the state of the current insertion on the stack. */
180 static void
181 push_insertion (enum insertion_type type, char *item_function)
182 {
183   INSERTION_ELT *new = xmalloc (sizeof (INSERTION_ELT));
184
185   new->item_function = item_function;
186   new->filling_enabled = filling_enabled;
187   new->indented_fill = indented_fill;
188   new->insertion = type;
189   new->line_number = line_number;
190   new->filename = xstrdup (input_filename);
191   new->inhibited = inhibit_paragraph_indentation;
192   new->in_fixed_width_font = in_fixed_width_font;
193   new->next = insertion_stack;
194   insertion_stack = new;
195   insertion_level++;
196 }
197
198  /* Pop the value on top of the insertion stack into the
199     global variables. */
200 void
201 pop_insertion (void)
202 {
203   INSERTION_ELT *temp = insertion_stack;
204
205   if (temp == NULL)
206     return;
207
208   in_fixed_width_font = temp->in_fixed_width_font;
209   inhibit_paragraph_indentation = temp->inhibited;
210   filling_enabled = temp->filling_enabled;
211   indented_fill = temp->indented_fill;
212   free_and_clear (&(temp->item_function));
213   free_and_clear (&(temp->filename));
214   insertion_stack = insertion_stack->next;
215   free (temp);
216   insertion_level--;
217 }
218
219  /* Return a pointer to the print name of this
220     enumerated type. */
221 static const char *
222 insertion_type_pname (enum insertion_type type)
223 {
224   if ((int) type < (int) bad_type)
225   {
226     if (type == rawdocbook)
227       return "docbook";
228     else if (type == rawhtml)
229       return "html";
230     else if (type == rawxml)
231       return "xml";
232     else if (type == rawtex)
233       return "tex";
234     else
235       return insertion_type_names[(int) type];
236   }
237   else
238     return _("Broken-Type in insertion_type_pname");
239 }
240
241 /* Return the insertion_type associated with NAME.
242    If the type is not one of the known ones, return BAD_TYPE. */
243 enum insertion_type
244 find_type_from_name (char *name)
245 {
246   int index = 0;
247   while (index < (int) bad_type)
248     {
249       if (STREQ (name, insertion_type_names[index]))
250         return (enum insertion_type) index;
251       if (index == rawdocbook && STREQ (name, "docbook"))
252         return rawdocbook;
253       if (index == rawhtml && STREQ (name, "html"))
254         return rawhtml;
255       if (index == rawxml && STREQ (name, "xml"))
256         return rawxml;
257       if (index == rawtex && STREQ (name, "tex"))
258         return rawtex;
259       index++;
260     }
261   return bad_type;
262 }
263
264 /* Simple function to query insertion_stack to see if we are inside a given
265    insertion type. */
266 int
267 is_in_insertion_of_type (int type)
268 {
269   INSERTION_ELT *temp = insertion_stack;
270
271   if (!insertion_level)
272     return 0;
273
274   while (temp)
275     {
276       if (temp->insertion == type)
277         return 1;
278       temp = temp->next;
279     }
280
281   return 0;
282 }
283
284
285 static int
286 defun_insertion (enum insertion_type type)
287 {
288   return 0
289      || (type == defcv)
290      || (type == deffn)
291      || (type == defivar)
292      || (type == defmac)
293      || (type == defmethod)
294      || (type == defop)
295      || (type == defopt)
296      || (type == defspec)
297      || (type == deftp)
298      || (type == deftypecv)
299      || (type == deftypefn)
300      || (type == deftypefun)
301      || (type == deftypeivar)
302      || (type == deftypemethod)
303      || (type == deftypeop)
304      || (type == deftypevar)
305      || (type == deftypevr)
306      || (type == defun)
307      || (type == defvar)
308      || (type == defvr)
309   ;
310 }
311
312 /* MAX_NS is the maximum nesting level for enumerations.  I picked 100
313    which seemed reasonable.  This doesn't control the number of items,
314    just the number of nested lists. */
315 #define max_stack_depth 100
316 #define ENUM_DIGITS 1
317 #define ENUM_ALPHA  2
318 typedef struct {
319   int enumtype;
320   int enumval;
321 } DIGIT_ALPHA;
322
323 DIGIT_ALPHA enumstack[max_stack_depth];
324 int enumstack_offset = 0;
325 int current_enumval = 1;
326 int current_enumtype = ENUM_DIGITS;
327 char *enumeration_arg = NULL;
328
329 static void
330 start_enumerating (int at, int type)
331 {
332   if ((enumstack_offset + 1) == max_stack_depth)
333     {
334       line_error (_("Enumeration stack overflow"));
335       return;
336     }
337   enumstack[enumstack_offset].enumtype = current_enumtype;
338   enumstack[enumstack_offset].enumval = current_enumval;
339   enumstack_offset++;
340   current_enumval = at;
341   current_enumtype = type;
342 }
343
344 static void
345 stop_enumerating (void)
346 {
347   --enumstack_offset;
348   if (enumstack_offset < 0)
349     enumstack_offset = 0;
350
351   current_enumval = enumstack[enumstack_offset].enumval;
352   current_enumtype = enumstack[enumstack_offset].enumtype;
353 }
354
355 /* Place a letter or digits into the output stream. */
356 static void
357 enumerate_item (void)
358 {
359   char temp[10];
360
361   if (current_enumtype == ENUM_ALPHA)
362     {
363       if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
364         {
365           current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
366           warning (_("lettering overflow, restarting at %c"), current_enumval);
367         }
368       sprintf (temp, "%c. ", current_enumval);
369     }
370   else
371     sprintf (temp, "%d. ", current_enumval);
372
373   indent (output_column += (current_indent - strlen (temp)));
374   add_word (temp);
375   current_enumval++;
376 }
377
378 static void
379 enum_html (void)
380 {
381   char type;
382   int start;
383
384   if (isdigit (*enumeration_arg))
385     {
386       type = '1';
387       start = atoi (enumeration_arg);
388     }
389   else if (isupper (*enumeration_arg))
390     {
391       type = 'A';
392       start = *enumeration_arg - 'A' + 1;
393     }
394   else
395     {
396       type = 'a';
397       start = *enumeration_arg - 'a' + 1;
398     }
399
400   add_html_block_elt_args ("<ol type=%c start=%d>\n", type, start);
401 }
402 \f
403 /* Conditionally parse based on the current command name. */
404 void
405 command_name_condition (void)
406 {
407   char *discarder = xmalloc (8 + strlen (command));
408
409   sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
410   discard_until (discarder);
411   discard_until ("\n");
412
413   free (discarder);
414 }
415
416 /* This is where the work for all the "insertion" style
417    commands is done.  A huge switch statement handles the
418    various setups, and generic code is on both sides. */
419 void
420 begin_insertion (enum insertion_type type)
421 {
422   int no_discard = 0;
423
424   if (defun_insertion (type))
425     {
426       push_insertion (type, xstrdup (""));
427       no_discard++;
428     }
429   else
430     {
431       push_insertion (type, get_item_function ());
432     }
433
434   switch (type)
435     {
436     case menu:
437       if (!no_headers)
438         close_paragraph ();
439
440       filling_enabled = no_indent = 0;
441       inhibit_paragraph_indentation = 1;
442
443       if (html)
444         {
445           had_menu_commentary = 1;
446         }
447       else if (!no_headers && !xml)
448         add_word ("* Menu:\n");
449
450       if (xml)
451         xml_insert_element (MENU, START);
452       else
453         in_fixed_width_font++;
454
455       next_menu_item_number = 1;
456       in_menu++;
457       no_discard++;
458       break;
459
460     case detailmenu:
461       if (!in_menu)
462         {
463           if (!no_headers)
464             close_paragraph ();
465
466           filling_enabled = no_indent = 0;
467           inhibit_paragraph_indentation = 1;
468
469           no_discard++;
470         }
471
472       if (xml)
473         {
474           xml_insert_element (DETAILMENU, START);
475           skip_whitespace_and_newlines();
476         }
477       else
478         in_fixed_width_font++;
479
480       in_detailmenu++;
481       break;
482
483     case direntry:
484       close_single_paragraph ();
485       filling_enabled = no_indent = 0;
486       inhibit_paragraph_indentation = 1;
487       insert_string ("START-INFO-DIR-ENTRY\n");
488       break;
489
490     case documentdescription:
491       {
492         char *desc;
493         int start_of_end;
494         int save_fixed_width;
495
496         discard_until ("\n"); /* ignore the @documentdescription line */
497         start_of_end = get_until ("\n@end documentdescription", &desc);
498         save_fixed_width = in_fixed_width_font;
499
500         in_fixed_width_font = 0;
501         document_description = expansion (desc, 0);
502         free (desc);
503
504         in_fixed_width_font = save_fixed_width;
505         input_text_offset = start_of_end; /* go back to the @end to match */
506       }
507       break;
508
509     case copying:
510         /* Save the copying text away for @insertcopying,
511            typically used on the back of the @titlepage (for TeX) and
512            the Top node (for info/html).  */
513       if (input_text[input_text_offset] != '\n')
514         discard_until ("\n"); /* ignore remainder of @copying line */
515
516         input_text_offset = get_until ("\n@end copying", &copying_text);
517         canon_white (copying_text);
518
519       /* For info, output the copying text right away, so it will end up
520          in the header of the Info file, before the first node, and thus
521          get copied automatically to all the split files.  For xml, also
522          output it right away since xml output is never split.
523          For html, we output it specifically in html_output_head. 
524          For plain text, there's no way to hide it, so the author must
525           use @insertcopying in the desired location.  */
526       if (docbook)
527         {
528           if (!xml_in_bookinfo)
529             {
530               xml_insert_element (BOOKINFO, START);
531               xml_in_bookinfo = 1;
532             }
533           xml_insert_element (LEGALNOTICE, START);
534         }
535
536       if (!html && !no_headers)
537         cm_insert_copying ();
538
539       if (docbook)
540         xml_insert_element (LEGALNOTICE, END);
541
542       break;
543
544     case quotation:
545       /* @quotation does filling (@display doesn't).  */
546       if (html)
547         add_html_block_elt ("<blockquote>\n");
548       else
549         {
550           /* with close_single_paragraph, we get no blank line above
551              within @copying.  */
552           close_paragraph ();
553           last_char_was_newline = no_indent = 0;
554           indented_fill = filling_enabled = 1;
555           inhibit_paragraph_indentation = 1;
556         }
557       current_indent += default_indentation_increment;
558       if (xml)
559         xml_insert_quotation (insertion_stack->item_function, START);
560       else if (strlen(insertion_stack->item_function))
561         execute_string ("@b{%s:} ", insertion_stack->item_function);
562       break;
563
564     case example:
565     case smallexample:
566     case lisp:
567     case smalllisp:
568       in_fixed_width_font++;
569       /* fall through */
570
571       /* Like @example but no fixed width font. */
572     case display:
573     case smalldisplay:
574       /* Like @display but without indentation. */
575     case smallformat:
576     case format:
577       close_single_paragraph ();
578       inhibit_paragraph_indentation = 1;
579       filling_enabled = 0;
580       last_char_was_newline = 0;
581
582       if (html)
583         /* Kludge alert: if <pre> is followed by a newline, IE3,
584            mozilla, maybe others render an extra blank line before the
585            pre-formatted block.  So don't output a newline.  */
586         add_html_block_elt_args ("<pre class=\"%s\">", command);
587
588       if (type != format && type != smallformat)
589         {
590           current_indent += example_indentation_increment;
591           if (html)
592             {
593               /* Since we didn't put \n after <pre>, we need to insert
594                  the indentation by hand.  */
595               int i;
596               for (i = current_indent; i > 0; i--)
597                 add_char (' ');
598             }
599         }
600       break;
601
602     case multitable:
603       do_multitable ();
604       break;
605
606     case table:
607     case ftable:
608     case vtable:
609     case itemize:
610       close_single_paragraph ();
611       current_indent += default_indentation_increment;
612       filling_enabled = indented_fill = 1;
613 #if defined (INDENT_PARAGRAPHS_IN_TABLE)
614       inhibit_paragraph_indentation = 0;
615 #else
616       inhibit_paragraph_indentation = 1;
617 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */
618
619       /* Make things work for losers who forget the itemize syntax. */
620       if (type == itemize)
621         {
622           if (!(*insertion_stack->item_function))
623             {
624               free (insertion_stack->item_function);
625               insertion_stack->item_function = xstrdup ("@bullet");
626             }
627         }
628
629       if (!*insertion_stack->item_function)
630         {
631           line_error (_("%s requires an argument: the formatter for %citem"),
632                       insertion_type_pname (type), COMMAND_PREFIX);
633         }
634
635       if (html)
636         {
637           if (type == itemize)
638             {
639               add_html_block_elt ("<ul>\n");
640               in_paragraph = 0;
641             }
642           else
643             { /* We are just starting, so this <dl>
644                  has no <dt> children yet.  */
645               html_deflist_has_term = 0;
646               add_html_block_elt ("<dl>\n");
647             }
648         }
649       if (xml)
650         xml_begin_table (type, insertion_stack->item_function);
651
652       while (input_text[input_text_offset] == '\n'
653           && input_text[input_text_offset+1] == '\n')
654         {
655           line_number++;
656           input_text_offset++;
657         }
658
659       break;
660
661     case enumerate:
662       close_single_paragraph ();
663       no_indent = 0;
664 #if defined (INDENT_PARAGRAPHS_IN_TABLE)
665       inhibit_paragraph_indentation = 0;
666 #else
667       inhibit_paragraph_indentation = 1;
668 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */
669
670       current_indent += default_indentation_increment;
671       filling_enabled = indented_fill = 1;
672
673       if (html)
674         {
675           enum_html ();
676           in_paragraph = 0;
677         }
678
679       if (xml)
680         xml_begin_enumerate (enumeration_arg);
681       
682       if (isdigit (*enumeration_arg))
683         start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
684       else
685         start_enumerating (*enumeration_arg, ENUM_ALPHA);
686       break;
687
688       /* @group produces no output in info. */
689     case group:
690       /* Only close the paragraph if we are not inside of an
691          @example-like environment. */
692       if (xml)
693         xml_insert_element (GROUP, START);
694       else if (!insertion_stack->next
695           || (insertion_stack->next->insertion != display
696               && insertion_stack->next->insertion != smalldisplay
697               && insertion_stack->next->insertion != example
698               && insertion_stack->next->insertion != smallexample
699               && insertion_stack->next->insertion != lisp
700               && insertion_stack->next->insertion != smalllisp
701               && insertion_stack->next->insertion != format
702               && insertion_stack->next->insertion != smallformat
703               && insertion_stack->next->insertion != flushleft
704               && insertion_stack->next->insertion != flushright))
705         close_single_paragraph ();
706       break;
707
708     case cartouche:
709       if (html)
710         add_html_block_elt ("<p><table class=\"cartouche\" summary=\"cartouche\" border=\"1\"><tr><td>\n");
711       if (in_menu)
712         no_discard++;
713       break;
714
715     case floatenv:
716       /* Cannot nest floats, so complain.  */
717       if (float_active)
718         {
719           line_error (_("%cfloat environments cannot be nested"), COMMAND_PREFIX);
720           pop_insertion ();
721           break;
722         }
723
724       float_active++;
725
726       { /* Collect data about this float.  */
727         /* Example: @float [FLOATTYPE][,XREFLABEL][,POSITION] */
728         char floattype[200] = "";
729         char xreflabel[200] = "";
730         char position[200]  = "";
731         char *text;
732         char *caption;
733         char *shortcaption;
734         int start_of_end;
735         int save_line_number = line_number;
736         int save_input_text_offset = input_text_offset;
737         int i;
738
739         if (strlen (insertion_stack->item_function) > 0)
740           {
741             int i = 0, t = 0, c = 0;
742             while (insertion_stack->item_function[i])
743               {
744                 if (insertion_stack->item_function[i] == ',')
745                   {
746                     switch (t)
747                       {
748                       case 0:
749                         floattype[c] = '\0';
750                         break;
751                       case 1:
752                         xreflabel[c] = '\0';
753                         break;
754                       case 2:
755                         position[c] = '\0';
756                         break;
757                       }
758                     c = 0;
759                     t++;
760                     i++;
761                     continue;
762                   }
763
764                 switch (t)
765                   {
766                   case 0:
767                     floattype[c] = insertion_stack->item_function[i];
768                     break;
769                   case 1:
770                     xreflabel[c] = insertion_stack->item_function[i];
771                     break;
772                   case 2:
773                     position[c] = insertion_stack->item_function[i];
774                     break;
775                   }
776                 c++;
777                 i++;
778               }
779           }
780
781         skip_whitespace_and_newlines ();
782
783         start_of_end = get_until ("\n@end float", &text);
784
785         /* Get also the @caption.  */
786         i = search_forward_until_pos ("\n@caption{",
787             save_input_text_offset, start_of_end);
788         if (i > -1)
789           {
790             input_text_offset = i + sizeof ("\n@caption{") - 1;
791             get_until_in_braces ("\n@end float", &caption);
792             input_text_offset = save_input_text_offset;
793           }
794         else
795           caption = "";
796
797         /* ... and the @shortcaption.  */
798         i = search_forward_until_pos ("\n@shortcaption{",
799             save_input_text_offset, start_of_end);
800         if (i > -1)
801           {
802             input_text_offset = i + sizeof ("\n@shortcaption{") - 1;
803             get_until_in_braces ("\n@end float", &shortcaption);
804             input_text_offset = save_input_text_offset;
805           }
806         else
807           shortcaption = "";
808
809         canon_white (xreflabel);
810         canon_white (floattype);
811         canon_white (position);
812         canon_white (caption);
813         canon_white (shortcaption);
814
815         add_new_float (xstrdup (xreflabel),
816             xstrdup (caption), xstrdup (shortcaption),
817             xstrdup (floattype), xstrdup (position));
818
819         /* Move to the start of the @float so the contents get processed as
820            usual.  */
821         input_text_offset = save_input_text_offset;
822         line_number = save_line_number;
823       }
824
825       if (html)
826         add_html_block_elt ("<div class=\"float\">\n");
827       else if (docbook)
828         xml_insert_element (FLOAT, START);
829       else if (xml)
830         {
831           xml_insert_element_with_attribute (FLOAT, START,
832               "name=\"%s\"", current_float_id ());
833
834           xml_insert_element (FLOATTYPE, START);
835           execute_string ("%s", current_float_type ());
836           xml_insert_element (FLOATTYPE, END);
837
838           xml_insert_element (FLOATPOS, START);
839           execute_string ("%s", current_float_position ());
840           xml_insert_element (FLOATPOS, END);
841         }
842       else
843         { /* Info */
844           close_single_paragraph ();
845           inhibit_paragraph_indentation = 1;
846         }
847
848       /* Anchor now.  Note that XML documents get their
849          anchors with <float name="anchor"> tag.  */
850       if ((!xml || docbook) && strlen (current_float_id ()) > 0)
851         execute_string ("@anchor{%s}", current_float_id ());
852
853       break;
854
855       /* Insertions that are no-ops in info, but do something in TeX. */
856     case ifclear:
857     case ifdocbook:
858     case ifhtml:
859     case ifinfo:
860     case ifnotdocbook:
861     case ifnothtml:
862     case ifnotinfo:
863     case ifnotplaintext:
864     case ifnottex:
865     case ifnotxml:
866     case ifplaintext:
867     case ifset:
868     case iftex:
869     case ifxml:
870     case rawtex:
871       if (in_menu)
872         no_discard++;
873       break;
874
875     case rawdocbook:
876     case rawhtml:
877     case rawxml:
878       raw_output_block++;
879
880       if (raw_output_block > 0)
881         {
882           xml_no_para = 1;
883           escape_html = 0;
884           xml_keep_space++;
885         }
886
887       {
888         /* Some deuglification for improved readability.  */
889         extern int xml_in_para;
890         if (xml && !xml_in_para && xml_indentation_increment > 0)
891           add_char ('\n');
892       }
893
894       break;
895
896     case defcv:
897     case deffn:
898     case defivar:
899     case defmac:
900     case defmethod:
901     case defop:
902     case defopt:
903     case defspec:
904     case deftp:
905     case deftypecv:
906     case deftypefn:
907     case deftypefun:
908     case deftypeivar:
909     case deftypemethod:
910     case deftypeop:
911     case deftypevar:
912     case deftypevr:
913     case defun:
914     case defvar:
915     case defvr:
916       inhibit_paragraph_indentation = 1;
917       filling_enabled = indented_fill = 1;
918       current_indent += default_indentation_increment;
919       no_indent = 0;
920       if (xml)
921         xml_begin_definition ();
922       break;
923
924     case flushleft:
925       close_single_paragraph ();
926       inhibit_paragraph_indentation = 1;
927       filling_enabled = indented_fill = no_indent = 0;
928       if (html)
929         add_html_block_elt ("<div align=\"left\">");
930       break;
931
932     case flushright:
933       close_single_paragraph ();
934       filling_enabled = indented_fill = no_indent = 0;
935       inhibit_paragraph_indentation = 1;
936       force_flush_right++;
937       if (html)
938         add_html_block_elt ("<div align=\"right\">");
939       break;
940
941     case titlepage:
942       xml_insert_element (TITLEPAGE, START);
943       break;
944
945     default:
946       line_error ("begin_insertion internal error: type=%d", type);
947     }
948
949   if (!no_discard)
950     discard_until ("\n");
951 }
952
953 /* Try to end the insertion with the specified TYPE.  With a value of
954    `bad_type', TYPE gets translated to match the value currently on top
955    of the stack.  Otherwise, if TYPE doesn't match the top of the
956    insertion stack, give error. */
957 static void
958 end_insertion (int type)
959 {
960   int temp_type;
961
962   if (!insertion_level)
963     return;
964
965   temp_type = current_insertion_type ();
966
967   if (type == bad_type)
968     type = temp_type;
969
970   if (type != temp_type)
971     {
972       line_error
973         (_("`@end' expected `%s', but saw `%s'"),
974          insertion_type_pname (temp_type), insertion_type_pname (type));
975       return;
976     }
977
978   pop_insertion ();
979
980   if (xml)
981     {
982       switch (type)
983         {
984         case ifinfo:
985         case documentdescription:       
986           break;
987         case quotation:
988           xml_insert_quotation ("", END);
989           break;
990         case example:
991           xml_insert_element (EXAMPLE, END);
992           if (docbook && current_insertion_type () == floatenv)
993             xml_insert_element (FLOATEXAMPLE, END);
994           break;
995         case smallexample:
996           xml_insert_element (SMALLEXAMPLE, END);
997           if (docbook && current_insertion_type () == floatenv)
998             xml_insert_element (FLOATEXAMPLE, END);
999           break;
1000         case lisp:
1001           xml_insert_element (LISP, END);
1002           if (docbook && current_insertion_type () == floatenv)
1003             xml_insert_element (FLOATEXAMPLE, END);
1004           break;
1005         case smalllisp:
1006           xml_insert_element (SMALLLISP, END);
1007           if (docbook && current_insertion_type () == floatenv)
1008             xml_insert_element (FLOATEXAMPLE, END);
1009           break;
1010         case cartouche:
1011           xml_insert_element (CARTOUCHE, END);
1012           break;
1013         case format:
1014           if (docbook && xml_in_bookinfo && xml_in_abstract)
1015             {
1016               xml_insert_element (ABSTRACT, END);
1017               xml_in_abstract = 0;
1018             }
1019           else
1020             xml_insert_element (FORMAT, END);
1021           break;
1022         case smallformat:
1023           xml_insert_element (SMALLFORMAT, END);
1024           break;
1025         case display:
1026           xml_insert_element (DISPLAY, END);
1027           break;
1028         case smalldisplay:
1029           xml_insert_element (SMALLDISPLAY, END);
1030           break;
1031         case table:
1032         case ftable:
1033         case vtable:      
1034         case itemize:
1035           xml_end_table (type);
1036           break;
1037         case enumerate:
1038           xml_end_enumerate ();
1039           break;
1040         case group:
1041           xml_insert_element (GROUP, END);
1042           break;
1043         case titlepage:
1044           xml_insert_element (TITLEPAGE, END);
1045           break;
1046         }
1047     }
1048   switch (type)
1049     {
1050       /* Insertions which have no effect on paragraph formatting. */
1051     case copying:
1052       line_number--;
1053       break;
1054
1055     case ifclear:
1056     case ifdocbook:
1057     case ifinfo:
1058     case ifhtml:
1059     case ifnotdocbook:
1060     case ifnothtml:
1061     case ifnotinfo:
1062     case ifnotplaintext:
1063     case ifnottex:
1064     case ifnotxml:
1065     case ifplaintext:
1066     case ifset:
1067     case iftex:
1068     case ifxml:
1069     case rawtex:
1070     case titlepage:
1071       break;
1072
1073     case rawdocbook:
1074     case rawhtml:
1075     case rawxml:
1076       raw_output_block--;
1077
1078       if (raw_output_block <= 0)
1079         {
1080           xml_no_para = 0;
1081           escape_html = 1;
1082           xml_keep_space--;
1083         }
1084
1085       if ((xml || html) && output_paragraph[output_paragraph_offset-1] == '\n')
1086         output_paragraph_offset--;
1087       break;
1088
1089     case detailmenu:
1090       if (xml)
1091         xml_insert_element (DETAILMENU, END);
1092
1093       in_detailmenu--;          /* No longer hacking menus. */
1094       if (!in_menu)
1095         {
1096           if (!no_headers)
1097             close_insertion_paragraph ();
1098         }
1099       break;
1100
1101     case direntry:              /* Eaten if html. */
1102       insert_string ("END-INFO-DIR-ENTRY\n\n");
1103       close_insertion_paragraph ();
1104       break;
1105
1106     case documentdescription:
1107       if (xml)
1108         insert_string (document_description);
1109         xml_insert_element (DOCUMENTDESCRIPTION, END);
1110       break;
1111       
1112     case menu:
1113       in_menu--;                /* No longer hacking menus. */
1114       if (html && !no_headers)
1115         add_html_block_elt ("</ul>\n");
1116       else if (!no_headers && !xml)
1117         close_insertion_paragraph ();
1118       break;
1119
1120     case multitable:
1121       end_multitable ();
1122       break;
1123
1124     case enumerate:
1125       stop_enumerating ();
1126       close_insertion_paragraph ();
1127       current_indent -= default_indentation_increment;
1128       if (html)
1129         add_html_block_elt ("</ol>\n");
1130       break;
1131
1132     case flushleft:
1133       if (html)
1134         add_html_block_elt ("</div>\n");
1135       close_insertion_paragraph ();
1136       break;
1137
1138     case cartouche:
1139       if (html)
1140         add_html_block_elt ("</td></tr></table>\n");
1141       close_insertion_paragraph ();
1142       break;
1143
1144     case group:
1145       if (!xml || docbook)
1146         close_insertion_paragraph ();
1147       break;
1148
1149     case floatenv:
1150       if (xml)
1151         xml_insert_element (FLOAT, END);
1152       else
1153         {
1154           if (html)
1155             add_html_block_elt ("<p><strong class=\"float-caption\">");
1156           else
1157             close_paragraph ();
1158
1159           no_indent = 1;
1160
1161           /* Legend:
1162                1) @float Foo,lbl & no caption:    Foo 1.1
1163                2) @float Foo & no caption:        Foo
1164                3) @float ,lbl & no caption:       1.1
1165                4) @float & no caption:                    */
1166
1167           if (!xml && !html)
1168             indent (current_indent);
1169
1170           if (strlen (current_float_type ()))
1171             execute_string ("%s", current_float_type ());
1172
1173           if (strlen (current_float_id ()) > 0)
1174             {
1175               if (strlen (current_float_type ()) > 0)
1176                 add_char (' ');
1177
1178               add_word (current_float_number ());
1179             }
1180
1181           if (strlen (current_float_title ()) > 0)
1182             {
1183               if (strlen (current_float_type ()) > 0
1184                   || strlen (current_float_id ()) > 0)
1185                 insert_string (": ");
1186
1187               execute_string ("%s", current_float_title ());
1188             }
1189
1190           /* Indent the following paragraph. */
1191           inhibit_paragraph_indentation = 0;
1192
1193           if (html)
1194             add_word ("</strong></p></div>\n");
1195           else
1196             close_paragraph ();
1197         }
1198       float_active--;
1199       break;
1200
1201     case format:
1202     case smallformat:
1203     case display:
1204     case smalldisplay:
1205     case example:
1206     case smallexample:
1207     case lisp:
1208     case smalllisp:
1209     case quotation:
1210       /* @format and @smallformat are the only fixed_width insertion
1211          without a change in indentation. */
1212       if (type != format && type != smallformat && type != quotation)
1213         current_indent -= example_indentation_increment;
1214       else if (type == quotation)
1215         current_indent -= default_indentation_increment;
1216
1217       if (html)
1218         { /* The complex code in close_paragraph that kills whitespace
1219              does not function here, since we've inserted non-whitespace
1220              (the </whatever>) before it.  The indentation already got
1221              inserted at the end of the last example line, so we have to
1222              delete it, or browsers wind up showing an extra blank line.  */
1223           kill_self_indent (default_indentation_increment);
1224           add_html_block_elt (type == quotation
1225               ? "</blockquote>\n" : "</pre>\n");
1226         }
1227
1228       /* The ending of one of these insertions always marks the
1229          start of a new paragraph, except for the XML output. */
1230       if (!xml || docbook)
1231         close_insertion_paragraph ();
1232
1233       /* </pre> closes paragraph without messing with </p>.  */
1234       if (html && type != quotation)
1235           paragraph_is_open = 0;
1236       break;
1237
1238     case table:
1239     case ftable:
1240     case vtable:
1241       current_indent -= default_indentation_increment;
1242       if (html)
1243         add_html_block_elt ("</dl>\n");
1244       close_insertion_paragraph ();
1245       break;
1246
1247     case itemize:
1248       current_indent -= default_indentation_increment;
1249       if (html)
1250         add_html_block_elt ("</ul>\n");
1251       close_insertion_paragraph ();
1252       break;
1253
1254     case flushright:
1255       force_flush_right--;
1256       if (html)
1257         add_html_block_elt ("</div>\n");
1258       close_insertion_paragraph ();
1259       break;
1260
1261     /* Handle the @defun insertions with this default clause. */
1262     default:
1263       {
1264         int base_type;
1265
1266         if (type < defcv || type > defvr)
1267           line_error ("end_insertion internal error: type=%d", type);
1268   
1269         base_type = get_base_type (type);
1270         switch (base_type)
1271           {
1272           case deffn:
1273           case defvr:
1274           case deftp:
1275           case deftypecv:
1276           case deftypefn:
1277           case deftypevr:
1278           case defcv:
1279           case defop:
1280           case deftypemethod:
1281           case deftypeop:
1282           case deftypeivar:
1283             if (html)
1284               {
1285                 if (paragraph_is_open)
1286                   add_html_block_elt ("</p>");
1287                 /* close the div and blockquote which has been opened in defun.c */
1288                 if (!rollback_empty_tag ("blockquote"))
1289                   add_html_block_elt ("</blockquote>");
1290                 add_html_block_elt ("</div>\n");
1291               }
1292             if (xml)
1293               xml_end_definition ();
1294             break;
1295           } /* switch (base_type)... */
1296   
1297         current_indent -= default_indentation_increment;
1298         close_insertion_paragraph ();
1299       }
1300       break;
1301       
1302     }
1303
1304   if (current_indent < 0)
1305     line_error ("end_insertion internal error: current indent=%d",
1306                 current_indent);
1307 }
1308
1309 /* Insertions cannot cross certain boundaries, such as node beginnings.  In
1310    code that creates such boundaries, you should call `discard_insertions'
1311    before doing anything else.  It prints the errors for you, and cleans up
1312    the insertion stack.
1313
1314    With nonzero SPECIALS_OK argument, allows unmatched
1315    @if... conditionals, otherwise not.  This is because conditionals can
1316    cross node boundaries.  Always happens with the @top node, for example.  */
1317 void
1318 discard_insertions (int specials_ok)
1319 {
1320   int real_line_number = line_number;
1321   while (insertion_stack)
1322     {
1323       if (specials_ok
1324           && ((ifclear <= insertion_stack->insertion
1325                && insertion_stack->insertion <= iftex)
1326               || insertion_stack->insertion == rawdocbook
1327               || insertion_stack->insertion == rawhtml
1328               || insertion_stack->insertion == rawxml
1329               || insertion_stack->insertion == rawtex))
1330         break;
1331       else
1332         {
1333           const char *offender = insertion_type_pname (insertion_stack->insertion);
1334
1335           file_line_error (insertion_stack->filename,
1336                            insertion_stack->line_number,
1337                            _("No matching `%cend %s'"), COMMAND_PREFIX,
1338                            offender);
1339           pop_insertion ();
1340         }
1341     }
1342   line_number = real_line_number;
1343 }
1344 \f
1345 /* Insertion (environment) commands.  */
1346
1347 void
1348 cm_quotation (void)
1349 {
1350   /* We start the blockquote element in the insertion.  */
1351   begin_insertion (quotation);
1352 }
1353
1354 void
1355 cm_example (void)
1356 {
1357   if (docbook && current_insertion_type () == floatenv)
1358     xml_begin_docbook_float (FLOATEXAMPLE);
1359
1360   if (xml)
1361     {
1362       /* Rollback previous newlines.  These occur between
1363          </para> and <example>.  */
1364       if (output_paragraph[output_paragraph_offset-1] == '\n')
1365         output_paragraph_offset--;
1366
1367       xml_insert_element (EXAMPLE, START);
1368
1369       /* Make sure example text is starting on a new line
1370          for improved readability.  */
1371       if (docbook)
1372         add_char ('\n');
1373     }
1374
1375   begin_insertion (example);
1376 }
1377
1378 void
1379 cm_smallexample (void)
1380 {
1381   if (docbook && current_insertion_type () == floatenv)
1382     xml_begin_docbook_float (FLOATEXAMPLE);
1383
1384   if (xml)
1385     {
1386       /* See cm_example comments about newlines.  */
1387       if (output_paragraph[output_paragraph_offset-1] == '\n')
1388         output_paragraph_offset--;
1389       xml_insert_element (SMALLEXAMPLE, START);
1390       if (docbook)
1391         add_char ('\n');
1392     }
1393
1394   begin_insertion (smallexample);
1395 }
1396
1397 void
1398 cm_lisp (void)
1399 {
1400   if (docbook && current_insertion_type () == floatenv)
1401     xml_begin_docbook_float (FLOATEXAMPLE);
1402
1403   if (xml)
1404     {
1405       /* See cm_example comments about newlines.  */
1406       if (output_paragraph[output_paragraph_offset-1] == '\n')
1407         output_paragraph_offset--;
1408       xml_insert_element (LISP, START);
1409       if (docbook)
1410         add_char ('\n');
1411     }
1412
1413   begin_insertion (lisp);
1414 }
1415
1416 void
1417 cm_smalllisp (void)
1418 {
1419   if (docbook && current_insertion_type () == floatenv)
1420     xml_begin_docbook_float (FLOATEXAMPLE);
1421
1422   if (xml)
1423     {
1424       /* See cm_example comments about newlines.  */
1425       if (output_paragraph[output_paragraph_offset-1] == '\n')
1426         output_paragraph_offset--;
1427       xml_insert_element (SMALLLISP, START);
1428       if (docbook)
1429         add_char ('\n');
1430     }
1431
1432   begin_insertion (smalllisp);
1433 }
1434
1435 void
1436 cm_cartouche (void)
1437 {
1438   if (docbook && current_insertion_type () == floatenv)
1439     xml_begin_docbook_float (CARTOUCHE);
1440
1441   if (xml)
1442     xml_insert_element (CARTOUCHE, START);
1443   begin_insertion (cartouche);
1444 }
1445
1446 void
1447 cm_copying (void)
1448 {
1449   begin_insertion (copying);
1450 }
1451
1452 /* Not an insertion, despite the name, but it goes with cm_copying.  */
1453 void
1454 cm_insert_copying (void)
1455 {
1456   if (!copying_text)
1457     {
1458       warning ("@copying not used before %s", command);
1459       return;
1460     }
1461
1462   execute_string ("%s", copying_text);
1463
1464   if (!xml && !html)
1465     {
1466       add_word ("\n\n");
1467       /* Update output_position so that the node positions in the tag
1468          tables will take account of the copying text.  */
1469       flush_output ();
1470     }
1471 }
1472
1473 void
1474 cm_format (void)
1475 {
1476   if (xml)
1477     {
1478       if (docbook && xml_in_bookinfo)
1479         {
1480           xml_insert_element (ABSTRACT, START);
1481           xml_in_abstract = 1;
1482         }
1483       else
1484         {
1485           /* See cm_example comments about newlines.  */
1486           if (output_paragraph[output_paragraph_offset-1] == '\n')
1487             output_paragraph_offset--;
1488           xml_insert_element (FORMAT, START);
1489           if (docbook)
1490             add_char ('\n');
1491         }
1492     }
1493   begin_insertion (format);
1494 }
1495
1496 void
1497 cm_smallformat (void)
1498 {
1499   if (xml)
1500     {
1501       /* See cm_example comments about newlines.  */
1502       if (output_paragraph[output_paragraph_offset-1] == '\n')
1503         output_paragraph_offset--;
1504       xml_insert_element (SMALLFORMAT, START);
1505       if (docbook)
1506         add_char ('\n');
1507     }
1508
1509   begin_insertion (smallformat);
1510 }
1511
1512 void
1513 cm_display (void)
1514 {
1515   if (xml)
1516     {
1517       /* See cm_example comments about newlines.  */
1518       if (output_paragraph[output_paragraph_offset-1] == '\n')
1519         output_paragraph_offset--;
1520       xml_insert_element (DISPLAY, START);
1521       if (docbook)
1522         add_char ('\n');
1523     }
1524
1525   begin_insertion (display);
1526 }
1527
1528 void
1529 cm_smalldisplay (void)
1530 {
1531   if (xml)
1532     {
1533       /* See cm_example comments about newlines.  */
1534       if (output_paragraph[output_paragraph_offset-1] == '\n')
1535         output_paragraph_offset--;
1536       xml_insert_element (SMALLDISPLAY, START);
1537       if (docbook)
1538         add_char ('\n');
1539     }
1540
1541   begin_insertion (smalldisplay);
1542 }
1543
1544 void
1545 cm_direntry (void)
1546 {
1547   if (html || xml || no_headers)
1548     command_name_condition ();
1549   else
1550     begin_insertion (direntry);
1551 }
1552
1553 void
1554 cm_documentdescription (void)
1555 {
1556   if (html)
1557     begin_insertion (documentdescription);
1558
1559   else if (xml)
1560     {
1561       xml_insert_element (DOCUMENTDESCRIPTION, START);
1562       begin_insertion (documentdescription);
1563     }
1564
1565   else
1566     command_name_condition ();
1567 }
1568
1569
1570 void
1571 cm_itemize (void)
1572 {
1573   begin_insertion (itemize);
1574 }
1575
1576 /* Start an enumeration insertion of type TYPE.  If the user supplied
1577    no argument on the line, then use DEFAULT_STRING as the initial string. */
1578 static void
1579 do_enumeration (int type, char *default_string)
1580 {
1581   get_until_in_line (0, ".", &enumeration_arg);
1582   canon_white (enumeration_arg);
1583
1584   if (!*enumeration_arg)
1585     {
1586       free (enumeration_arg);
1587       enumeration_arg = xstrdup (default_string);
1588     }
1589
1590   if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
1591     {
1592       warning (_("%s requires letter or digit"), insertion_type_pname (type));
1593
1594       switch (type)
1595         {
1596         case enumerate:
1597           default_string = "1";
1598           break;
1599         }
1600       enumeration_arg = xstrdup (default_string);
1601     }
1602   begin_insertion (type);
1603 }
1604
1605 void
1606 cm_enumerate (void)
1607 {
1608   do_enumeration (enumerate, "1");
1609 }
1610
1611 /*  Handle verbatim environment:
1612     find_end_verbatim == 0:  process until end of file
1613     find_end_verbatim != 0:  process until 'COMMAND_PREFIXend verbatim'
1614                              or end of file
1615
1616   We cannot simply copy input stream onto output stream; as the
1617   verbatim environment may be encapsulated in an @example environment,
1618   for example. */
1619 void
1620 handle_verbatim_environment (int find_end_verbatim)
1621 {
1622   int character;
1623   int seen_end = 0;
1624   int save_filling_enabled = filling_enabled;
1625   int save_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
1626   int save_escape_html = escape_html;
1627
1628   if (!insertion_stack)
1629     close_single_paragraph (); /* no blank lines if not at outer level */
1630   inhibit_paragraph_indentation = 1;
1631   filling_enabled = 0;
1632   in_fixed_width_font++;
1633   last_char_was_newline = 0;
1634
1635   /* No indentation: this is verbatim after all
1636      If you want indent, enclose @verbatim in @example
1637        current_indent += default_indentation_increment;
1638    */
1639
1640   if (html)
1641     { /* If inside @example, we'll be preceded by the indentation
1642          already.  Browsers will ignore those spaces because we're about
1643          to start another <pre> (don't ask me).  So, wipe them out for
1644          cleanliness, and re-insert.  */
1645       int i;
1646       kill_self_indent (default_indentation_increment);
1647       add_html_block_elt ("<pre class=\"verbatim\">");
1648       for (i = current_indent; i > 0; i--)
1649         add_char (' ');
1650     }
1651   else if (xml)
1652     {
1653       xml_insert_element (VERBATIM, START);
1654       escape_html = 0;
1655       add_word ("<![CDATA[");
1656     }
1657
1658   while (input_text_offset < input_text_length)
1659     {
1660       character = curchar ();
1661
1662       if (character == '\n')
1663         line_number++;
1664
1665       /* Assume no newlines in END_VERBATIM. */
1666       else if (find_end_verbatim && (character == COMMAND_PREFIX) /* @ */
1667           && (input_text_length - input_text_offset > sizeof (END_VERBATIM))
1668           && !strncmp (&input_text[input_text_offset+1], END_VERBATIM,
1669                        sizeof (END_VERBATIM)-1))
1670         {
1671           input_text_offset += sizeof (END_VERBATIM);
1672           seen_end = 1;
1673           break;
1674         }
1675
1676       if (html && character == '&' && escape_html)
1677         add_word ("&amp;");
1678       else if (html && character == '<' && escape_html)
1679         add_word ("&lt;");
1680       else
1681         add_char (character);
1682
1683       input_text_offset++;
1684     }
1685
1686   if (find_end_verbatim && !seen_end)
1687     warning (_("end of file inside verbatim block"));
1688
1689   if (html)
1690     { /* See comments in example case above.  */
1691       kill_self_indent (default_indentation_increment);
1692       add_word ("</pre>");
1693     }
1694   else if (xml)
1695     {
1696       add_word ("]]>");
1697       xml_insert_element (VERBATIM, END);
1698       escape_html = save_escape_html;
1699     }
1700   
1701   in_fixed_width_font--;
1702   filling_enabled = save_filling_enabled;
1703   inhibit_paragraph_indentation = save_inhibit_paragraph_indentation;
1704 }
1705
1706 void
1707 cm_verbatim (void)
1708 {
1709   handle_verbatim_environment (1);
1710 }
1711
1712 void
1713 cm_table (void)
1714 {
1715   begin_insertion (table);
1716 }
1717
1718 void
1719 cm_multitable (void)
1720 {
1721   begin_insertion (multitable); /* @@ */
1722 }
1723
1724 void
1725 cm_ftable (void)
1726 {
1727   begin_insertion (ftable);
1728 }
1729
1730 void
1731 cm_vtable (void)
1732 {
1733   begin_insertion (vtable);
1734 }
1735
1736 void
1737 cm_group (void)
1738 {
1739   begin_insertion (group);
1740 }
1741 \f
1742 /* Insert raw HTML (no escaping of `<' etc.). */
1743 void
1744 cm_html (int arg)
1745 {
1746   if (process_html)
1747     begin_insertion (rawhtml);
1748   else
1749     command_name_condition ();
1750 }
1751
1752 void
1753 cm_xml (int arg)
1754 {
1755   if (process_xml)
1756     begin_insertion (rawxml);
1757   else
1758     command_name_condition ();
1759 }
1760
1761 void
1762 cm_docbook (int arg)
1763 {
1764   if (process_docbook)
1765     begin_insertion (rawdocbook);
1766   else
1767     command_name_condition ();
1768 }
1769
1770 void
1771 cm_ifdocbook (void)
1772 {
1773   if (process_docbook)
1774     begin_insertion (ifdocbook);
1775   else
1776     command_name_condition ();
1777 }
1778
1779 void
1780 cm_ifnotdocbook (void)
1781 {
1782   if (!process_docbook)
1783     begin_insertion (ifnotdocbook);
1784   else
1785     command_name_condition ();
1786 }
1787
1788 void
1789 cm_ifhtml (void)
1790 {
1791   if (process_html)
1792     begin_insertion (ifhtml);
1793   else
1794     command_name_condition ();
1795 }
1796
1797 void
1798 cm_ifnothtml (void)
1799 {
1800   if (!process_html)
1801     begin_insertion (ifnothtml);
1802   else
1803     command_name_condition ();
1804 }
1805
1806
1807 void
1808 cm_ifinfo (void)
1809 {
1810   if (process_info)
1811     begin_insertion (ifinfo);
1812   else
1813     command_name_condition ();
1814 }
1815
1816 void
1817 cm_ifnotinfo (void)
1818 {
1819   if (!process_info)
1820     begin_insertion (ifnotinfo);
1821   else
1822     command_name_condition ();
1823 }
1824
1825
1826 void
1827 cm_ifplaintext (void)
1828 {
1829   if (process_plaintext)
1830     begin_insertion (ifplaintext);
1831   else
1832     command_name_condition ();
1833 }
1834
1835 void
1836 cm_ifnotplaintext (void)
1837 {
1838   if (!process_plaintext)
1839     begin_insertion (ifnotplaintext);
1840   else
1841     command_name_condition ();
1842 }
1843
1844
1845 void
1846 cm_tex (void)
1847 {
1848   if (process_tex)
1849     begin_insertion (rawtex);
1850   else
1851     command_name_condition ();
1852 }
1853
1854 void
1855 cm_iftex (void)
1856 {
1857   if (process_tex)
1858     begin_insertion (iftex);
1859   else
1860     command_name_condition ();
1861 }
1862
1863 void
1864 cm_ifnottex (void)
1865 {
1866   if (!process_tex)
1867     begin_insertion (ifnottex);
1868   else
1869     command_name_condition ();
1870 }
1871
1872 void
1873 cm_ifxml (void)
1874 {
1875   if (process_xml)
1876     begin_insertion (ifxml);
1877   else
1878     command_name_condition ();
1879 }
1880
1881 void
1882 cm_ifnotxml (void)
1883 {
1884   if (!process_xml)
1885     begin_insertion (ifnotxml);
1886   else
1887     command_name_condition ();
1888 }
1889
1890 \f
1891 /* Generic xrefable block with a caption.  */
1892 void
1893 cm_float (void)
1894 {
1895   begin_insertion (floatenv);
1896 }
1897
1898 void
1899 cm_caption (int arg)
1900 {
1901   char *temp;
1902
1903   /* This is a no_op command for most formats, as we handle it during @float
1904      insertion.  For XML though, we handle it here to keep document structure
1905      as close as possible, to the Texinfo source.  */
1906
1907   /* Everything is already handled at START.  */
1908   if (arg == END)
1909     return;
1910
1911   /* Check if it's mislocated.  */
1912   if (current_insertion_type () != floatenv)
1913     line_error (_("@%s not meaningful outside `@float' environment"), command);
1914
1915   get_until_in_braces ("\n@end float", &temp);
1916
1917   if (xml)
1918     {
1919       int elt = STREQ (command, "shortcaption") ? SHORTCAPTION : CAPTION;
1920       xml_insert_element (elt, START);
1921       if (!docbook)
1922         execute_string ("%s", temp);
1923       xml_insert_element (elt, END);
1924     }
1925
1926   free (temp);
1927 }
1928
1929 /* Begin an insertion where the lines are not filled or indented. */
1930 void
1931 cm_flushleft (void)
1932 {
1933   begin_insertion (flushleft);
1934 }
1935
1936 /* Begin an insertion where the lines are not filled, and each line is
1937    forced to the right-hand side of the page. */
1938 void
1939 cm_flushright (void)
1940 {
1941   begin_insertion (flushright);
1942 }
1943
1944 void
1945 cm_menu (void)
1946 {
1947   if (current_node == NULL && !macro_expansion_output_stream)
1948     {
1949       warning (_("@menu seen before first @node, creating `Top' node"));
1950       warning (_("perhaps your @top node should be wrapped in @ifnottex rather than @ifinfo?"));
1951       /* Include @top command so we can construct the implicit node tree.  */
1952       execute_string ("@node top\n@top Top\n");
1953     }
1954   begin_insertion (menu);
1955 }
1956
1957 void
1958 cm_detailmenu (void)
1959 {
1960   if (current_node == NULL && !macro_expansion_output_stream)
1961     { /* Problems anyway, @detailmenu should always be inside @menu.  */
1962       warning (_("@detailmenu seen before first node, creating `Top' node"));
1963       execute_string ("@node top\n@top Top\n");
1964     }
1965   begin_insertion (detailmenu);
1966 }
1967 \f
1968 /* Title page commands. */
1969
1970 void
1971 cm_titlepage (void)
1972 {
1973   titlepage_cmd_present = 1;
1974   if (xml && !docbook)
1975     begin_insertion (titlepage);
1976   else
1977     command_name_condition ();
1978 }
1979
1980 void
1981 cm_author (void)
1982 {
1983   char *rest;
1984   get_rest_of_line (1, &rest);
1985
1986   if (is_in_insertion_of_type (quotation))
1987     {
1988       if (html)
1989         add_word_args ("&mdash; %s", rest);
1990       else if (docbook)
1991         {
1992           /* FIXME Ideally, we should use an attribution element,
1993              but they are supposed to be at the start of quotation
1994              blocks.  So to avoid looking ahead mess, let's just
1995              use mdash like HTML for now.  */
1996           xml_insert_entity ("mdash");
1997           add_word (rest);
1998         }
1999       else if (xml)
2000         {
2001           xml_insert_element (AUTHOR, START);
2002           add_word (rest);
2003           xml_insert_element (AUTHOR, END);
2004         }
2005       else
2006         add_word_args ("-- %s", rest);
2007     }
2008   else if (is_in_insertion_of_type (titlepage))
2009     {
2010       if (xml && !docbook)
2011         {
2012           xml_insert_element (AUTHOR, START);
2013           add_word (rest);
2014           xml_insert_element (AUTHOR, END);
2015         }
2016     }
2017   else
2018     line_error (_("@%s not meaningful outside `@titlepage' and `@quotation' environments"),
2019         command);
2020
2021   free (rest);
2022 }
2023
2024 void
2025 cm_titlepage_cmds (void)
2026 {
2027   char *rest;
2028
2029   get_rest_of_line (1, &rest);
2030
2031   if (!is_in_insertion_of_type (titlepage))
2032     line_error (_("@%s not meaningful outside `@titlepage' environment"),
2033         command);
2034
2035   if (xml && !docbook)
2036     {
2037       int elt = 0;
2038
2039       if (STREQ (command, "title"))
2040         elt = BOOKTITLE;
2041       else if (STREQ (command, "subtitle"))
2042         elt = BOOKSUBTITLE;
2043
2044       xml_insert_element (elt, START);
2045       add_word (rest);
2046       xml_insert_element (elt, END);
2047     }
2048
2049     free (rest);
2050 }
2051
2052 /* End existing insertion block. */
2053 void
2054 cm_end (void)
2055 {
2056   char *temp;
2057   int type;
2058
2059   get_rest_of_line (0, &temp);
2060
2061   if (!insertion_level)
2062     {
2063       line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command);
2064       return;
2065     }
2066
2067   if (temp[0] == 0)
2068     line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command);
2069
2070   type = find_type_from_name (temp);
2071
2072   if (type == bad_type)
2073     {
2074       line_error (_("Bad argument `%s' to `@%s', using `%s'"),
2075            temp, command, insertion_type_pname (current_insertion_type ()));
2076     }
2077   if (xml && type == menu) /* fixme */
2078     {
2079       xml_end_menu ();
2080     }
2081   end_insertion (type);
2082   free (temp);
2083 }
2084 \f
2085 /* @itemx, @item. */
2086
2087 static int itemx_flag = 0;
2088
2089 /* Return whether CMD takes a brace-delimited {arg}.  */
2090 int
2091 command_needs_braces (char *cmd)
2092 {
2093   int i;
2094   for (i = 0; command_table[i].name; i++)
2095     {
2096       if (STREQ (command_table[i].name, cmd))
2097         return command_table[i].argument_in_braces == BRACE_ARGS;
2098     }
2099
2100   return 0; /* macro or alias */
2101 }
2102
2103
2104 void
2105 cm_item (void)
2106 {
2107   char *rest_of_line, *item_func;
2108
2109   /* Can only hack "@item" while inside of an insertion. */
2110   if (insertion_level)
2111     {
2112       INSERTION_ELT *stack = insertion_stack;
2113       int original_input_text_offset;
2114
2115       skip_whitespace ();
2116       original_input_text_offset = input_text_offset;
2117
2118       get_rest_of_line (0, &rest_of_line);
2119       item_func = current_item_function ();
2120
2121     /* Do the right thing depending on which insertion function is active. */
2122     switch_top:
2123       switch (stack->insertion)
2124         {
2125         case multitable:
2126           multitable_item ();
2127           /* Support text directly after the @item.  */
2128           if (*rest_of_line)
2129             {
2130               line_number--;
2131               input_text_offset = original_input_text_offset;
2132             }
2133           break;
2134
2135         case ifclear:
2136         case ifhtml:
2137         case ifinfo:
2138         case ifnothtml:
2139         case ifnotinfo:
2140         case ifnotplaintext:
2141         case ifnottex:
2142         case ifnotxml:
2143         case ifplaintext:
2144         case ifset:
2145         case iftex:
2146         case ifxml:
2147         case rawdocbook:
2148         case rawhtml:
2149         case rawxml:
2150         case rawtex:
2151         case tex:
2152         case cartouche:
2153           stack = stack->next;
2154           if (!stack)
2155             goto no_insertion;
2156           else
2157             goto switch_top;
2158           break;
2159
2160         case menu:
2161         case quotation:
2162         case example:
2163         case smallexample:
2164         case lisp:
2165         case smalllisp:
2166         case format:
2167         case smallformat:
2168         case display:
2169         case smalldisplay:
2170         case group:
2171           line_error (_("@%s not meaningful inside `@%s' block"),
2172                       command,
2173                       insertion_type_pname (current_insertion_type ()));
2174           break;
2175
2176         case itemize:
2177         case enumerate:
2178           if (itemx_flag)
2179             {
2180               line_error (_("@itemx not meaningful inside `%s' block"),
2181                           insertion_type_pname (current_insertion_type ()));
2182             }
2183           else
2184             {
2185               if (html)
2186                 add_html_block_elt ("<li>");
2187               else if (xml)
2188                 xml_begin_item ();
2189               else
2190                 {
2191                   start_paragraph ();
2192                   kill_self_indent (-1);
2193                   filling_enabled = indented_fill = 1;
2194
2195                   if (current_item_function ())
2196                     {
2197                       output_column = current_indent - 2;
2198                       indent (output_column);
2199
2200                       /* The item marker can be given with or without
2201                          braces -- @bullet and @bullet{} are both ok.
2202                          Or it might be something that doesn't take
2203                          braces at all, such as "o" or "#" or "@ ".
2204                          Thus, only supply braces if the item marker is
2205                          a command, they haven't supplied braces
2206                          themselves, and we know it needs them.  */
2207                       if (item_func && *item_func)
2208                         {
2209                           if (*item_func == COMMAND_PREFIX
2210                               && item_func[strlen (item_func) - 1] != '}'
2211                               && command_needs_braces (item_func + 1))
2212                             execute_string ("%s{}", item_func);
2213                           else
2214                             execute_string ("%s", item_func);
2215                         }
2216                       insert (' ');
2217                       output_column++;
2218                     }
2219                   else
2220                     enumerate_item ();
2221
2222                   /* Special hack.  This makes `close_paragraph' a no-op until
2223                      `start_paragraph' has been called. */
2224                   must_start_paragraph = 1;
2225                 }
2226
2227               /* Handle text directly after the @item.  */
2228               if (*rest_of_line)
2229                 {
2230                   line_number--;
2231                   input_text_offset = original_input_text_offset;
2232                 }
2233             }
2234           break;
2235
2236         case table:
2237         case ftable:
2238         case vtable:
2239           if (html)
2240             { /* If nothing has been output since the last <dd>,
2241                  remove the empty <dd> element.  Some browsers render
2242                  an extra empty line for <dd><dt>, which makes @itemx
2243                  conversion look ugly.  */
2244               rollback_empty_tag ("dd");
2245
2246               /* Force the browser to render one blank line before
2247                  each new @item in a table.  But don't do that if
2248                  this is the first <dt> after the <dl>, or if we are
2249                  converting @itemx.
2250
2251                  Note that there are some browsers which ignore <br>
2252                  in this context, but I cannot find any way to force
2253                  them all render exactly one blank line.  */
2254               if (!itemx_flag && html_deflist_has_term)
2255                 add_html_block_elt ("<br>");
2256
2257               /* We are about to insert a <dt>, so this <dl> has a term.
2258                  Feel free to insert a <br> next time. :)  */
2259               html_deflist_has_term = 1;
2260    
2261               add_html_block_elt ("<dt>");
2262               if (item_func && *item_func)
2263                 execute_string ("%s{%s}", item_func, rest_of_line);
2264               else
2265                 execute_string ("%s", rest_of_line);
2266
2267               if (current_insertion_type () == ftable)
2268                 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
2269
2270               if (current_insertion_type () == vtable)
2271                 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
2272
2273               add_html_block_elt ("<dd>");
2274             }
2275           else if (xml) /* && docbook)*/ /* 05-08 */
2276             {
2277               xml_begin_table_item ();
2278
2279               if (!docbook && current_insertion_type () == ftable)
2280                 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
2281
2282               if (!docbook && current_insertion_type () == vtable)
2283                 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
2284
2285               if (item_func && *item_func)
2286                 execute_string ("%s{%s}", item_func, rest_of_line);
2287               else
2288                 execute_string ("%s", rest_of_line);
2289               xml_continue_table_item ();
2290             }
2291           else
2292             {
2293               /* We need this to determine if we have two @item's in a row
2294                  (see test just below).  */
2295               static int last_item_output_position = 0;
2296
2297               /* Get rid of extra characters. */
2298               kill_self_indent (-1);
2299
2300               /* If we have one @item followed directly by another @item,
2301                  we need to insert a blank line.  This is not true for
2302                  @itemx, though.  */
2303               if (!itemx_flag && last_item_output_position == output_position)
2304                 insert ('\n');
2305
2306               /* `close_paragraph' almost does what we want.  The problem
2307                  is when paragraph_is_open, and last_char_was_newline, and
2308                  the last newline has been turned into a space, because
2309                  filling_enabled. I handle it here. */
2310               if (last_char_was_newline && filling_enabled &&
2311                   paragraph_is_open)
2312                 insert ('\n');
2313               close_paragraph ();
2314
2315 #if defined (INDENT_PARAGRAPHS_IN_TABLE)
2316               /* Indent on a new line, but back up one indentation level. */
2317               {
2318                 int save = inhibit_paragraph_indentation;
2319                 inhibit_paragraph_indentation = 1;
2320                 /* At this point, inserting any non-whitespace character will
2321                    force the existing indentation to be output. */
2322                 add_char ('i');
2323                 inhibit_paragraph_indentation = save;
2324               }
2325 #else /* !INDENT_PARAGRAPHS_IN_TABLE */
2326               add_char ('i');
2327 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */
2328
2329               output_paragraph_offset--;
2330               kill_self_indent (default_indentation_increment + 1);
2331
2332               /* Add item's argument to the line. */
2333               filling_enabled = 0;
2334               if (item_func && *item_func)
2335                 execute_string ("%s{%s}", item_func, rest_of_line);
2336               else
2337                 execute_string ("%s", rest_of_line);
2338
2339               if (current_insertion_type () == ftable)
2340                 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
2341               else if (current_insertion_type () == vtable)
2342                 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
2343
2344               /* Start a new line, and let start_paragraph ()
2345                  do the indenting of it for you. */
2346               close_single_paragraph ();
2347               indented_fill = filling_enabled = 1;
2348               last_item_output_position = output_position;
2349             }
2350         }
2351       free (rest_of_line);
2352     }
2353   else
2354     {
2355     no_insertion:
2356       line_error (_("%c%s found outside of an insertion block"),
2357                   COMMAND_PREFIX, command);
2358     }
2359 }
2360
2361 void
2362 cm_itemx (void)
2363 {
2364   itemx_flag++;
2365   cm_item ();
2366   itemx_flag--;
2367 }
2368
2369 int headitem_flag = 0;
2370
2371 void
2372 cm_headitem (void)
2373 {
2374   headitem_flag = 1;
2375   cm_item ();
2376 }