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