156160Sru/* insertion.c -- insertions for Texinfo.
2146515Sru   $Id: insertion.c,v 1.55 2004/11/11 18:34:28 karl Exp $
356160Sru
4146515Sru   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
5114472Sru   Foundation, Inc.
656160Sru
756160Sru   This program is free software; you can redistribute it and/or modify
856160Sru   it under the terms of the GNU General Public License as published by
956160Sru   the Free Software Foundation; either version 2, or (at your option)
1056160Sru   any later version.
1156160Sru
1256160Sru   This program is distributed in the hope that it will be useful,
1356160Sru   but WITHOUT ANY WARRANTY; without even the implied warranty of
1456160Sru   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1556160Sru   GNU General Public License for more details.
1656160Sru
1756160Sru   You should have received a copy of the GNU General Public License
1856160Sru   along with this program; if not, write to the Free Software Foundation,
1956160Sru   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2056160Sru
2156160Sru#include "system.h"
2256160Sru#include "cmds.h"
2356160Sru#include "defun.h"
24146515Sru#include "float.h"
25146515Sru#include "html.h"
2656160Sru#include "insertion.h"
2756160Sru#include "macro.h"
2856160Sru#include "makeinfo.h"
29146515Sru#include "multi.h"
3093139Sru#include "xml.h"
3156160Sru
3256160Sru/* Must match list in insertion.h.  */
3356160Srustatic char *insertion_type_names[] =
3493139Sru{
35100513Sru  "cartouche", "copying", "defcv", "deffn", "defivar", "defmac",
36146515Sru  "defmethod", "defop", "defopt", "defspec", "deftp", "deftypecv",
37146515Sru  "deftypefn", "deftypefun", "deftypeivar", "deftypemethod",
38146515Sru  "deftypeop", "deftypevar", "deftypevr", "defun", "defvar", "defvr",
39146515Sru  "detailmenu", "direntry", "display", "documentdescription",
40146515Sru  "enumerate", "example", "float", "flushleft", "flushright", "format",
41146515Sru  "ftable", "group", "ifclear", "ifdocbook", "ifhtml", "ifinfo",
42146515Sru  "ifnotdocbook", "ifnothtml", "ifnotinfo", "ifnotplaintext", "ifnottex",
43146515Sru  "ifnotxml", "ifplaintext", "ifset", "iftex", "ifxml", "itemize", "lisp",
44146515Sru  "menu", "multitable", "quotation", "rawdocbook", "rawhtml", "rawtex",
45146515Sru  "rawxml", "smalldisplay", "smallexample", "smallformat", "smalllisp",
46146515Sru  "verbatim", "table", "tex", "vtable", "titlepage", "bad_type"
4756160Sru};
4856160Sru
4956160Sru/* All nested environments.  */
5056160SruINSERTION_ELT *insertion_stack = NULL;
5156160Sru
5256160Sru/* How deeply we're nested.  */
5356160Sruint insertion_level = 0;
5456160Sru
55100513Sru/* Set to 1 if we've processed (commentary) text in a @menu that
56100513Sru   wasn't part of a menu item.  */
57100513Sruint had_menu_commentary;
5856160Sru
5956160Sru/* How to examine menu lines.  */
6056160Sruint in_detailmenu = 0;
6156160Sru
62100513Sru/* Whether to examine menu lines.  */
63100513Sruint in_menu = 0;
6456160Sru
6556160Sru/* Set to 1 if <p> is written in normal context.
6656160Sru   Used for menu and itemize. */
6756160Sruint in_paragraph = 0;
6856160Sru
69146515Sru/* Since an insertion is already in the stack before we reach the switch
70146515Sru   statement, we cannot use is_in_insertion_of_type (always returns true.) Also
71146515Sru   making it return the level found, and comparing it with the current level is
72146515Sru   no use, due to the order of stack.  */
73146515Srustatic int float_active = 0;
74100513Sru
75146515Sru/* Unsetting escape_html blindly causes text inside @html/etc. to be escaped if
76146515Sru   used within a rmacro.  */
77146515Srustatic int raw_output_block = 0;
78146515Sru
79146515Sru/* Non-zero if a <dl> element has a <dt> element in it.  We use this when
80146515Sru   deciding whether to insert a <br> or not.  */
81146515Srustatic int html_deflist_has_term = 0;
8256160Sru
8356160Sruvoid
84146515Sruinit_insertion_stack (void)
8556160Sru{
8656160Sru  insertion_stack = NULL;
8756160Sru}
8856160Sru
8956160Sru/* Return the type of the current insertion. */
9056160Srustatic enum insertion_type
91146515Srucurrent_insertion_type (void)
9256160Sru{
9356160Sru  return insertion_level ? insertion_stack->insertion : bad_type;
9456160Sru}
9556160Sru
9656160Sru/* Return the string which is the function to wrap around items, or NULL
9756160Sru   if we're not in an environment where @item is ok.  */
9856160Srustatic char *
99146515Srucurrent_item_function (void)
10056160Sru{
10156160Sru  int done = 0;
10256160Sru  INSERTION_ELT *elt = insertion_stack;
10356160Sru
10456160Sru  /* Skip down through the stack until we find an insertion with an
10556160Sru     itemize function defined, i.e., skip conditionals, @cartouche, etc.  */
10656160Sru  while (!done && elt)
10756160Sru    {
10856160Sru      switch (elt->insertion)
10956160Sru        {
11056160Sru        /* This list should match the one in cm_item.  */
11156160Sru        case ifclear:
11256160Sru        case ifhtml:
11356160Sru        case ifinfo:
11456160Sru        case ifnothtml:
11556160Sru        case ifnotinfo:
116100513Sru        case ifnotplaintext:
11756160Sru        case ifnottex:
118114472Sru	case ifnotxml:
119100513Sru        case ifplaintext:
12056160Sru        case ifset:
12156160Sru        case iftex:
122114472Sru	case ifxml:
123146515Sru        case rawdocbook:
12456160Sru        case rawhtml:
125146515Sru        case rawxml:
12656160Sru        case rawtex:
12756160Sru        case tex:
12856160Sru        case cartouche:
129114472Sru          elt = elt->next;
130114472Sru          break;
13156160Sru
13256160Sru        default:
13356160Sru          done = 1;
13456160Sru        }
13556160Sru    }
13656160Sru
13756160Sru  /* item_function usually gets assigned the empty string.  */
13856160Sru  return done && (*elt->item_function) ? elt->item_function : NULL;
13956160Sru}
14056160Sru
14156160Sru/* Parse the item marker function off the input.  If result is just "@",
14256160Sru   change it to "@ ", since "@" by itself is not a command.  This makes
14356160Sru   "@ ", "@\t", and "@\n" all the same, but their default meanings are
14456160Sru   the same anyway, and let's not worry about supporting redefining them.  */
145146515Srustatic char *
146146515Sruget_item_function (void)
14756160Sru{
14856160Sru  char *item_function;
149116525Sru  char *item_loc;
150116525Sru
15156160Sru  get_rest_of_line (0, &item_function);
15256160Sru
153116525Sru  /* If the document erroneously says
154116525Sru       @itemize @bullet @item foobar
155116525Sru     it's nicer to give an error up front than repeat `@bullet expected
156116525Sru     braces' until we get a segmentation fault.  */
157116525Sru  item_loc = strstr (item_function, "@item");
158116525Sru  if (item_loc)
159116525Sru    {
160116525Sru      line_error (_("@item not allowed in argument to @itemize"));
161116525Sru      *item_loc = 0;
162116525Sru    }
163116525Sru
16456160Sru  /* If we hit the end of text in get_rest_of_line, backing up
16556160Sru     input pointer will cause the last character of the last line
16656160Sru     be pushed back onto the input, which is wrong.  */
16756160Sru  if (input_text_offset < input_text_length)
16856160Sru    backup_input_pointer ();
16956160Sru
17056160Sru  if (STREQ (item_function, "@"))
17156160Sru    {
17256160Sru      free (item_function);
17356160Sru      item_function = xstrdup ("@ ");
17456160Sru    }
17556160Sru
17656160Sru  return item_function;
17756160Sru}
17856160Sru
17956160Sru /* Push the state of the current insertion on the stack. */
180146515Srustatic void
181146515Srupush_insertion (enum insertion_type type, char *item_function)
18256160Sru{
18356160Sru  INSERTION_ELT *new = xmalloc (sizeof (INSERTION_ELT));
18456160Sru
18556160Sru  new->item_function = item_function;
18656160Sru  new->filling_enabled = filling_enabled;
18756160Sru  new->indented_fill = indented_fill;
18856160Sru  new->insertion = type;
18956160Sru  new->line_number = line_number;
19056160Sru  new->filename = xstrdup (input_filename);
19156160Sru  new->inhibited = inhibit_paragraph_indentation;
19256160Sru  new->in_fixed_width_font = in_fixed_width_font;
19356160Sru  new->next = insertion_stack;
19456160Sru  insertion_stack = new;
19556160Sru  insertion_level++;
19656160Sru}
19756160Sru
19856160Sru /* Pop the value on top of the insertion stack into the
19956160Sru    global variables. */
20056160Sruvoid
201146515Srupop_insertion (void)
20256160Sru{
20356160Sru  INSERTION_ELT *temp = insertion_stack;
20456160Sru
20556160Sru  if (temp == NULL)
20656160Sru    return;
20756160Sru
20856160Sru  in_fixed_width_font = temp->in_fixed_width_font;
20956160Sru  inhibit_paragraph_indentation = temp->inhibited;
21056160Sru  filling_enabled = temp->filling_enabled;
21156160Sru  indented_fill = temp->indented_fill;
21256160Sru  free_and_clear (&(temp->item_function));
21356160Sru  free_and_clear (&(temp->filename));
21456160Sru  insertion_stack = insertion_stack->next;
21556160Sru  free (temp);
21656160Sru  insertion_level--;
21756160Sru}
21856160Sru
21956160Sru /* Return a pointer to the print name of this
22056160Sru    enumerated type. */
221146515Srustatic const char *
222146515Sruinsertion_type_pname (enum insertion_type type)
22356160Sru{
22456160Sru  if ((int) type < (int) bad_type)
225146515Sru  {
226146515Sru    if (type == rawdocbook)
227146515Sru      return "docbook";
228146515Sru    else if (type == rawhtml)
229146515Sru      return "html";
230146515Sru    else if (type == rawxml)
231146515Sru      return "xml";
232146515Sru    else if (type == rawtex)
233146515Sru      return "tex";
234146515Sru    else
235146515Sru      return insertion_type_names[(int) type];
236146515Sru  }
23756160Sru  else
23856160Sru    return _("Broken-Type in insertion_type_pname");
23956160Sru}
24056160Sru
24156160Sru/* Return the insertion_type associated with NAME.
24256160Sru   If the type is not one of the known ones, return BAD_TYPE. */
24356160Sruenum insertion_type
244146515Srufind_type_from_name (char *name)
24556160Sru{
24656160Sru  int index = 0;
24756160Sru  while (index < (int) bad_type)
24856160Sru    {
24956160Sru      if (STREQ (name, insertion_type_names[index]))
25056160Sru        return (enum insertion_type) index;
251146515Sru      if (index == rawdocbook && STREQ (name, "docbook"))
252146515Sru        return rawdocbook;
25356160Sru      if (index == rawhtml && STREQ (name, "html"))
25456160Sru        return rawhtml;
255146515Sru      if (index == rawxml && STREQ (name, "xml"))
256146515Sru        return rawxml;
25756160Sru      if (index == rawtex && STREQ (name, "tex"))
25856160Sru        return rawtex;
25956160Sru      index++;
26056160Sru    }
26156160Sru  return bad_type;
26256160Sru}
26356160Sru
264146515Sru/* Simple function to query insertion_stack to see if we are inside a given
265146515Sru   insertion type. */
26656160Sruint
267146515Sruis_in_insertion_of_type (int type)
26856160Sru{
269146515Sru  INSERTION_ELT *temp = insertion_stack;
270146515Sru
271146515Sru  if (!insertion_level)
272146515Sru    return 0;
273146515Sru
274146515Sru  while (temp)
275146515Sru    {
276146515Sru      if (temp->insertion == type)
277146515Sru        return 1;
278146515Sru      temp = temp->next;
279146515Sru    }
280146515Sru
281146515Sru  return 0;
282146515Sru}
283146515Sru
284146515Sru
285146515Srustatic int
286146515Srudefun_insertion (enum insertion_type type)
287146515Sru{
28856160Sru  return 0
28956160Sru     || (type == defcv)
29056160Sru     || (type == deffn)
29156160Sru     || (type == defivar)
29256160Sru     || (type == defmac)
29356160Sru     || (type == defmethod)
29456160Sru     || (type == defop)
29556160Sru     || (type == defopt)
29656160Sru     || (type == defspec)
29756160Sru     || (type == deftp)
298146515Sru     || (type == deftypecv)
29956160Sru     || (type == deftypefn)
30056160Sru     || (type == deftypefun)
30156160Sru     || (type == deftypeivar)
30256160Sru     || (type == deftypemethod)
30356160Sru     || (type == deftypeop)
30456160Sru     || (type == deftypevar)
30556160Sru     || (type == deftypevr)
30656160Sru     || (type == defun)
30756160Sru     || (type == defvar)
30856160Sru     || (type == defvr)
30956160Sru  ;
31056160Sru}
31156160Sru
31256160Sru/* MAX_NS is the maximum nesting level for enumerations.  I picked 100
31356160Sru   which seemed reasonable.  This doesn't control the number of items,
31456160Sru   just the number of nested lists. */
31556160Sru#define max_stack_depth 100
31656160Sru#define ENUM_DIGITS 1
31756160Sru#define ENUM_ALPHA  2
31856160Srutypedef struct {
31956160Sru  int enumtype;
32056160Sru  int enumval;
32156160Sru} DIGIT_ALPHA;
32256160Sru
32356160SruDIGIT_ALPHA enumstack[max_stack_depth];
32456160Sruint enumstack_offset = 0;
32556160Sruint current_enumval = 1;
32656160Sruint current_enumtype = ENUM_DIGITS;
32756160Sruchar *enumeration_arg = NULL;
32856160Sru
329146515Srustatic void
330146515Srustart_enumerating (int at, int type)
33156160Sru{
33256160Sru  if ((enumstack_offset + 1) == max_stack_depth)
33356160Sru    {
33456160Sru      line_error (_("Enumeration stack overflow"));
33556160Sru      return;
33656160Sru    }
33756160Sru  enumstack[enumstack_offset].enumtype = current_enumtype;
33856160Sru  enumstack[enumstack_offset].enumval = current_enumval;
33956160Sru  enumstack_offset++;
34056160Sru  current_enumval = at;
34156160Sru  current_enumtype = type;
34256160Sru}
34356160Sru
344146515Srustatic void
345146515Srustop_enumerating (void)
34656160Sru{
34756160Sru  --enumstack_offset;
34856160Sru  if (enumstack_offset < 0)
34956160Sru    enumstack_offset = 0;
35056160Sru
35156160Sru  current_enumval = enumstack[enumstack_offset].enumval;
35256160Sru  current_enumtype = enumstack[enumstack_offset].enumtype;
35356160Sru}
35456160Sru
35556160Sru/* Place a letter or digits into the output stream. */
356146515Srustatic void
357146515Sruenumerate_item (void)
35856160Sru{
35956160Sru  char temp[10];
36056160Sru
36156160Sru  if (current_enumtype == ENUM_ALPHA)
36256160Sru    {
36356160Sru      if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
36456160Sru        {
36556160Sru          current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
36656160Sru          warning (_("lettering overflow, restarting at %c"), current_enumval);
36756160Sru        }
36856160Sru      sprintf (temp, "%c. ", current_enumval);
36956160Sru    }
37056160Sru  else
37156160Sru    sprintf (temp, "%d. ", current_enumval);
37256160Sru
37356160Sru  indent (output_column += (current_indent - strlen (temp)));
37456160Sru  add_word (temp);
37556160Sru  current_enumval++;
37656160Sru}
37756160Sru
37856160Srustatic void
379146515Sruenum_html (void)
38056160Sru{
38156160Sru  char type;
38256160Sru  int start;
38356160Sru
38456160Sru  if (isdigit (*enumeration_arg))
38556160Sru    {
38656160Sru      type = '1';
38756160Sru      start = atoi (enumeration_arg);
38856160Sru    }
38956160Sru  else if (isupper (*enumeration_arg))
39056160Sru    {
39156160Sru      type = 'A';
39256160Sru      start = *enumeration_arg - 'A' + 1;
39356160Sru    }
39456160Sru  else
39556160Sru    {
39656160Sru      type = 'a';
39756160Sru      start = *enumeration_arg - 'a' + 1;
39856160Sru    }
39956160Sru
400146515Sru  add_html_block_elt_args ("<ol type=%c start=%d>\n", type, start);
40156160Sru}
40256160Sru
40356160Sru/* Conditionally parse based on the current command name. */
40456160Sruvoid
405146515Srucommand_name_condition (void)
40656160Sru{
40756160Sru  char *discarder = xmalloc (8 + strlen (command));
40856160Sru
40956160Sru  sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
41056160Sru  discard_until (discarder);
41156160Sru  discard_until ("\n");
41256160Sru
41356160Sru  free (discarder);
41456160Sru}
41556160Sru
41656160Sru/* This is where the work for all the "insertion" style
41756160Sru   commands is done.  A huge switch statement handles the
41856160Sru   various setups, and generic code is on both sides. */
41956160Sruvoid
420146515Srubegin_insertion (enum insertion_type type)
42156160Sru{
42256160Sru  int no_discard = 0;
42356160Sru
42456160Sru  if (defun_insertion (type))
42556160Sru    {
42656160Sru      push_insertion (type, xstrdup (""));
42756160Sru      no_discard++;
42856160Sru    }
42956160Sru  else
43093139Sru    {
43193139Sru      push_insertion (type, get_item_function ());
43293139Sru    }
43356160Sru
43456160Sru  switch (type)
43556160Sru    {
43656160Sru    case menu:
43756160Sru      if (!no_headers)
43856160Sru        close_paragraph ();
43956160Sru
44056160Sru      filling_enabled = no_indent = 0;
44156160Sru      inhibit_paragraph_indentation = 1;
44256160Sru
44356160Sru      if (html)
44456160Sru        {
44556160Sru          had_menu_commentary = 1;
44656160Sru        }
44793139Sru      else if (!no_headers && !xml)
44856160Sru        add_word ("* Menu:\n");
44956160Sru
45093139Sru      if (xml)
451114472Sru        xml_insert_element (MENU, START);
452146515Sru      else
453146515Sru        in_fixed_width_font++;
454100513Sru
455100513Sru      next_menu_item_number = 1;
45656160Sru      in_menu++;
45756160Sru      no_discard++;
45856160Sru      break;
45956160Sru
46056160Sru    case detailmenu:
46156160Sru      if (!in_menu)
46256160Sru        {
46356160Sru          if (!no_headers)
46456160Sru            close_paragraph ();
46556160Sru
46656160Sru          filling_enabled = no_indent = 0;
46756160Sru          inhibit_paragraph_indentation = 1;
46856160Sru
46956160Sru          no_discard++;
47056160Sru        }
47156160Sru
472146515Sru      if (xml)
473146515Sru        {
474146515Sru          xml_insert_element (DETAILMENU, START);
475146515Sru          skip_whitespace_and_newlines();
476146515Sru        }
477146515Sru      else
478146515Sru        in_fixed_width_font++;
479146515Sru
48056160Sru      in_detailmenu++;
48156160Sru      break;
48256160Sru
48356160Sru    case direntry:
48493139Sru      close_single_paragraph ();
48593139Sru      filling_enabled = no_indent = 0;
48693139Sru      inhibit_paragraph_indentation = 1;
48793139Sru      insert_string ("START-INFO-DIR-ENTRY\n");
48856160Sru      break;
48956160Sru
49093139Sru    case documentdescription:
49193139Sru      {
49293139Sru        char *desc;
49393139Sru        int start_of_end;
49493139Sru        int save_fixed_width;
49593139Sru
49693139Sru        discard_until ("\n"); /* ignore the @documentdescription line */
49793139Sru        start_of_end = get_until ("\n@end documentdescription", &desc);
49893139Sru        save_fixed_width = in_fixed_width_font;
49993139Sru
50093139Sru        in_fixed_width_font = 0;
50193139Sru        document_description = expansion (desc, 0);
50293139Sru        free (desc);
50393139Sru
50493139Sru        in_fixed_width_font = save_fixed_width;
50593139Sru        input_text_offset = start_of_end; /* go back to the @end to match */
50693139Sru      }
50793139Sru      break;
50893139Sru
509100513Sru    case copying:
510100513Sru        /* Save the copying text away for @insertcopying,
511100513Sru           typically used on the back of the @titlepage (for TeX) and
512100513Sru           the Top node (for info/html).  */
513146515Sru      if (input_text[input_text_offset] != '\n')
514100513Sru        discard_until ("\n"); /* ignore remainder of @copying line */
515100513Sru
516146515Sru        input_text_offset = get_until ("\n@end copying", &copying_text);
517146515Sru        canon_white (copying_text);
518100513Sru
519100513Sru      /* For info, output the copying text right away, so it will end up
520100513Sru         in the header of the Info file, before the first node, and thus
521100513Sru         get copied automatically to all the split files.  For xml, also
522100513Sru         output it right away since xml output is never split.
523100513Sru         For html, we output it specifically in html_output_head.
524100513Sru         For plain text, there's no way to hide it, so the author must
525100513Sru          use @insertcopying in the desired location.  */
526114472Sru      if (docbook)
527114472Sru	{
528114472Sru	  if (!xml_in_bookinfo)
529114472Sru	    {
530114472Sru	      xml_insert_element (BOOKINFO, START);
531114472Sru	      xml_in_bookinfo = 1;
532114472Sru	    }
533146515Sru          xml_insert_element (LEGALNOTICE, START);
534114472Sru	}
535146515Sru
536100513Sru      if (!html && !no_headers)
537100513Sru        cm_insert_copying ();
538146515Sru
539146515Sru      if (docbook)
540146515Sru        xml_insert_element (LEGALNOTICE, END);
541146515Sru
542100513Sru      break;
543146515Sru
54456160Sru    case quotation:
54556160Sru      /* @quotation does filling (@display doesn't).  */
54656160Sru      if (html)
547146515Sru        add_html_block_elt ("<blockquote>\n");
54856160Sru      else
54956160Sru        {
550100513Sru          /* with close_single_paragraph, we get no blank line above
551100513Sru             within @copying.  */
552100513Sru          close_paragraph ();
55356160Sru          last_char_was_newline = no_indent = 0;
55456160Sru          indented_fill = filling_enabled = 1;
55556160Sru          inhibit_paragraph_indentation = 1;
55656160Sru        }
55756160Sru      current_indent += default_indentation_increment;
558146515Sru      if (xml)
559146515Sru        xml_insert_quotation (insertion_stack->item_function, START);
560146515Sru      else if (strlen(insertion_stack->item_function))
561146515Sru        execute_string ("@b{%s:} ", insertion_stack->item_function);
56256160Sru      break;
56356160Sru
56456160Sru    case example:
56556160Sru    case smallexample:
56656160Sru    case lisp:
56756160Sru    case smalllisp:
568146515Sru      in_fixed_width_font++;
569146515Sru      /* fall through */
570146515Sru
571146515Sru      /* Like @example but no fixed width font. */
572146515Sru    case display:
573146515Sru    case smalldisplay:
57456160Sru      /* Like @display but without indentation. */
57556160Sru    case smallformat:
57656160Sru    case format:
57756160Sru      close_single_paragraph ();
57856160Sru      inhibit_paragraph_indentation = 1;
57956160Sru      filling_enabled = 0;
58056160Sru      last_char_was_newline = 0;
58156160Sru
58256160Sru      if (html)
583146515Sru        /* Kludge alert: if <pre> is followed by a newline, IE3,
584146515Sru           mozilla, maybe others render an extra blank line before the
585146515Sru           pre-formatted block.  So don't output a newline.  */
586146515Sru        add_html_block_elt_args ("<pre class=\"%s\">", command);
58756160Sru
58856160Sru      if (type != format && type != smallformat)
589114472Sru        {
590146515Sru          current_indent += example_indentation_increment;
591114472Sru          if (html)
592114472Sru            {
593114472Sru              /* Since we didn't put \n after <pre>, we need to insert
594114472Sru                 the indentation by hand.  */
595114472Sru              int i;
596114472Sru              for (i = current_indent; i > 0; i--)
597114472Sru                add_char (' ');
598114472Sru            }
599114472Sru        }
60056160Sru      break;
60156160Sru
60256160Sru    case multitable:
60356160Sru      do_multitable ();
60456160Sru      break;
60556160Sru
60656160Sru    case table:
60756160Sru    case ftable:
60856160Sru    case vtable:
60956160Sru    case itemize:
61056160Sru      close_single_paragraph ();
61156160Sru      current_indent += default_indentation_increment;
61256160Sru      filling_enabled = indented_fill = 1;
61356160Sru#if defined (INDENT_PARAGRAPHS_IN_TABLE)
61456160Sru      inhibit_paragraph_indentation = 0;
61556160Sru#else
61656160Sru      inhibit_paragraph_indentation = 1;
61756160Sru#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
61856160Sru
61956160Sru      /* Make things work for losers who forget the itemize syntax. */
62056160Sru      if (type == itemize)
62156160Sru        {
62256160Sru          if (!(*insertion_stack->item_function))
62356160Sru            {
62456160Sru              free (insertion_stack->item_function);
62556160Sru              insertion_stack->item_function = xstrdup ("@bullet");
62656160Sru            }
62756160Sru        }
62856160Sru
62956160Sru      if (!*insertion_stack->item_function)
63056160Sru        {
63156160Sru          line_error (_("%s requires an argument: the formatter for %citem"),
63256160Sru                      insertion_type_pname (type), COMMAND_PREFIX);
63356160Sru        }
63456160Sru
63556160Sru      if (html)
63656160Sru        {
63756160Sru          if (type == itemize)
638114472Sru            {
639146515Sru              add_html_block_elt ("<ul>\n");
640114472Sru              in_paragraph = 0;
641114472Sru            }
64256160Sru          else
643146515Sru            { /* We are just starting, so this <dl>
644146515Sru                 has no <dt> children yet.  */
645146515Sru              html_deflist_has_term = 0;
646146515Sru              add_html_block_elt ("<dl>\n");
647146515Sru            }
64856160Sru        }
64993139Sru      if (xml)
650114472Sru        xml_begin_table (type, insertion_stack->item_function);
651146515Sru
652146515Sru      while (input_text[input_text_offset] == '\n'
653146515Sru          && input_text[input_text_offset+1] == '\n')
654146515Sru        {
655146515Sru          line_number++;
656146515Sru          input_text_offset++;
657146515Sru        }
658146515Sru
65956160Sru      break;
66056160Sru
66156160Sru    case enumerate:
66256160Sru      close_single_paragraph ();
66356160Sru      no_indent = 0;
66456160Sru#if defined (INDENT_PARAGRAPHS_IN_TABLE)
66556160Sru      inhibit_paragraph_indentation = 0;
66656160Sru#else
66756160Sru      inhibit_paragraph_indentation = 1;
66856160Sru#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
66956160Sru
67056160Sru      current_indent += default_indentation_increment;
67156160Sru      filling_enabled = indented_fill = 1;
67256160Sru
67356160Sru      if (html)
674114472Sru        {
675114472Sru          enum_html ();
676114472Sru          in_paragraph = 0;
677114472Sru        }
67856160Sru
67993139Sru      if (xml)
680114472Sru        xml_begin_enumerate (enumeration_arg);
68193139Sru
68256160Sru      if (isdigit (*enumeration_arg))
68356160Sru        start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
68456160Sru      else
68556160Sru        start_enumerating (*enumeration_arg, ENUM_ALPHA);
68656160Sru      break;
68756160Sru
688146515Sru      /* @group produces no output in info. */
68956160Sru    case group:
69056160Sru      /* Only close the paragraph if we are not inside of an
69156160Sru         @example-like environment. */
69293139Sru      if (xml)
693114472Sru        xml_insert_element (GROUP, START);
69493139Sru      else if (!insertion_stack->next
69556160Sru          || (insertion_stack->next->insertion != display
69656160Sru              && insertion_stack->next->insertion != smalldisplay
69756160Sru              && insertion_stack->next->insertion != example
69856160Sru              && insertion_stack->next->insertion != smallexample
69956160Sru              && insertion_stack->next->insertion != lisp
70056160Sru              && insertion_stack->next->insertion != smalllisp
70156160Sru              && insertion_stack->next->insertion != format
70256160Sru              && insertion_stack->next->insertion != smallformat
70356160Sru              && insertion_stack->next->insertion != flushleft
70456160Sru              && insertion_stack->next->insertion != flushright))
70556160Sru        close_single_paragraph ();
70656160Sru      break;
70756160Sru
708116525Sru    case cartouche:
709116525Sru      if (html)
710146515Sru	add_html_block_elt ("<p><table class=\"cartouche\" summary=\"cartouche\" border=\"1\"><tr><td>\n");
711116525Sru      if (in_menu)
712116525Sru        no_discard++;
713116525Sru      break;
714116525Sru
715146515Sru    case floatenv:
716146515Sru      /* Cannot nest floats, so complain.  */
717146515Sru      if (float_active)
718146515Sru        {
719146515Sru          line_error (_("%cfloat environments cannot be nested"), COMMAND_PREFIX);
720146515Sru          pop_insertion ();
721146515Sru          break;
722146515Sru        }
723146515Sru
724146515Sru      float_active++;
725146515Sru
726146515Sru      { /* Collect data about this float.  */
727146515Sru        /* Example: @float [FLOATTYPE][,XREFLABEL][,POSITION] */
728146515Sru        char floattype[200] = "";
729146515Sru        char xreflabel[200] = "";
730146515Sru        char position[200]  = "";
731146515Sru        char *text;
732146515Sru        char *caption;
733146515Sru        char *shortcaption;
734146515Sru        int start_of_end;
735146515Sru        int save_line_number = line_number;
736146515Sru        int save_input_text_offset = input_text_offset;
737146515Sru        int i;
738146515Sru
739146515Sru        if (strlen (insertion_stack->item_function) > 0)
740146515Sru          {
741146515Sru            int i = 0, t = 0, c = 0;
742146515Sru            while (insertion_stack->item_function[i])
743146515Sru              {
744146515Sru                if (insertion_stack->item_function[i] == ',')
745146515Sru                  {
746146515Sru                    switch (t)
747146515Sru                      {
748146515Sru                      case 0:
749146515Sru                        floattype[c] = '\0';
750146515Sru                        break;
751146515Sru                      case 1:
752146515Sru                        xreflabel[c] = '\0';
753146515Sru                        break;
754146515Sru                      case 2:
755146515Sru                        position[c] = '\0';
756146515Sru                        break;
757146515Sru                      }
758146515Sru                    c = 0;
759146515Sru                    t++;
760146515Sru                    i++;
761146515Sru                    continue;
762146515Sru                  }
763146515Sru
764146515Sru                switch (t)
765146515Sru                  {
766146515Sru                  case 0:
767146515Sru                    floattype[c] = insertion_stack->item_function[i];
768146515Sru                    break;
769146515Sru                  case 1:
770146515Sru                    xreflabel[c] = insertion_stack->item_function[i];
771146515Sru                    break;
772146515Sru                  case 2:
773146515Sru                    position[c] = insertion_stack->item_function[i];
774146515Sru                    break;
775146515Sru                  }
776146515Sru                c++;
777146515Sru                i++;
778146515Sru              }
779146515Sru          }
780146515Sru
781146515Sru        skip_whitespace_and_newlines ();
782146515Sru
783146515Sru        start_of_end = get_until ("\n@end float", &text);
784146515Sru
785146515Sru        /* Get also the @caption.  */
786146515Sru        i = search_forward_until_pos ("\n@caption{",
787146515Sru            save_input_text_offset, start_of_end);
788146515Sru        if (i > -1)
789146515Sru          {
790146515Sru            input_text_offset = i + sizeof ("\n@caption{") - 1;
791146515Sru            get_until_in_braces ("\n@end float", &caption);
792146515Sru            input_text_offset = save_input_text_offset;
793146515Sru          }
794146515Sru        else
795146515Sru          caption = "";
796146515Sru
797146515Sru        /* ... and the @shortcaption.  */
798146515Sru        i = search_forward_until_pos ("\n@shortcaption{",
799146515Sru            save_input_text_offset, start_of_end);
800146515Sru        if (i > -1)
801146515Sru          {
802146515Sru            input_text_offset = i + sizeof ("\n@shortcaption{") - 1;
803146515Sru            get_until_in_braces ("\n@end float", &shortcaption);
804146515Sru            input_text_offset = save_input_text_offset;
805146515Sru          }
806146515Sru        else
807146515Sru          shortcaption = "";
808146515Sru
809146515Sru        canon_white (xreflabel);
810146515Sru        canon_white (floattype);
811146515Sru        canon_white (position);
812146515Sru        canon_white (caption);
813146515Sru        canon_white (shortcaption);
814146515Sru
815146515Sru        add_new_float (xstrdup (xreflabel),
816146515Sru            xstrdup (caption), xstrdup (shortcaption),
817146515Sru            xstrdup (floattype), xstrdup (position));
818146515Sru
819146515Sru        /* Move to the start of the @float so the contents get processed as
820146515Sru           usual.  */
821146515Sru        input_text_offset = save_input_text_offset;
822146515Sru        line_number = save_line_number;
823146515Sru      }
824146515Sru
825146515Sru      if (html)
826146515Sru        add_html_block_elt ("<div class=\"float\">\n");
827146515Sru      else if (docbook)
828146515Sru        xml_insert_element (FLOAT, START);
829146515Sru      else if (xml)
830146515Sru        {
831146515Sru          xml_insert_element_with_attribute (FLOAT, START,
832146515Sru              "name=\"%s\"", current_float_id ());
833146515Sru
834146515Sru          xml_insert_element (FLOATTYPE, START);
835146515Sru          execute_string ("%s", current_float_type ());
836146515Sru          xml_insert_element (FLOATTYPE, END);
837146515Sru
838146515Sru          xml_insert_element (FLOATPOS, START);
839146515Sru          execute_string ("%s", current_float_position ());
840146515Sru          xml_insert_element (FLOATPOS, END);
841146515Sru        }
842146515Sru      else
843146515Sru        { /* Info */
844146515Sru          close_single_paragraph ();
845146515Sru          inhibit_paragraph_indentation = 1;
846146515Sru        }
847146515Sru
848146515Sru      /* Anchor now.  Note that XML documents get their
849146515Sru         anchors with <float name="anchor"> tag.  */
850146515Sru      if ((!xml || docbook) && strlen (current_float_id ()) > 0)
851146515Sru        execute_string ("@anchor{%s}", current_float_id ());
852146515Sru
853146515Sru      break;
854146515Sru
85556160Sru      /* Insertions that are no-ops in info, but do something in TeX. */
85656160Sru    case ifclear:
857146515Sru    case ifdocbook:
85856160Sru    case ifhtml:
85956160Sru    case ifinfo:
860146515Sru    case ifnotdocbook:
86156160Sru    case ifnothtml:
86256160Sru    case ifnotinfo:
863100513Sru    case ifnotplaintext:
86456160Sru    case ifnottex:
865114472Sru    case ifnotxml:
866100513Sru    case ifplaintext:
86756160Sru    case ifset:
86856160Sru    case iftex:
869114472Sru    case ifxml:
87056160Sru    case rawtex:
87156160Sru      if (in_menu)
87256160Sru        no_discard++;
87356160Sru      break;
87456160Sru
875146515Sru    case rawdocbook:
87656160Sru    case rawhtml:
877146515Sru    case rawxml:
878146515Sru      raw_output_block++;
879146515Sru
880146515Sru      if (raw_output_block > 0)
881146515Sru        {
882146515Sru          xml_no_para = 1;
883146515Sru          escape_html = 0;
884146515Sru          xml_keep_space++;
885146515Sru        }
886146515Sru
887146515Sru      {
888146515Sru        /* Some deuglification for improved readability.  */
889146515Sru        extern int xml_in_para;
890146515Sru        if (xml && !xml_in_para && xml_indentation_increment > 0)
891146515Sru          add_char ('\n');
892146515Sru      }
893146515Sru
89456160Sru      break;
89556160Sru
89656160Sru    case defcv:
89756160Sru    case deffn:
89856160Sru    case defivar:
89956160Sru    case defmac:
90056160Sru    case defmethod:
90156160Sru    case defop:
90256160Sru    case defopt:
90356160Sru    case defspec:
90456160Sru    case deftp:
905146515Sru    case deftypecv:
90656160Sru    case deftypefn:
90756160Sru    case deftypefun:
90856160Sru    case deftypeivar:
90956160Sru    case deftypemethod:
91056160Sru    case deftypeop:
91156160Sru    case deftypevar:
91256160Sru    case deftypevr:
91356160Sru    case defun:
91456160Sru    case defvar:
91556160Sru    case defvr:
91656160Sru      inhibit_paragraph_indentation = 1;
91756160Sru      filling_enabled = indented_fill = 1;
91856160Sru      current_indent += default_indentation_increment;
91956160Sru      no_indent = 0;
920146515Sru      if (xml)
921146515Sru	xml_begin_definition ();
92256160Sru      break;
92356160Sru
92456160Sru    case flushleft:
92556160Sru      close_single_paragraph ();
92656160Sru      inhibit_paragraph_indentation = 1;
92756160Sru      filling_enabled = indented_fill = no_indent = 0;
92893139Sru      if (html)
929146515Sru        add_html_block_elt ("<div align=\"left\">");
93056160Sru      break;
93156160Sru
93256160Sru    case flushright:
93356160Sru      close_single_paragraph ();
93456160Sru      filling_enabled = indented_fill = no_indent = 0;
93556160Sru      inhibit_paragraph_indentation = 1;
93656160Sru      force_flush_right++;
93793139Sru      if (html)
938146515Sru        add_html_block_elt ("<div align=\"right\">");
93956160Sru      break;
94056160Sru
941146515Sru    case titlepage:
942146515Sru      xml_insert_element (TITLEPAGE, START);
943146515Sru      break;
944146515Sru
94556160Sru    default:
94656160Sru      line_error ("begin_insertion internal error: type=%d", type);
94756160Sru    }
94856160Sru
94956160Sru  if (!no_discard)
95056160Sru    discard_until ("\n");
95156160Sru}
95256160Sru
95356160Sru/* Try to end the insertion with the specified TYPE.  With a value of
95456160Sru   `bad_type', TYPE gets translated to match the value currently on top
95556160Sru   of the stack.  Otherwise, if TYPE doesn't match the top of the
95656160Sru   insertion stack, give error. */
957146515Srustatic void
958146515Sruend_insertion (int type)
95956160Sru{
960146515Sru  int temp_type;
96156160Sru
96256160Sru  if (!insertion_level)
96356160Sru    return;
96456160Sru
96556160Sru  temp_type = current_insertion_type ();
96656160Sru
96756160Sru  if (type == bad_type)
96856160Sru    type = temp_type;
96956160Sru
97056160Sru  if (type != temp_type)
97156160Sru    {
97256160Sru      line_error
97356160Sru        (_("`@end' expected `%s', but saw `%s'"),
97456160Sru         insertion_type_pname (temp_type), insertion_type_pname (type));
97556160Sru      return;
97656160Sru    }
97756160Sru
97856160Sru  pop_insertion ();
97956160Sru
98093139Sru  if (xml)
98193139Sru    {
98293139Sru      switch (type)
983114472Sru        {
984114472Sru        case ifinfo:
985114472Sru        case documentdescription:
986114472Sru          break;
987114472Sru        case quotation:
988146515Sru          xml_insert_quotation ("", END);
989114472Sru          break;
990114472Sru        case example:
991114472Sru          xml_insert_element (EXAMPLE, END);
992146515Sru          if (docbook && current_insertion_type () == floatenv)
993146515Sru            xml_insert_element (FLOATEXAMPLE, END);
994114472Sru          break;
995114472Sru        case smallexample:
996114472Sru          xml_insert_element (SMALLEXAMPLE, END);
997146515Sru          if (docbook && current_insertion_type () == floatenv)
998146515Sru            xml_insert_element (FLOATEXAMPLE, END);
999114472Sru          break;
1000114472Sru        case lisp:
1001114472Sru          xml_insert_element (LISP, END);
1002146515Sru          if (docbook && current_insertion_type () == floatenv)
1003146515Sru            xml_insert_element (FLOATEXAMPLE, END);
1004114472Sru          break;
1005114472Sru        case smalllisp:
1006114472Sru          xml_insert_element (SMALLLISP, END);
1007146515Sru          if (docbook && current_insertion_type () == floatenv)
1008146515Sru            xml_insert_element (FLOATEXAMPLE, END);
1009114472Sru          break;
1010114472Sru        case cartouche:
1011114472Sru          xml_insert_element (CARTOUCHE, END);
1012114472Sru          break;
1013114472Sru        case format:
1014114472Sru	  if (docbook && xml_in_bookinfo && xml_in_abstract)
1015114472Sru	    {
1016114472Sru	      xml_insert_element (ABSTRACT, END);
1017114472Sru	      xml_in_abstract = 0;
1018114472Sru	    }
1019114472Sru	  else
1020114472Sru	    xml_insert_element (FORMAT, END);
1021114472Sru          break;
1022114472Sru        case smallformat:
1023114472Sru          xml_insert_element (SMALLFORMAT, END);
1024114472Sru          break;
1025114472Sru        case display:
1026114472Sru          xml_insert_element (DISPLAY, END);
1027114472Sru          break;
1028114472Sru        case smalldisplay:
1029114472Sru          xml_insert_element (SMALLDISPLAY, END);
1030114472Sru          break;
1031114472Sru        case table:
1032114472Sru        case ftable:
1033114472Sru        case vtable:
1034114472Sru        case itemize:
1035114472Sru          xml_end_table (type);
1036114472Sru          break;
1037114472Sru        case enumerate:
1038146515Sru          xml_end_enumerate ();
1039114472Sru          break;
1040114472Sru        case group:
1041114472Sru          xml_insert_element (GROUP, END);
1042114472Sru          break;
1043146515Sru	case titlepage:
1044146515Sru	  xml_insert_element (TITLEPAGE, END);
1045146515Sru	  break;
1046114472Sru        }
104793139Sru    }
104856160Sru  switch (type)
104956160Sru    {
105056160Sru      /* Insertions which have no effect on paragraph formatting. */
1051100513Sru    case copying:
1052146515Sru      line_number--;
1053146515Sru      break;
1054146515Sru
105556160Sru    case ifclear:
1056146515Sru    case ifdocbook:
105793139Sru    case ifinfo:
105856160Sru    case ifhtml:
1059146515Sru    case ifnotdocbook:
106056160Sru    case ifnothtml:
106156160Sru    case ifnotinfo:
1062100513Sru    case ifnotplaintext:
106356160Sru    case ifnottex:
1064114472Sru    case ifnotxml:
1065100513Sru    case ifplaintext:
106656160Sru    case ifset:
106756160Sru    case iftex:
1068114472Sru    case ifxml:
106956160Sru    case rawtex:
1070146515Sru    case titlepage:
107156160Sru      break;
107256160Sru
1073146515Sru    case rawdocbook:
107456160Sru    case rawhtml:
1075146515Sru    case rawxml:
1076146515Sru      raw_output_block--;
1077146515Sru
1078146515Sru      if (raw_output_block <= 0)
1079146515Sru        {
1080146515Sru          xml_no_para = 0;
1081146515Sru          escape_html = 1;
1082146515Sru          xml_keep_space--;
1083146515Sru        }
1084146515Sru
1085146515Sru      if ((xml || html) && output_paragraph[output_paragraph_offset-1] == '\n')
1086146515Sru        output_paragraph_offset--;
108756160Sru      break;
108856160Sru
108956160Sru    case detailmenu:
1090146515Sru      if (xml)
1091146515Sru        xml_insert_element (DETAILMENU, END);
1092146515Sru
109356160Sru      in_detailmenu--;          /* No longer hacking menus. */
109456160Sru      if (!in_menu)
109556160Sru        {
109656160Sru          if (!no_headers)
109756160Sru            close_insertion_paragraph ();
109856160Sru        }
109956160Sru      break;
110056160Sru
1101100513Sru    case direntry:              /* Eaten if html. */
1102100513Sru      insert_string ("END-INFO-DIR-ENTRY\n\n");
1103100513Sru      close_insertion_paragraph ();
1104100513Sru      break;
1105100513Sru
1106146515Sru    case documentdescription:
1107146515Sru      if (xml)
1108146515Sru        insert_string (document_description);
1109146515Sru        xml_insert_element (DOCUMENTDESCRIPTION, END);
1110146515Sru      break;
1111146515Sru
111256160Sru    case menu:
111356160Sru      in_menu--;                /* No longer hacking menus. */
1114116525Sru      if (html && !no_headers)
1115146515Sru        add_html_block_elt ("</ul>\n");
1116146515Sru      else if (!no_headers && !xml)
111756160Sru        close_insertion_paragraph ();
111856160Sru      break;
111956160Sru
112056160Sru    case multitable:
112156160Sru      end_multitable ();
112256160Sru      break;
112356160Sru
112456160Sru    case enumerate:
112556160Sru      stop_enumerating ();
112656160Sru      close_insertion_paragraph ();
112756160Sru      current_indent -= default_indentation_increment;
112856160Sru      if (html)
1129146515Sru        add_html_block_elt ("</ol>\n");
113056160Sru      break;
113156160Sru
113256160Sru    case flushleft:
113393139Sru      if (html)
1134146515Sru        add_html_block_elt ("</div>\n");
113593139Sru      close_insertion_paragraph ();
113693139Sru      break;
113793139Sru
113856160Sru    case cartouche:
1139116525Sru      if (html)
1140146515Sru	add_html_block_elt ("</td></tr></table>\n");
114156160Sru      close_insertion_paragraph ();
114256160Sru      break;
114356160Sru
1144116525Sru    case group:
1145146515Sru      if (!xml || docbook)
1146146515Sru        close_insertion_paragraph ();
1147116525Sru      break;
1148116525Sru
1149146515Sru    case floatenv:
1150146515Sru      if (xml)
1151146515Sru        xml_insert_element (FLOAT, END);
1152146515Sru      else
1153146515Sru        {
1154146515Sru          if (html)
1155146515Sru            add_html_block_elt ("<p><strong class=\"float-caption\">");
1156146515Sru          else
1157146515Sru            close_paragraph ();
1158146515Sru
1159146515Sru          no_indent = 1;
1160146515Sru
1161146515Sru          /* Legend:
1162146515Sru               1) @float Foo,lbl & no caption:    Foo 1.1
1163146515Sru               2) @float Foo & no caption:        Foo
1164146515Sru               3) @float ,lbl & no caption:       1.1
1165146515Sru               4) @float & no caption:                    */
1166146515Sru
1167146515Sru          if (!xml && !html)
1168146515Sru            indent (current_indent);
1169146515Sru
1170146515Sru          if (strlen (current_float_type ()))
1171146515Sru            execute_string ("%s", current_float_type ());
1172146515Sru
1173146515Sru          if (strlen (current_float_id ()) > 0)
1174146515Sru            {
1175146515Sru              if (strlen (current_float_type ()) > 0)
1176146515Sru                add_char (' ');
1177146515Sru
1178146515Sru              add_word (current_float_number ());
1179146515Sru            }
1180146515Sru
1181146515Sru          if (strlen (current_float_title ()) > 0)
1182146515Sru            {
1183146515Sru              if (strlen (current_float_type ()) > 0
1184146515Sru                  || strlen (current_float_id ()) > 0)
1185146515Sru                insert_string (": ");
1186146515Sru
1187146515Sru              execute_string ("%s", current_float_title ());
1188146515Sru            }
1189146515Sru
1190146515Sru          /* Indent the following paragraph. */
1191146515Sru          inhibit_paragraph_indentation = 0;
1192146515Sru
1193146515Sru          if (html)
1194146515Sru            add_word ("</strong></p></div>\n");
1195146515Sru          else
1196146515Sru            close_paragraph ();
1197146515Sru        }
1198146515Sru      float_active--;
1199146515Sru      break;
1200146515Sru
120156160Sru    case format:
120256160Sru    case smallformat:
120356160Sru    case display:
120456160Sru    case smalldisplay:
120556160Sru    case example:
120656160Sru    case smallexample:
120756160Sru    case lisp:
120856160Sru    case smalllisp:
120956160Sru    case quotation:
121056160Sru      /* @format and @smallformat are the only fixed_width insertion
121156160Sru         without a change in indentation. */
1212146515Sru      if (type != format && type != smallformat && type != quotation)
1213146515Sru        current_indent -= example_indentation_increment;
1214146515Sru      else if (type == quotation)
121556160Sru        current_indent -= default_indentation_increment;
121656160Sru
121756160Sru      if (html)
1218146515Sru        { /* The complex code in close_paragraph that kills whitespace
1219146515Sru             does not function here, since we've inserted non-whitespace
1220146515Sru             (the </whatever>) before it.  The indentation already got
1221146515Sru             inserted at the end of the last example line, so we have to
1222146515Sru             delete it, or browsers wind up showing an extra blank line.  */
1223146515Sru          kill_self_indent (default_indentation_increment);
1224146515Sru          add_html_block_elt (type == quotation
1225146515Sru              ? "</blockquote>\n" : "</pre>\n");
1226146515Sru        }
122756160Sru
122856160Sru      /* The ending of one of these insertions always marks the
1229146515Sru         start of a new paragraph, except for the XML output. */
1230146515Sru      if (!xml || docbook)
1231146515Sru        close_insertion_paragraph ();
1232146515Sru
1233146515Sru      /* </pre> closes paragraph without messing with </p>.  */
1234146515Sru      if (html && type != quotation)
1235146515Sru          paragraph_is_open = 0;
123656160Sru      break;
123756160Sru
123856160Sru    case table:
123956160Sru    case ftable:
124056160Sru    case vtable:
124156160Sru      current_indent -= default_indentation_increment;
124256160Sru      if (html)
1243146515Sru        add_html_block_elt ("</dl>\n");
1244114472Sru      close_insertion_paragraph ();
124556160Sru      break;
124656160Sru
124756160Sru    case itemize:
124856160Sru      current_indent -= default_indentation_increment;
124956160Sru      if (html)
1250146515Sru        add_html_block_elt ("</ul>\n");
125156160Sru      close_insertion_paragraph ();
125256160Sru      break;
125356160Sru
125456160Sru    case flushright:
125556160Sru      force_flush_right--;
125693139Sru      if (html)
1257146515Sru        add_html_block_elt ("</div>\n");
125856160Sru      close_insertion_paragraph ();
125956160Sru      break;
126056160Sru
126156160Sru    /* Handle the @defun insertions with this default clause. */
126256160Sru    default:
126356160Sru      {
1264146515Sru        int base_type;
126556160Sru
126656160Sru        if (type < defcv || type > defvr)
126756160Sru          line_error ("end_insertion internal error: type=%d", type);
126856160Sru
126956160Sru        base_type = get_base_type (type);
127056160Sru        switch (base_type)
127156160Sru          {
127256160Sru          case deffn:
127356160Sru          case defvr:
127456160Sru          case deftp:
1275146515Sru          case deftypecv:
127656160Sru          case deftypefn:
127756160Sru          case deftypevr:
127856160Sru          case defcv:
127956160Sru          case defop:
1280114472Sru          case deftypemethod:
1281114472Sru          case deftypeop:
1282114472Sru          case deftypeivar:
1283114472Sru            if (html)
1284146515Sru              {
1285146515Sru                if (paragraph_is_open)
1286146515Sru                  add_html_block_elt ("</p>");
1287146515Sru                /* close the div and blockquote which has been opened in defun.c */
1288146515Sru                if (!rollback_empty_tag ("blockquote"))
1289146515Sru                  add_html_block_elt ("</blockquote>");
1290146515Sru                add_html_block_elt ("</div>\n");
1291146515Sru              }
1292146515Sru	    if (xml)
1293146515Sru	      xml_end_definition ();
129456160Sru            break;
129556160Sru          } /* switch (base_type)... */
129656160Sru
129756160Sru        current_indent -= default_indentation_increment;
129856160Sru        close_insertion_paragraph ();
129956160Sru      }
130056160Sru      break;
130156160Sru
130256160Sru    }
130356160Sru
130456160Sru  if (current_indent < 0)
130556160Sru    line_error ("end_insertion internal error: current indent=%d",
130656160Sru                current_indent);
130756160Sru}
130856160Sru
130956160Sru/* Insertions cannot cross certain boundaries, such as node beginnings.  In
131056160Sru   code that creates such boundaries, you should call `discard_insertions'
131156160Sru   before doing anything else.  It prints the errors for you, and cleans up
131256160Sru   the insertion stack.
131356160Sru
131456160Sru   With nonzero SPECIALS_OK argument, allows unmatched
131556160Sru   @if... conditionals, otherwise not.  This is because conditionals can
131656160Sru   cross node boundaries.  Always happens with the @top node, for example.  */
131756160Sruvoid
1318146515Srudiscard_insertions (int specials_ok)
131956160Sru{
132056160Sru  int real_line_number = line_number;
132156160Sru  while (insertion_stack)
132256160Sru    {
132356160Sru      if (specials_ok
132456160Sru          && ((ifclear <= insertion_stack->insertion
132556160Sru               && insertion_stack->insertion <= iftex)
1326146515Sru              || insertion_stack->insertion == rawdocbook
132756160Sru              || insertion_stack->insertion == rawhtml
1328146515Sru              || insertion_stack->insertion == rawxml
132956160Sru              || insertion_stack->insertion == rawtex))
133056160Sru        break;
133156160Sru      else
133256160Sru        {
1333116525Sru          const char *offender = insertion_type_pname (insertion_stack->insertion);
133456160Sru
133593139Sru          file_line_error (insertion_stack->filename,
1336114472Sru                           insertion_stack->line_number,
1337114472Sru                           _("No matching `%cend %s'"), COMMAND_PREFIX,
1338114472Sru                           offender);
133956160Sru          pop_insertion ();
134056160Sru        }
134156160Sru    }
134256160Sru  line_number = real_line_number;
134356160Sru}
134456160Sru
134556160Sru/* Insertion (environment) commands.  */
134656160Sru
134756160Sruvoid
1348146515Srucm_quotation (void)
134956160Sru{
1350146515Sru  /* We start the blockquote element in the insertion.  */
135156160Sru  begin_insertion (quotation);
135256160Sru}
135356160Sru
135456160Sruvoid
1355146515Srucm_example (void)
135656160Sru{
1357146515Sru  if (docbook && current_insertion_type () == floatenv)
1358146515Sru    xml_begin_docbook_float (FLOATEXAMPLE);
1359146515Sru
136093139Sru  if (xml)
1361146515Sru    {
1362146515Sru      /* Rollback previous newlines.  These occur between
1363146515Sru         </para> and <example>.  */
1364146515Sru      if (output_paragraph[output_paragraph_offset-1] == '\n')
1365146515Sru        output_paragraph_offset--;
1366146515Sru
1367146515Sru      xml_insert_element (EXAMPLE, START);
1368146515Sru
1369146515Sru      /* Make sure example text is starting on a new line
1370146515Sru         for improved readability.  */
1371146515Sru      if (docbook)
1372146515Sru        add_char ('\n');
1373146515Sru    }
1374146515Sru
137556160Sru  begin_insertion (example);
137656160Sru}
137756160Sru
137856160Sruvoid
1379146515Srucm_smallexample (void)
138056160Sru{
1381146515Sru  if (docbook && current_insertion_type () == floatenv)
1382146515Sru    xml_begin_docbook_float (FLOATEXAMPLE);
1383146515Sru
138493139Sru  if (xml)
1385146515Sru    {
1386146515Sru      /* See cm_example comments about newlines.  */
1387146515Sru      if (output_paragraph[output_paragraph_offset-1] == '\n')
1388146515Sru        output_paragraph_offset--;
1389146515Sru      xml_insert_element (SMALLEXAMPLE, START);
1390146515Sru      if (docbook)
1391146515Sru        add_char ('\n');
1392146515Sru    }
1393146515Sru
139456160Sru  begin_insertion (smallexample);
139556160Sru}
139656160Sru
139756160Sruvoid
1398146515Srucm_lisp (void)
139956160Sru{
1400146515Sru  if (docbook && current_insertion_type () == floatenv)
1401146515Sru    xml_begin_docbook_float (FLOATEXAMPLE);
1402146515Sru
140393139Sru  if (xml)
1404146515Sru    {
1405146515Sru      /* See cm_example comments about newlines.  */
1406146515Sru      if (output_paragraph[output_paragraph_offset-1] == '\n')
1407146515Sru        output_paragraph_offset--;
1408146515Sru      xml_insert_element (LISP, START);
1409146515Sru      if (docbook)
1410146515Sru        add_char ('\n');
1411146515Sru    }
1412146515Sru
141356160Sru  begin_insertion (lisp);
141456160Sru}
141556160Sru
141656160Sruvoid
1417146515Srucm_smalllisp (void)
141856160Sru{
1419146515Sru  if (docbook && current_insertion_type () == floatenv)
1420146515Sru    xml_begin_docbook_float (FLOATEXAMPLE);
1421146515Sru
142293139Sru  if (xml)
1423146515Sru    {
1424146515Sru      /* See cm_example comments about newlines.  */
1425146515Sru      if (output_paragraph[output_paragraph_offset-1] == '\n')
1426146515Sru        output_paragraph_offset--;
1427146515Sru      xml_insert_element (SMALLLISP, START);
1428146515Sru      if (docbook)
1429146515Sru        add_char ('\n');
1430146515Sru    }
1431146515Sru
143256160Sru  begin_insertion (smalllisp);
143356160Sru}
143456160Sru
143556160Sruvoid
1436146515Srucm_cartouche (void)
143756160Sru{
1438146515Sru  if (docbook && current_insertion_type () == floatenv)
1439146515Sru    xml_begin_docbook_float (CARTOUCHE);
1440146515Sru
144193139Sru  if (xml)
144293139Sru    xml_insert_element (CARTOUCHE, START);
144356160Sru  begin_insertion (cartouche);
144456160Sru}
144556160Sru
144656160Sruvoid
1447146515Srucm_copying (void)
1448100513Sru{
1449100513Sru  begin_insertion (copying);
1450100513Sru}
1451100513Sru
1452100513Sru/* Not an insertion, despite the name, but it goes with cm_copying.  */
1453100513Sruvoid
1454146515Srucm_insert_copying (void)
1455100513Sru{
1456146515Sru  if (!copying_text)
1457146515Sru    {
1458146515Sru      warning ("@copying not used before %s", command);
1459146515Sru      return;
1460146515Sru    }
1461146515Sru
1462146515Sru  execute_string ("%s", copying_text);
1463146515Sru
1464146515Sru  if (!xml && !html)
1465146515Sru    {
1466146515Sru      add_word ("\n\n");
1467114472Sru      /* Update output_position so that the node positions in the tag
1468114472Sru         tables will take account of the copying text.  */
1469114472Sru      flush_output ();
1470100513Sru    }
1471100513Sru}
1472100513Sru
1473100513Sruvoid
1474146515Srucm_format (void)
147556160Sru{
147693139Sru  if (xml)
1477114472Sru    {
1478114472Sru      if (docbook && xml_in_bookinfo)
1479114472Sru	{
1480114472Sru	  xml_insert_element (ABSTRACT, START);
1481114472Sru	  xml_in_abstract = 1;
1482114472Sru	}
1483114472Sru      else
1484146515Sru        {
1485146515Sru          /* See cm_example comments about newlines.  */
1486146515Sru          if (output_paragraph[output_paragraph_offset-1] == '\n')
1487146515Sru            output_paragraph_offset--;
1488146515Sru          xml_insert_element (FORMAT, START);
1489146515Sru          if (docbook)
1490146515Sru            add_char ('\n');
1491146515Sru        }
1492114472Sru    }
149356160Sru  begin_insertion (format);
149456160Sru}
149556160Sru
149656160Sruvoid
1497146515Srucm_smallformat (void)
149856160Sru{
149993139Sru  if (xml)
1500146515Sru    {
1501146515Sru      /* See cm_example comments about newlines.  */
1502146515Sru      if (output_paragraph[output_paragraph_offset-1] == '\n')
1503146515Sru        output_paragraph_offset--;
1504146515Sru      xml_insert_element (SMALLFORMAT, START);
1505146515Sru      if (docbook)
1506146515Sru        add_char ('\n');
1507146515Sru    }
1508146515Sru
150956160Sru  begin_insertion (smallformat);
151056160Sru}
151156160Sru
151256160Sruvoid
1513146515Srucm_display (void)
151456160Sru{
151593139Sru  if (xml)
1516146515Sru    {
1517146515Sru      /* See cm_example comments about newlines.  */
1518146515Sru      if (output_paragraph[output_paragraph_offset-1] == '\n')
1519146515Sru        output_paragraph_offset--;
1520146515Sru      xml_insert_element (DISPLAY, START);
1521146515Sru      if (docbook)
1522146515Sru        add_char ('\n');
1523146515Sru    }
1524146515Sru
152556160Sru  begin_insertion (display);
152656160Sru}
152756160Sru
152856160Sruvoid
1529146515Srucm_smalldisplay (void)
153056160Sru{
153193139Sru  if (xml)
1532146515Sru    {
1533146515Sru      /* See cm_example comments about newlines.  */
1534146515Sru      if (output_paragraph[output_paragraph_offset-1] == '\n')
1535146515Sru        output_paragraph_offset--;
1536146515Sru      xml_insert_element (SMALLDISPLAY, START);
1537146515Sru      if (docbook)
1538146515Sru        add_char ('\n');
1539146515Sru    }
1540146515Sru
154156160Sru  begin_insertion (smalldisplay);
154256160Sru}
154356160Sru
154456160Sruvoid
1545146515Srucm_direntry (void)
154656160Sru{
1547146515Sru  if (html || xml || no_headers)
154856160Sru    command_name_condition ();
154956160Sru  else
155056160Sru    begin_insertion (direntry);
155156160Sru}
155256160Sru
155356160Sruvoid
1554146515Srucm_documentdescription (void)
155593139Sru{
1556146515Sru  if (html)
155793139Sru    begin_insertion (documentdescription);
1558146515Sru
1559146515Sru  else if (xml)
1560146515Sru    {
1561146515Sru      xml_insert_element (DOCUMENTDESCRIPTION, START);
1562146515Sru      begin_insertion (documentdescription);
1563146515Sru    }
1564146515Sru
156593139Sru  else
156693139Sru    command_name_condition ();
156793139Sru}
156893139Sru
156993139Sru
157093139Sruvoid
1571146515Srucm_itemize (void)
157256160Sru{
157356160Sru  begin_insertion (itemize);
157456160Sru}
157556160Sru
157656160Sru/* Start an enumeration insertion of type TYPE.  If the user supplied
157756160Sru   no argument on the line, then use DEFAULT_STRING as the initial string. */
157856160Srustatic void
1579146515Srudo_enumeration (int type, char *default_string)
158056160Sru{
158156160Sru  get_until_in_line (0, ".", &enumeration_arg);
158256160Sru  canon_white (enumeration_arg);
158356160Sru
158456160Sru  if (!*enumeration_arg)
158556160Sru    {
158656160Sru      free (enumeration_arg);
158756160Sru      enumeration_arg = xstrdup (default_string);
158856160Sru    }
158956160Sru
159056160Sru  if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
159156160Sru    {
159256160Sru      warning (_("%s requires letter or digit"), insertion_type_pname (type));
159356160Sru
159456160Sru      switch (type)
159556160Sru        {
159656160Sru        case enumerate:
159756160Sru          default_string = "1";
159856160Sru          break;
159956160Sru        }
160056160Sru      enumeration_arg = xstrdup (default_string);
160156160Sru    }
160256160Sru  begin_insertion (type);
160356160Sru}
160456160Sru
160556160Sruvoid
1606146515Srucm_enumerate (void)
160756160Sru{
160856160Sru  do_enumeration (enumerate, "1");
160956160Sru}
161056160Sru
161193139Sru/*  Handle verbatim environment:
161293139Sru    find_end_verbatim == 0:  process until end of file
161393139Sru    find_end_verbatim != 0:  process until 'COMMAND_PREFIXend verbatim'
161493139Sru                             or end of file
161593139Sru
161693139Sru  We cannot simply copy input stream onto output stream; as the
161793139Sru  verbatim environment may be encapsulated in an @example environment,
161893139Sru  for example. */
161956160Sruvoid
1620146515Sruhandle_verbatim_environment (int find_end_verbatim)
162193139Sru{
162293139Sru  int character;
162393139Sru  int seen_end = 0;
162493139Sru  int save_filling_enabled = filling_enabled;
162593139Sru  int save_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
1626146515Sru  int save_escape_html = escape_html;
162793139Sru
1628146515Sru  if (!insertion_stack)
1629146515Sru    close_single_paragraph (); /* no blank lines if not at outer level */
163093139Sru  inhibit_paragraph_indentation = 1;
163193139Sru  filling_enabled = 0;
163293139Sru  in_fixed_width_font++;
163393139Sru  last_char_was_newline = 0;
163493139Sru
163593139Sru  /* No indentation: this is verbatim after all
163693139Sru     If you want indent, enclose @verbatim in @example
163793139Sru       current_indent += default_indentation_increment;
163893139Sru   */
163993139Sru
164093139Sru  if (html)
1641146515Sru    { /* If inside @example, we'll be preceded by the indentation
1642146515Sru         already.  Browsers will ignore those spaces because we're about
1643146515Sru         to start another <pre> (don't ask me).  So, wipe them out for
1644146515Sru         cleanliness, and re-insert.  */
1645146515Sru      int i;
1646146515Sru      kill_self_indent (default_indentation_increment);
1647146515Sru      add_html_block_elt ("<pre class=\"verbatim\">");
1648146515Sru      for (i = current_indent; i > 0; i--)
1649146515Sru        add_char (' ');
1650146515Sru    }
1651146515Sru  else if (xml)
1652146515Sru    {
1653146515Sru      xml_insert_element (VERBATIM, START);
1654146515Sru      escape_html = 0;
1655146515Sru      add_word ("<![CDATA[");
1656146515Sru    }
165793139Sru
165893139Sru  while (input_text_offset < input_text_length)
165993139Sru    {
166093139Sru      character = curchar ();
166193139Sru
166293139Sru      if (character == '\n')
166393139Sru        line_number++;
1664146515Sru
1665146515Sru      /* Assume no newlines in END_VERBATIM. */
166693139Sru      else if (find_end_verbatim && (character == COMMAND_PREFIX) /* @ */
1667114472Sru          && (input_text_length - input_text_offset > sizeof (END_VERBATIM))
1668114472Sru          && !strncmp (&input_text[input_text_offset+1], END_VERBATIM,
1669114472Sru                       sizeof (END_VERBATIM)-1))
1670114472Sru        {
1671114472Sru          input_text_offset += sizeof (END_VERBATIM);
1672114472Sru          seen_end = 1;
1673114472Sru          break;
1674114472Sru        }
167593139Sru
1676114472Sru      if (html && character == '&' && escape_html)
1677114472Sru        add_word ("&amp;");
1678114472Sru      else if (html && character == '<' && escape_html)
1679114472Sru        add_word ("&lt;");
1680114472Sru      else
1681114472Sru        add_char (character);
1682114472Sru
168393139Sru      input_text_offset++;
168493139Sru    }
168593139Sru
168693139Sru  if (find_end_verbatim && !seen_end)
168793139Sru    warning (_("end of file inside verbatim block"));
168893139Sru
168993139Sru  if (html)
1690146515Sru    { /* See comments in example case above.  */
1691146515Sru      kill_self_indent (default_indentation_increment);
1692146515Sru      add_word ("</pre>");
1693146515Sru    }
1694146515Sru  else if (xml)
1695146515Sru    {
1696146515Sru      add_word ("]]>");
1697146515Sru      xml_insert_element (VERBATIM, END);
1698146515Sru      escape_html = save_escape_html;
1699146515Sru    }
170093139Sru
170193139Sru  in_fixed_width_font--;
170293139Sru  filling_enabled = save_filling_enabled;
170393139Sru  inhibit_paragraph_indentation = save_inhibit_paragraph_indentation;
170493139Sru}
170593139Sru
170693139Sruvoid
1707146515Srucm_verbatim (void)
170893139Sru{
170993139Sru  handle_verbatim_environment (1);
171093139Sru}
171193139Sru
171293139Sruvoid
1713146515Srucm_table (void)
171456160Sru{
171556160Sru  begin_insertion (table);
171656160Sru}
171756160Sru
171856160Sruvoid
1719146515Srucm_multitable (void)
172056160Sru{
172156160Sru  begin_insertion (multitable); /* @@ */
172256160Sru}
172356160Sru
172456160Sruvoid
1725146515Srucm_ftable (void)
172656160Sru{
172756160Sru  begin_insertion (ftable);
172856160Sru}
172956160Sru
173056160Sruvoid
1731146515Srucm_vtable (void)
173256160Sru{
173356160Sru  begin_insertion (vtable);
173456160Sru}
173556160Sru
173656160Sruvoid
1737146515Srucm_group (void)
173856160Sru{
173956160Sru  begin_insertion (group);
174056160Sru}
174156160Sru
1742100513Sru/* Insert raw HTML (no escaping of `<' etc.). */
174356160Sruvoid
1744146515Srucm_html (int arg)
1745100513Sru{
1746146515Sru  if (process_html)
1747100513Sru    begin_insertion (rawhtml);
1748100513Sru  else
1749100513Sru    command_name_condition ();
1750100513Sru}
1751100513Sru
1752100513Sruvoid
1753146515Srucm_xml (int arg)
1754100513Sru{
1755146515Sru  if (process_xml)
1756146515Sru    begin_insertion (rawxml);
1757146515Sru  else
1758146515Sru    command_name_condition ();
1759146515Sru}
1760146515Sru
1761146515Sruvoid
1762146515Srucm_docbook (int arg)
1763146515Sru{
1764146515Sru  if (process_docbook)
1765146515Sru    begin_insertion (rawdocbook);
1766146515Sru  else
1767146515Sru    command_name_condition ();
1768146515Sru}
1769146515Sru
1770146515Sruvoid
1771146515Srucm_ifdocbook (void)
1772146515Sru{
1773146515Sru  if (process_docbook)
1774146515Sru    begin_insertion (ifdocbook);
1775146515Sru  else
1776146515Sru    command_name_condition ();
1777146515Sru}
1778146515Sru
1779146515Sruvoid
1780146515Srucm_ifnotdocbook (void)
1781146515Sru{
1782146515Sru  if (!process_docbook)
1783146515Sru    begin_insertion (ifnotdocbook);
1784146515Sru  else
1785146515Sru    command_name_condition ();
1786146515Sru}
1787146515Sru
1788146515Sruvoid
1789146515Srucm_ifhtml (void)
1790146515Sru{
1791100513Sru  if (process_html)
1792100513Sru    begin_insertion (ifhtml);
1793100513Sru  else
1794100513Sru    command_name_condition ();
1795100513Sru}
1796100513Sru
1797100513Sruvoid
1798146515Srucm_ifnothtml (void)
1799100513Sru{
1800100513Sru  if (!process_html)
1801100513Sru    begin_insertion (ifnothtml);
1802100513Sru  else
1803100513Sru    command_name_condition ();
1804100513Sru}
1805100513Sru
1806100513Sru
1807100513Sruvoid
1808146515Srucm_ifinfo (void)
180956160Sru{
181056160Sru  if (process_info)
181156160Sru    begin_insertion (ifinfo);
181256160Sru  else
181356160Sru    command_name_condition ();
181456160Sru}
181556160Sru
181656160Sruvoid
1817146515Srucm_ifnotinfo (void)
181856160Sru{
181956160Sru  if (!process_info)
182056160Sru    begin_insertion (ifnotinfo);
182156160Sru  else
182256160Sru    command_name_condition ();
182356160Sru}
182456160Sru
182556160Sru
182656160Sruvoid
1827146515Srucm_ifplaintext (void)
182856160Sru{
1829100513Sru  if (process_plaintext)
1830100513Sru    begin_insertion (ifplaintext);
183156160Sru  else
183256160Sru    command_name_condition ();
183356160Sru}
183456160Sru
183556160Sruvoid
1836146515Srucm_ifnotplaintext (void)
183756160Sru{
1838100513Sru  if (!process_plaintext)
1839100513Sru    begin_insertion (ifnotplaintext);
184056160Sru  else
184156160Sru    command_name_condition ();
184256160Sru}
184356160Sru
184456160Sru
184556160Sruvoid
1846146515Srucm_tex (void)
184756160Sru{
184856160Sru  if (process_tex)
184956160Sru    begin_insertion (rawtex);
185056160Sru  else
185156160Sru    command_name_condition ();
185256160Sru}
185356160Sru
185456160Sruvoid
1855146515Srucm_iftex (void)
185656160Sru{
185756160Sru  if (process_tex)
185856160Sru    begin_insertion (iftex);
185956160Sru  else
186056160Sru    command_name_condition ();
186156160Sru}
186256160Sru
186356160Sruvoid
1864146515Srucm_ifnottex (void)
186556160Sru{
186656160Sru  if (!process_tex)
186756160Sru    begin_insertion (ifnottex);
186856160Sru  else
186956160Sru    command_name_condition ();
187056160Sru}
1871114472Sru
1872114472Sruvoid
1873146515Srucm_ifxml (void)
1874114472Sru{
1875114472Sru  if (process_xml)
1876114472Sru    begin_insertion (ifxml);
1877114472Sru  else
1878114472Sru    command_name_condition ();
1879114472Sru}
1880114472Sru
1881114472Sruvoid
1882146515Srucm_ifnotxml (void)
1883114472Sru{
1884114472Sru  if (!process_xml)
1885114472Sru    begin_insertion (ifnotxml);
1886114472Sru  else
1887114472Sru    command_name_condition ();
1888114472Sru}
1889114472Sru
189056160Sru
1891146515Sru/* Generic xrefable block with a caption.  */
1892146515Sruvoid
1893146515Srucm_float (void)
1894146515Sru{
1895146515Sru  begin_insertion (floatenv);
1896146515Sru}
1897146515Sru
1898146515Sruvoid
1899146515Srucm_caption (int arg)
1900146515Sru{
1901146515Sru  char *temp;
1902146515Sru
1903146515Sru  /* This is a no_op command for most formats, as we handle it during @float
1904146515Sru     insertion.  For XML though, we handle it here to keep document structure
1905146515Sru     as close as possible, to the Texinfo source.  */
1906146515Sru
1907146515Sru  /* Everything is already handled at START.  */
1908146515Sru  if (arg == END)
1909146515Sru    return;
1910146515Sru
1911146515Sru  /* Check if it's mislocated.  */
1912146515Sru  if (current_insertion_type () != floatenv)
1913146515Sru    line_error (_("@%s not meaningful outside `@float' environment"), command);
1914146515Sru
1915146515Sru  get_until_in_braces ("\n@end float", &temp);
1916146515Sru
1917146515Sru  if (xml)
1918146515Sru    {
1919146515Sru      int elt = STREQ (command, "shortcaption") ? SHORTCAPTION : CAPTION;
1920146515Sru      xml_insert_element (elt, START);
1921146515Sru      if (!docbook)
1922146515Sru        execute_string ("%s", temp);
1923146515Sru      xml_insert_element (elt, END);
1924146515Sru    }
1925146515Sru
1926146515Sru  free (temp);
1927146515Sru}
1928146515Sru
192956160Sru/* Begin an insertion where the lines are not filled or indented. */
193056160Sruvoid
1931146515Srucm_flushleft (void)
193256160Sru{
193356160Sru  begin_insertion (flushleft);
193456160Sru}
193556160Sru
193656160Sru/* Begin an insertion where the lines are not filled, and each line is
193756160Sru   forced to the right-hand side of the page. */
193856160Sruvoid
1939146515Srucm_flushright (void)
194056160Sru{
194156160Sru  begin_insertion (flushright);
194256160Sru}
194356160Sru
194456160Sruvoid
1945146515Srucm_menu (void)
194656160Sru{
1947146515Sru  if (current_node == NULL && !macro_expansion_output_stream)
194856160Sru    {
194956160Sru      warning (_("@menu seen before first @node, creating `Top' node"));
195056160Sru      warning (_("perhaps your @top node should be wrapped in @ifnottex rather than @ifinfo?"));
195156160Sru      /* Include @top command so we can construct the implicit node tree.  */
195256160Sru      execute_string ("@node top\n@top Top\n");
195356160Sru    }
195456160Sru  begin_insertion (menu);
195556160Sru}
195656160Sru
195756160Sruvoid
1958146515Srucm_detailmenu (void)
195956160Sru{
1960146515Sru  if (current_node == NULL && !macro_expansion_output_stream)
196156160Sru    { /* Problems anyway, @detailmenu should always be inside @menu.  */
196256160Sru      warning (_("@detailmenu seen before first node, creating `Top' node"));
196356160Sru      execute_string ("@node top\n@top Top\n");
196456160Sru    }
196556160Sru  begin_insertion (detailmenu);
196656160Sru}
1967146515Sru
1968146515Sru/* Title page commands. */
196956160Sru
1970146515Sruvoid
1971146515Srucm_titlepage (void)
1972146515Sru{
1973146515Sru  titlepage_cmd_present = 1;
1974146515Sru  if (xml && !docbook)
1975146515Sru    begin_insertion (titlepage);
1976146515Sru  else
1977146515Sru    command_name_condition ();
1978146515Sru}
1979146515Sru
1980146515Sruvoid
1981146515Srucm_author (void)
1982146515Sru{
1983146515Sru  char *rest;
1984146515Sru  get_rest_of_line (1, &rest);
1985146515Sru
1986146515Sru  if (is_in_insertion_of_type (quotation))
1987146515Sru    {
1988146515Sru      if (html)
1989146515Sru        add_word_args ("&mdash; %s", rest);
1990146515Sru      else if (docbook)
1991146515Sru        {
1992146515Sru          /* FIXME Ideally, we should use an attribution element,
1993146515Sru             but they are supposed to be at the start of quotation
1994146515Sru             blocks.  So to avoid looking ahead mess, let's just
1995146515Sru             use mdash like HTML for now.  */
1996146515Sru          xml_insert_entity ("mdash");
1997146515Sru          add_word (rest);
1998146515Sru        }
1999146515Sru      else if (xml)
2000146515Sru        {
2001146515Sru          xml_insert_element (AUTHOR, START);
2002146515Sru          add_word (rest);
2003146515Sru          xml_insert_element (AUTHOR, END);
2004146515Sru        }
2005146515Sru      else
2006146515Sru        add_word_args ("-- %s", rest);
2007146515Sru    }
2008146515Sru  else if (is_in_insertion_of_type (titlepage))
2009146515Sru    {
2010146515Sru      if (xml && !docbook)
2011146515Sru        {
2012146515Sru          xml_insert_element (AUTHOR, START);
2013146515Sru          add_word (rest);
2014146515Sru          xml_insert_element (AUTHOR, END);
2015146515Sru        }
2016146515Sru    }
2017146515Sru  else
2018146515Sru    line_error (_("@%s not meaningful outside `@titlepage' and `@quotation' environments"),
2019146515Sru        command);
2020146515Sru
2021146515Sru  free (rest);
2022146515Sru}
2023146515Sru
2024146515Sruvoid
2025146515Srucm_titlepage_cmds (void)
2026146515Sru{
2027146515Sru  char *rest;
2028146515Sru
2029146515Sru  get_rest_of_line (1, &rest);
2030146515Sru
2031146515Sru  if (!is_in_insertion_of_type (titlepage))
2032146515Sru    line_error (_("@%s not meaningful outside `@titlepage' environment"),
2033146515Sru        command);
2034146515Sru
2035146515Sru  if (xml && !docbook)
2036146515Sru    {
2037146515Sru      int elt = 0;
2038146515Sru
2039146515Sru      if (STREQ (command, "title"))
2040146515Sru        elt = BOOKTITLE;
2041146515Sru      else if (STREQ (command, "subtitle"))
2042146515Sru        elt = BOOKSUBTITLE;
2043146515Sru
2044146515Sru      xml_insert_element (elt, START);
2045146515Sru      add_word (rest);
2046146515Sru      xml_insert_element (elt, END);
2047146515Sru    }
2048146515Sru
2049146515Sru    free (rest);
2050146515Sru}
2051146515Sru
205256160Sru/* End existing insertion block. */
205356160Sruvoid
2054146515Srucm_end (void)
205556160Sru{
205656160Sru  char *temp;
2057146515Sru  int type;
205856160Sru
2059146515Sru  get_rest_of_line (0, &temp);
2060146515Sru
206156160Sru  if (!insertion_level)
206256160Sru    {
206356160Sru      line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command);
206456160Sru      return;
206556160Sru    }
206656160Sru
206756160Sru  if (temp[0] == 0)
206856160Sru    line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command);
206956160Sru
207056160Sru  type = find_type_from_name (temp);
207156160Sru
207256160Sru  if (type == bad_type)
207356160Sru    {
2074146515Sru      line_error (_("Bad argument `%s' to `@%s', using `%s'"),
2075146515Sru           temp, command, insertion_type_pname (current_insertion_type ()));
207656160Sru    }
207793139Sru  if (xml && type == menu) /* fixme */
207893139Sru    {
207993139Sru      xml_end_menu ();
208093139Sru    }
208156160Sru  end_insertion (type);
208256160Sru  free (temp);
208356160Sru}
208456160Sru
208556160Sru/* @itemx, @item. */
208656160Sru
208756160Srustatic int itemx_flag = 0;
208856160Sru
208956160Sru/* Return whether CMD takes a brace-delimited {arg}.  */
2090146515Sruint
2091146515Srucommand_needs_braces (char *cmd)
209256160Sru{
209356160Sru  int i;
209456160Sru  for (i = 0; command_table[i].name; i++)
209556160Sru    {
209656160Sru      if (STREQ (command_table[i].name, cmd))
209756160Sru        return command_table[i].argument_in_braces == BRACE_ARGS;
209856160Sru    }
209956160Sru
210056160Sru  return 0; /* macro or alias */
210156160Sru}
210256160Sru
210356160Sru
210456160Sruvoid
2105146515Srucm_item (void)
210656160Sru{
210756160Sru  char *rest_of_line, *item_func;
210856160Sru
210956160Sru  /* Can only hack "@item" while inside of an insertion. */
211056160Sru  if (insertion_level)
211156160Sru    {
211256160Sru      INSERTION_ELT *stack = insertion_stack;
211356160Sru      int original_input_text_offset;
211456160Sru
211556160Sru      skip_whitespace ();
211656160Sru      original_input_text_offset = input_text_offset;
211756160Sru
211856160Sru      get_rest_of_line (0, &rest_of_line);
211956160Sru      item_func = current_item_function ();
212056160Sru
212156160Sru    /* Do the right thing depending on which insertion function is active. */
212256160Sru    switch_top:
212356160Sru      switch (stack->insertion)
212456160Sru        {
212556160Sru        case multitable:
212656160Sru          multitable_item ();
212756160Sru          /* Support text directly after the @item.  */
212856160Sru          if (*rest_of_line)
212956160Sru            {
213056160Sru              line_number--;
213156160Sru              input_text_offset = original_input_text_offset;
213256160Sru            }
213356160Sru          break;
213456160Sru
213556160Sru        case ifclear:
213656160Sru        case ifhtml:
213756160Sru        case ifinfo:
213856160Sru        case ifnothtml:
213956160Sru        case ifnotinfo:
2140100513Sru        case ifnotplaintext:
214156160Sru        case ifnottex:
2142114472Sru	case ifnotxml:
2143100513Sru        case ifplaintext:
214456160Sru        case ifset:
214556160Sru        case iftex:
2146114472Sru	case ifxml:
2147146515Sru        case rawdocbook:
214856160Sru        case rawhtml:
2149146515Sru        case rawxml:
215056160Sru        case rawtex:
215156160Sru        case tex:
215256160Sru        case cartouche:
215356160Sru          stack = stack->next;
215456160Sru          if (!stack)
215556160Sru            goto no_insertion;
215656160Sru          else
215756160Sru            goto switch_top;
215856160Sru          break;
215956160Sru
216056160Sru        case menu:
216156160Sru        case quotation:
216256160Sru        case example:
216356160Sru        case smallexample:
216456160Sru        case lisp:
216556160Sru        case smalllisp:
216656160Sru        case format:
216756160Sru        case smallformat:
216856160Sru        case display:
216956160Sru        case smalldisplay:
217056160Sru        case group:
217156160Sru          line_error (_("@%s not meaningful inside `@%s' block"),
217256160Sru                      command,
217356160Sru                      insertion_type_pname (current_insertion_type ()));
217456160Sru          break;
217556160Sru
217656160Sru        case itemize:
217756160Sru        case enumerate:
217856160Sru          if (itemx_flag)
217956160Sru            {
218056160Sru              line_error (_("@itemx not meaningful inside `%s' block"),
218156160Sru                          insertion_type_pname (current_insertion_type ()));
218256160Sru            }
218356160Sru          else
218456160Sru            {
218556160Sru              if (html)
2186146515Sru                add_html_block_elt ("<li>");
2187114472Sru              else if (xml)
2188114472Sru                xml_begin_item ();
218956160Sru              else
219056160Sru                {
219156160Sru                  start_paragraph ();
219256160Sru                  kill_self_indent (-1);
219356160Sru                  filling_enabled = indented_fill = 1;
219456160Sru
219556160Sru                  if (current_item_function ())
219656160Sru                    {
219756160Sru                      output_column = current_indent - 2;
219856160Sru                      indent (output_column);
219956160Sru
220056160Sru                      /* The item marker can be given with or without
220156160Sru                         braces -- @bullet and @bullet{} are both ok.
220256160Sru                         Or it might be something that doesn't take
220356160Sru                         braces at all, such as "o" or "#" or "@ ".
220456160Sru                         Thus, only supply braces if the item marker is
220556160Sru                         a command, they haven't supplied braces
220656160Sru                         themselves, and we know it needs them.  */
220756160Sru                      if (item_func && *item_func)
220856160Sru                        {
220956160Sru                          if (*item_func == COMMAND_PREFIX
221056160Sru                              && item_func[strlen (item_func) - 1] != '}'
221156160Sru                              && command_needs_braces (item_func + 1))
221256160Sru                            execute_string ("%s{}", item_func);
221356160Sru                          else
221456160Sru                            execute_string ("%s", item_func);
221556160Sru                        }
221656160Sru                      insert (' ');
221756160Sru                      output_column++;
221856160Sru                    }
221956160Sru                  else
222056160Sru                    enumerate_item ();
222156160Sru
222256160Sru                  /* Special hack.  This makes `close_paragraph' a no-op until
222356160Sru                     `start_paragraph' has been called. */
222456160Sru                  must_start_paragraph = 1;
222556160Sru                }
222656160Sru
2227114472Sru              /* Handle text directly after the @item.  */
2228114472Sru              if (*rest_of_line)
2229114472Sru                {
2230114472Sru                  line_number--;
2231114472Sru                  input_text_offset = original_input_text_offset;
2232114472Sru                }
223356160Sru            }
223456160Sru          break;
223556160Sru
223656160Sru        case table:
223756160Sru        case ftable:
223856160Sru        case vtable:
223956160Sru          if (html)
2240146515Sru            { /* If nothing has been output since the last <dd>,
224156160Sru                 remove the empty <dd> element.  Some browsers render
224256160Sru                 an extra empty line for <dd><dt>, which makes @itemx
224356160Sru                 conversion look ugly.  */
2244146515Sru              rollback_empty_tag ("dd");
224556160Sru
224656160Sru              /* Force the browser to render one blank line before
2247114472Sru                 each new @item in a table.  But don't do that if
224856160Sru                 this is the first <dt> after the <dl>, or if we are
224956160Sru                 converting @itemx.
225056160Sru
225156160Sru                 Note that there are some browsers which ignore <br>
225256160Sru                 in this context, but I cannot find any way to force
225356160Sru                 them all render exactly one blank line.  */
2254146515Sru              if (!itemx_flag && html_deflist_has_term)
2255146515Sru                add_html_block_elt ("<br>");
2256146515Sru
2257146515Sru              /* We are about to insert a <dt>, so this <dl> has a term.
2258146515Sru                 Feel free to insert a <br> next time. :)  */
2259146515Sru              html_deflist_has_term = 1;
226056160Sru
2261146515Sru              add_html_block_elt ("<dt>");
226256160Sru              if (item_func && *item_func)
226356160Sru                execute_string ("%s{%s}", item_func, rest_of_line);
226456160Sru              else
226556160Sru                execute_string ("%s", rest_of_line);
226656160Sru
226756160Sru              if (current_insertion_type () == ftable)
226856160Sru                execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
226956160Sru
227056160Sru              if (current_insertion_type () == vtable)
227156160Sru                execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
2272146515Sru
2273146515Sru              add_html_block_elt ("<dd>");
227456160Sru            }
2275114472Sru          else if (xml) /* && docbook)*/ /* 05-08 */
2276114472Sru            {
2277114472Sru              xml_begin_table_item ();
2278146515Sru
2279146515Sru              if (!docbook && current_insertion_type () == ftable)
2280146515Sru                execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
2281146515Sru
2282146515Sru              if (!docbook && current_insertion_type () == vtable)
2283146515Sru                execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
2284146515Sru
228593139Sru              if (item_func && *item_func)
228693139Sru                execute_string ("%s{%s}", item_func, rest_of_line);
228793139Sru              else
228893139Sru                execute_string ("%s", rest_of_line);
2289114472Sru              xml_continue_table_item ();
2290114472Sru            }
229156160Sru          else
229256160Sru            {
229356160Sru              /* We need this to determine if we have two @item's in a row
229456160Sru                 (see test just below).  */
229556160Sru              static int last_item_output_position = 0;
229656160Sru
229756160Sru              /* Get rid of extra characters. */
229856160Sru              kill_self_indent (-1);
229956160Sru
230056160Sru              /* If we have one @item followed directly by another @item,
230156160Sru                 we need to insert a blank line.  This is not true for
230256160Sru                 @itemx, though.  */
230356160Sru              if (!itemx_flag && last_item_output_position == output_position)
230456160Sru                insert ('\n');
230556160Sru
230656160Sru              /* `close_paragraph' almost does what we want.  The problem
230756160Sru                 is when paragraph_is_open, and last_char_was_newline, and
230856160Sru                 the last newline has been turned into a space, because
230956160Sru                 filling_enabled. I handle it here. */
231056160Sru              if (last_char_was_newline && filling_enabled &&
231156160Sru                  paragraph_is_open)
231256160Sru                insert ('\n');
231356160Sru              close_paragraph ();
231456160Sru
231556160Sru#if defined (INDENT_PARAGRAPHS_IN_TABLE)
231656160Sru              /* Indent on a new line, but back up one indentation level. */
231756160Sru              {
231856160Sru                int save = inhibit_paragraph_indentation;
231956160Sru                inhibit_paragraph_indentation = 1;
232056160Sru                /* At this point, inserting any non-whitespace character will
232156160Sru                   force the existing indentation to be output. */
232256160Sru                add_char ('i');
232356160Sru                inhibit_paragraph_indentation = save;
232456160Sru              }
232556160Sru#else /* !INDENT_PARAGRAPHS_IN_TABLE */
232656160Sru              add_char ('i');
232756160Sru#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
232856160Sru
232956160Sru              output_paragraph_offset--;
233056160Sru              kill_self_indent (default_indentation_increment + 1);
233156160Sru
233256160Sru              /* Add item's argument to the line. */
233356160Sru              filling_enabled = 0;
233456160Sru              if (item_func && *item_func)
233556160Sru                execute_string ("%s{%s}", item_func, rest_of_line);
233656160Sru              else
233756160Sru                execute_string ("%s", rest_of_line);
233856160Sru
233956160Sru              if (current_insertion_type () == ftable)
234056160Sru                execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
234156160Sru              else if (current_insertion_type () == vtable)
234256160Sru                execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
234356160Sru
234456160Sru              /* Start a new line, and let start_paragraph ()
234556160Sru                 do the indenting of it for you. */
234656160Sru              close_single_paragraph ();
234756160Sru              indented_fill = filling_enabled = 1;
234856160Sru              last_item_output_position = output_position;
234956160Sru            }
235056160Sru        }
235156160Sru      free (rest_of_line);
235256160Sru    }
235356160Sru  else
235456160Sru    {
235556160Sru    no_insertion:
235656160Sru      line_error (_("%c%s found outside of an insertion block"),
235756160Sru                  COMMAND_PREFIX, command);
235856160Sru    }
235956160Sru}
236056160Sru
236156160Sruvoid
2362146515Srucm_itemx (void)
236356160Sru{
236456160Sru  itemx_flag++;
236556160Sru  cm_item ();
236656160Sru  itemx_flag--;
236756160Sru}
2368146515Sru
2369146515Sruint headitem_flag = 0;
2370146515Sru
2371146515Sruvoid
2372146515Srucm_headitem (void)
2373146515Sru{
2374146515Sru  headitem_flag = 1;
2375146515Sru  cm_item ();
2376146515Sru}
2377