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