Back to index

tetex-bin  3.0
insertion.c
Go to the documentation of this file.
00001 /* insertion.c -- insertions for Texinfo.
00002    $Id: insertion.c,v 1.55 2004/11/11 18:34:28 karl Exp $
00003 
00004    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
00005    Foundation, Inc.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2, or (at your option)
00010    any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software Foundation,
00019    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00020 
00021 #include "system.h"
00022 #include "cmds.h"
00023 #include "defun.h"
00024 #include "float.h"
00025 #include "html.h"
00026 #include "insertion.h"
00027 #include "macro.h"
00028 #include "makeinfo.h"
00029 #include "multi.h"
00030 #include "xml.h"
00031 
00032 /* Must match list in insertion.h.  */
00033 static char *insertion_type_names[] =
00034 { 
00035   "cartouche", "copying", "defcv", "deffn", "defivar", "defmac",
00036   "defmethod", "defop", "defopt", "defspec", "deftp", "deftypecv",
00037   "deftypefn", "deftypefun", "deftypeivar", "deftypemethod",
00038   "deftypeop", "deftypevar", "deftypevr", "defun", "defvar", "defvr",
00039   "detailmenu", "direntry", "display", "documentdescription",
00040   "enumerate", "example", "float", "flushleft", "flushright", "format",
00041   "ftable", "group", "ifclear", "ifdocbook", "ifhtml", "ifinfo",
00042   "ifnotdocbook", "ifnothtml", "ifnotinfo", "ifnotplaintext", "ifnottex",
00043   "ifnotxml", "ifplaintext", "ifset", "iftex", "ifxml", "itemize", "lisp",
00044   "menu", "multitable", "quotation", "rawdocbook", "rawhtml", "rawtex",
00045   "rawxml", "smalldisplay", "smallexample", "smallformat", "smalllisp",
00046   "verbatim", "table", "tex", "vtable", "titlepage", "bad_type"
00047 };
00048 
00049 /* All nested environments.  */
00050 INSERTION_ELT *insertion_stack = NULL;
00051 
00052 /* How deeply we're nested.  */
00053 int insertion_level = 0;
00054 
00055 /* Set to 1 if we've processed (commentary) text in a @menu that
00056    wasn't part of a menu item.  */
00057 int had_menu_commentary;
00058 
00059 /* How to examine menu lines.  */
00060 int in_detailmenu = 0;
00061 
00062 /* Whether to examine menu lines.  */
00063 int in_menu = 0;
00064 
00065 /* Set to 1 if <p> is written in normal context. 
00066    Used for menu and itemize. */
00067 int in_paragraph = 0;
00068 
00069 /* Since an insertion is already in the stack before we reach the switch
00070    statement, we cannot use is_in_insertion_of_type (always returns true.) Also
00071    making it return the level found, and comparing it with the current level is
00072    no use, due to the order of stack.  */
00073 static int float_active = 0;
00074 
00075 /* Unsetting escape_html blindly causes text inside @html/etc. to be escaped if
00076    used within a rmacro.  */
00077 static int raw_output_block = 0;
00078 
00079 /* Non-zero if a <dl> element has a <dt> element in it.  We use this when
00080    deciding whether to insert a <br> or not.  */
00081 static int html_deflist_has_term = 0;
00082 
00083 void
00084 init_insertion_stack (void)
00085 {
00086   insertion_stack = NULL;
00087 }
00088 
00089 /* Return the type of the current insertion. */
00090 static enum insertion_type
00091 current_insertion_type (void)
00092 {
00093   return insertion_level ? insertion_stack->insertion : bad_type;
00094 }
00095 
00096 /* Return the string which is the function to wrap around items, or NULL
00097    if we're not in an environment where @item is ok.  */
00098 static char *
00099 current_item_function (void)
00100 {
00101   int done = 0;
00102   INSERTION_ELT *elt = insertion_stack;
00103 
00104   /* Skip down through the stack until we find an insertion with an
00105      itemize function defined, i.e., skip conditionals, @cartouche, etc.  */
00106   while (!done && elt)
00107     {
00108       switch (elt->insertion)
00109         {
00110         /* This list should match the one in cm_item.  */
00111         case ifclear:
00112         case ifhtml:
00113         case ifinfo:
00114         case ifnothtml:
00115         case ifnotinfo:
00116         case ifnotplaintext:
00117         case ifnottex:
00118        case ifnotxml:
00119         case ifplaintext:
00120         case ifset:
00121         case iftex:
00122        case ifxml:
00123         case rawdocbook:
00124         case rawhtml:
00125         case rawxml:
00126         case rawtex:
00127         case tex:
00128         case cartouche:
00129           elt = elt->next;
00130           break;
00131       
00132         default:
00133           done = 1;
00134         }
00135     }
00136 
00137   /* item_function usually gets assigned the empty string.  */
00138   return done && (*elt->item_function) ? elt->item_function : NULL;
00139 }
00140 
00141 /* Parse the item marker function off the input.  If result is just "@",
00142    change it to "@ ", since "@" by itself is not a command.  This makes
00143    "@ ", "@\t", and "@\n" all the same, but their default meanings are
00144    the same anyway, and let's not worry about supporting redefining them.  */
00145 static char *
00146 get_item_function (void)
00147 {
00148   char *item_function;
00149   char *item_loc;
00150   
00151   get_rest_of_line (0, &item_function);
00152 
00153   /* If the document erroneously says
00154        @itemize @bullet @item foobar
00155      it's nicer to give an error up front than repeat `@bullet expected
00156      braces' until we get a segmentation fault.  */
00157   item_loc = strstr (item_function, "@item");
00158   if (item_loc)
00159     {
00160       line_error (_("@item not allowed in argument to @itemize"));
00161       *item_loc = 0;
00162     }
00163 
00164   /* If we hit the end of text in get_rest_of_line, backing up
00165      input pointer will cause the last character of the last line
00166      be pushed back onto the input, which is wrong.  */
00167   if (input_text_offset < input_text_length)
00168     backup_input_pointer ();
00169 
00170   if (STREQ (item_function, "@"))
00171     {
00172       free (item_function);
00173       item_function = xstrdup ("@ ");
00174     }
00175 
00176   return item_function;
00177 }
00178 
00179  /* Push the state of the current insertion on the stack. */
00180 static void
00181 push_insertion (enum insertion_type type, char *item_function)
00182 {
00183   INSERTION_ELT *new = xmalloc (sizeof (INSERTION_ELT));
00184 
00185   new->item_function = item_function;
00186   new->filling_enabled = filling_enabled;
00187   new->indented_fill = indented_fill;
00188   new->insertion = type;
00189   new->line_number = line_number;
00190   new->filename = xstrdup (input_filename);
00191   new->inhibited = inhibit_paragraph_indentation;
00192   new->in_fixed_width_font = in_fixed_width_font;
00193   new->next = insertion_stack;
00194   insertion_stack = new;
00195   insertion_level++;
00196 }
00197 
00198  /* Pop the value on top of the insertion stack into the
00199     global variables. */
00200 void
00201 pop_insertion (void)
00202 {
00203   INSERTION_ELT *temp = insertion_stack;
00204 
00205   if (temp == NULL)
00206     return;
00207 
00208   in_fixed_width_font = temp->in_fixed_width_font;
00209   inhibit_paragraph_indentation = temp->inhibited;
00210   filling_enabled = temp->filling_enabled;
00211   indented_fill = temp->indented_fill;
00212   free_and_clear (&(temp->item_function));
00213   free_and_clear (&(temp->filename));
00214   insertion_stack = insertion_stack->next;
00215   free (temp);
00216   insertion_level--;
00217 }
00218 
00219  /* Return a pointer to the print name of this
00220     enumerated type. */
00221 static const char *
00222 insertion_type_pname (enum insertion_type type)
00223 {
00224   if ((int) type < (int) bad_type)
00225   {
00226     if (type == rawdocbook)
00227       return "docbook";
00228     else if (type == rawhtml)
00229       return "html";
00230     else if (type == rawxml)
00231       return "xml";
00232     else if (type == rawtex)
00233       return "tex";
00234     else
00235       return insertion_type_names[(int) type];
00236   }
00237   else
00238     return _("Broken-Type in insertion_type_pname");
00239 }
00240 
00241 /* Return the insertion_type associated with NAME.
00242    If the type is not one of the known ones, return BAD_TYPE. */
00243 enum insertion_type
00244 find_type_from_name (char *name)
00245 {
00246   int index = 0;
00247   while (index < (int) bad_type)
00248     {
00249       if (STREQ (name, insertion_type_names[index]))
00250         return (enum insertion_type) index;
00251       if (index == rawdocbook && STREQ (name, "docbook"))
00252         return rawdocbook;
00253       if (index == rawhtml && STREQ (name, "html"))
00254         return rawhtml;
00255       if (index == rawxml && STREQ (name, "xml"))
00256         return rawxml;
00257       if (index == rawtex && STREQ (name, "tex"))
00258         return rawtex;
00259       index++;
00260     }
00261   return bad_type;
00262 }
00263 
00264 /* Simple function to query insertion_stack to see if we are inside a given
00265    insertion type. */
00266 int
00267 is_in_insertion_of_type (int type)
00268 {
00269   INSERTION_ELT *temp = insertion_stack;
00270 
00271   if (!insertion_level)
00272     return 0;
00273 
00274   while (temp)
00275     {
00276       if (temp->insertion == type)
00277         return 1;
00278       temp = temp->next;
00279     }
00280 
00281   return 0;
00282 }
00283 
00284 
00285 static int
00286 defun_insertion (enum insertion_type type)
00287 {
00288   return 0
00289      || (type == defcv)
00290      || (type == deffn)
00291      || (type == defivar)
00292      || (type == defmac)
00293      || (type == defmethod)
00294      || (type == defop)
00295      || (type == defopt)
00296      || (type == defspec)
00297      || (type == deftp)
00298      || (type == deftypecv)
00299      || (type == deftypefn)
00300      || (type == deftypefun)
00301      || (type == deftypeivar)
00302      || (type == deftypemethod)
00303      || (type == deftypeop)
00304      || (type == deftypevar)
00305      || (type == deftypevr)
00306      || (type == defun)
00307      || (type == defvar)
00308      || (type == defvr)
00309   ;
00310 }
00311 
00312 /* MAX_NS is the maximum nesting level for enumerations.  I picked 100
00313    which seemed reasonable.  This doesn't control the number of items,
00314    just the number of nested lists. */
00315 #define max_stack_depth 100
00316 #define ENUM_DIGITS 1
00317 #define ENUM_ALPHA  2
00318 typedef struct {
00319   int enumtype;
00320   int enumval;
00321 } DIGIT_ALPHA;
00322 
00323 DIGIT_ALPHA enumstack[max_stack_depth];
00324 int enumstack_offset = 0;
00325 int current_enumval = 1;
00326 int current_enumtype = ENUM_DIGITS;
00327 char *enumeration_arg = NULL;
00328 
00329 static void
00330 start_enumerating (int at, int type)
00331 {
00332   if ((enumstack_offset + 1) == max_stack_depth)
00333     {
00334       line_error (_("Enumeration stack overflow"));
00335       return;
00336     }
00337   enumstack[enumstack_offset].enumtype = current_enumtype;
00338   enumstack[enumstack_offset].enumval = current_enumval;
00339   enumstack_offset++;
00340   current_enumval = at;
00341   current_enumtype = type;
00342 }
00343 
00344 static void
00345 stop_enumerating (void)
00346 {
00347   --enumstack_offset;
00348   if (enumstack_offset < 0)
00349     enumstack_offset = 0;
00350 
00351   current_enumval = enumstack[enumstack_offset].enumval;
00352   current_enumtype = enumstack[enumstack_offset].enumtype;
00353 }
00354 
00355 /* Place a letter or digits into the output stream. */
00356 static void
00357 enumerate_item (void)
00358 {
00359   char temp[10];
00360 
00361   if (current_enumtype == ENUM_ALPHA)
00362     {
00363       if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
00364         {
00365           current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
00366           warning (_("lettering overflow, restarting at %c"), current_enumval);
00367         }
00368       sprintf (temp, "%c. ", current_enumval);
00369     }
00370   else
00371     sprintf (temp, "%d. ", current_enumval);
00372 
00373   indent (output_column += (current_indent - strlen (temp)));
00374   add_word (temp);
00375   current_enumval++;
00376 }
00377 
00378 static void
00379 enum_html (void)
00380 {
00381   char type;
00382   int start;
00383 
00384   if (isdigit (*enumeration_arg))
00385     {
00386       type = '1';
00387       start = atoi (enumeration_arg);
00388     }
00389   else if (isupper (*enumeration_arg))
00390     {
00391       type = 'A';
00392       start = *enumeration_arg - 'A' + 1;
00393     }
00394   else
00395     {
00396       type = 'a';
00397       start = *enumeration_arg - 'a' + 1;
00398     }
00399 
00400   add_html_block_elt_args ("<ol type=%c start=%d>\n", type, start);
00401 }
00402 
00403 /* Conditionally parse based on the current command name. */
00404 void
00405 command_name_condition (void)
00406 {
00407   char *discarder = xmalloc (8 + strlen (command));
00408 
00409   sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
00410   discard_until (discarder);
00411   discard_until ("\n");
00412 
00413   free (discarder);
00414 }
00415 
00416 /* This is where the work for all the "insertion" style
00417    commands is done.  A huge switch statement handles the
00418    various setups, and generic code is on both sides. */
00419 void
00420 begin_insertion (enum insertion_type type)
00421 {
00422   int no_discard = 0;
00423 
00424   if (defun_insertion (type))
00425     {
00426       push_insertion (type, xstrdup (""));
00427       no_discard++;
00428     }
00429   else
00430     {
00431       push_insertion (type, get_item_function ());
00432     }
00433 
00434   switch (type)
00435     {
00436     case menu:
00437       if (!no_headers)
00438         close_paragraph ();
00439 
00440       filling_enabled = no_indent = 0;
00441       inhibit_paragraph_indentation = 1;
00442 
00443       if (html)
00444         {
00445           had_menu_commentary = 1;
00446         }
00447       else if (!no_headers && !xml)
00448         add_word ("* Menu:\n");
00449 
00450       if (xml)
00451         xml_insert_element (MENU, START);
00452       else
00453         in_fixed_width_font++;
00454 
00455       next_menu_item_number = 1;
00456       in_menu++;
00457       no_discard++;
00458       break;
00459 
00460     case detailmenu:
00461       if (!in_menu)
00462         {
00463           if (!no_headers)
00464             close_paragraph ();
00465 
00466           filling_enabled = no_indent = 0;
00467           inhibit_paragraph_indentation = 1;
00468 
00469           no_discard++;
00470         }
00471 
00472       if (xml)
00473         {
00474           xml_insert_element (DETAILMENU, START);
00475           skip_whitespace_and_newlines();
00476         }
00477       else
00478         in_fixed_width_font++;
00479 
00480       in_detailmenu++;
00481       break;
00482 
00483     case direntry:
00484       close_single_paragraph ();
00485       filling_enabled = no_indent = 0;
00486       inhibit_paragraph_indentation = 1;
00487       insert_string ("START-INFO-DIR-ENTRY\n");
00488       break;
00489 
00490     case documentdescription:
00491       {
00492         char *desc;
00493         int start_of_end;
00494         int save_fixed_width;
00495 
00496         discard_until ("\n"); /* ignore the @documentdescription line */
00497         start_of_end = get_until ("\n@end documentdescription", &desc);
00498         save_fixed_width = in_fixed_width_font;
00499 
00500         in_fixed_width_font = 0;
00501         document_description = expansion (desc, 0);
00502         free (desc);
00503 
00504         in_fixed_width_font = save_fixed_width;
00505         input_text_offset = start_of_end; /* go back to the @end to match */
00506       }
00507       break;
00508 
00509     case copying:
00510         /* Save the copying text away for @insertcopying,
00511            typically used on the back of the @titlepage (for TeX) and
00512            the Top node (for info/html).  */
00513       if (input_text[input_text_offset] != '\n')
00514         discard_until ("\n"); /* ignore remainder of @copying line */
00515 
00516         input_text_offset = get_until ("\n@end copying", &copying_text);
00517         canon_white (copying_text);
00518 
00519       /* For info, output the copying text right away, so it will end up
00520          in the header of the Info file, before the first node, and thus
00521          get copied automatically to all the split files.  For xml, also
00522          output it right away since xml output is never split.
00523          For html, we output it specifically in html_output_head. 
00524          For plain text, there's no way to hide it, so the author must
00525           use @insertcopying in the desired location.  */
00526       if (docbook)
00527        {
00528          if (!xml_in_bookinfo)
00529            {
00530              xml_insert_element (BOOKINFO, START);
00531              xml_in_bookinfo = 1;
00532            }
00533           xml_insert_element (LEGALNOTICE, START);
00534        }
00535 
00536       if (!html && !no_headers)
00537         cm_insert_copying ();
00538 
00539       if (docbook)
00540         xml_insert_element (LEGALNOTICE, END);
00541 
00542       break;
00543 
00544     case quotation:
00545       /* @quotation does filling (@display doesn't).  */
00546       if (html)
00547         add_html_block_elt ("<blockquote>\n");
00548       else
00549         {
00550           /* with close_single_paragraph, we get no blank line above
00551              within @copying.  */
00552           close_paragraph ();
00553           last_char_was_newline = no_indent = 0;
00554           indented_fill = filling_enabled = 1;
00555           inhibit_paragraph_indentation = 1;
00556         }
00557       current_indent += default_indentation_increment;
00558       if (xml)
00559         xml_insert_quotation (insertion_stack->item_function, START);
00560       else if (strlen(insertion_stack->item_function))
00561         execute_string ("@b{%s:} ", insertion_stack->item_function);
00562       break;
00563 
00564     case example:
00565     case smallexample:
00566     case lisp:
00567     case smalllisp:
00568       in_fixed_width_font++;
00569       /* fall through */
00570 
00571       /* Like @example but no fixed width font. */
00572     case display:
00573     case smalldisplay:
00574       /* Like @display but without indentation. */
00575     case smallformat:
00576     case format:
00577       close_single_paragraph ();
00578       inhibit_paragraph_indentation = 1;
00579       filling_enabled = 0;
00580       last_char_was_newline = 0;
00581 
00582       if (html)
00583         /* Kludge alert: if <pre> is followed by a newline, IE3,
00584            mozilla, maybe others render an extra blank line before the
00585            pre-formatted block.  So don't output a newline.  */
00586         add_html_block_elt_args ("<pre class=\"%s\">", command);
00587 
00588       if (type != format && type != smallformat)
00589         {
00590           current_indent += example_indentation_increment;
00591           if (html)
00592             {
00593               /* Since we didn't put \n after <pre>, we need to insert
00594                  the indentation by hand.  */
00595               int i;
00596               for (i = current_indent; i > 0; i--)
00597                 add_char (' ');
00598             }
00599         }
00600       break;
00601 
00602     case multitable:
00603       do_multitable ();
00604       break;
00605 
00606     case table:
00607     case ftable:
00608     case vtable:
00609     case itemize:
00610       close_single_paragraph ();
00611       current_indent += default_indentation_increment;
00612       filling_enabled = indented_fill = 1;
00613 #if defined (INDENT_PARAGRAPHS_IN_TABLE)
00614       inhibit_paragraph_indentation = 0;
00615 #else
00616       inhibit_paragraph_indentation = 1;
00617 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */
00618 
00619       /* Make things work for losers who forget the itemize syntax. */
00620       if (type == itemize)
00621         {
00622           if (!(*insertion_stack->item_function))
00623             {
00624               free (insertion_stack->item_function);
00625               insertion_stack->item_function = xstrdup ("@bullet");
00626             }
00627         }
00628 
00629       if (!*insertion_stack->item_function)
00630         {
00631           line_error (_("%s requires an argument: the formatter for %citem"),
00632                       insertion_type_pname (type), COMMAND_PREFIX);
00633         }
00634 
00635       if (html)
00636         {
00637           if (type == itemize)
00638             {
00639               add_html_block_elt ("<ul>\n");
00640               in_paragraph = 0;
00641             }
00642           else
00643             { /* We are just starting, so this <dl>
00644                  has no <dt> children yet.  */
00645               html_deflist_has_term = 0;
00646               add_html_block_elt ("<dl>\n");
00647             }
00648         }
00649       if (xml)
00650         xml_begin_table (type, insertion_stack->item_function);
00651 
00652       while (input_text[input_text_offset] == '\n'
00653           && input_text[input_text_offset+1] == '\n')
00654         {
00655           line_number++;
00656           input_text_offset++;
00657         }
00658 
00659       break;
00660 
00661     case enumerate:
00662       close_single_paragraph ();
00663       no_indent = 0;
00664 #if defined (INDENT_PARAGRAPHS_IN_TABLE)
00665       inhibit_paragraph_indentation = 0;
00666 #else
00667       inhibit_paragraph_indentation = 1;
00668 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */
00669 
00670       current_indent += default_indentation_increment;
00671       filling_enabled = indented_fill = 1;
00672 
00673       if (html)
00674         {
00675           enum_html ();
00676           in_paragraph = 0;
00677         }
00678 
00679       if (xml)
00680         xml_begin_enumerate (enumeration_arg);
00681       
00682       if (isdigit (*enumeration_arg))
00683         start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
00684       else
00685         start_enumerating (*enumeration_arg, ENUM_ALPHA);
00686       break;
00687 
00688       /* @group produces no output in info. */
00689     case group:
00690       /* Only close the paragraph if we are not inside of an
00691          @example-like environment. */
00692       if (xml)
00693         xml_insert_element (GROUP, START);
00694       else if (!insertion_stack->next
00695           || (insertion_stack->next->insertion != display
00696               && insertion_stack->next->insertion != smalldisplay
00697               && insertion_stack->next->insertion != example
00698               && insertion_stack->next->insertion != smallexample
00699               && insertion_stack->next->insertion != lisp
00700               && insertion_stack->next->insertion != smalllisp
00701               && insertion_stack->next->insertion != format
00702               && insertion_stack->next->insertion != smallformat
00703               && insertion_stack->next->insertion != flushleft
00704               && insertion_stack->next->insertion != flushright))
00705         close_single_paragraph ();
00706       break;
00707 
00708     case cartouche:
00709       if (html)
00710        add_html_block_elt ("<p><table class=\"cartouche\" summary=\"cartouche\" border=\"1\"><tr><td>\n");
00711       if (in_menu)
00712         no_discard++;
00713       break;
00714 
00715     case floatenv:
00716       /* Cannot nest floats, so complain.  */
00717       if (float_active)
00718         {
00719           line_error (_("%cfloat environments cannot be nested"), COMMAND_PREFIX);
00720           pop_insertion ();
00721           break;
00722         }
00723 
00724       float_active++;
00725 
00726       { /* Collect data about this float.  */
00727         /* Example: @float [FLOATTYPE][,XREFLABEL][,POSITION] */
00728         char floattype[200] = "";
00729         char xreflabel[200] = "";
00730         char position[200]  = "";
00731         char *text;
00732         char *caption;
00733         char *shortcaption;
00734         int start_of_end;
00735         int save_line_number = line_number;
00736         int save_input_text_offset = input_text_offset;
00737         int i;
00738 
00739         if (strlen (insertion_stack->item_function) > 0)
00740           {
00741             int i = 0, t = 0, c = 0;
00742             while (insertion_stack->item_function[i])
00743               {
00744                 if (insertion_stack->item_function[i] == ',')
00745                   {
00746                     switch (t)
00747                       {
00748                       case 0:
00749                         floattype[c] = '\0';
00750                         break;
00751                       case 1:
00752                         xreflabel[c] = '\0';
00753                         break;
00754                       case 2:
00755                         position[c] = '\0';
00756                         break;
00757                       }
00758                     c = 0;
00759                     t++;
00760                     i++;
00761                     continue;
00762                   }
00763 
00764                 switch (t)
00765                   {
00766                   case 0:
00767                     floattype[c] = insertion_stack->item_function[i];
00768                     break;
00769                   case 1:
00770                     xreflabel[c] = insertion_stack->item_function[i];
00771                     break;
00772                   case 2:
00773                     position[c] = insertion_stack->item_function[i];
00774                     break;
00775                   }
00776                 c++;
00777                 i++;
00778               }
00779           }
00780 
00781         skip_whitespace_and_newlines ();
00782 
00783         start_of_end = get_until ("\n@end float", &text);
00784 
00785         /* Get also the @caption.  */
00786         i = search_forward_until_pos ("\n@caption{",
00787             save_input_text_offset, start_of_end);
00788         if (i > -1)
00789           {
00790             input_text_offset = i + sizeof ("\n@caption{") - 1;
00791             get_until_in_braces ("\n@end float", &caption);
00792             input_text_offset = save_input_text_offset;
00793           }
00794         else
00795           caption = "";
00796 
00797         /* ... and the @shortcaption.  */
00798         i = search_forward_until_pos ("\n@shortcaption{",
00799             save_input_text_offset, start_of_end);
00800         if (i > -1)
00801           {
00802             input_text_offset = i + sizeof ("\n@shortcaption{") - 1;
00803             get_until_in_braces ("\n@end float", &shortcaption);
00804             input_text_offset = save_input_text_offset;
00805           }
00806         else
00807           shortcaption = "";
00808 
00809         canon_white (xreflabel);
00810         canon_white (floattype);
00811         canon_white (position);
00812         canon_white (caption);
00813         canon_white (shortcaption);
00814 
00815         add_new_float (xstrdup (xreflabel),
00816             xstrdup (caption), xstrdup (shortcaption),
00817             xstrdup (floattype), xstrdup (position));
00818 
00819         /* Move to the start of the @float so the contents get processed as
00820            usual.  */
00821         input_text_offset = save_input_text_offset;
00822         line_number = save_line_number;
00823       }
00824 
00825       if (html)
00826         add_html_block_elt ("<div class=\"float\">\n");
00827       else if (docbook)
00828         xml_insert_element (FLOAT, START);
00829       else if (xml)
00830         {
00831           xml_insert_element_with_attribute (FLOAT, START,
00832               "name=\"%s\"", current_float_id ());
00833 
00834           xml_insert_element (FLOATTYPE, START);
00835           execute_string ("%s", current_float_type ());
00836           xml_insert_element (FLOATTYPE, END);
00837 
00838           xml_insert_element (FLOATPOS, START);
00839           execute_string ("%s", current_float_position ());
00840           xml_insert_element (FLOATPOS, END);
00841         }
00842       else
00843         { /* Info */
00844           close_single_paragraph ();
00845           inhibit_paragraph_indentation = 1;
00846         }
00847 
00848       /* Anchor now.  Note that XML documents get their
00849          anchors with <float name="anchor"> tag.  */
00850       if ((!xml || docbook) && strlen (current_float_id ()) > 0)
00851         execute_string ("@anchor{%s}", current_float_id ());
00852 
00853       break;
00854 
00855       /* Insertions that are no-ops in info, but do something in TeX. */
00856     case ifclear:
00857     case ifdocbook:
00858     case ifhtml:
00859     case ifinfo:
00860     case ifnotdocbook:
00861     case ifnothtml:
00862     case ifnotinfo:
00863     case ifnotplaintext:
00864     case ifnottex:
00865     case ifnotxml:
00866     case ifplaintext:
00867     case ifset:
00868     case iftex:
00869     case ifxml:
00870     case rawtex:
00871       if (in_menu)
00872         no_discard++;
00873       break;
00874 
00875     case rawdocbook:
00876     case rawhtml:
00877     case rawxml:
00878       raw_output_block++;
00879 
00880       if (raw_output_block > 0)
00881         {
00882           xml_no_para = 1;
00883           escape_html = 0;
00884           xml_keep_space++;
00885         }
00886 
00887       {
00888         /* Some deuglification for improved readability.  */
00889         extern int xml_in_para;
00890         if (xml && !xml_in_para && xml_indentation_increment > 0)
00891           add_char ('\n');
00892       }
00893 
00894       break;
00895 
00896     case defcv:
00897     case deffn:
00898     case defivar:
00899     case defmac:
00900     case defmethod:
00901     case defop:
00902     case defopt:
00903     case defspec:
00904     case deftp:
00905     case deftypecv:
00906     case deftypefn:
00907     case deftypefun:
00908     case deftypeivar:
00909     case deftypemethod:
00910     case deftypeop:
00911     case deftypevar:
00912     case deftypevr:
00913     case defun:
00914     case defvar:
00915     case defvr:
00916       inhibit_paragraph_indentation = 1;
00917       filling_enabled = indented_fill = 1;
00918       current_indent += default_indentation_increment;
00919       no_indent = 0;
00920       if (xml)
00921        xml_begin_definition ();
00922       break;
00923 
00924     case flushleft:
00925       close_single_paragraph ();
00926       inhibit_paragraph_indentation = 1;
00927       filling_enabled = indented_fill = no_indent = 0;
00928       if (html)
00929         add_html_block_elt ("<div align=\"left\">");
00930       break;
00931 
00932     case flushright:
00933       close_single_paragraph ();
00934       filling_enabled = indented_fill = no_indent = 0;
00935       inhibit_paragraph_indentation = 1;
00936       force_flush_right++;
00937       if (html)
00938         add_html_block_elt ("<div align=\"right\">");
00939       break;
00940 
00941     case titlepage:
00942       xml_insert_element (TITLEPAGE, START);
00943       break;
00944 
00945     default:
00946       line_error ("begin_insertion internal error: type=%d", type);
00947     }
00948 
00949   if (!no_discard)
00950     discard_until ("\n");
00951 }
00952 
00953 /* Try to end the insertion with the specified TYPE.  With a value of
00954    `bad_type', TYPE gets translated to match the value currently on top
00955    of the stack.  Otherwise, if TYPE doesn't match the top of the
00956    insertion stack, give error. */
00957 static void
00958 end_insertion (int type)
00959 {
00960   int temp_type;
00961 
00962   if (!insertion_level)
00963     return;
00964 
00965   temp_type = current_insertion_type ();
00966 
00967   if (type == bad_type)
00968     type = temp_type;
00969 
00970   if (type != temp_type)
00971     {
00972       line_error
00973         (_("`@end' expected `%s', but saw `%s'"),
00974          insertion_type_pname (temp_type), insertion_type_pname (type));
00975       return;
00976     }
00977 
00978   pop_insertion ();
00979 
00980   if (xml)
00981     {
00982       switch (type)
00983         {
00984         case ifinfo:
00985         case documentdescription:       
00986           break;
00987         case quotation:
00988           xml_insert_quotation ("", END);
00989           break;
00990         case example:
00991           xml_insert_element (EXAMPLE, END);
00992           if (docbook && current_insertion_type () == floatenv)
00993             xml_insert_element (FLOATEXAMPLE, END);
00994           break;
00995         case smallexample:
00996           xml_insert_element (SMALLEXAMPLE, END);
00997           if (docbook && current_insertion_type () == floatenv)
00998             xml_insert_element (FLOATEXAMPLE, END);
00999           break;
01000         case lisp:
01001           xml_insert_element (LISP, END);
01002           if (docbook && current_insertion_type () == floatenv)
01003             xml_insert_element (FLOATEXAMPLE, END);
01004           break;
01005         case smalllisp:
01006           xml_insert_element (SMALLLISP, END);
01007           if (docbook && current_insertion_type () == floatenv)
01008             xml_insert_element (FLOATEXAMPLE, END);
01009           break;
01010         case cartouche:
01011           xml_insert_element (CARTOUCHE, END);
01012           break;
01013         case format:
01014          if (docbook && xml_in_bookinfo && xml_in_abstract)
01015            {
01016              xml_insert_element (ABSTRACT, END);
01017              xml_in_abstract = 0;
01018            }
01019          else
01020            xml_insert_element (FORMAT, END);
01021           break;
01022         case smallformat:
01023           xml_insert_element (SMALLFORMAT, END);
01024           break;
01025         case display:
01026           xml_insert_element (DISPLAY, END);
01027           break;
01028         case smalldisplay:
01029           xml_insert_element (SMALLDISPLAY, END);
01030           break;
01031         case table:
01032         case ftable:
01033         case vtable:      
01034         case itemize:
01035           xml_end_table (type);
01036           break;
01037         case enumerate:
01038           xml_end_enumerate ();
01039           break;
01040         case group:
01041           xml_insert_element (GROUP, END);
01042           break;
01043        case titlepage:
01044          xml_insert_element (TITLEPAGE, END);
01045          break;
01046         }
01047     }
01048   switch (type)
01049     {
01050       /* Insertions which have no effect on paragraph formatting. */
01051     case copying:
01052       line_number--;
01053       break;
01054 
01055     case ifclear:
01056     case ifdocbook:
01057     case ifinfo:
01058     case ifhtml:
01059     case ifnotdocbook:
01060     case ifnothtml:
01061     case ifnotinfo:
01062     case ifnotplaintext:
01063     case ifnottex:
01064     case ifnotxml:
01065     case ifplaintext:
01066     case ifset:
01067     case iftex:
01068     case ifxml:
01069     case rawtex:
01070     case titlepage:
01071       break;
01072 
01073     case rawdocbook:
01074     case rawhtml:
01075     case rawxml:
01076       raw_output_block--;
01077 
01078       if (raw_output_block <= 0)
01079         {
01080           xml_no_para = 0;
01081           escape_html = 1;
01082           xml_keep_space--;
01083         }
01084 
01085       if ((xml || html) && output_paragraph[output_paragraph_offset-1] == '\n')
01086         output_paragraph_offset--;
01087       break;
01088 
01089     case detailmenu:
01090       if (xml)
01091         xml_insert_element (DETAILMENU, END);
01092 
01093       in_detailmenu--;          /* No longer hacking menus. */
01094       if (!in_menu)
01095         {
01096           if (!no_headers)
01097             close_insertion_paragraph ();
01098         }
01099       break;
01100 
01101     case direntry:              /* Eaten if html. */
01102       insert_string ("END-INFO-DIR-ENTRY\n\n");
01103       close_insertion_paragraph ();
01104       break;
01105 
01106     case documentdescription:
01107       if (xml)
01108         insert_string (document_description);
01109         xml_insert_element (DOCUMENTDESCRIPTION, END);
01110       break;
01111       
01112     case menu:
01113       in_menu--;                /* No longer hacking menus. */
01114       if (html && !no_headers)
01115         add_html_block_elt ("</ul>\n");
01116       else if (!no_headers && !xml)
01117         close_insertion_paragraph ();
01118       break;
01119 
01120     case multitable:
01121       end_multitable ();
01122       break;
01123 
01124     case enumerate:
01125       stop_enumerating ();
01126       close_insertion_paragraph ();
01127       current_indent -= default_indentation_increment;
01128       if (html)
01129         add_html_block_elt ("</ol>\n");
01130       break;
01131 
01132     case flushleft:
01133       if (html)
01134         add_html_block_elt ("</div>\n");
01135       close_insertion_paragraph ();
01136       break;
01137 
01138     case cartouche:
01139       if (html)
01140        add_html_block_elt ("</td></tr></table>\n");
01141       close_insertion_paragraph ();
01142       break;
01143 
01144     case group:
01145       if (!xml || docbook)
01146         close_insertion_paragraph ();
01147       break;
01148 
01149     case floatenv:
01150       if (xml)
01151         xml_insert_element (FLOAT, END);
01152       else
01153         {
01154           if (html)
01155             add_html_block_elt ("<p><strong class=\"float-caption\">");
01156           else
01157             close_paragraph ();
01158 
01159           no_indent = 1;
01160 
01161           /* Legend:
01162                1) @float Foo,lbl & no caption:    Foo 1.1
01163                2) @float Foo & no caption:        Foo
01164                3) @float ,lbl & no caption:       1.1
01165                4) @float & no caption:                    */
01166 
01167           if (!xml && !html)
01168             indent (current_indent);
01169 
01170           if (strlen (current_float_type ()))
01171             execute_string ("%s", current_float_type ());
01172 
01173           if (strlen (current_float_id ()) > 0)
01174             {
01175               if (strlen (current_float_type ()) > 0)
01176                 add_char (' ');
01177 
01178               add_word (current_float_number ());
01179             }
01180 
01181           if (strlen (current_float_title ()) > 0)
01182             {
01183               if (strlen (current_float_type ()) > 0
01184                   || strlen (current_float_id ()) > 0)
01185                 insert_string (": ");
01186 
01187               execute_string ("%s", current_float_title ());
01188             }
01189 
01190           /* Indent the following paragraph. */
01191           inhibit_paragraph_indentation = 0;
01192 
01193           if (html)
01194             add_word ("</strong></p></div>\n");
01195           else
01196             close_paragraph ();
01197         }
01198       float_active--;
01199       break;
01200 
01201     case format:
01202     case smallformat:
01203     case display:
01204     case smalldisplay:
01205     case example:
01206     case smallexample:
01207     case lisp:
01208     case smalllisp:
01209     case quotation:
01210       /* @format and @smallformat are the only fixed_width insertion
01211          without a change in indentation. */
01212       if (type != format && type != smallformat && type != quotation)
01213         current_indent -= example_indentation_increment;
01214       else if (type == quotation)
01215         current_indent -= default_indentation_increment;
01216 
01217       if (html)
01218         { /* The complex code in close_paragraph that kills whitespace
01219              does not function here, since we've inserted non-whitespace
01220              (the </whatever>) before it.  The indentation already got
01221              inserted at the end of the last example line, so we have to
01222              delete it, or browsers wind up showing an extra blank line.  */
01223           kill_self_indent (default_indentation_increment);
01224           add_html_block_elt (type == quotation
01225               ? "</blockquote>\n" : "</pre>\n");
01226         }
01227 
01228       /* The ending of one of these insertions always marks the
01229          start of a new paragraph, except for the XML output. */
01230       if (!xml || docbook)
01231         close_insertion_paragraph ();
01232 
01233       /* </pre> closes paragraph without messing with </p>.  */
01234       if (html && type != quotation)
01235           paragraph_is_open = 0;
01236       break;
01237 
01238     case table:
01239     case ftable:
01240     case vtable:
01241       current_indent -= default_indentation_increment;
01242       if (html)
01243         add_html_block_elt ("</dl>\n");
01244       close_insertion_paragraph ();
01245       break;
01246 
01247     case itemize:
01248       current_indent -= default_indentation_increment;
01249       if (html)
01250         add_html_block_elt ("</ul>\n");
01251       close_insertion_paragraph ();
01252       break;
01253 
01254     case flushright:
01255       force_flush_right--;
01256       if (html)
01257         add_html_block_elt ("</div>\n");
01258       close_insertion_paragraph ();
01259       break;
01260 
01261     /* Handle the @defun insertions with this default clause. */
01262     default:
01263       {
01264         int base_type;
01265 
01266         if (type < defcv || type > defvr)
01267           line_error ("end_insertion internal error: type=%d", type);
01268   
01269         base_type = get_base_type (type);
01270         switch (base_type)
01271           {
01272           case deffn:
01273           case defvr:
01274           case deftp:
01275           case deftypecv:
01276           case deftypefn:
01277           case deftypevr:
01278           case defcv:
01279           case defop:
01280           case deftypemethod:
01281           case deftypeop:
01282           case deftypeivar:
01283             if (html)
01284               {
01285                 if (paragraph_is_open)
01286                   add_html_block_elt ("</p>");
01287                 /* close the div and blockquote which has been opened in defun.c */
01288                 if (!rollback_empty_tag ("blockquote"))
01289                   add_html_block_elt ("</blockquote>");
01290                 add_html_block_elt ("</div>\n");
01291               }
01292            if (xml)
01293              xml_end_definition ();
01294             break;
01295           } /* switch (base_type)... */
01296   
01297         current_indent -= default_indentation_increment;
01298         close_insertion_paragraph ();
01299       }
01300       break;
01301       
01302     }
01303 
01304   if (current_indent < 0)
01305     line_error ("end_insertion internal error: current indent=%d",
01306                 current_indent);
01307 }
01308 
01309 /* Insertions cannot cross certain boundaries, such as node beginnings.  In
01310    code that creates such boundaries, you should call `discard_insertions'
01311    before doing anything else.  It prints the errors for you, and cleans up
01312    the insertion stack.
01313 
01314    With nonzero SPECIALS_OK argument, allows unmatched
01315    @if... conditionals, otherwise not.  This is because conditionals can
01316    cross node boundaries.  Always happens with the @top node, for example.  */
01317 void
01318 discard_insertions (int specials_ok)
01319 {
01320   int real_line_number = line_number;
01321   while (insertion_stack)
01322     {
01323       if (specials_ok
01324           && ((ifclear <= insertion_stack->insertion
01325                && insertion_stack->insertion <= iftex)
01326               || insertion_stack->insertion == rawdocbook
01327               || insertion_stack->insertion == rawhtml
01328               || insertion_stack->insertion == rawxml
01329               || insertion_stack->insertion == rawtex))
01330         break;
01331       else
01332         {
01333           const char *offender = insertion_type_pname (insertion_stack->insertion);
01334 
01335           file_line_error (insertion_stack->filename,
01336                            insertion_stack->line_number,
01337                            _("No matching `%cend %s'"), COMMAND_PREFIX,
01338                            offender);
01339           pop_insertion ();
01340         }
01341     }
01342   line_number = real_line_number;
01343 }
01344 
01345 /* Insertion (environment) commands.  */
01346 
01347 void
01348 cm_quotation (void)
01349 {
01350   /* We start the blockquote element in the insertion.  */
01351   begin_insertion (quotation);
01352 }
01353 
01354 void
01355 cm_example (void)
01356 {
01357   if (docbook && current_insertion_type () == floatenv)
01358     xml_begin_docbook_float (FLOATEXAMPLE);
01359 
01360   if (xml)
01361     {
01362       /* Rollback previous newlines.  These occur between
01363          </para> and <example>.  */
01364       if (output_paragraph[output_paragraph_offset-1] == '\n')
01365         output_paragraph_offset--;
01366 
01367       xml_insert_element (EXAMPLE, START);
01368 
01369       /* Make sure example text is starting on a new line
01370          for improved readability.  */
01371       if (docbook)
01372         add_char ('\n');
01373     }
01374 
01375   begin_insertion (example);
01376 }
01377 
01378 void
01379 cm_smallexample (void)
01380 {
01381   if (docbook && current_insertion_type () == floatenv)
01382     xml_begin_docbook_float (FLOATEXAMPLE);
01383 
01384   if (xml)
01385     {
01386       /* See cm_example comments about newlines.  */
01387       if (output_paragraph[output_paragraph_offset-1] == '\n')
01388         output_paragraph_offset--;
01389       xml_insert_element (SMALLEXAMPLE, START);
01390       if (docbook)
01391         add_char ('\n');
01392     }
01393 
01394   begin_insertion (smallexample);
01395 }
01396 
01397 void
01398 cm_lisp (void)
01399 {
01400   if (docbook && current_insertion_type () == floatenv)
01401     xml_begin_docbook_float (FLOATEXAMPLE);
01402 
01403   if (xml)
01404     {
01405       /* See cm_example comments about newlines.  */
01406       if (output_paragraph[output_paragraph_offset-1] == '\n')
01407         output_paragraph_offset--;
01408       xml_insert_element (LISP, START);
01409       if (docbook)
01410         add_char ('\n');
01411     }
01412 
01413   begin_insertion (lisp);
01414 }
01415 
01416 void
01417 cm_smalllisp (void)
01418 {
01419   if (docbook && current_insertion_type () == floatenv)
01420     xml_begin_docbook_float (FLOATEXAMPLE);
01421 
01422   if (xml)
01423     {
01424       /* See cm_example comments about newlines.  */
01425       if (output_paragraph[output_paragraph_offset-1] == '\n')
01426         output_paragraph_offset--;
01427       xml_insert_element (SMALLLISP, START);
01428       if (docbook)
01429         add_char ('\n');
01430     }
01431 
01432   begin_insertion (smalllisp);
01433 }
01434 
01435 void
01436 cm_cartouche (void)
01437 {
01438   if (docbook && current_insertion_type () == floatenv)
01439     xml_begin_docbook_float (CARTOUCHE);
01440 
01441   if (xml)
01442     xml_insert_element (CARTOUCHE, START);
01443   begin_insertion (cartouche);
01444 }
01445 
01446 void
01447 cm_copying (void)
01448 {
01449   begin_insertion (copying);
01450 }
01451 
01452 /* Not an insertion, despite the name, but it goes with cm_copying.  */
01453 void
01454 cm_insert_copying (void)
01455 {
01456   if (!copying_text)
01457     {
01458       warning ("@copying not used before %s", command);
01459       return;
01460     }
01461 
01462   execute_string ("%s", copying_text);
01463 
01464   if (!xml && !html)
01465     {
01466       add_word ("\n\n");
01467       /* Update output_position so that the node positions in the tag
01468          tables will take account of the copying text.  */
01469       flush_output ();
01470     }
01471 }
01472 
01473 void
01474 cm_format (void)
01475 {
01476   if (xml)
01477     {
01478       if (docbook && xml_in_bookinfo)
01479        {
01480          xml_insert_element (ABSTRACT, START);
01481          xml_in_abstract = 1;
01482        }
01483       else
01484         {
01485           /* See cm_example comments about newlines.  */
01486           if (output_paragraph[output_paragraph_offset-1] == '\n')
01487             output_paragraph_offset--;
01488           xml_insert_element (FORMAT, START);
01489           if (docbook)
01490             add_char ('\n');
01491         }
01492     }
01493   begin_insertion (format);
01494 }
01495 
01496 void
01497 cm_smallformat (void)
01498 {
01499   if (xml)
01500     {
01501       /* See cm_example comments about newlines.  */
01502       if (output_paragraph[output_paragraph_offset-1] == '\n')
01503         output_paragraph_offset--;
01504       xml_insert_element (SMALLFORMAT, START);
01505       if (docbook)
01506         add_char ('\n');
01507     }
01508 
01509   begin_insertion (smallformat);
01510 }
01511 
01512 void
01513 cm_display (void)
01514 {
01515   if (xml)
01516     {
01517       /* See cm_example comments about newlines.  */
01518       if (output_paragraph[output_paragraph_offset-1] == '\n')
01519         output_paragraph_offset--;
01520       xml_insert_element (DISPLAY, START);
01521       if (docbook)
01522         add_char ('\n');
01523     }
01524 
01525   begin_insertion (display);
01526 }
01527 
01528 void
01529 cm_smalldisplay (void)
01530 {
01531   if (xml)
01532     {
01533       /* See cm_example comments about newlines.  */
01534       if (output_paragraph[output_paragraph_offset-1] == '\n')
01535         output_paragraph_offset--;
01536       xml_insert_element (SMALLDISPLAY, START);
01537       if (docbook)
01538         add_char ('\n');
01539     }
01540 
01541   begin_insertion (smalldisplay);
01542 }
01543 
01544 void
01545 cm_direntry (void)
01546 {
01547   if (html || xml || no_headers)
01548     command_name_condition ();
01549   else
01550     begin_insertion (direntry);
01551 }
01552 
01553 void
01554 cm_documentdescription (void)
01555 {
01556   if (html)
01557     begin_insertion (documentdescription);
01558 
01559   else if (xml)
01560     {
01561       xml_insert_element (DOCUMENTDESCRIPTION, START);
01562       begin_insertion (documentdescription);
01563     }
01564 
01565   else
01566     command_name_condition ();
01567 }
01568 
01569 
01570 void
01571 cm_itemize (void)
01572 {
01573   begin_insertion (itemize);
01574 }
01575 
01576 /* Start an enumeration insertion of type TYPE.  If the user supplied
01577    no argument on the line, then use DEFAULT_STRING as the initial string. */
01578 static void
01579 do_enumeration (int type, char *default_string)
01580 {
01581   get_until_in_line (0, ".", &enumeration_arg);
01582   canon_white (enumeration_arg);
01583 
01584   if (!*enumeration_arg)
01585     {
01586       free (enumeration_arg);
01587       enumeration_arg = xstrdup (default_string);
01588     }
01589 
01590   if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
01591     {
01592       warning (_("%s requires letter or digit"), insertion_type_pname (type));
01593 
01594       switch (type)
01595         {
01596         case enumerate:
01597           default_string = "1";
01598           break;
01599         }
01600       enumeration_arg = xstrdup (default_string);
01601     }
01602   begin_insertion (type);
01603 }
01604 
01605 void
01606 cm_enumerate (void)
01607 {
01608   do_enumeration (enumerate, "1");
01609 }
01610 
01611 /*  Handle verbatim environment:
01612     find_end_verbatim == 0:  process until end of file
01613     find_end_verbatim != 0:  process until 'COMMAND_PREFIXend verbatim'
01614                              or end of file
01615 
01616   We cannot simply copy input stream onto output stream; as the
01617   verbatim environment may be encapsulated in an @example environment,
01618   for example. */
01619 void
01620 handle_verbatim_environment (int find_end_verbatim)
01621 {
01622   int character;
01623   int seen_end = 0;
01624   int save_filling_enabled = filling_enabled;
01625   int save_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
01626   int save_escape_html = escape_html;
01627 
01628   if (!insertion_stack)
01629     close_single_paragraph (); /* no blank lines if not at outer level */
01630   inhibit_paragraph_indentation = 1;
01631   filling_enabled = 0;
01632   in_fixed_width_font++;
01633   last_char_was_newline = 0;
01634 
01635   /* No indentation: this is verbatim after all
01636      If you want indent, enclose @verbatim in @example
01637        current_indent += default_indentation_increment;
01638    */
01639 
01640   if (html)
01641     { /* If inside @example, we'll be preceded by the indentation
01642          already.  Browsers will ignore those spaces because we're about
01643          to start another <pre> (don't ask me).  So, wipe them out for
01644          cleanliness, and re-insert.  */
01645       int i;
01646       kill_self_indent (default_indentation_increment);
01647       add_html_block_elt ("<pre class=\"verbatim\">");
01648       for (i = current_indent; i > 0; i--)
01649         add_char (' ');
01650     }
01651   else if (xml)
01652     {
01653       xml_insert_element (VERBATIM, START);
01654       escape_html = 0;
01655       add_word ("<![CDATA[");
01656     }
01657 
01658   while (input_text_offset < input_text_length)
01659     {
01660       character = curchar ();
01661 
01662       if (character == '\n')
01663         line_number++;
01664 
01665       /* Assume no newlines in END_VERBATIM. */
01666       else if (find_end_verbatim && (character == COMMAND_PREFIX) /* @ */
01667           && (input_text_length - input_text_offset > sizeof (END_VERBATIM))
01668           && !strncmp (&input_text[input_text_offset+1], END_VERBATIM,
01669                        sizeof (END_VERBATIM)-1))
01670         {
01671           input_text_offset += sizeof (END_VERBATIM);
01672           seen_end = 1;
01673           break;
01674         }
01675 
01676       if (html && character == '&' && escape_html)
01677         add_word ("&amp;");
01678       else if (html && character == '<' && escape_html)
01679         add_word ("&lt;");
01680       else
01681         add_char (character);
01682 
01683       input_text_offset++;
01684     }
01685 
01686   if (find_end_verbatim && !seen_end)
01687     warning (_("end of file inside verbatim block"));
01688 
01689   if (html)
01690     { /* See comments in example case above.  */
01691       kill_self_indent (default_indentation_increment);
01692       add_word ("</pre>");
01693     }
01694   else if (xml)
01695     {
01696       add_word ("]]>");
01697       xml_insert_element (VERBATIM, END);
01698       escape_html = save_escape_html;
01699     }
01700   
01701   in_fixed_width_font--;
01702   filling_enabled = save_filling_enabled;
01703   inhibit_paragraph_indentation = save_inhibit_paragraph_indentation;
01704 }
01705 
01706 void
01707 cm_verbatim (void)
01708 {
01709   handle_verbatim_environment (1);
01710 }
01711 
01712 void
01713 cm_table (void)
01714 {
01715   begin_insertion (table);
01716 }
01717 
01718 void
01719 cm_multitable (void)
01720 {
01721   begin_insertion (multitable); /* @@ */
01722 }
01723 
01724 void
01725 cm_ftable (void)
01726 {
01727   begin_insertion (ftable);
01728 }
01729 
01730 void
01731 cm_vtable (void)
01732 {
01733   begin_insertion (vtable);
01734 }
01735 
01736 void
01737 cm_group (void)
01738 {
01739   begin_insertion (group);
01740 }
01741 
01742 /* Insert raw HTML (no escaping of `<' etc.). */
01743 void
01744 cm_html (int arg)
01745 {
01746   if (process_html)
01747     begin_insertion (rawhtml);
01748   else
01749     command_name_condition ();
01750 }
01751 
01752 void
01753 cm_xml (int arg)
01754 {
01755   if (process_xml)
01756     begin_insertion (rawxml);
01757   else
01758     command_name_condition ();
01759 }
01760 
01761 void
01762 cm_docbook (int arg)
01763 {
01764   if (process_docbook)
01765     begin_insertion (rawdocbook);
01766   else
01767     command_name_condition ();
01768 }
01769 
01770 void
01771 cm_ifdocbook (void)
01772 {
01773   if (process_docbook)
01774     begin_insertion (ifdocbook);
01775   else
01776     command_name_condition ();
01777 }
01778 
01779 void
01780 cm_ifnotdocbook (void)
01781 {
01782   if (!process_docbook)
01783     begin_insertion (ifnotdocbook);
01784   else
01785     command_name_condition ();
01786 }
01787 
01788 void
01789 cm_ifhtml (void)
01790 {
01791   if (process_html)
01792     begin_insertion (ifhtml);
01793   else
01794     command_name_condition ();
01795 }
01796 
01797 void
01798 cm_ifnothtml (void)
01799 {
01800   if (!process_html)
01801     begin_insertion (ifnothtml);
01802   else
01803     command_name_condition ();
01804 }
01805 
01806 
01807 void
01808 cm_ifinfo (void)
01809 {
01810   if (process_info)
01811     begin_insertion (ifinfo);
01812   else
01813     command_name_condition ();
01814 }
01815 
01816 void
01817 cm_ifnotinfo (void)
01818 {
01819   if (!process_info)
01820     begin_insertion (ifnotinfo);
01821   else
01822     command_name_condition ();
01823 }
01824 
01825 
01826 void
01827 cm_ifplaintext (void)
01828 {
01829   if (process_plaintext)
01830     begin_insertion (ifplaintext);
01831   else
01832     command_name_condition ();
01833 }
01834 
01835 void
01836 cm_ifnotplaintext (void)
01837 {
01838   if (!process_plaintext)
01839     begin_insertion (ifnotplaintext);
01840   else
01841     command_name_condition ();
01842 }
01843 
01844 
01845 void
01846 cm_tex (void)
01847 {
01848   if (process_tex)
01849     begin_insertion (rawtex);
01850   else
01851     command_name_condition ();
01852 }
01853 
01854 void
01855 cm_iftex (void)
01856 {
01857   if (process_tex)
01858     begin_insertion (iftex);
01859   else
01860     command_name_condition ();
01861 }
01862 
01863 void
01864 cm_ifnottex (void)
01865 {
01866   if (!process_tex)
01867     begin_insertion (ifnottex);
01868   else
01869     command_name_condition ();
01870 }
01871 
01872 void
01873 cm_ifxml (void)
01874 {
01875   if (process_xml)
01876     begin_insertion (ifxml);
01877   else
01878     command_name_condition ();
01879 }
01880 
01881 void
01882 cm_ifnotxml (void)
01883 {
01884   if (!process_xml)
01885     begin_insertion (ifnotxml);
01886   else
01887     command_name_condition ();
01888 }
01889 
01890 
01891 /* Generic xrefable block with a caption.  */
01892 void
01893 cm_float (void)
01894 {
01895   begin_insertion (floatenv);
01896 }
01897 
01898 void
01899 cm_caption (int arg)
01900 {
01901   char *temp;
01902 
01903   /* This is a no_op command for most formats, as we handle it during @float
01904      insertion.  For XML though, we handle it here to keep document structure
01905      as close as possible, to the Texinfo source.  */
01906 
01907   /* Everything is already handled at START.  */
01908   if (arg == END)
01909     return;
01910 
01911   /* Check if it's mislocated.  */
01912   if (current_insertion_type () != floatenv)
01913     line_error (_("@%s not meaningful outside `@float' environment"), command);
01914 
01915   get_until_in_braces ("\n@end float", &temp);
01916 
01917   if (xml)
01918     {
01919       int elt = STREQ (command, "shortcaption") ? SHORTCAPTION : CAPTION;
01920       xml_insert_element (elt, START);
01921       if (!docbook)
01922         execute_string ("%s", temp);
01923       xml_insert_element (elt, END);
01924     }
01925 
01926   free (temp);
01927 }
01928 
01929 /* Begin an insertion where the lines are not filled or indented. */
01930 void
01931 cm_flushleft (void)
01932 {
01933   begin_insertion (flushleft);
01934 }
01935 
01936 /* Begin an insertion where the lines are not filled, and each line is
01937    forced to the right-hand side of the page. */
01938 void
01939 cm_flushright (void)
01940 {
01941   begin_insertion (flushright);
01942 }
01943 
01944 void
01945 cm_menu (void)
01946 {
01947   if (current_node == NULL && !macro_expansion_output_stream)
01948     {
01949       warning (_("@menu seen before first @node, creating `Top' node"));
01950       warning (_("perhaps your @top node should be wrapped in @ifnottex rather than @ifinfo?"));
01951       /* Include @top command so we can construct the implicit node tree.  */
01952       execute_string ("@node top\n@top Top\n");
01953     }
01954   begin_insertion (menu);
01955 }
01956 
01957 void
01958 cm_detailmenu (void)
01959 {
01960   if (current_node == NULL && !macro_expansion_output_stream)
01961     { /* Problems anyway, @detailmenu should always be inside @menu.  */
01962       warning (_("@detailmenu seen before first node, creating `Top' node"));
01963       execute_string ("@node top\n@top Top\n");
01964     }
01965   begin_insertion (detailmenu);
01966 }
01967 
01968 /* Title page commands. */
01969 
01970 void
01971 cm_titlepage (void)
01972 {
01973   titlepage_cmd_present = 1;
01974   if (xml && !docbook)
01975     begin_insertion (titlepage);
01976   else
01977     command_name_condition ();
01978 }
01979 
01980 void
01981 cm_author (void)
01982 {
01983   char *rest;
01984   get_rest_of_line (1, &rest);
01985 
01986   if (is_in_insertion_of_type (quotation))
01987     {
01988       if (html)
01989         add_word_args ("&mdash; %s", rest);
01990       else if (docbook)
01991         {
01992           /* FIXME Ideally, we should use an attribution element,
01993              but they are supposed to be at the start of quotation
01994              blocks.  So to avoid looking ahead mess, let's just
01995              use mdash like HTML for now.  */
01996           xml_insert_entity ("mdash");
01997           add_word (rest);
01998         }
01999       else if (xml)
02000         {
02001           xml_insert_element (AUTHOR, START);
02002           add_word (rest);
02003           xml_insert_element (AUTHOR, END);
02004         }
02005       else
02006         add_word_args ("-- %s", rest);
02007     }
02008   else if (is_in_insertion_of_type (titlepage))
02009     {
02010       if (xml && !docbook)
02011         {
02012           xml_insert_element (AUTHOR, START);
02013           add_word (rest);
02014           xml_insert_element (AUTHOR, END);
02015         }
02016     }
02017   else
02018     line_error (_("@%s not meaningful outside `@titlepage' and `@quotation' environments"),
02019         command);
02020 
02021   free (rest);
02022 }
02023 
02024 void
02025 cm_titlepage_cmds (void)
02026 {
02027   char *rest;
02028 
02029   get_rest_of_line (1, &rest);
02030 
02031   if (!is_in_insertion_of_type (titlepage))
02032     line_error (_("@%s not meaningful outside `@titlepage' environment"),
02033         command);
02034 
02035   if (xml && !docbook)
02036     {
02037       int elt = 0;
02038 
02039       if (STREQ (command, "title"))
02040         elt = BOOKTITLE;
02041       else if (STREQ (command, "subtitle"))
02042         elt = BOOKSUBTITLE;
02043 
02044       xml_insert_element (elt, START);
02045       add_word (rest);
02046       xml_insert_element (elt, END);
02047     }
02048 
02049     free (rest);
02050 }
02051 
02052 /* End existing insertion block. */
02053 void
02054 cm_end (void)
02055 {
02056   char *temp;
02057   int type;
02058 
02059   get_rest_of_line (0, &temp);
02060 
02061   if (!insertion_level)
02062     {
02063       line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command);
02064       return;
02065     }
02066 
02067   if (temp[0] == 0)
02068     line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command);
02069 
02070   type = find_type_from_name (temp);
02071 
02072   if (type == bad_type)
02073     {
02074       line_error (_("Bad argument `%s' to `@%s', using `%s'"),
02075            temp, command, insertion_type_pname (current_insertion_type ()));
02076     }
02077   if (xml && type == menu) /* fixme */
02078     {
02079       xml_end_menu ();
02080     }
02081   end_insertion (type);
02082   free (temp);
02083 }
02084 
02085 /* @itemx, @item. */
02086 
02087 static int itemx_flag = 0;
02088 
02089 /* Return whether CMD takes a brace-delimited {arg}.  */
02090 int
02091 command_needs_braces (char *cmd)
02092 {
02093   int i;
02094   for (i = 0; command_table[i].name; i++)
02095     {
02096       if (STREQ (command_table[i].name, cmd))
02097         return command_table[i].argument_in_braces == BRACE_ARGS;
02098     }
02099 
02100   return 0; /* macro or alias */
02101 }
02102 
02103 
02104 void
02105 cm_item (void)
02106 {
02107   char *rest_of_line, *item_func;
02108 
02109   /* Can only hack "@item" while inside of an insertion. */
02110   if (insertion_level)
02111     {
02112       INSERTION_ELT *stack = insertion_stack;
02113       int original_input_text_offset;
02114 
02115       skip_whitespace ();
02116       original_input_text_offset = input_text_offset;
02117 
02118       get_rest_of_line (0, &rest_of_line);
02119       item_func = current_item_function ();
02120 
02121     /* Do the right thing depending on which insertion function is active. */
02122     switch_top:
02123       switch (stack->insertion)
02124         {
02125         case multitable:
02126           multitable_item ();
02127           /* Support text directly after the @item.  */
02128           if (*rest_of_line)
02129             {
02130               line_number--;
02131               input_text_offset = original_input_text_offset;
02132             }
02133           break;
02134 
02135         case ifclear:
02136         case ifhtml:
02137         case ifinfo:
02138         case ifnothtml:
02139         case ifnotinfo:
02140         case ifnotplaintext:
02141         case ifnottex:
02142        case ifnotxml:
02143         case ifplaintext:
02144         case ifset:
02145         case iftex:
02146        case ifxml:
02147         case rawdocbook:
02148         case rawhtml:
02149         case rawxml:
02150         case rawtex:
02151         case tex:
02152         case cartouche:
02153           stack = stack->next;
02154           if (!stack)
02155             goto no_insertion;
02156           else
02157             goto switch_top;
02158           break;
02159 
02160         case menu:
02161         case quotation:
02162         case example:
02163         case smallexample:
02164         case lisp:
02165         case smalllisp:
02166         case format:
02167         case smallformat:
02168         case display:
02169         case smalldisplay:
02170         case group:
02171           line_error (_("@%s not meaningful inside `@%s' block"),
02172                       command,
02173                       insertion_type_pname (current_insertion_type ()));
02174           break;
02175 
02176         case itemize:
02177         case enumerate:
02178           if (itemx_flag)
02179             {
02180               line_error (_("@itemx not meaningful inside `%s' block"),
02181                           insertion_type_pname (current_insertion_type ()));
02182             }
02183           else
02184             {
02185               if (html)
02186                 add_html_block_elt ("<li>");
02187               else if (xml)
02188                 xml_begin_item ();
02189               else
02190                 {
02191                   start_paragraph ();
02192                   kill_self_indent (-1);
02193                   filling_enabled = indented_fill = 1;
02194 
02195                   if (current_item_function ())
02196                     {
02197                       output_column = current_indent - 2;
02198                       indent (output_column);
02199 
02200                       /* The item marker can be given with or without
02201                          braces -- @bullet and @bullet{} are both ok.
02202                          Or it might be something that doesn't take
02203                          braces at all, such as "o" or "#" or "@ ".
02204                          Thus, only supply braces if the item marker is
02205                          a command, they haven't supplied braces
02206                          themselves, and we know it needs them.  */
02207                       if (item_func && *item_func)
02208                         {
02209                           if (*item_func == COMMAND_PREFIX
02210                               && item_func[strlen (item_func) - 1] != '}'
02211                               && command_needs_braces (item_func + 1))
02212                             execute_string ("%s{}", item_func);
02213                           else
02214                             execute_string ("%s", item_func);
02215                         }
02216                       insert (' ');
02217                       output_column++;
02218                     }
02219                   else
02220                     enumerate_item ();
02221 
02222                   /* Special hack.  This makes `close_paragraph' a no-op until
02223                      `start_paragraph' has been called. */
02224                   must_start_paragraph = 1;
02225                 }
02226 
02227               /* Handle text directly after the @item.  */
02228               if (*rest_of_line)
02229                 {
02230                   line_number--;
02231                   input_text_offset = original_input_text_offset;
02232                 }
02233             }
02234           break;
02235 
02236         case table:
02237         case ftable:
02238         case vtable:
02239           if (html)
02240             { /* If nothing has been output since the last <dd>,
02241                  remove the empty <dd> element.  Some browsers render
02242                  an extra empty line for <dd><dt>, which makes @itemx
02243                  conversion look ugly.  */
02244               rollback_empty_tag ("dd");
02245 
02246               /* Force the browser to render one blank line before
02247                  each new @item in a table.  But don't do that if
02248                  this is the first <dt> after the <dl>, or if we are
02249                  converting @itemx.
02250 
02251                  Note that there are some browsers which ignore <br>
02252                  in this context, but I cannot find any way to force
02253                  them all render exactly one blank line.  */
02254               if (!itemx_flag && html_deflist_has_term)
02255                 add_html_block_elt ("<br>");
02256 
02257               /* We are about to insert a <dt>, so this <dl> has a term.
02258                  Feel free to insert a <br> next time. :)  */
02259               html_deflist_has_term = 1;
02260    
02261               add_html_block_elt ("<dt>");
02262               if (item_func && *item_func)
02263                 execute_string ("%s{%s}", item_func, rest_of_line);
02264               else
02265                 execute_string ("%s", rest_of_line);
02266 
02267               if (current_insertion_type () == ftable)
02268                 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
02269 
02270               if (current_insertion_type () == vtable)
02271                 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
02272 
02273               add_html_block_elt ("<dd>");
02274             }
02275           else if (xml) /* && docbook)*/ /* 05-08 */
02276             {
02277               xml_begin_table_item ();
02278 
02279               if (!docbook && current_insertion_type () == ftable)
02280                 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
02281 
02282               if (!docbook && current_insertion_type () == vtable)
02283                 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
02284 
02285               if (item_func && *item_func)
02286                 execute_string ("%s{%s}", item_func, rest_of_line);
02287               else
02288                 execute_string ("%s", rest_of_line);
02289               xml_continue_table_item ();
02290             }
02291           else
02292             {
02293               /* We need this to determine if we have two @item's in a row
02294                  (see test just below).  */
02295               static int last_item_output_position = 0;
02296 
02297               /* Get rid of extra characters. */
02298               kill_self_indent (-1);
02299 
02300               /* If we have one @item followed directly by another @item,
02301                  we need to insert a blank line.  This is not true for
02302                  @itemx, though.  */
02303               if (!itemx_flag && last_item_output_position == output_position)
02304                 insert ('\n');
02305 
02306               /* `close_paragraph' almost does what we want.  The problem
02307                  is when paragraph_is_open, and last_char_was_newline, and
02308                  the last newline has been turned into a space, because
02309                  filling_enabled. I handle it here. */
02310               if (last_char_was_newline && filling_enabled &&
02311                   paragraph_is_open)
02312                 insert ('\n');
02313               close_paragraph ();
02314 
02315 #if defined (INDENT_PARAGRAPHS_IN_TABLE)
02316               /* Indent on a new line, but back up one indentation level. */
02317               {
02318                 int save = inhibit_paragraph_indentation;
02319                 inhibit_paragraph_indentation = 1;
02320                 /* At this point, inserting any non-whitespace character will
02321                    force the existing indentation to be output. */
02322                 add_char ('i');
02323                 inhibit_paragraph_indentation = save;
02324               }
02325 #else /* !INDENT_PARAGRAPHS_IN_TABLE */
02326               add_char ('i');
02327 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */
02328 
02329               output_paragraph_offset--;
02330               kill_self_indent (default_indentation_increment + 1);
02331 
02332               /* Add item's argument to the line. */
02333               filling_enabled = 0;
02334               if (item_func && *item_func)
02335                 execute_string ("%s{%s}", item_func, rest_of_line);
02336               else
02337                 execute_string ("%s", rest_of_line);
02338 
02339               if (current_insertion_type () == ftable)
02340                 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
02341               else if (current_insertion_type () == vtable)
02342                 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
02343 
02344               /* Start a new line, and let start_paragraph ()
02345                  do the indenting of it for you. */
02346               close_single_paragraph ();
02347               indented_fill = filling_enabled = 1;
02348               last_item_output_position = output_position;
02349             }
02350         }
02351       free (rest_of_line);
02352     }
02353   else
02354     {
02355     no_insertion:
02356       line_error (_("%c%s found outside of an insertion block"),
02357                   COMMAND_PREFIX, command);
02358     }
02359 }
02360 
02361 void
02362 cm_itemx (void)
02363 {
02364   itemx_flag++;
02365   cm_item ();
02366   itemx_flag--;
02367 }
02368 
02369 int headitem_flag = 0;
02370 
02371 void
02372 cm_headitem (void)
02373 {
02374   headitem_flag = 1;
02375   cm_item ();
02376 }