insertion.c revision 100513
1/* insertion.c -- insertions for Texinfo.
2   $Id: insertion.c,v 1.47 2002/04/01 14:01:36 karl Exp $
3
4   Copyright (C) 1998, 99, 2000, 01, 02 Free Software Foundation, Inc.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software Foundation,
18   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20#include "system.h"
21#include "cmds.h"
22#include "defun.h"
23#include "insertion.h"
24#include "macro.h"
25#include "makeinfo.h"
26#include "xml.h"
27
28/* Must match list in insertion.h.  */
29static char *insertion_type_names[] =
30{
31  "cartouche", "copying", "defcv", "deffn", "defivar", "defmac",
32  "defmethod", "defop", "defopt", "defspec", "deftp", "deftypefn",
33  "deftypefun", "deftypeivar", "deftypemethod", "deftypeop",
34  "deftypevar", "deftypevr", "defun", "defvar", "defvr", "detailmenu",
35  "direntry", "display", "documentdescription", "enumerate", "example",
36  "flushleft", "flushright", "format", "ftable", "group", "ifclear",
37  "ifhtml", "ifinfo", "ifnothtml", "ifnotinfo", "ifnotplaintext", "ifnottex",
38  "ifplaintext", "ifset", "iftex", "itemize", "lisp", "menu",
39  "multitable", "quotation", "rawhtml", "rawtex", "smalldisplay",
40  "smallexample", "smallformat", "smalllisp", "verbatim", "table",
41  "tex", "vtable", "bad_type"
42};
43
44/* All nested environments.  */
45INSERTION_ELT *insertion_stack = NULL;
46
47/* How deeply we're nested.  */
48int insertion_level = 0;
49
50/* Set to 1 if we've processed (commentary) text in a @menu that
51   wasn't part of a menu item.  */
52int had_menu_commentary;
53
54/* How to examine menu lines.  */
55int in_detailmenu = 0;
56
57/* Whether to examine menu lines.  */
58int in_menu = 0;
59
60/* Set to 1 if <p> is written in normal context.
61   Used for menu and itemize. */
62int in_paragraph = 0;
63
64static const char dl_tag[] = "<dl>\n";
65extern void cm_insert_copying ();
66
67
68void
69init_insertion_stack ()
70{
71  insertion_stack = NULL;
72}
73
74/* Return the type of the current insertion. */
75static enum insertion_type
76current_insertion_type ()
77{
78  return insertion_level ? insertion_stack->insertion : bad_type;
79}
80
81/* Return the string which is the function to wrap around items, or NULL
82   if we're not in an environment where @item is ok.  */
83static char *
84current_item_function ()
85{
86  int done = 0;
87  INSERTION_ELT *elt = insertion_stack;
88
89  /* Skip down through the stack until we find an insertion with an
90     itemize function defined, i.e., skip conditionals, @cartouche, etc.  */
91  while (!done && elt)
92    {
93      switch (elt->insertion)
94        {
95        /* This list should match the one in cm_item.  */
96        case ifclear:
97        case ifhtml:
98        case ifinfo:
99        case ifnothtml:
100        case ifnotinfo:
101        case ifnotplaintext:
102        case ifnottex:
103        case ifplaintext:
104        case ifset:
105        case iftex:
106        case rawhtml:
107        case rawtex:
108        case tex:
109        case cartouche:
110	  elt = elt->next;
111	  break;
112
113        default:
114          done = 1;
115        }
116    }
117
118  /* item_function usually gets assigned the empty string.  */
119  return done && (*elt->item_function) ? elt->item_function : NULL;
120}
121
122/* Parse the item marker function off the input.  If result is just "@",
123   change it to "@ ", since "@" by itself is not a command.  This makes
124   "@ ", "@\t", and "@\n" all the same, but their default meanings are
125   the same anyway, and let's not worry about supporting redefining them.  */
126char *
127get_item_function ()
128{
129  char *item_function;
130  get_rest_of_line (0, &item_function);
131
132  /* If we hit the end of text in get_rest_of_line, backing up
133     input pointer will cause the last character of the last line
134     be pushed back onto the input, which is wrong.  */
135  if (input_text_offset < input_text_length)
136    backup_input_pointer ();
137
138  if (STREQ (item_function, "@"))
139    {
140      free (item_function);
141      item_function = xstrdup ("@ ");
142    }
143
144  return item_function;
145}
146
147 /* Push the state of the current insertion on the stack. */
148void
149push_insertion (type, item_function)
150     enum insertion_type type;
151     char *item_function;
152{
153  INSERTION_ELT *new = xmalloc (sizeof (INSERTION_ELT));
154
155  new->item_function = item_function;
156  new->filling_enabled = filling_enabled;
157  new->indented_fill = indented_fill;
158  new->insertion = type;
159  new->line_number = line_number;
160  new->filename = xstrdup (input_filename);
161  new->inhibited = inhibit_paragraph_indentation;
162  new->in_fixed_width_font = in_fixed_width_font;
163  new->next = insertion_stack;
164  insertion_stack = new;
165  insertion_level++;
166}
167
168 /* Pop the value on top of the insertion stack into the
169    global variables. */
170void
171pop_insertion ()
172{
173  INSERTION_ELT *temp = insertion_stack;
174
175  if (temp == NULL)
176    return;
177
178  in_fixed_width_font = temp->in_fixed_width_font;
179  inhibit_paragraph_indentation = temp->inhibited;
180  filling_enabled = temp->filling_enabled;
181  indented_fill = temp->indented_fill;
182  free_and_clear (&(temp->item_function));
183  free_and_clear (&(temp->filename));
184  insertion_stack = insertion_stack->next;
185  free (temp);
186  insertion_level--;
187}
188
189 /* Return a pointer to the print name of this
190    enumerated type. */
191char *
192insertion_type_pname (type)
193     enum insertion_type type;
194{
195  if ((int) type < (int) bad_type)
196    return insertion_type_names[(int) type];
197  else
198    return _("Broken-Type in insertion_type_pname");
199}
200
201/* Return the insertion_type associated with NAME.
202   If the type is not one of the known ones, return BAD_TYPE. */
203enum insertion_type
204find_type_from_name (name)
205     char *name;
206{
207  int index = 0;
208  while (index < (int) bad_type)
209    {
210      if (STREQ (name, insertion_type_names[index]))
211        return (enum insertion_type) index;
212      if (index == rawhtml && STREQ (name, "html"))
213        return rawhtml;
214      if (index == rawtex && STREQ (name, "tex"))
215        return rawtex;
216      index++;
217    }
218  return bad_type;
219}
220
221int
222defun_insertion (type)
223     enum insertion_type type;
224{
225  return 0
226     || (type == defcv)
227     || (type == deffn)
228     || (type == defivar)
229     || (type == defmac)
230     || (type == defmethod)
231     || (type == defop)
232     || (type == defopt)
233     || (type == defspec)
234     || (type == deftp)
235     || (type == deftypefn)
236     || (type == deftypefun)
237     || (type == deftypeivar)
238     || (type == deftypemethod)
239     || (type == deftypeop)
240     || (type == deftypevar)
241     || (type == deftypevr)
242     || (type == defun)
243     || (type == defvar)
244     || (type == defvr)
245  ;
246}
247
248/* MAX_NS is the maximum nesting level for enumerations.  I picked 100
249   which seemed reasonable.  This doesn't control the number of items,
250   just the number of nested lists. */
251#define max_stack_depth 100
252#define ENUM_DIGITS 1
253#define ENUM_ALPHA  2
254typedef struct {
255  int enumtype;
256  int enumval;
257} DIGIT_ALPHA;
258
259DIGIT_ALPHA enumstack[max_stack_depth];
260int enumstack_offset = 0;
261int current_enumval = 1;
262int current_enumtype = ENUM_DIGITS;
263char *enumeration_arg = NULL;
264
265void
266start_enumerating (at, type)
267     int at, type;
268{
269  if ((enumstack_offset + 1) == max_stack_depth)
270    {
271      line_error (_("Enumeration stack overflow"));
272      return;
273    }
274  enumstack[enumstack_offset].enumtype = current_enumtype;
275  enumstack[enumstack_offset].enumval = current_enumval;
276  enumstack_offset++;
277  current_enumval = at;
278  current_enumtype = type;
279}
280
281void
282stop_enumerating ()
283{
284  --enumstack_offset;
285  if (enumstack_offset < 0)
286    enumstack_offset = 0;
287
288  current_enumval = enumstack[enumstack_offset].enumval;
289  current_enumtype = enumstack[enumstack_offset].enumtype;
290}
291
292/* Place a letter or digits into the output stream. */
293void
294enumerate_item ()
295{
296  char temp[10];
297
298  if (current_enumtype == ENUM_ALPHA)
299    {
300      if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
301        {
302          current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
303          warning (_("lettering overflow, restarting at %c"), current_enumval);
304        }
305      sprintf (temp, "%c. ", current_enumval);
306    }
307  else
308    sprintf (temp, "%d. ", current_enumval);
309
310  indent (output_column += (current_indent - strlen (temp)));
311  add_word (temp);
312  current_enumval++;
313}
314
315static void
316enum_html ()
317{
318  char type;
319  int start;
320
321  if (isdigit (*enumeration_arg))
322    {
323      type = '1';
324      start = atoi (enumeration_arg);
325    }
326  else if (isupper (*enumeration_arg))
327    {
328      type = 'A';
329      start = *enumeration_arg - 'A' + 1;
330    }
331  else
332    {
333      type = 'a';
334      start = *enumeration_arg - 'a' + 1;
335    }
336
337  add_word_args ("<ol type=%c start=%d>\n", type, start);
338}
339
340/* Conditionally parse based on the current command name. */
341void
342command_name_condition ()
343{
344  char *discarder = xmalloc (8 + strlen (command));
345
346  sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
347  discard_until (discarder);
348  discard_until ("\n");
349
350  free (discarder);
351}
352
353/* This is where the work for all the "insertion" style
354   commands is done.  A huge switch statement handles the
355   various setups, and generic code is on both sides. */
356void
357begin_insertion (type)
358     enum insertion_type type;
359{
360  int no_discard = 0;
361
362  if (defun_insertion (type))
363    {
364      push_insertion (type, xstrdup (""));
365      no_discard++;
366    }
367  else
368    {
369      push_insertion (type, get_item_function ());
370    }
371
372  switch (type)
373    {
374    case menu:
375      if (!no_headers)
376        close_paragraph ();
377
378      filling_enabled = no_indent = 0;
379      inhibit_paragraph_indentation = 1;
380
381      if (html)
382        {
383          had_menu_commentary = 1;
384        }
385      else if (!no_headers && !xml)
386        add_word ("* Menu:\n");
387
388      if (xml)
389	xml_insert_element (MENU, START);
390
391      next_menu_item_number = 1;
392      in_menu++;
393      in_fixed_width_font++;
394      no_discard++;
395      break;
396
397    case detailmenu:
398      if (!in_menu)
399        {
400          if (!no_headers)
401            close_paragraph ();
402
403          filling_enabled = no_indent = 0;
404          inhibit_paragraph_indentation = 1;
405
406          no_discard++;
407        }
408
409      in_fixed_width_font++;
410      in_detailmenu++;
411      break;
412
413    case direntry:
414      close_single_paragraph ();
415      filling_enabled = no_indent = 0;
416      inhibit_paragraph_indentation = 1;
417      insert_string ("START-INFO-DIR-ENTRY\n");
418      break;
419
420    case documentdescription:
421      {
422        char *desc;
423        int start_of_end;
424        int save_fixed_width;
425
426        discard_until ("\n"); /* ignore the @documentdescription line */
427        start_of_end = get_until ("\n@end documentdescription", &desc);
428        save_fixed_width = in_fixed_width_font;
429
430        in_fixed_width_font = 0;
431        document_description = expansion (desc, 0);
432        free (desc);
433
434        in_fixed_width_font = save_fixed_width;
435        input_text_offset = start_of_end; /* go back to the @end to match */
436      }
437      break;
438
439    case copying:
440      {
441        /* Save the copying text away for @insertcopying,
442           typically used on the back of the @titlepage (for TeX) and
443           the Top node (for info/html).  */
444        char *text;
445        int start_of_end;
446
447        discard_until ("\n"); /* ignore remainder of @copying line */
448        start_of_end = get_until ("\n@end copying", &text);
449
450        /* include all the output-format-specific markup.  */
451        copying_text = full_expansion (text, 0);
452        free (text);
453
454        input_text_offset = start_of_end; /* go back to the @end to match */
455      }
456
457      /* For info, output the copying text right away, so it will end up
458         in the header of the Info file, before the first node, and thus
459         get copied automatically to all the split files.  For xml, also
460         output it right away since xml output is never split.
461         For html, we output it specifically in html_output_head.
462         For plain text, there's no way to hide it, so the author must
463          use @insertcopying in the desired location.  */
464      if (!html && !no_headers)
465        cm_insert_copying ();
466      break;
467
468    case quotation:
469      /* @quotation does filling (@display doesn't).  */
470      if (html)
471        add_word ("<blockquote>\n");
472      else
473        {
474          /* with close_single_paragraph, we get no blank line above
475             within @copying.  */
476          close_paragraph ();
477          last_char_was_newline = no_indent = 0;
478          indented_fill = filling_enabled = 1;
479          inhibit_paragraph_indentation = 1;
480        }
481      current_indent += default_indentation_increment;
482      break;
483
484    case display:
485    case smalldisplay:
486    case example:
487    case smallexample:
488    case lisp:
489    case smalllisp:
490      /* Like @display but without indentation. */
491    case smallformat:
492    case format:
493      close_single_paragraph ();
494      inhibit_paragraph_indentation = 1;
495      in_fixed_width_font++;
496      filling_enabled = 0;
497      last_char_was_newline = 0;
498
499      if (html)
500        /* Kludge alert: if <pre> is followed by a newline, IE3
501           renders an extra blank line before the pre-formatted block.
502           Other browsers seem to not mind one way or the other.  */
503        add_word ("<br><pre>");
504
505      if (type != format && type != smallformat)
506        current_indent += default_indentation_increment;
507      break;
508
509    case multitable:
510      do_multitable ();
511      break;
512
513    case table:
514    case ftable:
515    case vtable:
516    case itemize:
517      close_single_paragraph ();
518      current_indent += default_indentation_increment;
519      filling_enabled = indented_fill = 1;
520#if defined (INDENT_PARAGRAPHS_IN_TABLE)
521      inhibit_paragraph_indentation = 0;
522#else
523      inhibit_paragraph_indentation = 1;
524#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
525
526      /* Make things work for losers who forget the itemize syntax. */
527      if (type == itemize)
528        {
529          if (!(*insertion_stack->item_function))
530            {
531              free (insertion_stack->item_function);
532              insertion_stack->item_function = xstrdup ("@bullet");
533            }
534        }
535
536      if (!*insertion_stack->item_function)
537        {
538          line_error (_("%s requires an argument: the formatter for %citem"),
539                      insertion_type_pname (type), COMMAND_PREFIX);
540        }
541
542      if (html)
543        {
544          if (type == itemize)
545	    {
546	      add_word ("<ul>\n");
547	      in_paragraph = 0;
548	    }
549          else
550            add_word (dl_tag);
551        }
552      if (xml)
553	xml_begin_table (type, insertion_stack->item_function);
554      break;
555
556    case enumerate:
557      close_single_paragraph ();
558      no_indent = 0;
559#if defined (INDENT_PARAGRAPHS_IN_TABLE)
560      inhibit_paragraph_indentation = 0;
561#else
562      inhibit_paragraph_indentation = 1;
563#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
564
565      current_indent += default_indentation_increment;
566      filling_enabled = indented_fill = 1;
567
568      if (html)
569        enum_html ();
570
571      if (xml)
572	xml_begin_enumerate (enumeration_arg);
573
574      if (isdigit (*enumeration_arg))
575        start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
576      else
577        start_enumerating (*enumeration_arg, ENUM_ALPHA);
578      break;
579
580      /* @group does nothing special in makeinfo. */
581    case group:
582      /* Only close the paragraph if we are not inside of an
583         @example-like environment. */
584      if (xml)
585	xml_insert_element (GROUP, START);
586      else if (!insertion_stack->next
587          || (insertion_stack->next->insertion != display
588              && insertion_stack->next->insertion != smalldisplay
589              && insertion_stack->next->insertion != example
590              && insertion_stack->next->insertion != smallexample
591              && insertion_stack->next->insertion != lisp
592              && insertion_stack->next->insertion != smalllisp
593              && insertion_stack->next->insertion != format
594              && insertion_stack->next->insertion != smallformat
595              && insertion_stack->next->insertion != flushleft
596              && insertion_stack->next->insertion != flushright))
597        close_single_paragraph ();
598      break;
599
600      /* Insertions that are no-ops in info, but do something in TeX. */
601    case cartouche:
602    case ifclear:
603    case ifhtml:
604    case ifinfo:
605    case ifnothtml:
606    case ifnotinfo:
607    case ifnotplaintext:
608    case ifnottex:
609    case ifplaintext:
610    case ifset:
611    case iftex:
612    case rawtex:
613      if (in_menu)
614        no_discard++;
615      break;
616
617    case rawhtml:
618      escape_html = 0;
619      break;
620
621    case defcv:
622    case deffn:
623    case defivar:
624    case defmac:
625    case defmethod:
626    case defop:
627    case defopt:
628    case defspec:
629    case deftp:
630    case deftypefn:
631    case deftypefun:
632    case deftypeivar:
633    case deftypemethod:
634    case deftypeop:
635    case deftypevar:
636    case deftypevr:
637    case defun:
638    case defvar:
639    case defvr:
640      inhibit_paragraph_indentation = 1;
641      filling_enabled = indented_fill = 1;
642      current_indent += default_indentation_increment;
643      no_indent = 0;
644      break;
645
646    case flushleft:
647      close_single_paragraph ();
648      inhibit_paragraph_indentation = 1;
649      filling_enabled = indented_fill = no_indent = 0;
650      if (html)
651	add_word ("<div align=\"left\">");
652      break;
653
654    case flushright:
655      close_single_paragraph ();
656      filling_enabled = indented_fill = no_indent = 0;
657      inhibit_paragraph_indentation = 1;
658      force_flush_right++;
659      if (html)
660	add_word ("<div align=\"right\">");
661      break;
662
663    default:
664      line_error ("begin_insertion internal error: type=%d", type);
665
666    }
667
668  if (!no_discard)
669    discard_until ("\n");
670}
671
672/* Try to end the insertion with the specified TYPE.  With a value of
673   `bad_type', TYPE gets translated to match the value currently on top
674   of the stack.  Otherwise, if TYPE doesn't match the top of the
675   insertion stack, give error. */
676void
677end_insertion (type)
678     enum insertion_type type;
679{
680  enum insertion_type temp_type;
681
682  if (!insertion_level)
683    return;
684
685  temp_type = current_insertion_type ();
686
687  if (type == bad_type)
688    type = temp_type;
689
690  if (type != temp_type)
691    {
692      line_error
693        (_("`@end' expected `%s', but saw `%s'"),
694         insertion_type_pname (temp_type), insertion_type_pname (type));
695      return;
696    }
697
698  pop_insertion ();
699
700  if (xml)
701    {
702      switch (type)
703	{
704	case ifinfo:
705	case documentdescription:
706	  break;
707	case copying:
708	  xml_insert_element (COPYING, END);
709	  break;
710	case quotation:
711	  xml_insert_element (QUOTATION, END);
712	  break;
713	case example:
714	  xml_insert_element (EXAMPLE, END);
715	  break;
716	case smallexample:
717	  xml_insert_element (SMALLEXAMPLE, END);
718	  break;
719	case lisp:
720	  xml_insert_element (LISP, END);
721	  break;
722	case smalllisp:
723	  xml_insert_element (SMALLLISP, END);
724	  break;
725	case cartouche:
726	  xml_insert_element (CARTOUCHE, END);
727	  break;
728	case format:
729	  xml_insert_element (FORMAT, END);
730	  break;
731	case smallformat:
732	  xml_insert_element (SMALLFORMAT, END);
733	  break;
734	case display:
735	  xml_insert_element (DISPLAY, END);
736	  break;
737	case smalldisplay:
738	  xml_insert_element (SMALLDISPLAY, END);
739	  break;
740	case table:
741	case ftable:
742	case vtable:
743	case itemize:
744	  xml_end_table (type);
745	  break;
746	case enumerate:
747	  xml_end_enumerate (type);
748	  break;
749	case group:
750	  xml_insert_element (GROUP, END);
751	  break;
752	}
753    }
754  switch (type)
755    {
756      /* Insertions which have no effect on paragraph formatting. */
757    case copying:
758    case documentdescription:
759    case ifclear:
760    case ifinfo:
761    case ifhtml:
762    case ifnothtml:
763    case ifnotinfo:
764    case ifnotplaintext:
765    case ifnottex:
766    case ifplaintext:
767    case ifset:
768    case iftex:
769    case rawtex:
770      break;
771
772    case rawhtml:
773      escape_html = 1;
774      break;
775
776    case detailmenu:
777      in_detailmenu--;          /* No longer hacking menus. */
778      if (!in_menu)
779        {
780          if (!no_headers)
781            close_insertion_paragraph ();
782        }
783      break;
784
785    case direntry:              /* Eaten if html. */
786      insert_string ("END-INFO-DIR-ENTRY\n\n");
787      close_insertion_paragraph ();
788      break;
789
790    case menu:
791      in_menu--;                /* No longer hacking menus. */
792      if (html)
793        add_word ("</ul>\n");
794      else if (!no_headers)
795        close_insertion_paragraph ();
796      break;
797
798    case multitable:
799      end_multitable ();
800      break;
801
802    case enumerate:
803      stop_enumerating ();
804      close_insertion_paragraph ();
805      current_indent -= default_indentation_increment;
806      if (html)
807        add_word ("</ol>\n");
808      break;
809
810    case flushleft:
811      if (html)
812	add_word ("</div>\n");
813      close_insertion_paragraph ();
814      break;
815
816    case group:
817    case cartouche:
818      close_insertion_paragraph ();
819      break;
820
821    case format:
822    case smallformat:
823    case display:
824    case smalldisplay:
825    case example:
826    case smallexample:
827    case lisp:
828    case smalllisp:
829    case quotation:
830      /* @format and @smallformat are the only fixed_width insertion
831         without a change in indentation. */
832      if (type != format && type != smallformat)
833        current_indent -= default_indentation_increment;
834
835      if (html)
836        add_word (type == quotation ? "</blockquote>\n" : "</pre>\n");
837
838      /* The ending of one of these insertions always marks the
839         start of a new paragraph. */
840      close_insertion_paragraph ();
841      break;
842
843    case table:
844    case ftable:
845    case vtable:
846      current_indent -= default_indentation_increment;
847      if (html)
848        add_word ("</dl>\n");
849      break;
850
851    case itemize:
852      current_indent -= default_indentation_increment;
853      if (html)
854        add_word ("</ul>\n");
855      close_insertion_paragraph ();
856      break;
857
858    case flushright:
859      force_flush_right--;
860      if (html)
861	add_word ("</div>\n");
862      close_insertion_paragraph ();
863      break;
864
865    /* Handle the @defun insertions with this default clause. */
866    default:
867      {
868	enum insertion_type base_type;
869
870        if (type < defcv || type > defvr)
871          line_error ("end_insertion internal error: type=%d", type);
872
873        base_type = get_base_type (type);
874        switch (base_type)
875          {
876          case deffn:
877          case defvr:
878          case deftp:
879          case deftypefn:
880          case deftypevr:
881          case defcv:
882          case defop:
883	  case deftypemethod:
884	  case deftypeop:
885	  case deftypeivar:
886	    if (html)
887	      /* close the tables which has been opened in defun.c */
888              add_word ("</td></tr>\n</table>\n");
889            break;
890          } /* switch (base_type)... */
891
892        current_indent -= default_indentation_increment;
893        close_insertion_paragraph ();
894      }
895      break;
896
897    }
898
899  if (current_indent < 0)
900    line_error ("end_insertion internal error: current indent=%d",
901                current_indent);
902}
903
904/* Insertions cannot cross certain boundaries, such as node beginnings.  In
905   code that creates such boundaries, you should call `discard_insertions'
906   before doing anything else.  It prints the errors for you, and cleans up
907   the insertion stack.
908
909   With nonzero SPECIALS_OK argument, allows unmatched
910   @if... conditionals, otherwise not.  This is because conditionals can
911   cross node boundaries.  Always happens with the @top node, for example.  */
912void
913discard_insertions (specials_ok)
914    int specials_ok;
915{
916  int real_line_number = line_number;
917  while (insertion_stack)
918    {
919      if (specials_ok
920          && ((ifclear <= insertion_stack->insertion
921               && insertion_stack->insertion <= iftex)
922              || insertion_stack->insertion == rawhtml
923              || insertion_stack->insertion == rawtex))
924        break;
925      else
926        {
927          char *offender = insertion_type_pname (insertion_stack->insertion);
928
929          file_line_error (insertion_stack->filename,
930			   insertion_stack->line_number,
931			   _("No matching `%cend %s'"), COMMAND_PREFIX,
932			   offender);
933          pop_insertion ();
934        }
935    }
936  line_number = real_line_number;
937}
938
939/* Insertion (environment) commands.  */
940
941void
942cm_quotation ()
943{
944  if (xml)
945    xml_insert_element (QUOTATION, START);
946  begin_insertion (quotation);
947}
948
949void
950cm_example ()
951{
952  if (xml)
953    xml_insert_element (EXAMPLE, START);
954  begin_insertion (example);
955}
956
957void
958cm_smallexample ()
959{
960  if (xml)
961    xml_insert_element (SMALLEXAMPLE, START);
962  begin_insertion (smallexample);
963}
964
965void
966cm_lisp ()
967{
968  if (xml)
969    xml_insert_element (LISP, START);
970  begin_insertion (lisp);
971}
972
973void
974cm_smalllisp ()
975{
976  if (xml)
977    xml_insert_element (SMALLLISP, START);
978  begin_insertion (smalllisp);
979}
980
981void
982cm_cartouche ()
983{
984  if (xml)
985    xml_insert_element (CARTOUCHE, START);
986  begin_insertion (cartouche);
987}
988
989void
990cm_copying ()
991{
992  if (xml)
993    xml_insert_element (COPYING, START);
994  begin_insertion (copying);
995}
996
997/* Not an insertion, despite the name, but it goes with cm_copying.  */
998void
999cm_insert_copying ()
1000{
1001  if (copying_text)
1002    { /* insert_string rather than add_word because we've already done
1003         full expansion on copying_text when we saved it.  */
1004      insert_string (copying_text);
1005      insert ('\n');
1006    }
1007}
1008
1009void
1010cm_format ()
1011{
1012  if (xml)
1013    xml_insert_element (FORMAT, START);
1014  begin_insertion (format);
1015}
1016
1017void
1018cm_smallformat ()
1019{
1020  if (xml)
1021    xml_insert_element (SMALLFORMAT, START);
1022  begin_insertion (smallformat);
1023}
1024
1025void
1026cm_display ()
1027{
1028  if (xml)
1029    xml_insert_element (DISPLAY, START);
1030  begin_insertion (display);
1031}
1032
1033void
1034cm_smalldisplay ()
1035{
1036  if (xml)
1037    xml_insert_element (SMALLDISPLAY, START);
1038  begin_insertion (smalldisplay);
1039}
1040
1041void
1042cm_direntry ()
1043{
1044  if (html || xml)
1045    command_name_condition ();
1046  else
1047    begin_insertion (direntry);
1048}
1049
1050void
1051cm_documentdescription ()
1052{
1053  if (html || xml)
1054    begin_insertion (documentdescription);
1055  else
1056    command_name_condition ();
1057}
1058
1059
1060void
1061cm_itemize ()
1062{
1063  begin_insertion (itemize);
1064}
1065
1066/* Start an enumeration insertion of type TYPE.  If the user supplied
1067   no argument on the line, then use DEFAULT_STRING as the initial string. */
1068static void
1069do_enumeration (type, default_string)
1070     int type;
1071     char *default_string;
1072{
1073  get_until_in_line (0, ".", &enumeration_arg);
1074  canon_white (enumeration_arg);
1075
1076  if (!*enumeration_arg)
1077    {
1078      free (enumeration_arg);
1079      enumeration_arg = xstrdup (default_string);
1080    }
1081
1082  if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
1083    {
1084      warning (_("%s requires letter or digit"), insertion_type_pname (type));
1085
1086      switch (type)
1087        {
1088        case enumerate:
1089          default_string = "1";
1090          break;
1091        }
1092      enumeration_arg = xstrdup (default_string);
1093    }
1094  begin_insertion (type);
1095}
1096
1097void
1098cm_enumerate ()
1099{
1100  do_enumeration (enumerate, "1");
1101}
1102
1103/*  Handle verbatim environment:
1104    find_end_verbatim == 0:  process until end of file
1105    find_end_verbatim != 0:  process until 'COMMAND_PREFIXend verbatim'
1106                             or end of file
1107
1108  We cannot simply copy input stream onto output stream; as the
1109  verbatim environment may be encapsulated in an @example environment,
1110  for example. */
1111void
1112handle_verbatim_environment (find_end_verbatim)
1113  int find_end_verbatim;
1114{
1115  int character;
1116  int seen_end = 0;
1117  int save_filling_enabled = filling_enabled;
1118  int save_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
1119
1120  close_single_paragraph ();
1121  inhibit_paragraph_indentation = 1;
1122  filling_enabled = 0;
1123  in_fixed_width_font++;
1124  last_char_was_newline = 0;
1125
1126  /* No indentation: this is verbatim after all
1127     If you want indent, enclose @verbatim in @example
1128       current_indent += default_indentation_increment;
1129   */
1130
1131  if (html)
1132    add_word ("<pre>");
1133
1134  while (input_text_offset < input_text_length)
1135    {
1136      character = curchar ();
1137
1138      if (character == '\n')
1139        line_number++;
1140      /*
1141	Assume no newlines in END_VERBATIM
1142      */
1143      else if (find_end_verbatim && (character == COMMAND_PREFIX) /* @ */
1144	  && (input_text_length - input_text_offset > sizeof (END_VERBATIM))
1145	  && !strncmp (&input_text[input_text_offset+1], END_VERBATIM,
1146		       sizeof (END_VERBATIM)-1))
1147	{
1148	  input_text_offset += sizeof (END_VERBATIM);
1149	  seen_end = 1;
1150	  break;
1151	}
1152
1153      add_char (character);
1154      input_text_offset++;
1155    }
1156
1157  if (find_end_verbatim && !seen_end)
1158    warning (_("end of file inside verbatim block"));
1159
1160  if (html)
1161    add_word ("</pre>");
1162
1163  in_fixed_width_font--;
1164  filling_enabled = save_filling_enabled;
1165  inhibit_paragraph_indentation = save_inhibit_paragraph_indentation;
1166}
1167
1168void
1169cm_verbatim ()
1170{
1171  handle_verbatim_environment (1);
1172}
1173
1174void
1175cm_table ()
1176{
1177  begin_insertion (table);
1178}
1179
1180void
1181cm_multitable ()
1182{
1183  begin_insertion (multitable); /* @@ */
1184}
1185
1186void
1187cm_ftable ()
1188{
1189  begin_insertion (ftable);
1190}
1191
1192void
1193cm_vtable ()
1194{
1195  begin_insertion (vtable);
1196}
1197
1198void
1199cm_group ()
1200{
1201  begin_insertion (group);
1202}
1203
1204/* Insert raw HTML (no escaping of `<' etc.). */
1205void
1206cm_html ()
1207{
1208  if (process_html)
1209    begin_insertion (rawhtml);
1210  else
1211    command_name_condition ();
1212}
1213
1214void
1215cm_ifhtml ()
1216{
1217  if (process_html)
1218    begin_insertion (ifhtml);
1219  else
1220    command_name_condition ();
1221}
1222
1223void
1224cm_ifnothtml ()
1225{
1226  if (!process_html)
1227    begin_insertion (ifnothtml);
1228  else
1229    command_name_condition ();
1230}
1231
1232
1233void
1234cm_ifinfo ()
1235{
1236  if (process_info)
1237    begin_insertion (ifinfo);
1238  else
1239    command_name_condition ();
1240}
1241
1242void
1243cm_ifnotinfo ()
1244{
1245  if (!process_info)
1246    begin_insertion (ifnotinfo);
1247  else
1248    command_name_condition ();
1249}
1250
1251
1252void
1253cm_ifplaintext ()
1254{
1255  if (process_plaintext)
1256    begin_insertion (ifplaintext);
1257  else
1258    command_name_condition ();
1259}
1260
1261void
1262cm_ifnotplaintext ()
1263{
1264  if (!process_plaintext)
1265    begin_insertion (ifnotplaintext);
1266  else
1267    command_name_condition ();
1268}
1269
1270
1271void
1272cm_tex ()
1273{
1274  if (process_tex)
1275    begin_insertion (rawtex);
1276  else
1277    command_name_condition ();
1278}
1279
1280void
1281cm_iftex ()
1282{
1283  if (process_tex)
1284    begin_insertion (iftex);
1285  else
1286    command_name_condition ();
1287}
1288
1289void
1290cm_ifnottex ()
1291{
1292  if (!process_tex)
1293    begin_insertion (ifnottex);
1294  else
1295    command_name_condition ();
1296}
1297
1298/* Begin an insertion where the lines are not filled or indented. */
1299void
1300cm_flushleft ()
1301{
1302  begin_insertion (flushleft);
1303}
1304
1305/* Begin an insertion where the lines are not filled, and each line is
1306   forced to the right-hand side of the page. */
1307void
1308cm_flushright ()
1309{
1310  begin_insertion (flushright);
1311}
1312
1313void
1314cm_menu ()
1315{
1316  if (current_node == NULL)
1317    {
1318      warning (_("@menu seen before first @node, creating `Top' node"));
1319      warning (_("perhaps your @top node should be wrapped in @ifnottex rather than @ifinfo?"));
1320      /* Include @top command so we can construct the implicit node tree.  */
1321      execute_string ("@node top\n@top Top\n");
1322    }
1323  begin_insertion (menu);
1324}
1325
1326void
1327cm_detailmenu ()
1328{
1329  if (current_node == NULL)
1330    { /* Problems anyway, @detailmenu should always be inside @menu.  */
1331      warning (_("@detailmenu seen before first node, creating `Top' node"));
1332      execute_string ("@node top\n@top Top\n");
1333    }
1334  begin_insertion (detailmenu);
1335}
1336
1337/* End existing insertion block. */
1338void
1339cm_end ()
1340{
1341  char *temp;
1342  enum insertion_type type;
1343
1344  if (!insertion_level)
1345    {
1346      line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command);
1347      return;
1348    }
1349
1350  get_rest_of_line (0, &temp);
1351
1352  if (temp[0] == 0)
1353    line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command);
1354
1355  type = find_type_from_name (temp);
1356
1357  if (type == bad_type)
1358    {
1359      line_error (_("Bad argument to `%s', `%s', using `%s'"),
1360           command, temp, insertion_type_pname (current_insertion_type ()));
1361    }
1362  if (xml && type == menu) /* fixme */
1363    {
1364      xml_end_menu ();
1365    }
1366  end_insertion (type);
1367  free (temp);
1368}
1369
1370/* @itemx, @item. */
1371
1372static int itemx_flag = 0;
1373
1374/* Return whether CMD takes a brace-delimited {arg}.  */
1375/*static */int
1376command_needs_braces (cmd)
1377     char *cmd;
1378{
1379  int i;
1380  for (i = 0; command_table[i].name; i++)
1381    {
1382      if (STREQ (command_table[i].name, cmd))
1383        return command_table[i].argument_in_braces == BRACE_ARGS;
1384    }
1385
1386  return 0; /* macro or alias */
1387}
1388
1389
1390void
1391cm_item ()
1392{
1393  char *rest_of_line, *item_func;
1394
1395  /* Can only hack "@item" while inside of an insertion. */
1396  if (insertion_level)
1397    {
1398      INSERTION_ELT *stack = insertion_stack;
1399      int original_input_text_offset;
1400
1401      skip_whitespace ();
1402      original_input_text_offset = input_text_offset;
1403
1404      get_rest_of_line (0, &rest_of_line);
1405      item_func = current_item_function ();
1406
1407    /* Do the right thing depending on which insertion function is active. */
1408    switch_top:
1409      switch (stack->insertion)
1410        {
1411        case multitable:
1412          multitable_item ();
1413          /* Support text directly after the @item.  */
1414          if (*rest_of_line)
1415            {
1416              line_number--;
1417              input_text_offset = original_input_text_offset;
1418            }
1419          break;
1420
1421        case ifclear:
1422        case ifhtml:
1423        case ifinfo:
1424        case ifnothtml:
1425        case ifnotinfo:
1426        case ifnotplaintext:
1427        case ifnottex:
1428        case ifplaintext:
1429        case ifset:
1430        case iftex:
1431        case rawhtml:
1432        case rawtex:
1433        case tex:
1434        case cartouche:
1435          stack = stack->next;
1436          if (!stack)
1437            goto no_insertion;
1438          else
1439            goto switch_top;
1440          break;
1441
1442        case menu:
1443        case quotation:
1444        case example:
1445        case smallexample:
1446        case lisp:
1447        case smalllisp:
1448        case format:
1449        case smallformat:
1450        case display:
1451        case smalldisplay:
1452        case group:
1453          line_error (_("@%s not meaningful inside `@%s' block"),
1454                      command,
1455                      insertion_type_pname (current_insertion_type ()));
1456          break;
1457
1458        case itemize:
1459        case enumerate:
1460          if (itemx_flag)
1461            {
1462              line_error (_("@itemx not meaningful inside `%s' block"),
1463                          insertion_type_pname (current_insertion_type ()));
1464            }
1465          else
1466            {
1467              if (html)
1468		{
1469		  if (in_paragraph)
1470		    {
1471		      add_word ("</p>");
1472		      in_paragraph = 0;
1473		    }
1474		  add_word ("<li>");
1475		}
1476	      else if (xml)
1477		xml_begin_item ();
1478              else
1479                {
1480                  start_paragraph ();
1481                  kill_self_indent (-1);
1482                  filling_enabled = indented_fill = 1;
1483
1484                  if (current_item_function ())
1485                    {
1486                      output_column = current_indent - 2;
1487                      indent (output_column);
1488
1489                      /* The item marker can be given with or without
1490                         braces -- @bullet and @bullet{} are both ok.
1491                         Or it might be something that doesn't take
1492                         braces at all, such as "o" or "#" or "@ ".
1493                         Thus, only supply braces if the item marker is
1494                         a command, they haven't supplied braces
1495                         themselves, and we know it needs them.  */
1496                      if (item_func && *item_func)
1497                        {
1498                          if (*item_func == COMMAND_PREFIX
1499                              && item_func[strlen (item_func) - 1] != '}'
1500                              && command_needs_braces (item_func + 1))
1501                            execute_string ("%s{}", item_func);
1502                          else
1503                            execute_string ("%s", item_func);
1504                        }
1505                      insert (' ');
1506                      output_column++;
1507                    }
1508                  else
1509                    enumerate_item ();
1510
1511                  /* Special hack.  This makes `close_paragraph' a no-op until
1512                     `start_paragraph' has been called. */
1513                  must_start_paragraph = 1;
1514                }
1515
1516	      /* Handle text directly after the @item.  */
1517	      if (*rest_of_line)
1518		{
1519		  line_number--;
1520		  input_text_offset = original_input_text_offset;
1521		}
1522            }
1523          break;
1524
1525        case table:
1526        case ftable:
1527        case vtable:
1528          if (html)
1529            {
1530              static int last_html_output_position = 0;
1531
1532              /* If nothing has been output since the last <dd>,
1533                 remove the empty <dd> element.  Some browsers render
1534                 an extra empty line for <dd><dt>, which makes @itemx
1535                 conversion look ugly.  */
1536              if (last_html_output_position == output_position
1537                  && strncmp ((char *) output_paragraph, "<dd>",
1538                                output_paragraph_offset) == 0)
1539                output_paragraph_offset = 0;
1540
1541              /* Force the browser to render one blank line before
1542                 each new @item in a table.  But don't do that unless
1543                 this is the first <dt> after the <dl>, or if we are
1544                 converting @itemx.
1545
1546                 Note that there are some browsers which ignore <br>
1547                 in this context, but I cannot find any way to force
1548                 them all render exactly one blank line.  */
1549              if (!itemx_flag
1550                  && strncmp ((char *) output_paragraph
1551                              + output_paragraph_offset - sizeof (dl_tag) + 1,
1552                              dl_tag, sizeof (dl_tag) - 1) != 0)
1553                add_word ("<br>");
1554
1555              add_word ("<dt>");
1556              if (item_func && *item_func)
1557                execute_string ("%s{%s}", item_func, rest_of_line);
1558              else
1559                execute_string ("%s", rest_of_line);
1560
1561              if (current_insertion_type () == ftable)
1562                execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
1563
1564              if (current_insertion_type () == vtable)
1565                execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
1566              /* Make sure output_position is updated, so we could
1567                 remember it.  */
1568              close_single_paragraph ();
1569              last_html_output_position = output_position;
1570              add_word ("<dd>");
1571            }
1572	  else if (xml) /* && docbook)*/ /* 05-08 */
1573	    {
1574	      xml_begin_table_item ();
1575              if (item_func && *item_func)
1576                execute_string ("%s{%s}", item_func, rest_of_line);
1577              else
1578                execute_string ("%s", rest_of_line);
1579	      xml_continue_table_item ();
1580	    }
1581          else
1582            {
1583              /* We need this to determine if we have two @item's in a row
1584                 (see test just below).  */
1585              static int last_item_output_position = 0;
1586
1587              /* Get rid of extra characters. */
1588              kill_self_indent (-1);
1589
1590              /* If we have one @item followed directly by another @item,
1591                 we need to insert a blank line.  This is not true for
1592                 @itemx, though.  */
1593              if (!itemx_flag && last_item_output_position == output_position)
1594                insert ('\n');
1595
1596              /* `close_paragraph' almost does what we want.  The problem
1597                 is when paragraph_is_open, and last_char_was_newline, and
1598                 the last newline has been turned into a space, because
1599                 filling_enabled. I handle it here. */
1600              if (last_char_was_newline && filling_enabled &&
1601                  paragraph_is_open)
1602                insert ('\n');
1603              close_paragraph ();
1604
1605#if defined (INDENT_PARAGRAPHS_IN_TABLE)
1606              /* Indent on a new line, but back up one indentation level. */
1607              {
1608                int save = inhibit_paragraph_indentation;
1609                inhibit_paragraph_indentation = 1;
1610                /* At this point, inserting any non-whitespace character will
1611                   force the existing indentation to be output. */
1612                add_char ('i');
1613                inhibit_paragraph_indentation = save;
1614              }
1615#else /* !INDENT_PARAGRAPHS_IN_TABLE */
1616              add_char ('i');
1617#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
1618
1619              output_paragraph_offset--;
1620              kill_self_indent (default_indentation_increment + 1);
1621
1622              /* Add item's argument to the line. */
1623              filling_enabled = 0;
1624              if (item_func && *item_func)
1625                execute_string ("%s{%s}", item_func, rest_of_line);
1626              else
1627                execute_string ("%s", rest_of_line);
1628
1629              if (current_insertion_type () == ftable)
1630                execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
1631              else if (current_insertion_type () == vtable)
1632                execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
1633
1634              /* Start a new line, and let start_paragraph ()
1635                 do the indenting of it for you. */
1636              close_single_paragraph ();
1637              indented_fill = filling_enabled = 1;
1638              last_item_output_position = output_position;
1639            }
1640        }
1641      free (rest_of_line);
1642    }
1643  else
1644    {
1645    no_insertion:
1646      line_error (_("%c%s found outside of an insertion block"),
1647                  COMMAND_PREFIX, command);
1648    }
1649}
1650
1651void
1652cm_itemx ()
1653{
1654  itemx_flag++;
1655  cm_item ();
1656  itemx_flag--;
1657}
1658