source: trunk/third/texinfo/makeinfo/insertion.c @ 18945

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