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