insertion.c revision 114472
11590Srgrimes/* insertion.c -- insertions for Texinfo.
21590Srgrimes   $Id: insertion.c,v 1.14 2003/01/02 23:46:29 karl Exp $
31590Srgrimes
41590Srgrimes   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software
51590Srgrimes   Foundation, Inc.
61590Srgrimes
71590Srgrimes   This program is free software; you can redistribute it and/or modify
81590Srgrimes   it under the terms of the GNU General Public License as published by
91590Srgrimes   the Free Software Foundation; either version 2, or (at your option)
101590Srgrimes   any later version.
111590Srgrimes
121590Srgrimes   This program is distributed in the hope that it will be useful,
131590Srgrimes   but WITHOUT ANY WARRANTY; without even the implied warranty of
141590Srgrimes   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151590Srgrimes   GNU General Public License for more details.
161590Srgrimes
171590Srgrimes   You should have received a copy of the GNU General Public License
181590Srgrimes   along with this program; if not, write to the Free Software Foundation,
191590Srgrimes   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
201590Srgrimes
211590Srgrimes#include "system.h"
221590Srgrimes#include "cmds.h"
231590Srgrimes#include "defun.h"
241590Srgrimes#include "insertion.h"
251590Srgrimes#include "macro.h"
261590Srgrimes#include "makeinfo.h"
271590Srgrimes#include "xml.h"
281590Srgrimes
291590Srgrimes/* Must match list in insertion.h.  */
301590Srgrimesstatic char *insertion_type_names[] =
3174769Smikeh{
321590Srgrimes  "cartouche", "copying", "defcv", "deffn", "defivar", "defmac",
3374769Smikeh  "defmethod", "defop", "defopt", "defspec", "deftp", "deftypefn",
341590Srgrimes  "deftypefun", "deftypeivar", "deftypemethod", "deftypeop",
3599112Sobrien  "deftypevar", "deftypevr", "defun", "defvar", "defvr", "detailmenu",
3699112Sobrien  "direntry", "display", "documentdescription", "enumerate", "example",
371590Srgrimes  "flushleft", "flushright", "format", "ftable", "group", "ifclear",
3891227Sbde  "ifhtml", "ifinfo", "ifnothtml", "ifnotinfo", "ifnotplaintext", "ifnottex", "ifnotxml",
3991227Sbde  "ifplaintext", "ifset", "iftex", "ifxml", "itemize", "lisp", "menu",
401590Srgrimes  "multitable", "quotation", "rawhtml", "rawtex", "smalldisplay",
411590Srgrimes  "smallexample", "smallformat", "smalllisp", "verbatim", "table",
421590Srgrimes  "tex", "vtable", "bad_type"
431590Srgrimes};
441590Srgrimes
451590Srgrimes/* All nested environments.  */
461590SrgrimesINSERTION_ELT *insertion_stack = NULL;
471590Srgrimes
481590Srgrimes/* How deeply we're nested.  */
4992921Simpint insertion_level = 0;
5077274Smikeh
511590Srgrimes/* Set to 1 if we've processed (commentary) text in a @menu that
521590Srgrimes   wasn't part of a menu item.  */
531590Srgrimesint had_menu_commentary;
541590Srgrimes
55216564Scharnier/* How to examine menu lines.  */
561590Srgrimesint in_detailmenu = 0;
571590Srgrimes
581590Srgrimes/* Whether to examine menu lines.  */
591590Srgrimesint in_menu = 0;
6077274Smikeh
611590Srgrimes/* Set to 1 if <p> is written in normal context.
6277274Smikeh   Used for menu and itemize. */
631590Srgrimesint in_paragraph = 0;
641590Srgrimes
651590Srgrimesstatic const char dl_tag[] = "<dl>\n";
661590Srgrimesextern void cm_insert_copying ();
671590Srgrimes
68173438Sdds
69216564Scharniervoid
701590Srgrimesinit_insertion_stack ()
711590Srgrimes{
721590Srgrimes  insertion_stack = NULL;
731590Srgrimes}
741590Srgrimes
7577274Smikeh/* Return the type of the current insertion. */
761590Srgrimesstatic enum insertion_type
771590Srgrimescurrent_insertion_type ()
781590Srgrimes{
791590Srgrimes  return insertion_level ? insertion_stack->insertion : bad_type;
801590Srgrimes}
811590Srgrimes
8277274Smikeh/* Return the string which is the function to wrap around items, or NULL
831590Srgrimes   if we're not in an environment where @item is ok.  */
841590Srgrimesstatic char *
851590Srgrimescurrent_item_function ()
861590Srgrimes{
871590Srgrimes  int done = 0;
881590Srgrimes  INSERTION_ELT *elt = insertion_stack;
891590Srgrimes
901590Srgrimes  /* Skip down through the stack until we find an insertion with an
91216564Scharnier     itemize function defined, i.e., skip conditionals, @cartouche, etc.  */
921590Srgrimes  while (!done && elt)
931590Srgrimes    {
941590Srgrimes      switch (elt->insertion)
951590Srgrimes        {
961590Srgrimes        /* This list should match the one in cm_item.  */
971590Srgrimes        case ifclear:
981590Srgrimes        case ifhtml:
991590Srgrimes        case ifinfo:
1001590Srgrimes        case ifnothtml:
1011590Srgrimes        case ifnotinfo:
1021590Srgrimes        case ifnotplaintext:
1031590Srgrimes        case ifnottex:
104216564Scharnier	case ifnotxml:
1051590Srgrimes        case ifplaintext:
1061590Srgrimes        case ifset:
1071590Srgrimes        case iftex:
1081590Srgrimes	case ifxml:
10977274Smikeh        case rawhtml:
11077274Smikeh        case rawtex:
1111590Srgrimes        case tex:
1121590Srgrimes        case cartouche:
1131590Srgrimes          elt = elt->next;
1141590Srgrimes          break;
1151590Srgrimes
1161590Srgrimes        default:
117216564Scharnier          done = 1;
1181590Srgrimes        }
11977274Smikeh    }
1201590Srgrimes
12177274Smikeh  /* item_function usually gets assigned the empty string.  */
1228874Srgrimes  return done && (*elt->item_function) ? elt->item_function : NULL;
12377274Smikeh}
1241590Srgrimes
1251590Srgrimes/* Parse the item marker function off the input.  If result is just "@",
1261590Srgrimes   change it to "@ ", since "@" by itself is not a command.  This makes
1271590Srgrimes   "@ ", "@\t", and "@\n" all the same, but their default meanings are
12877274Smikeh   the same anyway, and let's not worry about supporting redefining them.  */
1291590Srgrimeschar *
1301590Srgrimesget_item_function ()
131216564Scharnier{
1321590Srgrimes  char *item_function;
13377274Smikeh  get_rest_of_line (0, &item_function);
1341590Srgrimes
13577274Smikeh  /* If we hit the end of text in get_rest_of_line, backing up
13677274Smikeh     input pointer will cause the last character of the last line
13777274Smikeh     be pushed back onto the input, which is wrong.  */
1381590Srgrimes  if (input_text_offset < input_text_length)
1391590Srgrimes    backup_input_pointer ();
1401590Srgrimes
14177274Smikeh  if (STREQ (item_function, "@"))
1421590Srgrimes    {
14377274Smikeh      free (item_function);
1441590Srgrimes      item_function = xstrdup ("@ ");
1451590Srgrimes    }
14677274Smikeh
14727643Scharnier  return item_function;
1481590Srgrimes}
1491590Srgrimes
15077274Smikeh /* Push the state of the current insertion on the stack. */
1511590Srgrimesvoid
1521590Srgrimespush_insertion (type, item_function)
1531590Srgrimes     enum insertion_type type;
1541590Srgrimes     char *item_function;
1551590Srgrimes{
1561590Srgrimes  INSERTION_ELT *new = xmalloc (sizeof (INSERTION_ELT));
1571590Srgrimes
1581590Srgrimes  new->item_function = item_function;
1591590Srgrimes  new->filling_enabled = filling_enabled;
160216564Scharnier  new->indented_fill = indented_fill;
1611590Srgrimes  new->insertion = type;
1621590Srgrimes  new->line_number = line_number;
16377274Smikeh  new->filename = xstrdup (input_filename);
16477274Smikeh  new->inhibited = inhibit_paragraph_indentation;
1651590Srgrimes  new->in_fixed_width_font = in_fixed_width_font;
1661590Srgrimes  new->next = insertion_stack;
1671590Srgrimes  insertion_stack = new;
16877274Smikeh  insertion_level++;
1691590Srgrimes}
17077274Smikeh
17188227Sache /* Pop the value on top of the insertion stack into the
17277274Smikeh    global variables. */
1731590Srgrimesvoid
1741590Srgrimespop_insertion ()
1751590Srgrimes{
1761590Srgrimes  INSERTION_ELT *temp = insertion_stack;
1771590Srgrimes
1781590Srgrimes  if (temp == NULL)
1791590Srgrimes    return;
1801590Srgrimes
1811590Srgrimes  in_fixed_width_font = temp->in_fixed_width_font;
1821590Srgrimes  inhibit_paragraph_indentation = temp->inhibited;
1831590Srgrimes  filling_enabled = temp->filling_enabled;
1841590Srgrimes  indented_fill = temp->indented_fill;
1851590Srgrimes  free_and_clear (&(temp->item_function));
1861590Srgrimes  free_and_clear (&(temp->filename));
1871590Srgrimes  insertion_stack = insertion_stack->next;
1881590Srgrimes  free (temp);
1891590Srgrimes  insertion_level--;
1901590Srgrimes}
1911590Srgrimes
1921590Srgrimes /* Return a pointer to the print name of this
1931590Srgrimes    enumerated type. */
1941590Srgrimeschar *
1951590Srgrimesinsertion_type_pname (type)
1961590Srgrimes     enum insertion_type type;
1971590Srgrimes{
1981590Srgrimes  if ((int) type < (int) bad_type)
1991590Srgrimes    return insertion_type_names[(int) type];
2001590Srgrimes  else
2011590Srgrimes    return _("Broken-Type in insertion_type_pname");
2021590Srgrimes}
2031590Srgrimes
20477274Smikeh/* Return the insertion_type associated with NAME.
2051590Srgrimes   If the type is not one of the known ones, return BAD_TYPE. */
2061590Srgrimesenum insertion_type
2071590Srgrimesfind_type_from_name (name)
2081590Srgrimes     char *name;
2091590Srgrimes{
2101590Srgrimes  int index = 0;
2111590Srgrimes  while (index < (int) bad_type)
2121590Srgrimes    {
2131590Srgrimes      if (STREQ (name, insertion_type_names[index]))
2141590Srgrimes        return (enum insertion_type) index;
215216564Scharnier      if (index == rawhtml && STREQ (name, "html"))
2161590Srgrimes        return rawhtml;
21777274Smikeh      if (index == rawhtml && STREQ (name, "xml"))
2181590Srgrimes        return rawhtml;
2191590Srgrimes      if (index == rawtex && STREQ (name, "tex"))
2201590Srgrimes        return rawtex;
2211590Srgrimes      index++;
22277274Smikeh    }
2231590Srgrimes  return bad_type;
2241590Srgrimes}
2251590Srgrimes
2261590Srgrimesint
22777274Smikehdefun_insertion (type)
2281590Srgrimes     enum insertion_type type;
2291590Srgrimes{
2301590Srgrimes  return 0
23174769Smikeh     || (type == defcv)
23274769Smikeh     || (type == deffn)
2331590Srgrimes     || (type == defivar)
2341590Srgrimes     || (type == defmac)
235216564Scharnier     || (type == defmethod)
2361590Srgrimes     || (type == defop)
2371590Srgrimes     || (type == defopt)
23874769Smikeh     || (type == defspec)
23974769Smikeh     || (type == deftp)
24088227Sache     || (type == deftypefn)
2411590Srgrimes     || (type == deftypefun)
2421590Srgrimes     || (type == deftypeivar)
2431590Srgrimes     || (type == deftypemethod)
2441590Srgrimes     || (type == deftypeop)
2451590Srgrimes     || (type == deftypevar)
2461590Srgrimes     || (type == deftypevr)
2471590Srgrimes     || (type == defun)
2481590Srgrimes     || (type == defvar)
2491590Srgrimes     || (type == defvr)
2501590Srgrimes  ;
2511590Srgrimes}
2521590Srgrimes
2531590Srgrimes/* MAX_NS is the maximum nesting level for enumerations.  I picked 100
25418532Sbde   which seemed reasonable.  This doesn't control the number of items,
25518532Sbde   just the number of nested lists. */
25618532Sbde#define max_stack_depth 100
2571590Srgrimes#define ENUM_DIGITS 1
2581590Srgrimes#define ENUM_ALPHA  2
2591590Srgrimestypedef struct {
2601590Srgrimes  int enumtype;
2611590Srgrimes  int enumval;
2621590Srgrimes} DIGIT_ALPHA;
2631590Srgrimes
264216564ScharnierDIGIT_ALPHA enumstack[max_stack_depth];
2651590Srgrimesint enumstack_offset = 0;
2661590Srgrimesint current_enumval = 1;
2671590Srgrimesint current_enumtype = ENUM_DIGITS;
2681590Srgrimeschar *enumeration_arg = NULL;
26977274Smikeh
27077274Smikehvoid
2711590Srgrimesstart_enumerating (at, type)
27274769Smikeh     int at, type;
27377274Smikeh{
2741590Srgrimes  if ((enumstack_offset + 1) == max_stack_depth)
27518532Sbde    {
2761590Srgrimes      line_error (_("Enumeration stack overflow"));
27777274Smikeh      return;
27877274Smikeh    }
2791590Srgrimes  enumstack[enumstack_offset].enumtype = current_enumtype;
2801590Srgrimes  enumstack[enumstack_offset].enumval = current_enumval;
2811590Srgrimes  enumstack_offset++;
2821590Srgrimes  current_enumval = at;
2831590Srgrimes  current_enumtype = type;
2841590Srgrimes}
2851590Srgrimes
2861590Srgrimesvoid
2871590Srgrimesstop_enumerating ()
28877274Smikeh{
2891590Srgrimes  --enumstack_offset;
2901590Srgrimes  if (enumstack_offset < 0)
2911590Srgrimes    enumstack_offset = 0;
2921590Srgrimes
2931590Srgrimes  current_enumval = enumstack[enumstack_offset].enumval;
2941590Srgrimes  current_enumtype = enumstack[enumstack_offset].enumtype;
2951590Srgrimes}
296216564Scharnier
2971590Srgrimes/* Place a letter or digits into the output stream. */
2981590Srgrimesvoid
2991590Srgrimesenumerate_item ()
3001590Srgrimes{
30177274Smikeh  char temp[10];
3021590Srgrimes
30377274Smikeh  if (current_enumtype == ENUM_ALPHA)
3041590Srgrimes    {
3051590Srgrimes      if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
3061590Srgrimes        {
3071590Srgrimes          current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
3081590Srgrimes          warning (_("lettering overflow, restarting at %c"), current_enumval);
3091590Srgrimes        }
3101590Srgrimes      sprintf (temp, "%c. ", current_enumval);
3111590Srgrimes    }
31277274Smikeh  else
3131590Srgrimes    sprintf (temp, "%d. ", current_enumval);
3141590Srgrimes
3151590Srgrimes  indent (output_column += (current_indent - strlen (temp)));
3161590Srgrimes  add_word (temp);
3171590Srgrimes  current_enumval++;
3181590Srgrimes}
3191590Srgrimes
320216564Scharnierstatic void
3211590Srgrimesenum_html ()
3221590Srgrimes{
3231590Srgrimes  char type;
3241590Srgrimes  int start;
3251590Srgrimes
3261590Srgrimes  if (isdigit (*enumeration_arg))
32788150Smikeh    {
32888150Smikeh      type = '1';
329205793Sed      start = atoi (enumeration_arg);
3301590Srgrimes    }
3311590Srgrimes  else if (isupper (*enumeration_arg))
3321590Srgrimes    {
3331590Srgrimes      type = 'A';
3341590Srgrimes      start = *enumeration_arg - 'A' + 1;
3351590Srgrimes    }
3361590Srgrimes  else
3371590Srgrimes    {
3381590Srgrimes      type = 'a';
339216564Scharnier      start = *enumeration_arg - 'a' + 1;
3401590Srgrimes    }
34177274Smikeh
3421590Srgrimes  add_word_args ("<ol type=%c start=%d>\n", type, start);
3431590Srgrimes}
3441590Srgrimes
34577274Smikeh/* Conditionally parse based on the current command name. */
34674769Smikehvoid
3471590Srgrimescommand_name_condition ()
3481590Srgrimes{
3491590Srgrimes  char *discarder = xmalloc (8 + strlen (command));
3501590Srgrimes
35177274Smikeh  sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
35277274Smikeh  discard_until (discarder);
3531590Srgrimes  discard_until ("\n");
3541590Srgrimes
3551590Srgrimes  free (discarder);
3561590Srgrimes}
3571590Srgrimes
3581590Srgrimes/* This is where the work for all the "insertion" style
3591590Srgrimes   commands is done.  A huge switch statement handles the
360216564Scharnier   various setups, and generic code is on both sides. */
3611590Srgrimesvoid
36277274Smikehbegin_insertion (type)
3631590Srgrimes     enum insertion_type type;
3641590Srgrimes{
3651590Srgrimes  int no_discard = 0;
3661590Srgrimes
3671590Srgrimes  if (defun_insertion (type))
3681590Srgrimes    {
3691590Srgrimes      push_insertion (type, xstrdup (""));
3701590Srgrimes      no_discard++;
3711590Srgrimes    }
3721590Srgrimes  else
3731590Srgrimes    {
3741590Srgrimes      push_insertion (type, get_item_function ());
3751590Srgrimes    }
3761590Srgrimes
3771590Srgrimes  switch (type)
37877274Smikeh    {
3791590Srgrimes    case menu:
3801590Srgrimes      if (!no_headers)
3811590Srgrimes        close_paragraph ();
3821590Srgrimes
3831590Srgrimes      filling_enabled = no_indent = 0;
3841590Srgrimes      inhibit_paragraph_indentation = 1;
3851590Srgrimes
386216564Scharnier      if (html)
3871590Srgrimes        {
38877274Smikeh          had_menu_commentary = 1;
38977274Smikeh        }
3901590Srgrimes      else if (!no_headers && !xml)
39177274Smikeh        add_word ("* Menu:\n");
39277274Smikeh
39377274Smikeh      if (xml)
39477274Smikeh        xml_insert_element (MENU, START);
39577274Smikeh
39674769Smikeh      next_menu_item_number = 1;
39774769Smikeh      in_menu++;
39877274Smikeh      in_fixed_width_font++;
39974769Smikeh      no_discard++;
4001590Srgrimes      break;
4011590Srgrimes
4021590Srgrimes    case detailmenu:
40377274Smikeh      if (!in_menu)
4041590Srgrimes        {
4051590Srgrimes          if (!no_headers)
4061590Srgrimes            close_paragraph ();
4071590Srgrimes
4081590Srgrimes          filling_enabled = no_indent = 0;
4091590Srgrimes          inhibit_paragraph_indentation = 1;
4101590Srgrimes
4111590Srgrimes          no_discard++;
4121590Srgrimes        }
4131590Srgrimes
4141590Srgrimes      in_fixed_width_font++;
41577274Smikeh      in_detailmenu++;
4161590Srgrimes      break;
4171590Srgrimes
4181590Srgrimes    case direntry:
4191590Srgrimes      close_single_paragraph ();
4201590Srgrimes      filling_enabled = no_indent = 0;
42177274Smikeh      inhibit_paragraph_indentation = 1;
4221590Srgrimes      insert_string ("START-INFO-DIR-ENTRY\n");
4231590Srgrimes      break;
4241590Srgrimes
4251590Srgrimes    case documentdescription:
4261590Srgrimes      {
4271590Srgrimes        char *desc;
4281590Srgrimes        int start_of_end;
4291590Srgrimes        int save_fixed_width;
4301590Srgrimes
4311590Srgrimes        discard_until ("\n"); /* ignore the @documentdescription line */
4321590Srgrimes        start_of_end = get_until ("\n@end documentdescription", &desc);
4331590Srgrimes        save_fixed_width = in_fixed_width_font;
4341590Srgrimes
4351590Srgrimes        in_fixed_width_font = 0;
4361590Srgrimes        document_description = expansion (desc, 0);
4371590Srgrimes        free (desc);
4381590Srgrimes
4391590Srgrimes        in_fixed_width_font = save_fixed_width;
4401590Srgrimes        input_text_offset = start_of_end; /* go back to the @end to match */
4411590Srgrimes      }
4421590Srgrimes      break;
4431590Srgrimes
4441590Srgrimes    case copying:
4451590Srgrimes      {
4461590Srgrimes        /* Save the copying text away for @insertcopying,
4471590Srgrimes           typically used on the back of the @titlepage (for TeX) and
44877274Smikeh           the Top node (for info/html).  */
4491590Srgrimes        char *text;
4501590Srgrimes        int start_of_end;
4511590Srgrimes	int save_paragraph_indentation;
4521590Srgrimes
45377274Smikeh        discard_until ("\n"); /* ignore remainder of @copying line */
4541590Srgrimes        start_of_end = get_until ("\n@end copying", &text);
4551590Srgrimes
4561590Srgrimes        /* include all the output-format-specific markup.  */
45777274Smikeh	if (docbook)
4581590Srgrimes	  {
4591590Srgrimes	    save_paragraph_indentation = inhibit_paragraph_indentation;
4601590Srgrimes	    inhibit_paragraph_indentation = 1;
4611590Srgrimes	  }
4621590Srgrimes        copying_text = full_expansion (text, 0);
4631590Srgrimes        free (text);
464102412Scharnier
4651590Srgrimes	if (docbook)
4661590Srgrimes	  inhibit_paragraph_indentation = save_paragraph_indentation;
4671590Srgrimes
4681590Srgrimes        input_text_offset = start_of_end; /* go back to the @end to match */
4691590Srgrimes      }
4701590Srgrimes
4711590Srgrimes      /* For info, output the copying text right away, so it will end up
472208592Suqs         in the header of the Info file, before the first node, and thus
473208592Suqs         get copied automatically to all the split files.  For xml, also
4741590Srgrimes         output it right away since xml output is never split.
475208592Suqs         For html, we output it specifically in html_output_head.
476208592Suqs         For plain text, there's no way to hide it, so the author must
4771590Srgrimes          use @insertcopying in the desired location.  */
4781590Srgrimes      if (docbook)
4791590Srgrimes	{
4801590Srgrimes	  if (!xml_in_bookinfo)
4811590Srgrimes	    {
48277274Smikeh	      xml_insert_element (BOOKINFO, START);
4831590Srgrimes	      xml_in_bookinfo = 1;
48483848Smikeh	    }
48583848Smikeh	  if (!xml_in_abstract)
48677274Smikeh	    {
4871590Srgrimes	      xml_insert_element (ABSTRACT, START);
4881590Srgrimes	      xml_in_abstract = 1;
4891590Srgrimes	    }
4901590Srgrimes	}
4911590Srgrimes      if (!html && !no_headers)
4921590Srgrimes        cm_insert_copying ();
4931590Srgrimes      if (docbook && xml_in_abstract)
4941590Srgrimes	{
4951590Srgrimes	  xml_insert_element (ABSTRACT, END);
4961590Srgrimes	  xml_in_abstract = 0;
497216564Scharnier	}
4981590Srgrimes      break;
4991590Srgrimes
5001590Srgrimes    case quotation:
50177274Smikeh      /* @quotation does filling (@display doesn't).  */
50277274Smikeh      if (html)
5031590Srgrimes        add_word ("<blockquote>\n");
5041590Srgrimes      else
50577274Smikeh        {
50677274Smikeh          /* with close_single_paragraph, we get no blank line above
50777274Smikeh             within @copying.  */
50877274Smikeh          close_paragraph ();
5091590Srgrimes          last_char_was_newline = no_indent = 0;
51027643Scharnier          indented_fill = filling_enabled = 1;
5111590Srgrimes          inhibit_paragraph_indentation = 1;
51277274Smikeh        }
5131590Srgrimes      current_indent += default_indentation_increment;
51477274Smikeh      break;
5151590Srgrimes
5161590Srgrimes    case display:
5171590Srgrimes    case smalldisplay:
5181590Srgrimes    case example:
51977274Smikeh    case smallexample:
52077274Smikeh    case lisp:
5211590Srgrimes    case smalllisp:
5221590Srgrimes      /* Like @display but without indentation. */
5231590Srgrimes    case smallformat:
52477274Smikeh    case format:
52574769Smikeh      close_single_paragraph ();
52677274Smikeh      inhibit_paragraph_indentation = 1;
5271590Srgrimes      in_fixed_width_font++;
52877274Smikeh      filling_enabled = 0;
52974769Smikeh      last_char_was_newline = 0;
5301590Srgrimes
53174769Smikeh      if (html)
5321590Srgrimes        /* Kludge alert: if <pre> is followed by a newline, IE3
5331590Srgrimes           renders an extra blank line before the pre-formatted block.
5341590Srgrimes           Other browsers seem to not mind one way or the other.  */
53574769Smikeh        add_word_args ("<pre class=\"%s\">", command);
5361590Srgrimes
5371590Srgrimes      if (type != format && type != smallformat)
5381590Srgrimes        {
53974769Smikeh          current_indent += default_indentation_increment;
5401590Srgrimes          if (html)
5411590Srgrimes            {
54274769Smikeh              /* Since we didn't put \n after <pre>, we need to insert
54374769Smikeh                 the indentation by hand.  */
5441590Srgrimes              int i;
5451590Srgrimes              for (i = current_indent; i > 0; i--)
5461590Srgrimes                add_char (' ');
5471590Srgrimes            }
5481590Srgrimes        }
54977274Smikeh
5501590Srgrimes      break;
5511590Srgrimes
5521590Srgrimes    case multitable:
553229655Suqs      do_multitable ();
5541590Srgrimes      break;
5551590Srgrimes
556216564Scharnier    case table:
5571590Srgrimes    case ftable:
55877274Smikeh    case vtable:
55977274Smikeh    case itemize:
5601590Srgrimes      close_single_paragraph ();
56177274Smikeh      current_indent += default_indentation_increment;
5621590Srgrimes      filling_enabled = indented_fill = 1;
5631590Srgrimes#if defined (INDENT_PARAGRAPHS_IN_TABLE)
56477274Smikeh      inhibit_paragraph_indentation = 0;
5651590Srgrimes#else
5661590Srgrimes      inhibit_paragraph_indentation = 1;
5671590Srgrimes#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
5681590Srgrimes
5691590Srgrimes      /* Make things work for losers who forget the itemize syntax. */
5701590Srgrimes      if (type == itemize)
571216564Scharnier        {
5721590Srgrimes          if (!(*insertion_stack->item_function))
57374769Smikeh            {
5741590Srgrimes              free (insertion_stack->item_function);
5751590Srgrimes              insertion_stack->item_function = xstrdup ("@bullet");
57677274Smikeh            }
5771590Srgrimes        }
5781590Srgrimes
5791590Srgrimes      if (!*insertion_stack->item_function)
5801590Srgrimes        {
58174769Smikeh          line_error (_("%s requires an argument: the formatter for %citem"),
5821590Srgrimes                      insertion_type_pname (type), COMMAND_PREFIX);
5831590Srgrimes        }
5841590Srgrimes
5851590Srgrimes      if (html)
5861590Srgrimes        {
5871590Srgrimes          if (type == itemize)
5881590Srgrimes            {
589216564Scharnier              add_word ("<ul>\n");
5901590Srgrimes              in_paragraph = 0;
59177274Smikeh            }
5921590Srgrimes          else
59377274Smikeh            add_word (dl_tag);
5941590Srgrimes        }
5951590Srgrimes      if (xml)
5961590Srgrimes        xml_begin_table (type, insertion_stack->item_function);
5971590Srgrimes      break;
5981590Srgrimes
599    case enumerate:
600      close_single_paragraph ();
601      no_indent = 0;
602#if defined (INDENT_PARAGRAPHS_IN_TABLE)
603      inhibit_paragraph_indentation = 0;
604#else
605      inhibit_paragraph_indentation = 1;
606#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
607
608      current_indent += default_indentation_increment;
609      filling_enabled = indented_fill = 1;
610
611      if (html)
612        {
613          enum_html ();
614          in_paragraph = 0;
615        }
616
617      if (xml)
618        xml_begin_enumerate (enumeration_arg);
619
620      if (isdigit (*enumeration_arg))
621        start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
622      else
623        start_enumerating (*enumeration_arg, ENUM_ALPHA);
624      break;
625
626      /* @group does nothing special in makeinfo. */
627    case group:
628      /* Only close the paragraph if we are not inside of an
629         @example-like environment. */
630      if (xml)
631        xml_insert_element (GROUP, START);
632      else if (!insertion_stack->next
633          || (insertion_stack->next->insertion != display
634              && insertion_stack->next->insertion != smalldisplay
635              && insertion_stack->next->insertion != example
636              && insertion_stack->next->insertion != smallexample
637              && insertion_stack->next->insertion != lisp
638              && insertion_stack->next->insertion != smalllisp
639              && insertion_stack->next->insertion != format
640              && insertion_stack->next->insertion != smallformat
641              && insertion_stack->next->insertion != flushleft
642              && insertion_stack->next->insertion != flushright))
643        close_single_paragraph ();
644      break;
645
646      /* Insertions that are no-ops in info, but do something in TeX. */
647    case cartouche:
648    case ifclear:
649    case ifhtml:
650    case ifinfo:
651    case ifnothtml:
652    case ifnotinfo:
653    case ifnotplaintext:
654    case ifnottex:
655    case ifnotxml:
656    case ifplaintext:
657    case ifset:
658    case iftex:
659    case ifxml:
660    case rawtex:
661      if (in_menu)
662        no_discard++;
663      break;
664
665    case rawhtml:
666      escape_html = 0;
667      break;
668
669    case defcv:
670    case deffn:
671    case defivar:
672    case defmac:
673    case defmethod:
674    case defop:
675    case defopt:
676    case defspec:
677    case deftp:
678    case deftypefn:
679    case deftypefun:
680    case deftypeivar:
681    case deftypemethod:
682    case deftypeop:
683    case deftypevar:
684    case deftypevr:
685    case defun:
686    case defvar:
687    case defvr:
688      inhibit_paragraph_indentation = 1;
689      filling_enabled = indented_fill = 1;
690      current_indent += default_indentation_increment;
691      no_indent = 0;
692      break;
693
694    case flushleft:
695      close_single_paragraph ();
696      inhibit_paragraph_indentation = 1;
697      filling_enabled = indented_fill = no_indent = 0;
698      if (html)
699        add_word ("<div align=\"left\">");
700      break;
701
702    case flushright:
703      close_single_paragraph ();
704      filling_enabled = indented_fill = no_indent = 0;
705      inhibit_paragraph_indentation = 1;
706      force_flush_right++;
707      if (html)
708        add_word ("<div align=\"right\">");
709      break;
710
711    default:
712      line_error ("begin_insertion internal error: type=%d", type);
713
714    }
715
716  if (!no_discard)
717    discard_until ("\n");
718}
719
720/* Try to end the insertion with the specified TYPE.  With a value of
721   `bad_type', TYPE gets translated to match the value currently on top
722   of the stack.  Otherwise, if TYPE doesn't match the top of the
723   insertion stack, give error. */
724void
725end_insertion (type)
726     enum insertion_type type;
727{
728  enum insertion_type temp_type;
729
730  if (!insertion_level)
731    return;
732
733  temp_type = current_insertion_type ();
734
735  if (type == bad_type)
736    type = temp_type;
737
738  if (type != temp_type)
739    {
740      line_error
741        (_("`@end' expected `%s', but saw `%s'"),
742         insertion_type_pname (temp_type), insertion_type_pname (type));
743      return;
744    }
745
746  pop_insertion ();
747
748  if (xml)
749    {
750      switch (type)
751        {
752        case ifinfo:
753        case documentdescription:
754          break;
755        case copying:
756          xml_insert_element (COPYING, END);
757          break;
758        case quotation:
759          xml_insert_element (QUOTATION, END);
760          break;
761        case example:
762          xml_insert_element (EXAMPLE, END);
763          break;
764        case smallexample:
765          xml_insert_element (SMALLEXAMPLE, END);
766          break;
767        case lisp:
768          xml_insert_element (LISP, END);
769          break;
770        case smalllisp:
771          xml_insert_element (SMALLLISP, END);
772          break;
773        case cartouche:
774          xml_insert_element (CARTOUCHE, END);
775          break;
776        case format:
777	  if (docbook && xml_in_bookinfo && xml_in_abstract)
778	    {
779	      xml_insert_element (ABSTRACT, END);
780	      xml_in_abstract = 0;
781	    }
782	  else
783	    xml_insert_element (FORMAT, END);
784          break;
785        case smallformat:
786          xml_insert_element (SMALLFORMAT, END);
787          break;
788        case display:
789          xml_insert_element (DISPLAY, END);
790          break;
791        case smalldisplay:
792          xml_insert_element (SMALLDISPLAY, END);
793          break;
794        case table:
795        case ftable:
796        case vtable:
797        case itemize:
798          xml_end_table (type);
799          break;
800        case enumerate:
801          xml_end_enumerate (type);
802          break;
803        case group:
804          xml_insert_element (GROUP, END);
805          break;
806        }
807    }
808  switch (type)
809    {
810      /* Insertions which have no effect on paragraph formatting. */
811    case copying:
812    case documentdescription:
813    case ifclear:
814    case ifinfo:
815    case ifhtml:
816    case ifnothtml:
817    case ifnotinfo:
818    case ifnotplaintext:
819    case ifnottex:
820    case ifnotxml:
821    case ifplaintext:
822    case ifset:
823    case iftex:
824    case ifxml:
825    case rawtex:
826      break;
827
828    case rawhtml:
829      escape_html = 1;
830      break;
831
832    case detailmenu:
833      in_detailmenu--;          /* No longer hacking menus. */
834      if (!in_menu)
835        {
836          if (!no_headers)
837            close_insertion_paragraph ();
838        }
839      break;
840
841    case direntry:              /* Eaten if html. */
842      insert_string ("END-INFO-DIR-ENTRY\n\n");
843      close_insertion_paragraph ();
844      break;
845
846    case menu:
847      in_menu--;                /* No longer hacking menus. */
848      if (html)
849        add_word ("</ul>\n");
850      else if (!no_headers)
851        close_insertion_paragraph ();
852      break;
853
854    case multitable:
855      end_multitable ();
856      break;
857
858    case enumerate:
859      stop_enumerating ();
860      close_insertion_paragraph ();
861      current_indent -= default_indentation_increment;
862      if (html)
863        add_word ("</ol>\n");
864      break;
865
866    case flushleft:
867      if (html)
868        add_word ("</div>\n");
869      close_insertion_paragraph ();
870      break;
871
872    case group:
873    case cartouche:
874      close_insertion_paragraph ();
875      break;
876
877    case format:
878    case smallformat:
879    case display:
880    case smalldisplay:
881    case example:
882    case smallexample:
883    case lisp:
884    case smalllisp:
885    case quotation:
886      /* @format and @smallformat are the only fixed_width insertion
887         without a change in indentation. */
888      if (type != format && type != smallformat)
889        current_indent -= default_indentation_increment;
890
891      if (html)
892        add_word (type == quotation ? "</blockquote>\n" : "</pre>\n");
893
894      /* The ending of one of these insertions always marks the
895         start of a new paragraph. */
896      close_insertion_paragraph ();
897      break;
898
899    case table:
900    case ftable:
901    case vtable:
902      current_indent -= default_indentation_increment;
903      if (html)
904        add_word ("</dl>\n");
905      close_insertion_paragraph ();
906      break;
907
908    case itemize:
909      current_indent -= default_indentation_increment;
910      if (html)
911        add_word ("</ul>\n");
912      close_insertion_paragraph ();
913      break;
914
915    case flushright:
916      force_flush_right--;
917      if (html)
918        add_word ("</div>\n");
919      close_insertion_paragraph ();
920      break;
921
922    /* Handle the @defun insertions with this default clause. */
923    default:
924      {
925        enum insertion_type base_type;
926
927        if (type < defcv || type > defvr)
928          line_error ("end_insertion internal error: type=%d", type);
929
930        base_type = get_base_type (type);
931        switch (base_type)
932          {
933          case deffn:
934          case defvr:
935          case deftp:
936          case deftypefn:
937          case deftypevr:
938          case defcv:
939          case defop:
940          case deftypemethod:
941          case deftypeop:
942          case deftypeivar:
943            if (html)
944              /* close the tables which has been opened in defun.c */
945              add_word ("</td></tr>\n</table>\n");
946            break;
947          } /* switch (base_type)... */
948
949        current_indent -= default_indentation_increment;
950        close_insertion_paragraph ();
951      }
952      break;
953
954    }
955
956  if (current_indent < 0)
957    line_error ("end_insertion internal error: current indent=%d",
958                current_indent);
959}
960
961/* Insertions cannot cross certain boundaries, such as node beginnings.  In
962   code that creates such boundaries, you should call `discard_insertions'
963   before doing anything else.  It prints the errors for you, and cleans up
964   the insertion stack.
965
966   With nonzero SPECIALS_OK argument, allows unmatched
967   @if... conditionals, otherwise not.  This is because conditionals can
968   cross node boundaries.  Always happens with the @top node, for example.  */
969void
970discard_insertions (specials_ok)
971    int specials_ok;
972{
973  int real_line_number = line_number;
974  while (insertion_stack)
975    {
976      if (specials_ok
977          && ((ifclear <= insertion_stack->insertion
978               && insertion_stack->insertion <= iftex)
979              || insertion_stack->insertion == rawhtml
980              || insertion_stack->insertion == rawtex))
981        break;
982      else
983        {
984          char *offender = insertion_type_pname (insertion_stack->insertion);
985
986          file_line_error (insertion_stack->filename,
987                           insertion_stack->line_number,
988                           _("No matching `%cend %s'"), COMMAND_PREFIX,
989                           offender);
990          pop_insertion ();
991        }
992    }
993  line_number = real_line_number;
994}
995
996/* Insertion (environment) commands.  */
997
998void
999cm_quotation ()
1000{
1001  if (xml)
1002    xml_insert_element (QUOTATION, START);
1003  begin_insertion (quotation);
1004}
1005
1006void
1007cm_example ()
1008{
1009  if (xml)
1010    xml_insert_element (EXAMPLE, START);
1011  begin_insertion (example);
1012}
1013
1014void
1015cm_smallexample ()
1016{
1017  if (xml)
1018    xml_insert_element (SMALLEXAMPLE, START);
1019  begin_insertion (smallexample);
1020}
1021
1022void
1023cm_lisp ()
1024{
1025  if (xml)
1026    xml_insert_element (LISP, START);
1027  begin_insertion (lisp);
1028}
1029
1030void
1031cm_smalllisp ()
1032{
1033  if (xml)
1034    xml_insert_element (SMALLLISP, START);
1035  begin_insertion (smalllisp);
1036}
1037
1038void
1039cm_cartouche ()
1040{
1041  if (xml)
1042    xml_insert_element (CARTOUCHE, START);
1043  begin_insertion (cartouche);
1044}
1045
1046void
1047cm_copying ()
1048{
1049  if (xml)
1050    xml_insert_element (COPYING, START);
1051  begin_insertion (copying);
1052}
1053
1054/* Not an insertion, despite the name, but it goes with cm_copying.  */
1055void
1056cm_insert_copying ()
1057{
1058  if (copying_text)
1059    { /* insert_string rather than add_word because we've already done
1060         full expansion on copying_text when we saved it.  */
1061      insert_string (copying_text);
1062      insert ('\n');
1063
1064      /* Update output_position so that the node positions in the tag
1065         tables will take account of the copying text.  */
1066      flush_output ();
1067    }
1068}
1069
1070void
1071cm_format ()
1072{
1073  if (xml)
1074    {
1075      if (docbook && xml_in_bookinfo)
1076	{
1077	  xml_insert_element (ABSTRACT, START);
1078	  xml_in_abstract = 1;
1079	}
1080      else
1081	xml_insert_element (FORMAT, START);
1082    }
1083  begin_insertion (format);
1084}
1085
1086void
1087cm_smallformat ()
1088{
1089  if (xml)
1090    xml_insert_element (SMALLFORMAT, START);
1091  begin_insertion (smallformat);
1092}
1093
1094void
1095cm_display ()
1096{
1097  if (xml)
1098    xml_insert_element (DISPLAY, START);
1099  begin_insertion (display);
1100}
1101
1102void
1103cm_smalldisplay ()
1104{
1105  if (xml)
1106    xml_insert_element (SMALLDISPLAY, START);
1107  begin_insertion (smalldisplay);
1108}
1109
1110void
1111cm_direntry ()
1112{
1113  if (html || xml)
1114    command_name_condition ();
1115  else
1116    begin_insertion (direntry);
1117}
1118
1119void
1120cm_documentdescription ()
1121{
1122  if (html || xml)
1123    begin_insertion (documentdescription);
1124  else
1125    command_name_condition ();
1126}
1127
1128
1129void
1130cm_itemize ()
1131{
1132  begin_insertion (itemize);
1133}
1134
1135/* Start an enumeration insertion of type TYPE.  If the user supplied
1136   no argument on the line, then use DEFAULT_STRING as the initial string. */
1137static void
1138do_enumeration (type, default_string)
1139     int type;
1140     char *default_string;
1141{
1142  get_until_in_line (0, ".", &enumeration_arg);
1143  canon_white (enumeration_arg);
1144
1145  if (!*enumeration_arg)
1146    {
1147      free (enumeration_arg);
1148      enumeration_arg = xstrdup (default_string);
1149    }
1150
1151  if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
1152    {
1153      warning (_("%s requires letter or digit"), insertion_type_pname (type));
1154
1155      switch (type)
1156        {
1157        case enumerate:
1158          default_string = "1";
1159          break;
1160        }
1161      enumeration_arg = xstrdup (default_string);
1162    }
1163  begin_insertion (type);
1164}
1165
1166void
1167cm_enumerate ()
1168{
1169  do_enumeration (enumerate, "1");
1170}
1171
1172/*  Handle verbatim environment:
1173    find_end_verbatim == 0:  process until end of file
1174    find_end_verbatim != 0:  process until 'COMMAND_PREFIXend verbatim'
1175                             or end of file
1176
1177  We cannot simply copy input stream onto output stream; as the
1178  verbatim environment may be encapsulated in an @example environment,
1179  for example. */
1180void
1181handle_verbatim_environment (find_end_verbatim)
1182  int find_end_verbatim;
1183{
1184  int character;
1185  int seen_end = 0;
1186  int save_filling_enabled = filling_enabled;
1187  int save_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
1188
1189  close_single_paragraph ();
1190  inhibit_paragraph_indentation = 1;
1191  filling_enabled = 0;
1192  in_fixed_width_font++;
1193  last_char_was_newline = 0;
1194
1195  /* No indentation: this is verbatim after all
1196     If you want indent, enclose @verbatim in @example
1197       current_indent += default_indentation_increment;
1198   */
1199
1200  if (html)
1201    add_word ("<pre class=\"verbatim\">");
1202
1203  while (input_text_offset < input_text_length)
1204    {
1205      character = curchar ();
1206
1207      if (character == '\n')
1208        line_number++;
1209      /*
1210        Assume no newlines in END_VERBATIM
1211      */
1212      else if (find_end_verbatim && (character == COMMAND_PREFIX) /* @ */
1213          && (input_text_length - input_text_offset > sizeof (END_VERBATIM))
1214          && !strncmp (&input_text[input_text_offset+1], END_VERBATIM,
1215                       sizeof (END_VERBATIM)-1))
1216        {
1217          input_text_offset += sizeof (END_VERBATIM);
1218          seen_end = 1;
1219          break;
1220        }
1221
1222      if (html && character == '&' && escape_html)
1223        add_word ("&amp;");
1224      else if (html && character == '<' && escape_html)
1225        add_word ("&lt;");
1226      else
1227        add_char (character);
1228
1229      input_text_offset++;
1230    }
1231
1232  if (find_end_verbatim && !seen_end)
1233    warning (_("end of file inside verbatim block"));
1234
1235  if (html)
1236    add_word ("</pre>");
1237
1238  in_fixed_width_font--;
1239  filling_enabled = save_filling_enabled;
1240  inhibit_paragraph_indentation = save_inhibit_paragraph_indentation;
1241}
1242
1243void
1244cm_verbatim ()
1245{
1246  handle_verbatim_environment (1);
1247}
1248
1249void
1250cm_table ()
1251{
1252  begin_insertion (table);
1253}
1254
1255void
1256cm_multitable ()
1257{
1258  begin_insertion (multitable); /* @@ */
1259}
1260
1261void
1262cm_ftable ()
1263{
1264  begin_insertion (ftable);
1265}
1266
1267void
1268cm_vtable ()
1269{
1270  begin_insertion (vtable);
1271}
1272
1273void
1274cm_group ()
1275{
1276  begin_insertion (group);
1277}
1278
1279/* Insert raw HTML (no escaping of `<' etc.). */
1280void
1281cm_html ()
1282{
1283  if (process_html || process_xml)
1284    begin_insertion (rawhtml);
1285  else
1286    command_name_condition ();
1287}
1288
1289void
1290cm_ifhtml ()
1291{
1292  if (process_html)
1293    begin_insertion (ifhtml);
1294  else
1295    command_name_condition ();
1296}
1297
1298void
1299cm_ifnothtml ()
1300{
1301  if (!process_html)
1302    begin_insertion (ifnothtml);
1303  else
1304    command_name_condition ();
1305}
1306
1307
1308void
1309cm_ifinfo ()
1310{
1311  if (process_info)
1312    begin_insertion (ifinfo);
1313  else
1314    command_name_condition ();
1315}
1316
1317void
1318cm_ifnotinfo ()
1319{
1320  if (!process_info)
1321    begin_insertion (ifnotinfo);
1322  else
1323    command_name_condition ();
1324}
1325
1326
1327void
1328cm_ifplaintext ()
1329{
1330  if (process_plaintext)
1331    begin_insertion (ifplaintext);
1332  else
1333    command_name_condition ();
1334}
1335
1336void
1337cm_ifnotplaintext ()
1338{
1339  if (!process_plaintext)
1340    begin_insertion (ifnotplaintext);
1341  else
1342    command_name_condition ();
1343}
1344
1345
1346void
1347cm_tex ()
1348{
1349  if (process_tex)
1350    begin_insertion (rawtex);
1351  else
1352    command_name_condition ();
1353}
1354
1355void
1356cm_iftex ()
1357{
1358  if (process_tex)
1359    begin_insertion (iftex);
1360  else
1361    command_name_condition ();
1362}
1363
1364void
1365cm_ifnottex ()
1366{
1367  if (!process_tex)
1368    begin_insertion (ifnottex);
1369  else
1370    command_name_condition ();
1371}
1372
1373void
1374cm_ifxml ()
1375{
1376  if (process_xml)
1377    begin_insertion (ifxml);
1378  else
1379    command_name_condition ();
1380}
1381
1382void
1383cm_ifnotxml ()
1384{
1385  if (!process_xml)
1386    begin_insertion (ifnotxml);
1387  else
1388    command_name_condition ();
1389}
1390
1391
1392/* Begin an insertion where the lines are not filled or indented. */
1393void
1394cm_flushleft ()
1395{
1396  begin_insertion (flushleft);
1397}
1398
1399/* Begin an insertion where the lines are not filled, and each line is
1400   forced to the right-hand side of the page. */
1401void
1402cm_flushright ()
1403{
1404  begin_insertion (flushright);
1405}
1406
1407void
1408cm_menu ()
1409{
1410  if (current_node == NULL)
1411    {
1412      warning (_("@menu seen before first @node, creating `Top' node"));
1413      warning (_("perhaps your @top node should be wrapped in @ifnottex rather than @ifinfo?"));
1414      /* Include @top command so we can construct the implicit node tree.  */
1415      execute_string ("@node top\n@top Top\n");
1416    }
1417  begin_insertion (menu);
1418}
1419
1420void
1421cm_detailmenu ()
1422{
1423  if (current_node == NULL)
1424    { /* Problems anyway, @detailmenu should always be inside @menu.  */
1425      warning (_("@detailmenu seen before first node, creating `Top' node"));
1426      execute_string ("@node top\n@top Top\n");
1427    }
1428  begin_insertion (detailmenu);
1429}
1430
1431/* End existing insertion block. */
1432void
1433cm_end ()
1434{
1435  char *temp;
1436  enum insertion_type type;
1437
1438  if (!insertion_level)
1439    {
1440      line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command);
1441      return;
1442    }
1443
1444  get_rest_of_line (0, &temp);
1445
1446  if (temp[0] == 0)
1447    line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command);
1448
1449  type = find_type_from_name (temp);
1450
1451  if (type == bad_type)
1452    {
1453      line_error (_("Bad argument to `%s', `%s', using `%s'"),
1454           command, temp, insertion_type_pname (current_insertion_type ()));
1455    }
1456  if (xml && type == menu) /* fixme */
1457    {
1458      xml_end_menu ();
1459    }
1460  end_insertion (type);
1461  free (temp);
1462}
1463
1464/* @itemx, @item. */
1465
1466static int itemx_flag = 0;
1467
1468/* Return whether CMD takes a brace-delimited {arg}.  */
1469/*static */int
1470command_needs_braces (cmd)
1471     char *cmd;
1472{
1473  int i;
1474  for (i = 0; command_table[i].name; i++)
1475    {
1476      if (STREQ (command_table[i].name, cmd))
1477        return command_table[i].argument_in_braces == BRACE_ARGS;
1478    }
1479
1480  return 0; /* macro or alias */
1481}
1482
1483
1484void
1485cm_item ()
1486{
1487  char *rest_of_line, *item_func;
1488
1489  /* Can only hack "@item" while inside of an insertion. */
1490  if (insertion_level)
1491    {
1492      INSERTION_ELT *stack = insertion_stack;
1493      int original_input_text_offset;
1494
1495      skip_whitespace ();
1496      original_input_text_offset = input_text_offset;
1497
1498      get_rest_of_line (0, &rest_of_line);
1499      item_func = current_item_function ();
1500
1501    /* Do the right thing depending on which insertion function is active. */
1502    switch_top:
1503      switch (stack->insertion)
1504        {
1505        case multitable:
1506          multitable_item ();
1507          /* Support text directly after the @item.  */
1508          if (*rest_of_line)
1509            {
1510              line_number--;
1511              input_text_offset = original_input_text_offset;
1512            }
1513          break;
1514
1515        case ifclear:
1516        case ifhtml:
1517        case ifinfo:
1518        case ifnothtml:
1519        case ifnotinfo:
1520        case ifnotplaintext:
1521        case ifnottex:
1522	case ifnotxml:
1523        case ifplaintext:
1524        case ifset:
1525        case iftex:
1526	case ifxml:
1527        case rawhtml:
1528        case rawtex:
1529        case tex:
1530        case cartouche:
1531          stack = stack->next;
1532          if (!stack)
1533            goto no_insertion;
1534          else
1535            goto switch_top;
1536          break;
1537
1538        case menu:
1539        case quotation:
1540        case example:
1541        case smallexample:
1542        case lisp:
1543        case smalllisp:
1544        case format:
1545        case smallformat:
1546        case display:
1547        case smalldisplay:
1548        case group:
1549          line_error (_("@%s not meaningful inside `@%s' block"),
1550                      command,
1551                      insertion_type_pname (current_insertion_type ()));
1552          break;
1553
1554        case itemize:
1555        case enumerate:
1556          if (itemx_flag)
1557            {
1558              line_error (_("@itemx not meaningful inside `%s' block"),
1559                          insertion_type_pname (current_insertion_type ()));
1560            }
1561          else
1562            {
1563              if (html)
1564                {
1565                  if (in_paragraph)
1566                    {
1567                      add_word ("</p>");
1568                      in_paragraph = 0;
1569                    }
1570                  add_word ("<li>");
1571                }
1572              else if (xml)
1573                xml_begin_item ();
1574              else
1575                {
1576                  start_paragraph ();
1577                  kill_self_indent (-1);
1578                  filling_enabled = indented_fill = 1;
1579
1580                  if (current_item_function ())
1581                    {
1582                      output_column = current_indent - 2;
1583                      indent (output_column);
1584
1585                      /* The item marker can be given with or without
1586                         braces -- @bullet and @bullet{} are both ok.
1587                         Or it might be something that doesn't take
1588                         braces at all, such as "o" or "#" or "@ ".
1589                         Thus, only supply braces if the item marker is
1590                         a command, they haven't supplied braces
1591                         themselves, and we know it needs them.  */
1592                      if (item_func && *item_func)
1593                        {
1594                          if (*item_func == COMMAND_PREFIX
1595                              && item_func[strlen (item_func) - 1] != '}'
1596                              && command_needs_braces (item_func + 1))
1597                            execute_string ("%s{}", item_func);
1598                          else
1599                            execute_string ("%s", item_func);
1600                        }
1601                      insert (' ');
1602                      output_column++;
1603                    }
1604                  else
1605                    enumerate_item ();
1606
1607                  /* Special hack.  This makes `close_paragraph' a no-op until
1608                     `start_paragraph' has been called. */
1609                  must_start_paragraph = 1;
1610                }
1611
1612              /* Handle text directly after the @item.  */
1613              if (*rest_of_line)
1614                {
1615                  line_number--;
1616                  input_text_offset = original_input_text_offset;
1617                }
1618            }
1619          break;
1620
1621        case table:
1622        case ftable:
1623        case vtable:
1624          if (html)
1625            {
1626              static int last_html_output_position = 0;
1627
1628              /* If nothing has been output since the last <dd>,
1629                 remove the empty <dd> element.  Some browsers render
1630                 an extra empty line for <dd><dt>, which makes @itemx
1631                 conversion look ugly.  */
1632              if (last_html_output_position == output_position
1633                  && strncmp ((char *) output_paragraph, "<dd>",
1634                                output_paragraph_offset) == 0)
1635                output_paragraph_offset = 0;
1636
1637              /* Force the browser to render one blank line before
1638                 each new @item in a table.  But don't do that if
1639                 this is the first <dt> after the <dl>, or if we are
1640                 converting @itemx.
1641
1642                 Note that there are some browsers which ignore <br>
1643                 in this context, but I cannot find any way to force
1644                 them all render exactly one blank line.  */
1645              if (!itemx_flag
1646                  && strncmp ((char *) output_paragraph
1647                              + output_paragraph_offset - sizeof (dl_tag) + 1,
1648                              dl_tag, sizeof (dl_tag) - 1) != 0)
1649                add_word ("<br>");
1650
1651              add_word ("<dt>");
1652              if (item_func && *item_func)
1653                execute_string ("%s{%s}", item_func, rest_of_line);
1654              else
1655                execute_string ("%s", rest_of_line);
1656
1657              if (current_insertion_type () == ftable)
1658                execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
1659
1660              if (current_insertion_type () == vtable)
1661                execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
1662              /* Make sure output_position is updated, so we could
1663                 remember it.  */
1664              close_single_paragraph ();
1665              last_html_output_position = output_position;
1666              add_word ("<dd>");
1667            }
1668          else if (xml) /* && docbook)*/ /* 05-08 */
1669            {
1670              xml_begin_table_item ();
1671              if (item_func && *item_func)
1672                execute_string ("%s{%s}", item_func, rest_of_line);
1673              else
1674                execute_string ("%s", rest_of_line);
1675              xml_continue_table_item ();
1676            }
1677          else
1678            {
1679              /* We need this to determine if we have two @item's in a row
1680                 (see test just below).  */
1681              static int last_item_output_position = 0;
1682
1683              /* Get rid of extra characters. */
1684              kill_self_indent (-1);
1685
1686              /* If we have one @item followed directly by another @item,
1687                 we need to insert a blank line.  This is not true for
1688                 @itemx, though.  */
1689              if (!itemx_flag && last_item_output_position == output_position)
1690                insert ('\n');
1691
1692              /* `close_paragraph' almost does what we want.  The problem
1693                 is when paragraph_is_open, and last_char_was_newline, and
1694                 the last newline has been turned into a space, because
1695                 filling_enabled. I handle it here. */
1696              if (last_char_was_newline && filling_enabled &&
1697                  paragraph_is_open)
1698                insert ('\n');
1699              close_paragraph ();
1700
1701#if defined (INDENT_PARAGRAPHS_IN_TABLE)
1702              /* Indent on a new line, but back up one indentation level. */
1703              {
1704                int save = inhibit_paragraph_indentation;
1705                inhibit_paragraph_indentation = 1;
1706                /* At this point, inserting any non-whitespace character will
1707                   force the existing indentation to be output. */
1708                add_char ('i');
1709                inhibit_paragraph_indentation = save;
1710              }
1711#else /* !INDENT_PARAGRAPHS_IN_TABLE */
1712              add_char ('i');
1713#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
1714
1715              output_paragraph_offset--;
1716              kill_self_indent (default_indentation_increment + 1);
1717
1718              /* Add item's argument to the line. */
1719              filling_enabled = 0;
1720              if (item_func && *item_func)
1721                execute_string ("%s{%s}", item_func, rest_of_line);
1722              else
1723                execute_string ("%s", rest_of_line);
1724
1725              if (current_insertion_type () == ftable)
1726                execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
1727              else if (current_insertion_type () == vtable)
1728                execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
1729
1730              /* Start a new line, and let start_paragraph ()
1731                 do the indenting of it for you. */
1732              close_single_paragraph ();
1733              indented_fill = filling_enabled = 1;
1734              last_item_output_position = output_position;
1735            }
1736        }
1737      free (rest_of_line);
1738    }
1739  else
1740    {
1741    no_insertion:
1742      line_error (_("%c%s found outside of an insertion block"),
1743                  COMMAND_PREFIX, command);
1744    }
1745}
1746
1747void
1748cm_itemx ()
1749{
1750  itemx_flag++;
1751  cm_item ();
1752  itemx_flag--;
1753}
1754