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.  */
35static 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.  */
52INSERTION_ELT *insertion_stack = NULL;
53
54/* How deeply we're nested.  */
55int 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.  */
59int had_menu_commentary;
60
61/* How to examine menu lines.  */
62int in_detailmenu = 0;
63
64/* Whether to examine menu lines.  */
65int in_menu = 0;
66
67/* Set to 1 if <p> is written in normal context.
68   Used for menu and itemize. */
69int 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.  */
75static int float_active = 0;
76
77/* Unsetting escape_html blindly causes text inside @html/etc. to be escaped if
78   used within a rmacro.  */
79static 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.  */
83static int html_deflist_has_term = 0;
84
85void
86init_insertion_stack (void)
87{
88  insertion_stack = NULL;
89}
90
91/* Return the type of the current insertion. */
92static enum insertion_type
93current_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.  */
100static char *
101current_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.  */
147static char *
148get_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. */
182static void
183push_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. */
202void
203pop_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. */
223static const char *
224insertion_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. */
245enum insertion_type
246find_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. */
268int
269is_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
287static int
288defun_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
320typedef struct {
321  int enumtype;
322  int enumval;
323} DIGIT_ALPHA;
324
325DIGIT_ALPHA enumstack[max_stack_depth];
326int enumstack_offset = 0;
327int current_enumval = 1;
328int current_enumtype = ENUM_DIGITS;
329char *enumeration_arg = NULL;
330
331static void
332start_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
346static void
347stop_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. */
358static void
359enumerate_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
380static void
381enum_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. */
406void
407command_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. */
421void
422begin_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. */
959static void
960end_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.  */
1319void
1320discard_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
1349void
1350cm_quotation (void)
1351{
1352  /* We start the blockquote element in the insertion.  */
1353  begin_insertion (quotation);
1354}
1355
1356void
1357cm_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
1380void
1381cm_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
1399void
1400cm_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
1418void
1419cm_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
1437void
1438cm_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
1448void
1449cm_copying (void)
1450{
1451  begin_insertion (copying);
1452}
1453
1454/* Not an insertion, despite the name, but it goes with cm_copying.  */
1455void
1456cm_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
1475void
1476cm_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
1498void
1499cm_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
1514void
1515cm_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
1530void
1531cm_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
1546void
1547cm_direntry (void)
1548{
1549  if (html || xml || no_headers)
1550    command_name_condition ();
1551  else
1552    begin_insertion (direntry);
1553}
1554
1555void
1556cm_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
1572void
1573cm_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. */
1580static void
1581do_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
1607void
1608cm_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. */
1621void
1622handle_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
1708void
1709cm_verbatim (void)
1710{
1711  handle_verbatim_environment (1);
1712}
1713
1714void
1715cm_table (void)
1716{
1717  begin_insertion (table);
1718}
1719
1720void
1721cm_multitable (void)
1722{
1723  begin_insertion (multitable); /* @@ */
1724}
1725
1726void
1727cm_ftable (void)
1728{
1729  begin_insertion (ftable);
1730}
1731
1732void
1733cm_vtable (void)
1734{
1735  begin_insertion (vtable);
1736}
1737
1738void
1739cm_group (void)
1740{
1741  begin_insertion (group);
1742}
1743
1744/* Insert raw HTML (no escaping of `<' etc.). */
1745void
1746cm_html (int arg)
1747{
1748  if (process_html)
1749    begin_insertion (rawhtml);
1750  else
1751    command_name_condition ();
1752}
1753
1754void
1755cm_xml (int arg)
1756{
1757  if (process_xml)
1758    begin_insertion (rawxml);
1759  else
1760    command_name_condition ();
1761}
1762
1763void
1764cm_docbook (int arg)
1765{
1766  if (process_docbook)
1767    begin_insertion (rawdocbook);
1768  else
1769    command_name_condition ();
1770}
1771
1772void
1773cm_ifdocbook (void)
1774{
1775  if (process_docbook)
1776    begin_insertion (ifdocbook);
1777  else
1778    command_name_condition ();
1779}
1780
1781void
1782cm_ifnotdocbook (void)
1783{
1784  if (!process_docbook)
1785    begin_insertion (ifnotdocbook);
1786  else
1787    command_name_condition ();
1788}
1789
1790void
1791cm_ifhtml (void)
1792{
1793  if (process_html)
1794    begin_insertion (ifhtml);
1795  else
1796    command_name_condition ();
1797}
1798
1799void
1800cm_ifnothtml (void)
1801{
1802  if (!process_html)
1803    begin_insertion (ifnothtml);
1804  else
1805    command_name_condition ();
1806}
1807
1808
1809void
1810cm_ifinfo (void)
1811{
1812  if (process_info)
1813    begin_insertion (ifinfo);
1814  else
1815    command_name_condition ();
1816}
1817
1818void
1819cm_ifnotinfo (void)
1820{
1821  if (!process_info)
1822    begin_insertion (ifnotinfo);
1823  else
1824    command_name_condition ();
1825}
1826
1827
1828void
1829cm_ifplaintext (void)
1830{
1831  if (process_plaintext)
1832    begin_insertion (ifplaintext);
1833  else
1834    command_name_condition ();
1835}
1836
1837void
1838cm_ifnotplaintext (void)
1839{
1840  if (!process_plaintext)
1841    begin_insertion (ifnotplaintext);
1842  else
1843    command_name_condition ();
1844}
1845
1846
1847void
1848cm_tex (void)
1849{
1850  if (process_tex)
1851    begin_insertion (rawtex);
1852  else
1853    command_name_condition ();
1854}
1855
1856void
1857cm_iftex (void)
1858{
1859  if (process_tex)
1860    begin_insertion (iftex);
1861  else
1862    command_name_condition ();
1863}
1864
1865void
1866cm_ifnottex (void)
1867{
1868  if (!process_tex)
1869    begin_insertion (ifnottex);
1870  else
1871    command_name_condition ();
1872}
1873
1874void
1875cm_ifxml (void)
1876{
1877  if (process_xml)
1878    begin_insertion (ifxml);
1879  else
1880    command_name_condition ();
1881}
1882
1883void
1884cm_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.  */
1894void
1895cm_float (void)
1896{
1897  begin_insertion (floatenv);
1898}
1899
1900void
1901cm_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. */
1932void
1933cm_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. */
1940void
1941cm_flushright (void)
1942{
1943  begin_insertion (flushright);
1944}
1945
1946void
1947cm_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
1959void
1960cm_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
1972void
1973cm_titlepage (void)
1974{
1975  titlepage_cmd_present = 1;
1976  if (xml && !docbook)
1977    begin_insertion (titlepage);
1978  else
1979    command_name_condition ();
1980}
1981
1982void
1983cm_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
2026void
2027cm_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. */
2055void
2056cm_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
2089static int itemx_flag = 0;
2090
2091/* Return whether CMD takes a brace-delimited {arg}.  */
2092int
2093command_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
2106void
2107cm_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
2363void
2364cm_itemx (void)
2365{
2366  itemx_flag++;
2367  cm_item ();
2368  itemx_flag--;
2369}
2370
2371int headitem_flag = 0;
2372
2373void
2374cm_headitem (void)
2375{
2376  headitem_flag = 1;
2377  cm_item ();
2378}
2379