summaryrefslogtreecommitdiffstats
path: root/contrib/texinfo/makeinfo
diff options
context:
space:
mode:
authorru <ru@FreeBSD.org>2000-01-17 10:39:58 +0000
committerru <ru@FreeBSD.org>2000-01-17 10:39:58 +0000
commit05f7b4b96773cc26ff78d5e68babd66861aa07a8 (patch)
tree523981ba621cd82428ac347585e7631052314d54 /contrib/texinfo/makeinfo
parent15da023077f02380356169c9b5f4a62a6dc51f63 (diff)
downloadFreeBSD-src-05f7b4b96773cc26ff78d5e68babd66861aa07a8.zip
FreeBSD-src-05f7b4b96773cc26ff78d5e68babd66861aa07a8.tar.gz
Virgin import of GNU texinfo 4.0
Diffstat (limited to 'contrib/texinfo/makeinfo')
-rw-r--r--contrib/texinfo/makeinfo/README4
-rw-r--r--contrib/texinfo/makeinfo/cmds.c1121
-rw-r--r--contrib/texinfo/makeinfo/cmds.h50
-rw-r--r--contrib/texinfo/makeinfo/defun.c663
-rw-r--r--contrib/texinfo/makeinfo/defun.h31
-rw-r--r--contrib/texinfo/makeinfo/files.c529
-rw-r--r--contrib/texinfo/makeinfo/files.h45
-rw-r--r--contrib/texinfo/makeinfo/footnote.c359
-rw-r--r--contrib/texinfo/makeinfo/footnote.h37
-rw-r--r--contrib/texinfo/makeinfo/html.c182
-rw-r--r--contrib/texinfo/makeinfo/html.h44
-rw-r--r--contrib/texinfo/makeinfo/index.c823
-rw-r--r--contrib/texinfo/makeinfo/index.h36
-rw-r--r--contrib/texinfo/makeinfo/insertion.c1368
-rw-r--r--contrib/texinfo/makeinfo/insertion.h61
-rw-r--r--contrib/texinfo/makeinfo/lang.c415
-rw-r--r--contrib/texinfo/makeinfo/lang.h86
-rw-r--r--contrib/texinfo/makeinfo/macro.c1114
-rw-r--r--contrib/texinfo/makeinfo/macro.h71
-rw-r--r--contrib/texinfo/makeinfo/makeinfo.c8639
-rw-r--r--contrib/texinfo/makeinfo/makeinfo.h247
-rw-r--r--contrib/texinfo/makeinfo/multi.c214
-rw-r--r--contrib/texinfo/makeinfo/node.c1568
-rw-r--r--contrib/texinfo/makeinfo/node.h111
-rw-r--r--contrib/texinfo/makeinfo/sectioning.c691
-rw-r--r--contrib/texinfo/makeinfo/sectioning.h80
-rw-r--r--contrib/texinfo/makeinfo/toc.c476
-rw-r--r--contrib/texinfo/makeinfo/toc.h49
28 files changed, 11703 insertions, 7411 deletions
diff --git a/contrib/texinfo/makeinfo/README b/contrib/texinfo/makeinfo/README
index 2bfe6e1..a6f97eb 100644
--- a/contrib/texinfo/makeinfo/README
+++ b/contrib/texinfo/makeinfo/README
@@ -1,8 +1,8 @@
makeinfo is a standalone program to convert Texinfo source into Info
files readable with standalone info or M-x info in Emacs.
-makeinfo can also output plain ASCII. Work to support HTML and Troff
-output is almost complete.
+makeinfo can also output plain ASCII (with --no-headers)
+or HTML (with --html).
The Emacs function M-x texinfo-format-buffer does more or less the same
job, but makeinfo is faster and gives better error messages.
diff --git a/contrib/texinfo/makeinfo/cmds.c b/contrib/texinfo/makeinfo/cmds.c
new file mode 100644
index 0000000..65d382e
--- /dev/null
+++ b/contrib/texinfo/makeinfo/cmds.c
@@ -0,0 +1,1121 @@
+/* cmds.c -- Texinfo commands.
+ $Id: cmds.c,v 1.57 1999/09/19 16:39:35 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "cmds.h"
+#include "defun.h"
+#include "files.h"
+#include "footnote.h"
+#include "insertion.h"
+#include "lang.h"
+#include "macro.h"
+#include "makeinfo.h"
+#include "node.h"
+#include "sectioning.h"
+#include "toc.h"
+
+#ifdef TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+
+void insert_self (), insert_space (), cm_ignore_line (), cm_ignore_arg ();
+
+void
+ cm_TeX (), cm_acronym (), cm_asterisk (), cm_b (), cm_bullet (), cm_cite (),
+ cm_code (), cm_copyright (), cm_ctrl (), cm_dfn (), cm_dircategory (),
+ cm_direntry (), cm_dmn (), cm_dots (), cm_emph (), cm_enddots (), cm_i (),
+ cm_image (), cm_kbd (), cm_key (), cm_no_op (),
+ cm_novalidate (), cm_not_fixed_width (), cm_r (),
+ cm_strong (), cm_var (), cm_sc (), cm_w (), cm_email (), cm_url ();
+
+void
+ cm_anchor (), cm_node (), cm_menu (), cm_xref (), cm_ftable (),
+ cm_vtable (), cm_pxref (), cm_inforef (), cm_uref (), cm_email (),
+ cm_quotation (), cm_display (), cm_smalldisplay (), cm_itemize (),
+ cm_enumerate (), cm_tab (), cm_table (), cm_itemx (), cm_noindent (),
+ cm_setfilename (), cm_br (), cm_sp (), cm_page (), cm_group (),
+ cm_center (), cm_ref (), cm_include (), cm_bye (), cm_item (), cm_end (),
+ cm_kindex (), cm_cindex (), cm_findex (), cm_pindex (), cm_vindex (),
+ cm_tindex (), cm_synindex (), cm_printindex (), cm_minus (),
+ cm_example (), cm_smallexample (), cm_smalllisp (), cm_lisp (),
+ cm_format (), cm_smallformat (), cm_exdent (), cm_defindex (),
+ cm_defcodeindex (), cm_result (), cm_expansion (), cm_equiv (),
+ cm_print (), cm_error (), cm_point (), cm_today (), cm_flushleft (),
+ cm_flushright (), cm_finalout (), cm_cartouche (), cm_detailmenu (),
+ cm_multitable (), cm_settitle (), cm_titlefont (), cm_tt ();
+
+/* Conditionals. */
+void cm_set (), cm_clear (), cm_ifset (), cm_ifclear ();
+void cm_value (), cm_ifeq ();
+
+/* Options. */
+static void cm_paragraphindent (), cm_exampleindent ();
+
+/* Internals. */
+static void cm_obsolete ();
+
+/* A random string. */
+static const char small_tag[] = "small";
+
+/* The dispatch table. */
+COMMAND command_table[] = {
+ { "\t", insert_space, NO_BRACE_ARGS },
+ { "\n", insert_space, NO_BRACE_ARGS },
+ { " ", insert_self, NO_BRACE_ARGS },
+ { "!", insert_self, NO_BRACE_ARGS },
+ { "\"", cm_accent_umlaut, MAYBE_BRACE_ARGS },
+ { "'", cm_accent_acute, MAYBE_BRACE_ARGS },
+ { "*", cm_asterisk, NO_BRACE_ARGS },
+ { ",", cm_accent_cedilla, MAYBE_BRACE_ARGS },
+ { "-", cm_no_op, NO_BRACE_ARGS },
+ { ".", insert_self, NO_BRACE_ARGS },
+ { ":", cm_no_op, NO_BRACE_ARGS },
+ { "=", cm_accent, MAYBE_BRACE_ARGS },
+ { "?", insert_self, NO_BRACE_ARGS },
+ { "@", insert_self, NO_BRACE_ARGS },
+ { "^", cm_accent_hat, MAYBE_BRACE_ARGS },
+ { "`", cm_accent_grave, MAYBE_BRACE_ARGS },
+ { "{", insert_self, NO_BRACE_ARGS },
+ { "|", cm_no_op, NO_BRACE_ARGS },
+ { "}", insert_self, NO_BRACE_ARGS },
+ { "~", cm_accent_tilde, MAYBE_BRACE_ARGS },
+ { "AA", cm_special_char, BRACE_ARGS },
+ { "AE", cm_special_char, BRACE_ARGS },
+ { "H", cm_accent, MAYBE_BRACE_ARGS },
+ { "L", cm_special_char, BRACE_ARGS },
+ { "O", cm_special_char, BRACE_ARGS },
+ { "OE", cm_special_char, BRACE_ARGS },
+ { "TeX", cm_TeX, BRACE_ARGS },
+ { "aa", cm_special_char, BRACE_ARGS },
+ { "acronym", cm_acronym, BRACE_ARGS },
+ { "ae", cm_special_char, BRACE_ARGS },
+ { "afourpaper", cm_ignore_line, NO_BRACE_ARGS },
+ { "alias", cm_alias, NO_BRACE_ARGS },
+ { "anchor", cm_anchor, BRACE_ARGS },
+ { "appendix", cm_appendix, NO_BRACE_ARGS },
+ { "appendixsection", cm_appendixsec, NO_BRACE_ARGS },
+ { "appendixsec", cm_appendixsec, NO_BRACE_ARGS },
+ { "appendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS },
+ { "appendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS },
+ { "asis", cm_no_op, BRACE_ARGS },
+ { "b", cm_b, BRACE_ARGS },
+ { "bullet", cm_bullet, BRACE_ARGS },
+ { "bye", cm_bye, NO_BRACE_ARGS },
+ { "c", cm_ignore_line, NO_BRACE_ARGS },
+ { "cartouche", cm_cartouche, NO_BRACE_ARGS },
+ { "center", cm_center, NO_BRACE_ARGS },
+ { "centerchap", cm_unnumbered, NO_BRACE_ARGS },
+ { "chapheading", cm_chapheading, NO_BRACE_ARGS },
+ { "chapter", cm_chapter, NO_BRACE_ARGS },
+ { "cindex", cm_cindex, NO_BRACE_ARGS },
+ { "cite", cm_cite, BRACE_ARGS },
+ { "clear", cm_clear, NO_BRACE_ARGS },
+ { "code", cm_code, BRACE_ARGS },
+ { "command", cm_code, BRACE_ARGS },
+ { "comment", cm_ignore_line, NO_BRACE_ARGS },
+ { "contents", cm_contents, NO_BRACE_ARGS },
+ { "copyright", cm_copyright, BRACE_ARGS },
+ { "ctrl", cm_obsolete, BRACE_ARGS },
+ { "defcodeindex", cm_defcodeindex, NO_BRACE_ARGS },
+ { "defcv", cm_defun, NO_BRACE_ARGS },
+ { "defcvx", cm_defun, NO_BRACE_ARGS },
+ { "deffn", cm_defun, NO_BRACE_ARGS },
+ { "deffnx", cm_defun, NO_BRACE_ARGS },
+ { "defindex", cm_defindex, NO_BRACE_ARGS },
+ { "definfoenclose", cm_definfoenclose, NO_BRACE_ARGS },
+ { "defivar", cm_defun, NO_BRACE_ARGS },
+ { "defivarx", cm_defun, NO_BRACE_ARGS },
+ { "defmac", cm_defun, NO_BRACE_ARGS },
+ { "defmacx", cm_defun, NO_BRACE_ARGS },
+ { "defmethod", cm_defun, NO_BRACE_ARGS },
+ { "defmethodx", cm_defun, NO_BRACE_ARGS },
+ { "defop", cm_defun, NO_BRACE_ARGS },
+ { "defopt", cm_defun, NO_BRACE_ARGS },
+ { "defoptx", cm_defun, NO_BRACE_ARGS },
+ { "defopx", cm_defun, NO_BRACE_ARGS },
+ { "defspec", cm_defun, NO_BRACE_ARGS },
+ { "defspecx", cm_defun, NO_BRACE_ARGS },
+ { "deftp", cm_defun, NO_BRACE_ARGS },
+ { "deftpx", cm_defun, NO_BRACE_ARGS },
+ { "deftypefn", cm_defun, NO_BRACE_ARGS },
+ { "deftypefnx", cm_defun, NO_BRACE_ARGS },
+ { "deftypefun", cm_defun, NO_BRACE_ARGS },
+ { "deftypefunx", cm_defun, NO_BRACE_ARGS },
+ { "deftypeivar", cm_defun, NO_BRACE_ARGS },
+ { "deftypeivarx", cm_defun, NO_BRACE_ARGS },
+ { "deftypemethod", cm_defun, NO_BRACE_ARGS },
+ { "deftypemethodx", cm_defun, NO_BRACE_ARGS },
+ { "deftypeop", cm_defun, NO_BRACE_ARGS },
+ { "deftypeopx", cm_defun, NO_BRACE_ARGS },
+ { "deftypevar", cm_defun, NO_BRACE_ARGS },
+ { "deftypevarx", cm_defun, NO_BRACE_ARGS },
+ { "deftypevr", cm_defun, NO_BRACE_ARGS },
+ { "deftypevrx", cm_defun, NO_BRACE_ARGS },
+ { "defun", cm_defun, NO_BRACE_ARGS },
+ { "defunx", cm_defun, NO_BRACE_ARGS },
+ { "defvar", cm_defun, NO_BRACE_ARGS },
+ { "defvarx", cm_defun, NO_BRACE_ARGS },
+ { "defvr", cm_defun, NO_BRACE_ARGS },
+ { "defvrx", cm_defun, NO_BRACE_ARGS },
+ { "detailmenu", cm_detailmenu, NO_BRACE_ARGS },
+ { "dfn", cm_dfn, BRACE_ARGS },
+ { "dircategory", cm_dircategory, NO_BRACE_ARGS },
+ { "direntry", cm_direntry, NO_BRACE_ARGS },
+ { "display", cm_display, NO_BRACE_ARGS },
+ { "dmn", cm_no_op, BRACE_ARGS },
+ { "documentencoding", cm_documentencoding, NO_BRACE_ARGS },
+ { "documentlanguage", cm_documentlanguage, NO_BRACE_ARGS },
+ { "dotaccent", cm_accent, MAYBE_BRACE_ARGS },
+ { "dotless", cm_dotless, BRACE_ARGS },
+ { "dots", cm_dots, BRACE_ARGS },
+ { "email", cm_email, BRACE_ARGS },
+ { "emph", cm_emph, BRACE_ARGS },
+ { "end", cm_end, NO_BRACE_ARGS },
+ { "enddots", cm_enddots, BRACE_ARGS },
+ { "enumerate", cm_enumerate, NO_BRACE_ARGS },
+ { "env", cm_code, BRACE_ARGS },
+ { "equiv", cm_equiv, BRACE_ARGS },
+ { "error", cm_error, BRACE_ARGS },
+ { "example", cm_example, NO_BRACE_ARGS },
+ { "exampleindent", cm_exampleindent, NO_BRACE_ARGS },
+ { "exclamdown", cm_special_char, BRACE_ARGS },
+ { "exdent", cm_exdent, NO_BRACE_ARGS },
+ { "expansion", cm_expansion, BRACE_ARGS },
+ { "file", cm_code, BRACE_ARGS },
+ { "finalout", cm_no_op, NO_BRACE_ARGS },
+ { "findex", cm_findex, NO_BRACE_ARGS },
+ { "flushleft", cm_flushleft, NO_BRACE_ARGS },
+ { "flushright", cm_flushright, NO_BRACE_ARGS },
+ { "footnote", cm_footnote, NO_BRACE_ARGS}, /* self-arg eater */
+ { "footnotestyle", cm_footnotestyle, NO_BRACE_ARGS },
+ { "format", cm_format, NO_BRACE_ARGS },
+ { "ftable", cm_ftable, NO_BRACE_ARGS },
+ { "group", cm_group, NO_BRACE_ARGS },
+ { "heading", cm_heading, NO_BRACE_ARGS },
+ { "headings", cm_ignore_line, NO_BRACE_ARGS },
+ { "html", cm_html, NO_BRACE_ARGS },
+ { "hyphenation", cm_ignore_arg, BRACE_ARGS },
+ { "i", cm_i, BRACE_ARGS },
+ { "ifclear", cm_ifclear, NO_BRACE_ARGS },
+ { "ifeq", cm_ifeq, NO_BRACE_ARGS },
+ { "ifhtml", cm_ifhtml, NO_BRACE_ARGS },
+ { "ifinfo", cm_ifinfo, NO_BRACE_ARGS },
+ { "ifnothtml", cm_ifnothtml, NO_BRACE_ARGS },
+ { "ifnotinfo", cm_ifnotinfo, NO_BRACE_ARGS },
+ { "ifnottex", cm_ifnottex, NO_BRACE_ARGS },
+ { "ifset", cm_ifset, NO_BRACE_ARGS },
+ { "iftex", cm_iftex, NO_BRACE_ARGS },
+ { "ignore", command_name_condition, NO_BRACE_ARGS },
+ { "image", cm_image, BRACE_ARGS },
+ { "include", cm_include, NO_BRACE_ARGS },
+ { "inforef", cm_inforef, BRACE_ARGS },
+ { "item", cm_item, NO_BRACE_ARGS },
+ { "itemize", cm_itemize, NO_BRACE_ARGS },
+ { "itemx", cm_itemx, NO_BRACE_ARGS },
+ { "kbd", cm_kbd, BRACE_ARGS },
+ { "kbdinputstyle", cm_ignore_line, NO_BRACE_ARGS },
+ { "key", cm_key, BRACE_ARGS },
+ { "kindex", cm_kindex, NO_BRACE_ARGS },
+ { "l", cm_special_char, BRACE_ARGS },
+ { "lisp", cm_lisp, NO_BRACE_ARGS },
+ { "lowersections", cm_lowersections, NO_BRACE_ARGS },
+ { "macro", cm_macro, NO_BRACE_ARGS },
+ { "majorheading", cm_majorheading, NO_BRACE_ARGS },
+ { "math", cm_no_op, BRACE_ARGS },
+ { "menu", cm_menu, NO_BRACE_ARGS },
+ { "minus", cm_minus, BRACE_ARGS },
+ { "multitable", cm_multitable, NO_BRACE_ARGS },
+ { "need", cm_ignore_line, NO_BRACE_ARGS },
+ { "node", cm_node, NO_BRACE_ARGS },
+ { "noindent", cm_noindent, NO_BRACE_ARGS },
+ { "noindent", cm_novalidate, NO_BRACE_ARGS },
+ { "nwnode", cm_node, NO_BRACE_ARGS },
+ { "o", cm_special_char, BRACE_ARGS },
+ { "oe", cm_special_char, BRACE_ARGS },
+ { "option", cm_code, BRACE_ARGS },
+ { "page", cm_no_op, NO_BRACE_ARGS },
+ { "pagesizes", cm_ignore_line, NO_BRACE_ARGS },
+ { "paragraphindent", cm_paragraphindent, NO_BRACE_ARGS },
+ { "pindex", cm_pindex, NO_BRACE_ARGS },
+ { "point", cm_point, BRACE_ARGS },
+ { "pounds", cm_special_char, BRACE_ARGS },
+ { "print", cm_print, BRACE_ARGS },
+ { "printindex", cm_printindex, NO_BRACE_ARGS },
+ { "pxref", cm_pxref, BRACE_ARGS },
+ { "questiondown", cm_special_char, BRACE_ARGS },
+ { "quotation", cm_quotation, NO_BRACE_ARGS },
+ { "r", cm_r, BRACE_ARGS },
+ { "raisesections", cm_raisesections, NO_BRACE_ARGS },
+ { "ref", cm_ref, BRACE_ARGS },
+ { "refill", cm_no_op, NO_BRACE_ARGS },
+ { "result", cm_result, BRACE_ARGS },
+ { "ringaccent", cm_accent, MAYBE_BRACE_ARGS },
+ { "rmacro", cm_rmacro, NO_BRACE_ARGS },
+ { "samp", cm_code, BRACE_ARGS },
+ { "sc", cm_sc, BRACE_ARGS },
+ { "section", cm_section, NO_BRACE_ARGS },
+ { "set", cm_set, NO_BRACE_ARGS },
+ { "setchapternewpage", cm_ignore_line, NO_BRACE_ARGS },
+ { "setchapterstyle", cm_obsolete, NO_BRACE_ARGS },
+ { "setcontentsaftertitlepage", cm_no_op, NO_BRACE_ARGS },
+ { "setfilename", cm_setfilename, NO_BRACE_ARGS },
+ { "setshortcontentsaftertitlepage", cm_no_op, NO_BRACE_ARGS },
+ { "settitle", cm_settitle, NO_BRACE_ARGS },
+ { "shortcontents", cm_shortcontents, NO_BRACE_ARGS },
+ { "shorttitlepage", cm_ignore_line, NO_BRACE_ARGS },
+ { "smallbook", cm_ignore_line, NO_BRACE_ARGS },
+ { "smalldisplay", cm_smalldisplay, NO_BRACE_ARGS },
+ { "smallexample", cm_smallexample, NO_BRACE_ARGS },
+ { "smallformat", cm_smallformat, NO_BRACE_ARGS },
+ { "smalllisp", cm_smalllisp, NO_BRACE_ARGS },
+ { "sp", cm_sp, NO_BRACE_ARGS },
+ { "ss", cm_special_char, BRACE_ARGS },
+ { "strong", cm_strong, BRACE_ARGS },
+ { "subheading", cm_subheading, NO_BRACE_ARGS },
+ { "subsection", cm_subsection, NO_BRACE_ARGS },
+ { "subsubheading", cm_subsubheading, NO_BRACE_ARGS },
+ { "subsubsection", cm_subsubsection, NO_BRACE_ARGS },
+ { "summarycontents", cm_no_op, NO_BRACE_ARGS },
+ { "syncodeindex", cm_synindex, NO_BRACE_ARGS },
+ { "synindex", cm_synindex, NO_BRACE_ARGS },
+ { "t", cm_tt, BRACE_ARGS },
+ { "tab", cm_tab, NO_BRACE_ARGS },
+ { "table", cm_table, NO_BRACE_ARGS },
+ { "tex", cm_tex, NO_BRACE_ARGS },
+ { "tieaccent", cm_accent, MAYBE_BRACE_ARGS },
+ { "tindex", cm_tindex, NO_BRACE_ARGS },
+ { "titlefont", cm_titlefont, BRACE_ARGS },
+ { "titlepage", command_name_condition, NO_BRACE_ARGS },
+ { "today", cm_today, BRACE_ARGS },
+ { "top", cm_top, NO_BRACE_ARGS },
+ { "u", cm_accent, MAYBE_BRACE_ARGS },
+ { "ubaraccent", cm_accent, MAYBE_BRACE_ARGS },
+ { "udotaccent", cm_accent, MAYBE_BRACE_ARGS },
+ { "unmacro", cm_unmacro, NO_BRACE_ARGS },
+ { "unnumbered", cm_unnumbered, NO_BRACE_ARGS },
+ { "unnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS },
+ { "unnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS },
+ { "unnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS },
+ { "uref", cm_uref, BRACE_ARGS },
+ { "url", cm_url, BRACE_ARGS },
+ { "v", cm_accent, MAYBE_BRACE_ARGS },
+ { "value", cm_value, BRACE_ARGS },
+ { "var", cm_var, BRACE_ARGS },
+ { "vindex", cm_vindex, NO_BRACE_ARGS },
+ { "vtable", cm_vtable, NO_BRACE_ARGS },
+ { "w", cm_w, BRACE_ARGS },
+ { "xref", cm_xref, BRACE_ARGS },
+
+ /* Deprecated commands. These used to be for italics. */
+ { "iappendix", cm_ideprecated, NO_BRACE_ARGS },
+ { "iappendixsec", cm_ideprecated, NO_BRACE_ARGS },
+ { "iappendixsection", cm_ideprecated, NO_BRACE_ARGS },
+ { "iappendixsubsec", cm_ideprecated, NO_BRACE_ARGS },
+ { "iappendixsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
+ { "ichapter", cm_ideprecated, NO_BRACE_ARGS },
+ { "isection", cm_ideprecated, NO_BRACE_ARGS },
+ { "isubsection", cm_ideprecated, NO_BRACE_ARGS },
+ { "isubsubsection", cm_ideprecated, NO_BRACE_ARGS },
+ { "iunnumbered", cm_ideprecated, NO_BRACE_ARGS },
+ { "iunnumberedsec", cm_ideprecated, NO_BRACE_ARGS },
+ { "iunnumberedsubsec", cm_ideprecated, NO_BRACE_ARGS },
+ { "iunnumberedsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
+
+ /* Now @include does what this was used to. */
+ { "infoinclude", cm_obsolete, NO_BRACE_ARGS },
+ { "titlespec", cm_obsolete, NO_BRACE_ARGS },
+
+ { NULL, NULL, NO_BRACE_ARGS }
+};
+
+/* The bulk of the Texinfo commands. */
+
+/* Commands which insert their own names. */
+void
+insert_self (arg)
+ int arg;
+{
+ if (arg == START)
+ add_word (command);
+}
+
+void
+insert_space (arg)
+ int arg;
+{
+ if (arg == START)
+ add_char (' ');
+}
+
+/* Force a line break in the output. */
+void
+cm_asterisk ()
+{
+ if (html)
+ add_word ("<br>");
+ else
+ {
+ close_single_paragraph ();
+ cm_noindent ();
+ }
+}
+
+/* Insert ellipsis. */
+void
+cm_dots (arg)
+ int arg;
+{
+ if (arg == START)
+ add_word (html ? "<small>...</small>" : "...");
+}
+
+/* Insert ellipsis for sentence end. */
+void
+cm_enddots (arg)
+ int arg;
+{
+ if (arg == START)
+ add_word (html ? "<small>...</small>." : "....");
+}
+
+void
+cm_bullet (arg)
+ int arg;
+{
+ if (arg == START)
+ {
+ if (html)
+ add_word ("&#149;");
+ else
+ add_char ('*');
+ }
+}
+
+void
+cm_minus (arg)
+ int arg;
+{
+ if (arg == START)
+ add_char ('-');
+}
+
+/* Insert "TeX". */
+void
+cm_TeX (arg)
+ int arg;
+{
+ if (arg == START)
+ add_word ("TeX");
+}
+
+/* Copyright symbol. */
+void
+cm_copyright (arg)
+ int arg;
+{
+ if (arg == START)
+ if (html)
+ add_word ("&copy;");
+ else
+ add_word ("(C)");
+}
+
+void
+cm_today (arg)
+ int arg;
+{
+ static char *months[12] =
+ { N_("January"), N_("February"), N_("March"), N_("April"), N_("May"),
+ N_("June"), N_("July"), N_("August"), N_("September"), N_("October"),
+ N_("November"), N_("December") };
+ if (arg == START)
+ {
+ time_t timer = time (0);
+ struct tm *ts = localtime (&timer);
+ add_word_args ("%d %s %d", ts->tm_mday, _(months[ts->tm_mon]),
+ ts->tm_year + 1900);
+ }
+}
+
+void
+cm_acronym (arg)
+ int arg;
+{
+ if (html)
+ insert_html_tag (arg, small_tag);
+}
+
+void
+cm_tt (arg)
+ int arg;
+{
+ /* @t{} is a no-op in Info. */
+ if (html)
+ insert_html_tag (arg, "tt");
+}
+
+void
+cm_code (arg)
+ int arg;
+{
+ extern int printing_index;
+
+ if (arg == START)
+ {
+ in_fixed_width_font++;
+
+ if (html)
+ insert_html_tag (arg, "code");
+ else if (!printing_index)
+ add_char ('`');
+ }
+ else if (html)
+ insert_html_tag (arg, "code");
+ else
+ {
+ if (!printing_index)
+ add_meta_char ('\'');
+ }
+}
+
+void
+cm_kbd (arg)
+ int arg;
+{
+ if (html)
+ { /* Seems like we should increment in_fixed_width_font for Info
+ format too, but then the quote-omitting special case gets
+ confused. Punt. */
+ if (arg == START)
+ in_fixed_width_font++;
+ insert_html_tag (arg, "kbd");
+ }
+ else
+ { /* People use @kbd in an example to get the "user input" font.
+ We don't want quotes in that case. */
+ if (!in_fixed_width_font)
+ cm_code (arg);
+ }
+}
+
+void
+cm_url (arg, start, end)
+{
+ if (html)
+ {
+ if (arg == START)
+ add_word ("&lt;<code>");
+ else
+ add_word ("</code>&gt;");
+ }
+ else
+ if (arg == START)
+ add_word ("<");
+ else
+ add_word (">");
+}
+
+void
+cm_key (arg)
+ int arg;
+{
+ if (html)
+ add_word (arg == START ? "&lt;" : "&gt;");
+ else
+ add_char (arg == START ? '<' : '>');
+}
+
+/* Handle a command that switches to a non-fixed-width font. */
+void
+not_fixed_width (arg)
+ int arg;
+{
+ if (arg == START)
+ in_fixed_width_font = 0;
+}
+
+/* @var in makeinfo just uppercases the text. */
+void
+cm_var (arg, start_pos, end_pos)
+ int arg, start_pos, end_pos;
+{
+ not_fixed_width (arg);
+
+ if (html)
+ insert_html_tag (arg, "var");
+ else if (arg == END)
+ {
+ while (start_pos < end_pos)
+ {
+ unsigned char c = output_paragraph[start_pos];
+ if (strchr ("[](),", c))
+ warning (_("unlikely character %c in @var"), c);
+ output_paragraph[start_pos] = coerce_to_upper (c);
+ start_pos++;
+ }
+ }
+}
+
+void
+cm_sc (arg, start_pos, end_pos)
+ int arg, start_pos, end_pos;
+{
+ not_fixed_width (arg);
+
+ if (arg == START)
+ {
+ if (html)
+ insert_html_tag (arg, small_tag);
+ }
+ else
+ {
+ int all_upper = 1;
+
+ if (html)
+ start_pos += sizeof (small_tag) + 2 - 1; /* skip <small> */
+
+ while (start_pos < end_pos)
+ {
+ unsigned char c = output_paragraph[start_pos];
+ if (!isupper (c))
+ all_upper = 0;
+ output_paragraph[start_pos] = coerce_to_upper (c);
+ start_pos++;
+ }
+ if (all_upper)
+ warning (_("@sc argument all uppercase, thus no effect"));
+
+ if (html)
+ insert_html_tag (arg, small_tag);
+ }
+}
+
+void
+cm_dfn (arg, position)
+ int arg, position;
+{
+ if (html)
+ insert_html_tag (arg, "dfn");
+ else if (arg == START)
+ add_char ('"');
+ else
+ add_meta_char ('"');
+}
+
+void
+cm_emph (arg)
+ int arg;
+{
+ if (html)
+ insert_html_tag (arg, "em");
+ else
+ add_char ('_');
+}
+
+void
+cm_strong (arg, position)
+ int arg, position;
+{
+ if (html)
+ insert_html_tag (arg, "strong");
+ else
+ add_char ('*');
+}
+
+void
+cm_cite (arg, position)
+ int arg, position;
+{
+ if (html)
+ insert_html_tag (arg, "cite");
+ else
+ {
+ if (arg == START)
+ add_char ('`');
+ else
+ add_char ('\'');
+ }
+}
+
+/* No highlighting, but argument switches fonts. */
+void
+cm_not_fixed_width (arg, start, end)
+ int arg, start, end;
+{
+ not_fixed_width (arg);
+}
+
+void
+cm_i (arg)
+ int arg;
+{
+ if (html)
+ insert_html_tag (arg, "i");
+ else
+ not_fixed_width (arg);
+}
+
+void
+cm_b (arg)
+ int arg;
+{
+ if (html)
+ insert_html_tag (arg, "b");
+ else
+ not_fixed_width (arg);
+}
+
+void
+cm_r (arg)
+ int arg;
+{
+ extern int printing_index;
+
+ /* People use @r{} in index entries like this:
+
+ @findex foo@r{, some text}
+
+ This is supposed to produce output as if the entry were saying
+ "@code{foo}, some text", since the "fn" index is typeset as
+ @code. The following attempts to do the same in HTML. Note that
+ this relies on the fact that only @code bumps up the variable
+ in_fixed_width_font while processing index entries in HTML mode. */
+ if (html && printing_index)
+ {
+ int level = in_fixed_width_font;
+
+ while (level--)
+ insert_html_tag (arg == START ? END : START, "code");
+ }
+
+ not_fixed_width (arg);
+}
+
+void
+cm_titlefont (arg)
+ int arg;
+{
+ not_fixed_width (arg);
+}
+
+/* Various commands are no-op's. */
+void
+cm_no_op ()
+{
+}
+
+
+/* For proofing single chapters, etc. */
+void
+cm_novalidate ()
+{
+ validating = 0;
+}
+
+
+/* Prevent the argument from being split across two lines. */
+void
+cm_w (arg, start, end)
+ int arg, start, end;
+{
+ if (arg == START)
+ non_splitting_words++;
+ else
+ non_splitting_words--;
+}
+
+
+/* Explain that this command is obsolete, thus the user shouldn't
+ do anything with it. */
+static void
+cm_obsolete (arg, start, end)
+ int arg, start, end;
+{
+ if (arg == START)
+ warning (_("%c%s is obsolete"), COMMAND_PREFIX, command);
+}
+
+
+/* This says to inhibit the indentation of the next paragraph, but
+ not of following paragraphs. */
+void
+cm_noindent ()
+{
+ if (!inhibit_paragraph_indentation)
+ inhibit_paragraph_indentation = -1;
+}
+
+/* I don't know exactly what to do with this. Should I allow
+ someone to switch filenames in the middle of output? Since the
+ file could be partially written, this doesn't seem to make sense.
+ Another option: ignore it, since they don't *really* want to
+ switch files. Finally, complain, or at least warn. It doesn't
+ really matter, anyway, since this doesn't get executed. */
+void
+cm_setfilename ()
+{
+ char *filename;
+ get_rest_of_line (1, &filename);
+ /* warning ("`@%s %s' encountered and ignored", command, filename); */
+ free (filename);
+}
+
+void
+cm_settitle ()
+{
+ get_rest_of_line (0, &title);
+}
+
+/* Ignore argument in braces. */
+void
+cm_ignore_arg (arg, start_pos, end_pos)
+ int arg, start_pos, end_pos;
+{
+ if (arg == END)
+ output_paragraph_offset = start_pos;
+}
+
+/* Ignore argument on rest of line. */
+void
+cm_ignore_line ()
+{
+ discard_until ("\n");
+}
+
+/* Insert the number of blank lines passed as argument. */
+void
+cm_sp ()
+{
+ int lines;
+ char *line;
+
+ get_rest_of_line (1, &line);
+
+ if (sscanf (line, "%d", &lines) != 1 || lines <= 0)
+ line_error (_("@sp requires a positive numeric argument, not `%s'"), line);
+ else
+ { /* Must disable filling since otherwise multiple newlines is like
+ multiple spaces. Must close paragraph since that's what the
+ manual says and that's what TeX does. */
+ int save_filling_enabled = filling_enabled;
+ filling_enabled = 0;
+
+ close_paragraph ();
+
+ while (lines--)
+ {
+ if (html)
+ insert_string ("<br><p>\n");
+ else
+ add_char ('\n');
+ }
+
+ filling_enabled = save_filling_enabled;
+ }
+ free (line);
+}
+
+/* @dircategory LINE outputs INFO-DIR-SECTION LINE, unless --no-headers. */
+void
+cm_dircategory ()
+{
+ char *line;
+
+ if (html)
+ cm_ignore_line ();
+ else
+ {
+ get_rest_of_line (1, &line);
+
+ if (!no_headers && !html)
+ {
+ kill_self_indent (-1); /* make sure there's no indentation */
+ insert_string ("INFO-DIR-SECTION ");
+ insert_string (line);
+ insert ('\n');
+ }
+
+ free (line);
+ }
+}
+
+/* Start a new line with just this text on it.
+ Then center the line of text.
+ This always ends the current paragraph. */
+void
+cm_center ()
+{
+ int i, start, length;
+ unsigned char *line;
+ int save_indented_fill = indented_fill;
+ int save_filling_enabled = filling_enabled;
+ int fudge_factor = 1;
+
+ close_paragraph ();
+ filling_enabled = indented_fill = 0;
+ cm_noindent ();
+ start = output_paragraph_offset;
+
+ if (html)
+ add_word ("<p align=\"center\">");
+
+ inhibit_output_flushing ();
+ get_rest_of_line (0, (char **)&line);
+ execute_string ("%s", (char *)line);
+ free (line);
+ uninhibit_output_flushing ();
+ if (html)
+ add_word ("</p>");
+
+ else
+ {
+ i = output_paragraph_offset - 1;
+ while (i > (start - 1) && output_paragraph[i] == '\n')
+ i--;
+
+ output_paragraph_offset = ++i;
+ length = output_paragraph_offset - start;
+
+ if (length < (fill_column - fudge_factor))
+ {
+ line = xmalloc (1 + length);
+ memcpy (line, (char *)(output_paragraph + start), length);
+
+ i = (fill_column - fudge_factor - length) / 2;
+ output_paragraph_offset = start;
+
+ while (i--)
+ insert (' ');
+
+ for (i = 0; i < length; i++)
+ insert (line[i]);
+
+ free (line);
+ }
+ }
+
+ insert ('\n');
+ close_paragraph ();
+ filling_enabled = save_filling_enabled;
+ indented_fill = save_indented_fill;
+}
+
+/* Show what an expression returns. */
+void
+cm_result (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word (html ? "=&gt;" : "=>");
+}
+
+/* What an expression expands to. */
+void
+cm_expansion (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word (html ? "==&gt;" : "==>");
+}
+
+/* Indicates two expressions are equivalent. */
+void
+cm_equiv (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word ("==");
+}
+
+/* What an expression may print. */
+void
+cm_print (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word ("-|");
+}
+
+/* An error signaled. */
+void
+cm_error (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word (html ? "error--&gt;" : "error-->");
+}
+
+/* The location of point in an example of a buffer. */
+void
+cm_point (arg)
+ int arg;
+{
+ if (arg == END)
+ add_word ("-!-");
+}
+
+/* @exdent: Start a new line with just this text on it.
+ The text is outdented one level if possible. */
+void
+cm_exdent ()
+{
+ char *line;
+ int save_indent = current_indent;
+ int save_in_fixed_width_font = in_fixed_width_font;
+
+ /* Read argument */
+ get_rest_of_line (0, &line);
+
+ /* Exdent the output. Actually this may be a no-op. */
+ if (current_indent)
+ current_indent -= default_indentation_increment;
+
+ /* @exdent arg is supposed to be in roman. */
+ in_fixed_width_font = 0;
+
+ /* The preceding newline already inserted the `current_indent'.
+ Remove one level's worth. */
+ kill_self_indent (default_indentation_increment);
+
+ if (html)
+ add_word ("<br>");
+
+ /* Can't close_single_paragraph, then we lose preceding blank lines. */
+ flush_output ();
+ execute_string ("%s", line);
+ free (line);
+
+ if (html)
+ add_word ("<br>");
+ close_single_paragraph ();
+
+ current_indent = save_indent;
+ in_fixed_width_font = save_in_fixed_width_font;
+}
+
+
+/* Remember this file, and move onto the next. */
+void
+cm_include ()
+{
+ char *filename;
+
+ if (macro_expansion_output_stream && !executing_string)
+ me_append_before_this_command ();
+
+ close_paragraph ();
+ get_rest_of_line (0, &filename);
+
+ if (macro_expansion_output_stream && !executing_string)
+ remember_itext (input_text, input_text_offset);
+
+ pushfile ();
+
+ /* In verbose mode we print info about including another file. */
+ if (verbose_mode)
+ {
+ int i = 0;
+ FSTACK *stack = filestack;
+
+ for (i = 0, stack = filestack; stack; stack = stack->next, i++);
+
+ i *= 2;
+
+ printf ("%*s", i, "");
+ printf ("%c%s %s\n", COMMAND_PREFIX, command, filename);
+ fflush (stdout);
+ }
+
+ if (!find_and_load (filename))
+ {
+ extern int errno;
+
+ popfile ();
+ line_number--;
+
+ /* Cannot "@include foo", in line 5 of "/wh/bar". */
+ line_error ("%c%s %s: %s", COMMAND_PREFIX, command, filename,
+ strerror (errno));
+
+ free (filename);
+ return;
+ }
+ else
+ {
+ if (macro_expansion_output_stream && !executing_string)
+ remember_itext (input_text, input_text_offset);
+ reader_loop ();
+ }
+ free (filename);
+ popfile ();
+}
+
+
+/* @bye: Signals end of processing. Easy to make this happen. */
+
+void
+cm_bye ()
+{
+ discard_braces (); /* should not have any unclosed braces left */
+ flush_output ();
+ input_text_offset = input_text_length;
+}
+
+/* @paragraphindent */
+
+static void
+cm_paragraphindent ()
+{
+ char *arg;
+
+ get_rest_of_line (1, &arg);
+ if (set_paragraph_indent (arg) != 0)
+ line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
+
+ free (arg);
+}
+
+/* @exampleindent: change indentation of example-like environments. */
+static int
+set_default_indentation_increment (string)
+ char *string;
+{
+ if (strcmp (string, "asis") == 0 || strcmp (string, _("asis")) == 0)
+ ;
+ else if (strcmp (string, "none") == 0 || strcmp (string, _("none")) == 0)
+ default_indentation_increment = 0;
+ else if (sscanf (string, "%d", &default_indentation_increment) != 1)
+ return -1;
+ return 0;
+}
+
+static void
+cm_exampleindent ()
+{
+ char *arg;
+
+ get_rest_of_line (1, &arg);
+ if (set_default_indentation_increment (arg) != 0)
+ line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
+
+ free (arg);
+}
diff --git a/contrib/texinfo/makeinfo/cmds.h b/contrib/texinfo/makeinfo/cmds.h
new file mode 100644
index 0000000..7edc810
--- /dev/null
+++ b/contrib/texinfo/makeinfo/cmds.h
@@ -0,0 +1,50 @@
+/* cmds.h -- declarations for cmds.c.
+ $Id: cmds.h,v 1.4 1999/04/25 20:43:51 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef CMDS_H
+#define CMDS_H
+
+/* The three arguments a command can get are a flag saying whether it is
+ before argument parsing (START) or after (END), the starting position
+ of the arguments, and the ending position. */
+typedef void COMMAND_FUNCTION (); /* So we can say COMMAND_FUNCTION *foo; */
+
+/* Each command has an associated function. When the command is
+ encountered in the text, the associated function is called with START
+ as the argument. If the function expects arguments in braces, it
+ remembers itself on the stack. When the corresponding close brace is
+ encountered, the function is called with END as the argument. */
+#define START 0
+#define END 1
+
+/* Does the command expect braces? */
+#define NO_BRACE_ARGS 0
+#define BRACE_ARGS 1
+#define MAYBE_BRACE_ARGS 2
+
+typedef struct
+{
+ char *name;
+ COMMAND_FUNCTION *proc;
+ int argument_in_braces;
+} COMMAND;
+
+extern COMMAND command_table[];
+
+#endif /* !CMDS_H */
diff --git a/contrib/texinfo/makeinfo/defun.c b/contrib/texinfo/makeinfo/defun.c
new file mode 100644
index 0000000..c62aba7
--- /dev/null
+++ b/contrib/texinfo/makeinfo/defun.c
@@ -0,0 +1,663 @@
+/* defun.c -- @defun and friends.
+ $Id: defun.c,v 1.11 1999/07/11 16:50:19 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "defun.h"
+#include "insertion.h"
+#include "makeinfo.h"
+
+
+#define DEFUN_SELF_DELIMITING(c) \
+ ((c) == '(' || (c) == ')' || (c) == '[' || (c) == ']')
+
+struct token_accumulator
+{
+ unsigned int length;
+ unsigned int index;
+ char **tokens;
+};
+
+static void
+initialize_token_accumulator (accumulator)
+ struct token_accumulator *accumulator;
+{
+ accumulator->length = 0;
+ accumulator->index = 0;
+ accumulator->tokens = NULL;
+}
+
+static void
+accumulate_token (accumulator, token)
+ struct token_accumulator *accumulator;
+ char *token;
+{
+ if (accumulator->index >= accumulator->length)
+ {
+ accumulator->length += 10;
+ accumulator->tokens = xrealloc (accumulator->tokens,
+ (accumulator->length * sizeof (char *)));
+ }
+ accumulator->tokens[accumulator->index] = token;
+ accumulator->index += 1;
+}
+
+/* Given STRING_POINTER pointing at an open brace, skip forward and return a
+ pointer to just past the matching close brace. */
+static int
+scan_group_in_string (string_pointer)
+ char **string_pointer;
+{
+ char *scan_string = (*string_pointer) + 1;
+ unsigned int level = 1;
+
+ for (;;)
+ {
+ int c;
+ if (level == 0)
+ {
+ *string_pointer = scan_string;
+ return 1;
+ }
+ c = *scan_string++;
+ if (c == 0)
+ {
+ /* Tweak line_number to compensate for fact that
+ we gobbled the whole line before coming here. */
+ line_number -= 1;
+ line_error (_("Missing `}' in @def arg"));
+ line_number += 1;
+ *string_pointer = scan_string - 1;
+ return 0;
+ }
+
+ if (c == '{')
+ level += 1;
+ if (c == '}')
+ level -= 1;
+ }
+}
+
+/* Return a list of tokens from the contents of STRING.
+ Commands and brace-delimited groups count as single tokens.
+ Contiguous whitespace characters are converted to a token
+ consisting of a single space. */
+static char **
+args_from_string (string)
+ char *string;
+{
+ struct token_accumulator accumulator;
+ char *token_start, *token_end;
+ char *scan_string = string;
+
+ initialize_token_accumulator (&accumulator);
+
+ while (*scan_string)
+ { /* Replace arbitrary whitespace by a single space. */
+ if (whitespace (*scan_string))
+ {
+ scan_string += 1;
+ while (whitespace (*scan_string))
+ scan_string += 1;
+ accumulate_token ((&accumulator), (xstrdup (" ")));
+ continue;
+ }
+
+ /* Commands count as single tokens. */
+ if (*scan_string == COMMAND_PREFIX)
+ {
+ token_start = scan_string;
+ scan_string += 1;
+ if (self_delimiting (*scan_string))
+ scan_string += 1;
+ else
+ {
+ int c;
+ while (1)
+ {
+ c = *scan_string++;
+
+ if ((c == 0) || (c == '{') || (whitespace (c)))
+ {
+ scan_string -= 1;
+ break;
+ }
+ }
+
+ if (*scan_string == '{')
+ {
+ char *s = scan_string;
+ (void) scan_group_in_string (&s);
+ scan_string = s;
+ }
+ }
+ token_end = scan_string;
+ }
+
+ /* Parentheses and brackets are self-delimiting. */
+ else if (DEFUN_SELF_DELIMITING (*scan_string))
+ {
+ token_start = scan_string;
+ scan_string += 1;
+ token_end = scan_string;
+ }
+
+ /* Open brace introduces a group that is a single token. */
+ else if (*scan_string == '{')
+ {
+ char *s = scan_string;
+ int balanced = scan_group_in_string (&s);
+
+ token_start = scan_string + 1;
+ scan_string = s;
+ token_end = balanced ? (scan_string - 1) : scan_string;
+ }
+
+ /* Otherwise a token is delimited by whitespace, parentheses,
+ brackets, or braces. A token is also ended by a command. */
+ else
+ {
+ token_start = scan_string;
+
+ for (;;)
+ {
+ int c;
+
+ c = *scan_string++;
+
+ /* Do not back up if we're looking at a }; since the only
+ valid }'s are those matched with {'s, we want to give
+ an error. If we back up, we go into an infinite loop. */
+ if (!c || whitespace (c) || DEFUN_SELF_DELIMITING (c)
+ || c == '{')
+ {
+ scan_string--;
+ break;
+ }
+
+ /* If we encounter a command embedded within a token,
+ then end the token. */
+ if (c == COMMAND_PREFIX)
+ {
+ scan_string--;
+ break;
+ }
+ }
+ token_end = scan_string;
+ }
+
+ accumulate_token (&accumulator, substring (token_start, token_end));
+ }
+ accumulate_token (&accumulator, NULL);
+ return accumulator.tokens;
+}
+
+static void
+process_defun_args (defun_args, auto_var_p)
+ char **defun_args;
+ int auto_var_p;
+{
+ int pending_space = 0;
+
+ for (;;)
+ {
+ char *defun_arg = *defun_args++;
+
+ if (defun_arg == NULL)
+ break;
+
+ if (defun_arg[0] == ' ')
+ {
+ pending_space = 1;
+ continue;
+ }
+
+ if (pending_space)
+ {
+ add_char (' ');
+ pending_space = 0;
+ }
+
+ if (DEFUN_SELF_DELIMITING (defun_arg[0]))
+ add_char (defun_arg[0]);
+ else if (defun_arg[0] == '&')
+ if (html)
+ {
+ defun_arg = escape_string (xstrdup (defun_arg));
+ add_word (defun_arg);
+ free (defun_arg);
+ }
+ else
+ add_word (defun_arg);
+ else if (defun_arg[0] == COMMAND_PREFIX)
+ execute_string ("%s", defun_arg);
+ else if (auto_var_p)
+ if (html)
+ {
+ defun_arg = escape_string (xstrdup (defun_arg));
+ add_word (defun_arg);
+ free (defun_arg);
+ }
+ else
+ add_word (defun_arg);
+ else
+ add_word (defun_arg);
+ }
+}
+
+static char *
+next_nonwhite_defun_arg (arg_pointer)
+ char ***arg_pointer;
+{
+ char **scan = (*arg_pointer);
+ char *arg = (*scan++);
+
+ if ((arg != 0) && (*arg == ' '))
+ arg = *scan++;
+
+ if (arg == 0)
+ scan -= 1;
+
+ *arg_pointer = scan;
+
+ return (arg == 0) ? "" : arg;
+}
+
+
+/* This is needed also in insertion.c. */
+
+enum insertion_type
+get_base_type (type)
+ enum insertion_type type;
+{
+ enum insertion_type base_type;
+ switch (type)
+ {
+ case defivar: base_type = defcv; break;
+ case defmac: base_type = deffn; break;
+ case defmethod: base_type = defop; break;
+ case defopt: base_type = defvr; break;
+ case defspec: base_type = deffn; break;
+ case deftypefun: base_type = deftypefn; break;
+ case deftypeivar: base_type = deftypeivar; break;
+ case deftypemethod: base_type = deftypemethod; break;
+ case deftypeop: base_type = deftypeop; break;
+ case deftypevar: base_type = deftypevr; break;
+ case defun: base_type = deffn; break;
+ case defvar: base_type = defvr; break;
+ default:
+ base_type = type;
+ break;
+ }
+
+ return base_type;
+}
+
+/* Make the defun type insertion.
+ TYPE says which insertion this is.
+ X_P, if nonzero, says not to start a new insertion. */
+static void
+defun_internal (type, x_p)
+ enum insertion_type type;
+ int x_p;
+{
+ enum insertion_type base_type;
+ char **defun_args, **scan_args;
+ char *category, *defined_name, *type_name, *type_name2;
+
+ {
+ char *line;
+
+ /* The @def.. line is the only place in Texinfo where you are
+ allowed to use unquoted braces that don't delimit arguments of
+ a command or a macro; in any other place it will trigger an
+ error message from the reader loop. The special handling of
+ this case inside `args_from_string' is an extra special hack
+ which allows this. The side effect is that if we try to expand
+ the rest of the line below, the recursive reader loop will
+ signal an error if there are brace-delimited arguments on that line.
+
+ The best solution to this would be to change the syntax of
+ @def.. commands so that it doesn't violate Texinfo's own rules.
+ But it's probably too late for this now, as it will break a lot
+ of existing manuals.
+
+ Unfortunately, this means that you can't call macros, use @value, etc.
+ inside @def.. commands, sigh. */
+ get_rest_of_line (0, &line);
+ defun_args = (args_from_string (line));
+ free (line);
+ }
+
+ scan_args = defun_args;
+
+ /* Get base type and category string. */
+ base_type = get_base_type (type);
+
+ /* xx all these const strings should be determined upon
+ documentlanguage argument and NOT via gettext (kama). */
+ switch (type)
+ {
+ case defun:
+ case deftypefun:
+ category = _("Function");
+ break;
+ case defmac:
+ category = _("Macro");
+ break;
+ case defspec:
+ category = _("Special Form");
+ break;
+ case defvar:
+ case deftypevar:
+ category = _("Variable");
+ break;
+ case defopt:
+ category = _("User Option");
+ break;
+ case defivar:
+ case deftypeivar:
+ category = _("Instance Variable");
+ break;
+ case defmethod:
+ case deftypemethod:
+ category = _("Method");
+ break;
+ default:
+ category = next_nonwhite_defun_arg (&scan_args);
+ break;
+ }
+
+ /* The class name. */
+ if ((base_type == deftypefn)
+ || (base_type == deftypevr)
+ || (base_type == defcv)
+ || (base_type == defop)
+ || (base_type == deftypeivar)
+ || (base_type == deftypemethod)
+ || (base_type == deftypeop)
+ )
+ type_name = next_nonwhite_defun_arg (&scan_args);
+
+ /* The type name for typed languages. */
+ if (base_type == deftypemethod
+ || base_type == deftypeivar
+ || base_type == deftypeop
+ )
+ type_name2 = next_nonwhite_defun_arg (&scan_args);
+
+ /* The function or whatever that's actually being defined. */
+ defined_name = next_nonwhite_defun_arg (&scan_args);
+
+ /* This hack exists solely for the purposes of formatting the Texinfo
+ manual. I couldn't think of a better way. The token might be a
+ simple @@ followed immediately by more text. If this is the case,
+ then the next defun arg is part of this one, and we should
+ concatenate them. */
+ if (*scan_args && **scan_args && !whitespace (**scan_args)
+ && STREQ (defined_name, "@@"))
+ {
+ char *tem = xmalloc (3 + strlen (scan_args[0]));
+
+ sprintf (tem, "@@%s", scan_args[0]);
+
+ free (scan_args[0]);
+ scan_args[0] = tem;
+ scan_args++;
+ defined_name = tem;
+ }
+
+ if (!x_p)
+ begin_insertion (type);
+
+ /* Write the definition header line.
+ This should start at the normal indentation. */
+ current_indent -= default_indentation_increment;
+ start_paragraph ();
+
+ if (html && !x_p)
+ /* Start the definition on new paragraph. */
+ add_word ("<p>\n");
+
+ if (!html)
+ switch (base_type)
+ {
+ case deffn:
+ case defvr:
+ case deftp:
+ execute_string (" -- %s: %s", category, defined_name);
+ break;
+ case deftypefn:
+ case deftypevr:
+ execute_string (" -- %s: %s %s", category, type_name, defined_name);
+ break;
+ case defcv:
+ execute_string (" -- %s %s %s: %s", category, _("of"), type_name,
+ defined_name);
+ break;
+ case deftypeivar:
+ execute_string (" -- %s %s %s: %s %s", category, _("of"), type_name,
+ type_name2, defined_name);
+ break;
+ case defop:
+ execute_string (" -- %s %s %s: %s", category, _("on"), type_name,
+ defined_name);
+ break;
+ case deftypeop:
+ execute_string (" -- %s %s %s: %s %s", category, _("on"), type_name,
+ type_name2, defined_name);
+ break;
+ case deftypemethod:
+ execute_string (" -- %s %s %s: %s %s", category, _("on"), type_name,
+ type_name2, defined_name);
+ break;
+ }
+
+ if (html)
+ {
+ /* If this is not a @def...x version, it could only
+ be a normal version @def.... So start the table here. */
+ if (!x_p)
+ add_word ("<table width=\"100%\">\n");
+
+ /* If this is an @def...x there has to be an other @def... before
+ it, so this is only a new row within an existing table. With
+ two complete standalone tables the gap between them is too big. */
+ add_word ("<tr>\n");
+ add_word ("<td align=\"left\">");
+
+ switch (base_type)
+ {
+ case deffn:
+ case defvr:
+ case deftp:
+ /* <i> is for the following function arguments. */
+ add_word_args ("<b>%s</b><i>", defined_name);
+ break;
+ case deftypefn:
+ case deftypevr:
+ add_word_args ("%s <b>%s</b><i>", type_name, defined_name);
+ break;
+ case defcv:
+ case defop:
+ add_word_args ("<b>%s</b><i>", defined_name);
+ break;
+ case deftypemethod:
+ case deftypeop:
+ case deftypeivar:
+ add_word_args ("%s <b>%s</b><i>", type_name2, defined_name);
+ break;
+ }
+ } /* if (html)... */
+
+ current_indent += default_indentation_increment;
+
+ /* Now process the function arguments, if any. If these carry onto
+ the next line, they should be indented by two increments to
+ distinguish them from the body of the definition, which is indented
+ by one increment. */
+ current_indent += default_indentation_increment;
+
+ switch (base_type)
+ {
+ case deffn:
+ case defop:
+ process_defun_args (scan_args, 1);
+ break;
+
+ /* Through Makeinfo 1.67 we processed remaining args only for deftp,
+ deftypefn, and deftypemethod. But the libc manual, for example,
+ needs to say:
+ @deftypevar {char *} tzname[2]
+ And simply allowing the extra text seems far simpler than trying
+ to invent yet more defn commands. In any case, we should either
+ output it or give an error, not silently ignore it. */
+ default:
+ process_defun_args (scan_args, 0);
+ break;
+ }
+
+ current_indent -= default_indentation_increment;
+ close_single_paragraph ();
+
+ if (html)
+ {
+ /* xx The single words (on, off) used here, should depend on
+ documentlanguage and NOT on gettext --kama. */
+ switch (base_type)
+ {
+ case deffn:
+ case defvr:
+ case deftp:
+ case deftypefn:
+ case deftypevr:
+ add_word ("</i>"); /* close italic area for arguments */
+ /* put the rest into the second column */
+ add_word_args ("</td>\n<td align=\"right\">%s", category);
+ break;
+
+ case defcv:
+ add_word ("</td>\n<td align=\"right\">");
+ add_word_args ("%s %s %s", category, _("of"), type_name);
+ break;
+
+ case defop:
+ case deftypemethod:
+ case deftypeop:
+ add_word ("</i>");
+ add_word ("</td>\n<td align=\"right\">");
+ add_word_args ("%s %s %s", category, _("on"), type_name);
+ break;
+
+ case deftypeivar:
+ add_word ("</i>");
+ add_word ("</td>\n<td align=\"right\">");
+ add_word_args ("%s %s %s", category, _("of"), type_name);
+ break;
+ } /* switch (base_type)... */
+
+ add_word ("</td>\n"); /* close second column */
+ add_word ("</tr>\n"); /* close row */
+
+ /* This is needed because I have to know if the next line is
+ normal text or another @def..x. If text follows, create a new
+ table to get the indentation for the following text.
+
+ This construction would fail if someone uses:
+ @deffn
+ @sp 2
+ @deffnx
+ .
+ @end deffn
+ But we don't care. */
+ if (!looking_at ("@def"))
+ {
+ add_word ("</table>\n");
+ add_word ("<table width=\"95%\" align=\"center\">\n");
+ add_word ("<tr><td>\n");
+ }
+
+ } /* if (html)... */
+
+ /* Make an entry in the appropriate index. */
+ switch (base_type)
+ {
+ case deffn:
+ case deftypefn:
+ execute_string ("@findex %s\n", defined_name);
+ break;
+ case defvr:
+ case deftypevr:
+ case defcv:
+ execute_string ("@vindex %s\n", defined_name);
+ break;
+ case deftypeivar:
+ execute_string ("@vindex %s %s %s\n", defined_name, _("of"), type_name);
+ break;
+ case defop:
+ case deftypeop:
+ case deftypemethod:
+ execute_string ("@findex %s %s %s\n", defined_name, _("on"), type_name);
+ break;
+ case deftp:
+ execute_string ("@tindex %s\n", defined_name);
+ break;
+ }
+
+ /* Deallocate the token list. */
+ scan_args = defun_args;
+ while (1)
+ {
+ char * arg = (*scan_args++);
+ if (arg == NULL)
+ break;
+ free (arg);
+ }
+ free (defun_args);
+}
+
+/* Add an entry for a function, macro, special form, variable, or option.
+ If the name of the calling command ends in `x', then this is an extra
+ entry included in the body of an insertion of the same type. */
+void
+cm_defun ()
+{
+ int x_p;
+ enum insertion_type type;
+ char *temp = xstrdup (command);
+
+ x_p = (command[strlen (command) - 1] == 'x');
+
+ if (x_p)
+ temp[strlen (temp) - 1] = 0;
+
+ type = find_type_from_name (temp);
+ free (temp);
+
+ /* If we are adding to an already existing insertion, then make sure
+ that we are already in an insertion of type TYPE. */
+ if (x_p && (!insertion_level || insertion_stack->insertion != type))
+ {
+ line_error (_("Must be in `%s' insertion to use `%sx'"),
+ command, command);
+ discard_until ("\n");
+ return;
+ }
+
+ defun_internal (type, x_p);
+}
diff --git a/contrib/texinfo/makeinfo/defun.h b/contrib/texinfo/makeinfo/defun.h
new file mode 100644
index 0000000..ebff9d6
--- /dev/null
+++ b/contrib/texinfo/makeinfo/defun.h
@@ -0,0 +1,31 @@
+/* defun.h -- declaration for defuns.
+ $Id: defun.h,v 1.2 1999/03/25 22:49:10 karl Exp $
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written by Karl Heinz Marbaise <kama@hippo.fido.de>. */
+
+#ifndef DEFUN_H
+#define DEFUN_H
+
+#include "insertion.h"
+
+extern enum insertion_type get_base_type ();
+extern void cm_defun ();
+
+#endif /* !DEFUN_H */
+
diff --git a/contrib/texinfo/makeinfo/files.c b/contrib/texinfo/makeinfo/files.c
new file mode 100644
index 0000000..ce8ace0
--- /dev/null
+++ b/contrib/texinfo/makeinfo/files.c
@@ -0,0 +1,529 @@
+/* files.c -- file-related functions for Texinfo.
+ $Id: files.c,v 1.5 1999/03/23 21:42:44 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "files.h"
+#include "macro.h"
+#include "makeinfo.h"
+
+FSTACK *filestack = NULL;
+
+static int node_filename_stack_index = 0;
+static int node_filename_stack_size = 0;
+static char **node_filename_stack = NULL;
+
+
+/* Looking for include files. */
+
+/* Given a string containing units of information separated by colons,
+ return the next one pointed to by INDEX, or NULL if there are no more.
+ Advance INDEX to the character after the colon. */
+static char *
+extract_colon_unit (string, index)
+ char *string;
+ int *index;
+{
+ int start;
+ int path_sep_char = PATH_SEP[0];
+ int i = *index;
+
+ if (!string || (i >= strlen (string)))
+ return NULL;
+
+ /* Each call to this routine leaves the index pointing at a colon if
+ there is more to the path. If i > 0, then increment past the
+ `:'. If i == 0, then the path has a leading colon. Trailing colons
+ are handled OK by the `else' part of the if statement; an empty
+ string is returned in that case. */
+ if (i && string[i] == path_sep_char)
+ i++;
+
+ start = i;
+ while (string[i] && string[i] != path_sep_char) i++;
+ *index = i;
+
+ if (i == start)
+ {
+ if (string[i])
+ (*index)++;
+
+ /* Return "" in the case of a trailing `:'. */
+ return xstrdup ("");
+ }
+ else
+ {
+ char *value;
+
+ value = xmalloc (1 + (i - start));
+ memcpy (value, &string[start], (i - start));
+ value [i - start] = 0;
+
+ return value;
+ }
+}
+
+/* Return the full pathname for FILENAME by searching along PATH.
+ When found, return the stat () info for FILENAME in FINFO.
+ If PATH is NULL, only the current directory is searched.
+ If the file could not be found, return a NULL pointer. */
+static char *
+get_file_info_in_path (filename, path, finfo)
+ char *filename, *path;
+ struct stat *finfo;
+{
+ char *dir;
+ int result, index = 0;
+
+ if (path == NULL)
+ path = ".";
+
+ /* Handle absolute pathnames. */
+ if (IS_ABSOLUTE (filename)
+ || (*filename == '.'
+ && (IS_SLASH (filename[1])
+ || (filename[1] == '.' && IS_SLASH (filename[2])))))
+ {
+ if (stat (filename, finfo) == 0)
+ return xstrdup (filename);
+ else
+ return NULL;
+ }
+
+ while ((dir = extract_colon_unit (path, &index)))
+ {
+ char *fullpath;
+
+ if (!*dir)
+ {
+ free (dir);
+ dir = xstrdup (".");
+ }
+
+ fullpath = xmalloc (2 + strlen (dir) + strlen (filename));
+ sprintf (fullpath, "%s/%s", dir, filename);
+ free (dir);
+
+ result = stat (fullpath, finfo);
+
+ if (result == 0)
+ return fullpath;
+ else
+ free (fullpath);
+ }
+ return NULL;
+}
+
+/* Find and load the file named FILENAME. Return a pointer to
+ the loaded file, or NULL if it can't be loaded. */
+char *
+find_and_load (filename)
+ char *filename;
+{
+ struct stat fileinfo;
+ long file_size;
+ int file = -1, count = 0;
+ char *fullpath, *result;
+#if O_BINARY || defined (VMS)
+ int n;
+#endif
+
+ result = fullpath = NULL;
+
+ fullpath = get_file_info_in_path (filename, include_files_path, &fileinfo);
+
+ if (!fullpath)
+ goto error_exit;
+
+ filename = fullpath;
+ file_size = (long) fileinfo.st_size;
+
+ file = open (filename, O_RDONLY);
+ if (file < 0)
+ goto error_exit;
+
+ /* Load the file, with enough room for a newline and a null. */
+ result = xmalloc (file_size + 2);
+
+ /* VMS stat lies about the st_size value. The actual number of
+ readable bytes is always less than this value. The arcane
+ mysteries of VMS/RMS are too much to probe, so this hack
+ suffices to make things work. */
+#if O_BINARY || defined (VMS)
+#ifdef VMS
+ while ((n = read (file, result + count, file_size)) > 0)
+#else /* !VMS */
+#ifndef WIN32
+ while ((n = read (file, result + count, file_size)) > 0)
+#else /* WIN32 */
+ /* Does WIN32 really need reading 1 character at a time?? */
+ while ((n = read (file, result + count, 1)) > 0)
+#endif /* WIN32 */
+#endif /* !VMS */
+ count += n;
+ if (0 < count && count < file_size)
+ result = xrealloc (result, count + 2); /* why waste the slack? */
+ else if (n == -1)
+#else /* !VMS && !O_BINARY */
+ count = file_size;
+ if (read (file, result, file_size) != file_size)
+#endif /* !VMS && !WIN32 */
+
+ error_exit:
+ {
+ if (result)
+ free (result);
+
+ if (fullpath)
+ free (fullpath);
+
+ if (file != -1)
+ close (file);
+
+ return NULL;
+ }
+ close (file);
+
+ /* Set the globals to the new file. */
+ input_text = result;
+ input_text_length = count;
+ input_filename = fullpath;
+ node_filename = xstrdup (fullpath);
+ input_text_offset = 0;
+ line_number = 1;
+ /* Not strictly necessary. This magic prevents read_token () from doing
+ extra unnecessary work each time it is called (that is a lot of times).
+ INPUT_TEXT_LENGTH is one past the actual end of the text. */
+ input_text[input_text_length] = '\n';
+ /* This, on the other hand, is always necessary. */
+ input_text[input_text_length+1] = 0;
+ return result;
+}
+
+/* Pushing and popping files. */
+void
+push_node_filename ()
+{
+ if (node_filename_stack_index + 1 > node_filename_stack_size)
+ node_filename_stack = xrealloc
+ (node_filename_stack, (node_filename_stack_size += 10) * sizeof (char *));
+
+ node_filename_stack[node_filename_stack_index] = node_filename;
+ node_filename_stack_index++;
+}
+
+void
+pop_node_filename ()
+{
+ node_filename = node_filename_stack[--node_filename_stack_index];
+}
+
+/* Save the state of the current input file. */
+void
+pushfile ()
+{
+ FSTACK *newstack = xmalloc (sizeof (FSTACK));
+ newstack->filename = input_filename;
+ newstack->text = input_text;
+ newstack->size = input_text_length;
+ newstack->offset = input_text_offset;
+ newstack->line_number = line_number;
+ newstack->next = filestack;
+
+ filestack = newstack;
+ push_node_filename ();
+}
+
+/* Make the current file globals be what is on top of the file stack. */
+void
+popfile ()
+{
+ FSTACK *tos = filestack;
+
+ if (!tos)
+ abort (); /* My fault. I wonder what I did? */
+
+ if (macro_expansion_output_stream)
+ {
+ maybe_write_itext (input_text, input_text_offset);
+ forget_itext (input_text);
+ }
+
+ /* Pop the stack. */
+ filestack = filestack->next;
+
+ /* Make sure that commands with braces have been satisfied. */
+ if (!executing_string && !me_executing_string)
+ discard_braces ();
+
+ /* Get the top of the stack into the globals. */
+ input_filename = tos->filename;
+ input_text = tos->text;
+ input_text_length = tos->size;
+ input_text_offset = tos->offset;
+ line_number = tos->line_number;
+ free (tos);
+
+ /* Go back to the (now) current node. */
+ pop_node_filename ();
+}
+
+/* Flush all open files on the file stack. */
+void
+flush_file_stack ()
+{
+ while (filestack)
+ {
+ char *fname = input_filename;
+ char *text = input_text;
+ popfile ();
+ free (fname);
+ free (text);
+ }
+}
+
+/* Return the index of the first character in the filename
+ which is past all the leading directory characters. */
+static int
+skip_directory_part (filename)
+ char *filename;
+{
+ int i = strlen (filename) - 1;
+
+ while (i && !IS_SLASH (filename[i]))
+ i--;
+ if (IS_SLASH (filename[i]))
+ i++;
+ else if (filename[i] && HAVE_DRIVE (filename))
+ i = 2;
+
+ return i;
+}
+
+char *
+filename_non_directory (name)
+ char *name;
+{
+ return xstrdup (name + skip_directory_part (name));
+}
+
+/* Return just the simple part of the filename; i.e. the
+ filename without the path information, or extensions.
+ This conses up a new string. */
+char *
+filename_part (filename)
+ char *filename;
+{
+ char *basename = filename_non_directory (filename);
+
+#ifdef REMOVE_OUTPUT_EXTENSIONS
+ /* See if there is an extension to remove. If so, remove it. */
+ {
+ char *temp;
+
+ temp = strrchr (basename, '.');
+ if (temp)
+ *temp = 0;
+ }
+#endif /* REMOVE_OUTPUT_EXTENSIONS */
+ return basename;
+}
+
+/* Return the pathname part of filename. This can be NULL. */
+char *
+pathname_part (filename)
+ char *filename;
+{
+ char *expand_filename ();
+ char *result = NULL;
+ int i;
+
+ filename = expand_filename (filename, "");
+
+ i = skip_directory_part (filename);
+ if (i)
+ {
+ result = xmalloc (1 + i);
+ strncpy (result, filename, i);
+ result[i] = 0;
+ }
+ free (filename);
+ return result;
+}
+
+/* Return the expansion of FILENAME. */
+char *
+expand_filename (filename, input_name)
+ char *filename, *input_name;
+{
+ int i;
+ char *full_pathname ();
+
+ if (filename)
+ {
+ filename = full_pathname (filename);
+ if (IS_ABSOLUTE (filename)
+ || (*filename == '.' &&
+ (IS_SLASH (filename[1]) ||
+ (filename[1] == '.' && IS_SLASH (filename[2])))))
+ return filename;
+ }
+ else
+ {
+ filename = filename_non_directory (input_name);
+
+ if (!*filename)
+ {
+ free (filename);
+ filename = xstrdup ("noname.texi");
+ }
+
+ for (i = strlen (filename) - 1; i; i--)
+ if (filename[i] == '.')
+ break;
+
+ if (!i)
+ i = strlen (filename);
+
+ if (i + 6 > (strlen (filename)))
+ filename = xrealloc (filename, i + 6);
+ strcpy (filename + i, html ? ".html" : ".info");
+ return filename;
+ }
+
+ if (IS_ABSOLUTE (input_name))
+ {
+ /* Make it so that relative names work. */
+ char *result;
+
+ i = strlen (input_name) - 1;
+
+ result = xmalloc (1 + strlen (input_name) + strlen (filename));
+ strcpy (result, input_name);
+
+ while (!IS_SLASH (result[i]) && i)
+ i--;
+ if (IS_SLASH (result[i]))
+ i++;
+
+ strcpy (&result[i], filename);
+ free (filename);
+ return result;
+ }
+ return filename;
+}
+
+/* Return the full path to FILENAME. */
+char *
+full_pathname (filename)
+ char *filename;
+{
+ int initial_character;
+ char *result;
+
+ /* No filename given? */
+ if (!filename || !*filename)
+ return xstrdup ("");
+
+ /* Already absolute? */
+ if (IS_ABSOLUTE (filename) ||
+ (*filename == '.' &&
+ (IS_SLASH (filename[1]) ||
+ (filename[1] == '.' && IS_SLASH (filename[2])))))
+ return xstrdup (filename);
+
+ initial_character = *filename;
+ if (initial_character != '~')
+ {
+ char *localdir = xmalloc (1025);
+#ifdef HAVE_GETCWD
+ if (!getcwd (localdir, 1024))
+#else
+ if (!getwd (localdir))
+#endif
+ {
+ fprintf (stderr, _("%s: getwd: %s, %s\n"),
+ progname, filename, localdir);
+ xexit (1);
+ }
+
+ strcat (localdir, "/");
+ strcat (localdir, filename);
+ result = xstrdup (localdir);
+ free (localdir);
+ }
+ else
+ { /* Does anybody know why WIN32 doesn't want to support $HOME?
+ If the reason is they don't have getpwnam, they should
+ only disable the else clause below. */
+#ifndef WIN32
+ if (IS_SLASH (filename[1]))
+ {
+ /* Return the concatenation of the environment variable HOME
+ and the rest of the string. */
+ char *temp_home;
+
+ temp_home = (char *) getenv ("HOME");
+ result = xmalloc (strlen (&filename[1])
+ + 1
+ + temp_home ? strlen (temp_home)
+ : 0);
+ *result = 0;
+
+ if (temp_home)
+ strcpy (result, temp_home);
+
+ strcat (result, &filename[1]);
+ }
+ else
+ {
+ struct passwd *user_entry;
+ int i, c;
+ char *username = xmalloc (257);
+
+ for (i = 1; (c = filename[i]); i++)
+ {
+ if (IS_SLASH (c))
+ break;
+ else
+ username[i - 1] = c;
+ }
+ if (c)
+ username[i - 1] = 0;
+
+ user_entry = getpwnam (username);
+
+ if (!user_entry)
+ return xstrdup (filename);
+
+ result = xmalloc (1 + strlen (user_entry->pw_dir)
+ + strlen (&filename[i]));
+ strcpy (result, user_entry->pw_dir);
+ strcat (result, &filename[i]);
+ }
+#endif /* not WIN32 */
+ }
+ return result;
+}
+
+char *
+output_name_from_input_name (name)
+ char *name;
+{
+ return expand_filename (NULL, name);
+}
diff --git a/contrib/texinfo/makeinfo/files.h b/contrib/texinfo/makeinfo/files.h
new file mode 100644
index 0000000..d96c444
--- /dev/null
+++ b/contrib/texinfo/makeinfo/files.h
@@ -0,0 +1,45 @@
+/* files.h -- declarations for files.c.
+ $Id: files.h,v 1.1 1998/10/24 21:37:25 karl Exp $
+
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FILES_H
+#define FILES_H
+
+/* A stack of file information records. If a new file is read in with
+ "@input", we remember the old input file state on this stack. */
+typedef struct fstack
+{
+ struct fstack *next;
+ char *filename;
+ char *text;
+ int size;
+ int offset;
+ int line_number;
+} FSTACK;
+extern FSTACK *filestack;
+
+extern void pushfile (), popfile ();
+extern void flush_file_stack ();
+extern char *find_and_load ();
+extern char *output_name_from_input_name ();
+extern char *expand_filename ();
+extern char *filename_part ();
+extern char *pathname_part ();
+
+#endif /* !FILES_H */
diff --git a/contrib/texinfo/makeinfo/footnote.c b/contrib/texinfo/makeinfo/footnote.c
new file mode 100644
index 0000000..c1a056d
--- /dev/null
+++ b/contrib/texinfo/makeinfo/footnote.c
@@ -0,0 +1,359 @@
+/* footnote.c -- footnotes for Texinfo.
+ $Id: footnote.c,v 1.10 1999/09/20 12:20:52 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "footnote.h"
+#include "macro.h"
+#include "makeinfo.h"
+
+/* Nonzero means that the footnote style for this document was set on
+ the command line, which overrides any other settings. */
+int footnote_style_preset = 0;
+
+/* The current footnote number in this node. Each time a new node is
+ started this is reset to 1. */
+int current_footnote_number = 1;
+
+/* Nonzero means we automatically number footnotes with no specified marker. */
+int number_footnotes = 1;
+
+/* Nonzero means we are currently outputting footnotes. */
+int already_outputting_pending_notes = 0;
+
+
+/* Footnotes can be handled in one of two ways:
+
+ separate_node:
+ Make them look like followed references, with the reference
+ destinations in a makeinfo manufactured node or,
+ end_node:
+ Make them appear at the bottom of the node that they originally
+ appeared in. */
+
+#define separate_node 0
+#define end_node 1
+
+int footnote_style = end_node;
+int first_footnote_this_node = 1;
+int footnote_count = 0;
+
+/* Set the footnote style based on the style identifier in STRING. */
+int
+set_footnote_style (string)
+ char *string;
+{
+ if (strcasecmp (string, "separate") == 0)
+ footnote_style = separate_node;
+ else if (strcasecmp (string, "end") == 0)
+ footnote_style = end_node;
+ else
+ return -1;
+
+ return 0;
+}
+
+void
+cm_footnotestyle ()
+{
+ char *arg;
+
+ get_rest_of_line (1, &arg);
+
+ /* If set on command line, do not change the footnote style. */
+ if (!footnote_style_preset && set_footnote_style (arg) != 0)
+ line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
+
+ free (arg);
+}
+
+typedef struct fn
+{
+ struct fn *next;
+ char *marker;
+ char *note;
+ int number;
+} FN;
+
+FN *pending_notes = NULL;
+
+/* A method for remembering footnotes. Note that this list gets output
+ at the end of the current node. */
+void
+remember_note (marker, note)
+ char *marker, *note;
+{
+ FN *temp = xmalloc (sizeof (FN));
+
+ temp->marker = xstrdup (marker);
+ temp->note = xstrdup (note);
+ temp->next = pending_notes;
+ temp->number = current_footnote_number;
+ pending_notes = temp;
+ footnote_count++;
+}
+
+/* How to get rid of existing footnotes. */
+static void
+free_pending_notes ()
+{
+ FN *temp;
+
+ while ((temp = pending_notes))
+ {
+ free (temp->marker);
+ free (temp->note);
+ pending_notes = pending_notes->next;
+ free (temp);
+ }
+ first_footnote_this_node = 1;
+ footnote_count = 0;
+ current_footnote_number = 1; /* for html */
+}
+
+/* What to do when you see a @footnote construct. */
+
+ /* Handle a "footnote".
+ footnote *{this is a footnote}
+ where "*" is the (optional) marker character for this note. */
+void
+cm_footnote ()
+{
+ char *marker;
+ char *note;
+
+ get_until ("{", &marker);
+ canon_white (marker);
+
+ if (macro_expansion_output_stream && !executing_string)
+ append_to_expansion_output (input_text_offset + 1); /* include the { */
+
+ /* Read the argument in braces. */
+ if (curchar () != '{')
+ {
+ line_error (_("`%c%s' needs an argument `{...}', not just `%s'"),
+ COMMAND_PREFIX, command, marker);
+ free (marker);
+ return;
+ }
+ else
+ {
+ int len;
+ int braces = 1;
+ int loc = ++input_text_offset;
+
+ while (braces)
+ {
+ if (loc == input_text_length)
+ {
+ line_error (_("No closing brace for footnote `%s'"), marker);
+ return;
+ }
+
+ if (input_text[loc] == '{')
+ braces++;
+ else if (input_text[loc] == '}')
+ braces--;
+ else if (input_text[loc] == '\n')
+ line_number++;
+
+ loc++;
+ }
+
+ len = (loc - input_text_offset) - 1;
+ note = xmalloc (len + 1);
+ memcpy (note, &input_text[input_text_offset], len);
+ note[len] = 0;
+ input_text_offset = loc;
+ }
+
+ /* Must write the macro-expanded argument to the macro expansion
+ output stream. This is like the case in index_add_arg. */
+ if (macro_expansion_output_stream && !executing_string)
+ {
+ /* Calling me_execute_string on a lone } provokes an error, since
+ as far as the reader knows there is no matching {. We wrote
+ the { above in the call to append_to_expansion_output. */
+ me_execute_string_keep_state (note, "}");
+ }
+
+ if (!current_node || !*current_node)
+ {
+ line_error (_("Footnote defined without parent node"));
+ free (marker);
+ free (note);
+ return;
+ }
+
+ if (!*marker)
+ {
+ free (marker);
+
+ if (number_footnotes)
+ {
+ marker = xmalloc (10);
+ sprintf (marker, "%d", current_footnote_number);
+ }
+ else
+ marker = xstrdup ("*");
+ }
+
+ remember_note (marker, note);
+
+ /* fixme: html: footnote processing needs work; we currently ignore
+ the style requested; we could clash with a node name of the form
+ `fn-<n>', though that's unlikely. */
+ if (html)
+ add_word_args ("<a rel=footnote href=\"#fn-%d\"><sup>%s</sup></a>",
+ current_footnote_number, marker);
+ else
+ /* Your method should at least insert MARKER. */
+ switch (footnote_style)
+ {
+ case separate_node:
+ add_word_args ("(%s)", marker);
+ execute_string (" (*note %s-Footnote-%d::)",
+ current_node, current_footnote_number);
+ if (first_footnote_this_node)
+ {
+ char *temp_string, *expanded_ref;
+
+ temp_string = xmalloc (strlen (current_node)
+ + strlen ("-Footnotes") + 1);
+
+ strcpy (temp_string, current_node);
+ strcat (temp_string, "-Footnotes");
+ expanded_ref = expansion (temp_string, 0);
+ remember_node_reference (expanded_ref, line_number,
+ followed_reference);
+ free (temp_string);
+ free (expanded_ref);
+ first_footnote_this_node = 0;
+ }
+ break;
+
+ case end_node:
+ add_word_args ("(%s)", marker);
+ break;
+
+ default:
+ break;
+ }
+ current_footnote_number++;
+
+ free (marker);
+ free (note);
+}
+
+/* Output the footnotes. We are at the end of the current node. */
+void
+output_pending_notes ()
+{
+ FN *footnote = pending_notes;
+
+ if (!pending_notes)
+ return;
+
+ if (html)
+ { /* The type= attribute is used just in case some weirdo browser
+ out there doesn't use numbers by default. Since we rely on the
+ browser to produce the footnote numbers, we need to make sure
+ they ARE indeed numbers. Pre-HTML4 browsers seem to not care. */
+ add_word ("<hr><h4>");
+ add_word (_("Footnotes"));
+ add_word ("</h4>\n<ol type=\"1\">\n");
+ }
+ else
+ switch (footnote_style)
+ {
+ case separate_node:
+ {
+ char *old_current_node = current_node;
+ char *old_command = xstrdup (command);
+
+ already_outputting_pending_notes++;
+ execute_string ("%cnode %s-Footnotes,,,%s\n",
+ COMMAND_PREFIX, current_node, current_node);
+ already_outputting_pending_notes--;
+ current_node = old_current_node;
+ free (command);
+ command = old_command;
+ }
+ break;
+
+ case end_node:
+ close_paragraph ();
+ in_fixed_width_font++;
+ /* This string should be translated according to the
+ @documentlanguage, not the current LANG. We can't do that
+ yet, so leave it in English. */
+ execute_string ("---------- Footnotes ----------\n\n");
+ in_fixed_width_font--;
+ break;
+ }
+
+ /* Handle the footnotes in reverse order. */
+ {
+ FN **array = xmalloc ((footnote_count + 1) * sizeof (FN *));
+ array[footnote_count] = NULL;
+
+ while (--footnote_count > -1)
+ {
+ array[footnote_count] = footnote;
+ footnote = footnote->next;
+ }
+
+ filling_enabled = 1;
+ indented_fill = 1;
+
+ while ((footnote = array[++footnote_count]))
+ {
+ if (html)
+ {
+ /* Make the text of every footnote begin a separate paragraph. */
+ add_word_args ("<li><a name=\"fn-%d\"></a>\n<p>",
+ footnote->number);
+ execute_string ("%s", footnote->note);
+ add_word ("</p>\n");
+ }
+ else
+ {
+ char *old_current_node = current_node;
+ char *old_command = xstrdup (command);
+
+ already_outputting_pending_notes++;
+ execute_string ("%canchor{%s-Footnote-%d}(%s) %s",
+ COMMAND_PREFIX, current_node, footnote->number,
+ footnote->marker, footnote->note);
+ already_outputting_pending_notes--;
+ current_node = old_current_node;
+ free (command);
+ command = old_command;
+ }
+
+ close_paragraph ();
+ }
+
+ if (html)
+ add_word ("</ol><hr>");
+ close_paragraph ();
+ free (array);
+ }
+
+ free_pending_notes ();
+}
diff --git a/contrib/texinfo/makeinfo/footnote.h b/contrib/texinfo/makeinfo/footnote.h
new file mode 100644
index 0000000..c87a0aa
--- /dev/null
+++ b/contrib/texinfo/makeinfo/footnote.h
@@ -0,0 +1,37 @@
+/* footnote.h -- declarations for footnote.c.
+ $Id: footnote.h,v 1.2 1998/10/26 22:16:15 karl Exp $
+
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FOOTNOTE_H
+#define FOOTNOTE_H
+
+extern int footnote_style_preset;
+extern int current_footnote_number;
+extern int number_footnotes;
+extern int already_outputting_pending_notes;
+
+/* The Texinfo @commands. */
+extern void cm_footnote ();
+extern void cm_footnotestyle ();
+
+extern int set_footnote_style (); /* called for -s option */
+
+extern void output_pending_notes (); /* called for output */
+
+#endif /* !FOOTNOTE_H */
diff --git a/contrib/texinfo/makeinfo/html.c b/contrib/texinfo/makeinfo/html.c
new file mode 100644
index 0000000..f2e53e5
--- /dev/null
+++ b/contrib/texinfo/makeinfo/html.c
@@ -0,0 +1,182 @@
+/* html.c -- html-related utilities.
+ $Id: html.c,v 1.5 1999/09/18 19:27:41 karl Exp $
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "cmds.h"
+#include "html.h"
+#include "lang.h"
+#include "makeinfo.h"
+#include "sectioning.h"
+
+/* See html.h. */
+int html_output_head_p = 0;
+
+void
+html_output_head ()
+{
+ char *html_title;
+
+ if (html_output_head_p)
+ return;
+ html_output_head_p = 1;
+
+ /* The <title> should not have markup. */
+ html_title = title ? text_expansion (title) : _("Untitled");
+
+ add_word_args ("<html lang=\"%s\"><head>\n<title>%s</title>\n",
+ language_table[language_code].abbrev, html_title);
+
+ add_word ("<meta http-equiv=\"Content-Type\" content=\"text/html");
+ if (document_encoding)
+ add_word_args ("; charset=%s", document_encoding);
+ add_word ("\">\n");
+
+ add_word_args ("<meta name=description content=\"%s\">\n", html_title);
+ add_word_args ("<meta name=generator content=\"makeinfo %s\">\n", VERSION);
+ add_word ("<link href=\"http://texinfo.org/\" rel=generator-home>\n");
+ add_word ("</head><body>\n\n");
+}
+
+
+/* Escape HTML special characters in the string if necessary,
+ returning a pointer to a possibly newly-allocated one. */
+char *
+escape_string (string)
+ char * string;
+{
+ int i=0, newlen=0;
+ char * newstring;
+
+ do
+ {
+ /* Find how much to allocate. */
+ switch (string[i])
+ {
+ case '&':
+ newlen += 5; /* `&amp;' */
+ break;
+ case '<':
+ case '>':
+ newlen += 4; /* `&lt;', `&gt;' */
+ break;
+ default:
+ newlen++;
+ }
+ i++;
+ }
+ while (string[i]);
+
+ if (newlen == i) return string; /* Already OK. */
+
+ newstring = xmalloc (newlen + 2);
+ i = 0;
+ do
+ {
+ switch (string[i])
+ {
+ case '&':
+ strcpy (newstring, "&amp;");
+ newstring += 5;
+ break;
+ case '<':
+ strcpy (newstring, "&lt;");
+ newstring += 4;
+ break;
+ case '>':
+ strcpy (newstring, "&gt;");
+ newstring += 4;
+ break;
+ default:
+ newstring[0] = string[i];
+ newstring++;
+ }
+ }
+ while (string[i++]);
+ free (string);
+ return newstring - newlen -1;
+}
+
+/* Open or close TAG according to START_OR_END. */
+void
+insert_html_tag (start_or_end, tag)
+ int start_or_end;
+ char *tag;
+{
+ if (!paragraph_is_open && (start_or_end == START))
+ {
+ /* Need to compensate for the <p> we are about to insert, or
+ else cm_xxx functions that call us will get wrong text
+ between START and END. */
+ adjust_braces_following (output_paragraph_offset, 3);
+ add_word ("<p>");
+ }
+ add_char ('<');
+ if (start_or_end != START)
+ add_char ('/');
+ add_word (tag);
+ add_char ('>');
+}
+
+/* Output an HTML <link> to the filename for NODE, including the
+ other string as extra attributes. */
+void
+add_link (node, attributes)
+ char *node, *attributes;
+{
+ if (node)
+ {
+ add_word_args ("<link %s href=\"", attributes);
+ add_anchor_name (node, 1);
+ add_word ("\">\n");
+ }
+}
+
+/* Output NAME with characters escaped as appropriate for an anchor
+ name, i.e., escape URL special characters as %<n>. */
+void
+add_escaped_anchor_name (name)
+ char *name;
+{
+ for (; *name; name++)
+ {
+ if (*name == '&')
+ add_word ("&amp;");
+ else if (! URL_SAFE_CHAR (*name))
+ /* Cast so characters with the high bit set are treated as >128,
+ for example o-umlaut should be 246, not -10. */
+ add_word_args ("%%%x", (unsigned char) *name);
+ else
+ add_char (*name);
+ }
+}
+
+/* Insert the text for the name of a reference in an HTML anchor
+ appropriate for NODENAME. If HREF is nonzero, it will be
+ appropriate for a href= attribute, rather than name= i.e., including
+ the `#' if it's an internal reference. */
+void
+add_anchor_name (nodename, href)
+ char *nodename;
+ int href;
+{
+ if (href)
+ add_char ('#');
+
+ add_escaped_anchor_name (nodename);
+}
diff --git a/contrib/texinfo/makeinfo/html.h b/contrib/texinfo/makeinfo/html.h
new file mode 100644
index 0000000..2d68c77
--- /dev/null
+++ b/contrib/texinfo/makeinfo/html.h
@@ -0,0 +1,44 @@
+/* html.h -- declarations for html-related utilities.
+ $Id: html.h,v 1.1 1999/04/25 20:53:33 karl Exp $
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef HTML_H
+#define HTML_H
+
+/* Nonzero if we have output the <head>. */
+extern int html_output_head_p;
+
+/* Perform the <head> output. */
+extern void html_output_head ();
+
+/* Escape &<>. */
+extern char *escape_string (/* char * */);
+
+/* Open or close TAG according to START_OR_END. */
+extern void insert_html_tag (/* int start_or_end, char *tag */);
+
+/* Output HTML <link> to NODE, plus extra ATTRIBUTES. */
+extern void add_link (/* char *node, char *attributes */);
+
+/* Escape URL-special characters as %xy. */
+extern void add_escaped_anchor_name (/* char *name */);
+
+/* See html.c. */
+extern void add_anchor_name (/* nodename, href */);
+
+#endif /* !HTML_H */
diff --git a/contrib/texinfo/makeinfo/index.c b/contrib/texinfo/makeinfo/index.c
new file mode 100644
index 0000000..05466ce
--- /dev/null
+++ b/contrib/texinfo/makeinfo/index.c
@@ -0,0 +1,823 @@
+/* index.c -- indexing for Texinfo.
+ $Id: index.c,v 1.21 1999/07/18 18:50:02 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "index.h"
+#include "lang.h"
+#include "macro.h"
+#include "toc.h"
+
+/* An index element... */
+typedef struct index_elt
+{
+ struct index_elt *next;
+ char *entry; /* The index entry itself, after expansion. */
+ char *entry_text; /* The original, non-expanded entry text. */
+ char *node; /* The node from whence it came. */
+ int code; /* Nonzero means add `@code{...}' when
+ printing this element. */
+ int defining_line; /* Line number where this entry was written. */
+ char *defining_file; /* Source file for defining_line. */
+} INDEX_ELT;
+
+
+/* A list of short-names for each index.
+ There are two indices into the the_indices array.
+ * read_index is the index that points to the list of index
+ entries that we will find if we ask for the list of entries for
+ this name.
+ * write_index is the index that points to the list of index entries
+ that we will add new entries to.
+
+ Initially, read_index and write_index are the same, but the
+ @syncodeindex and @synindex commands can change the list we add
+ entries to.
+
+ For example, after the commands
+ @cindex foo
+ @defindex ii
+ @synindex cp ii
+ @cindex bar
+
+ the cp index will contain the entry `foo', and the new ii
+ index will contain the entry `bar'. This is consistent with the
+ way texinfo.tex handles the same situation.
+
+ In addition, for each index, it is remembered whether that index is
+ a code index or not. Code indices have @code{} inserted around the
+ first word when they are printed with printindex. */
+typedef struct
+{
+ char *name;
+ int read_index; /* index entries for `name' */
+ int write_index; /* store index entries here, @synindex can change it */
+ int code;
+} INDEX_ALIST;
+
+INDEX_ALIST **name_index_alist = NULL;
+
+/* An array of pointers. Each one is for a different index. The
+ "synindex" command changes which array slot is pointed to by a
+ given "index". */
+INDEX_ELT **the_indices = NULL;
+
+/* The number of defined indices. */
+int defined_indices = 0;
+
+/* Stuff for defining commands on the fly. */
+COMMAND **user_command_array = NULL;
+int user_command_array_len = 0;
+
+/* How to compare index entries for sorting. May be set to strcoll. */
+int (*index_compare_fn) () = strcasecmp;
+
+/* Find which element in the known list of indices has this name.
+ Returns -1 if NAME isn't found. */
+static int
+find_index_offset (name)
+ char *name;
+{
+ int i;
+ for (i = 0; i < defined_indices; i++)
+ if (name_index_alist[i] && STREQ (name, name_index_alist[i]->name))
+ return i;
+ return -1;
+}
+
+/* Return a pointer to the entry of (name . index) for this name.
+ Return NULL if the index doesn't exist. */
+INDEX_ALIST *
+find_index (name)
+ char *name;
+{
+ int offset = find_index_offset (name);
+ if (offset > -1)
+ return name_index_alist[offset];
+ else
+ return NULL;
+}
+
+/* User-defined commands, which happens only from user-defined indexes.
+ Used to initialize the builtin indices, too. */
+void
+define_user_command (name, proc, needs_braces_p)
+ char *name;
+ COMMAND_FUNCTION *proc;
+ int needs_braces_p;
+{
+ int slot = user_command_array_len;
+ user_command_array_len++;
+
+ if (!user_command_array)
+ user_command_array = xmalloc (1 * sizeof (COMMAND *));
+
+ user_command_array = xrealloc (user_command_array,
+ (1 + user_command_array_len) * sizeof (COMMAND *));
+
+ user_command_array[slot] = xmalloc (sizeof (COMMAND));
+ user_command_array[slot]->name = xstrdup (name);
+ user_command_array[slot]->proc = proc;
+ user_command_array[slot]->argument_in_braces = needs_braces_p;
+}
+
+/* Please release me, let me go... */
+static void
+free_index (index)
+ INDEX_ELT *index;
+{
+ INDEX_ELT *temp;
+
+ while ((temp = index))
+ {
+ free (temp->entry);
+ free (temp->entry_text);
+ /* Do not free the node, because we already freed the tag table,
+ which freed all the node names. */
+ /* free (temp->node); */
+ index = index->next;
+ free (temp);
+ }
+}
+
+/* Flush an index by name. This will delete the list of entries that
+ would be written by a @printindex command for this index. */
+static void
+undefindex (name)
+ char *name;
+{
+ int i;
+ int which = find_index_offset (name);
+
+ /* The index might have already been freed if this was the target of
+ an @synindex. */
+ if (which < 0 || !name_index_alist[which])
+ return;
+
+ i = name_index_alist[which]->read_index;
+
+ free_index (the_indices[i]);
+ the_indices[i] = NULL;
+
+ free (name_index_alist[which]->name);
+ free (name_index_alist[which]);
+ name_index_alist[which] = NULL;
+}
+
+/* Add the arguments to the current index command to the index NAME.
+ html fixxme generate specific html anchor */
+static void
+index_add_arg (name)
+ char *name;
+{
+ int which;
+ char *index_entry;
+ INDEX_ALIST *tem;
+
+ tem = find_index (name);
+
+ which = tem ? tem->write_index : -1;
+
+ if (macro_expansion_output_stream && !executing_string)
+ append_to_expansion_output (input_text_offset + 1);
+
+ get_rest_of_line (0, &index_entry);
+ ignore_blank_line ();
+
+ if (macro_expansion_output_stream && !executing_string)
+ {
+ char *index_line = xmalloc (strlen (index_entry) + 2);
+ sprintf (index_line, "%s\n", index_entry);
+ me_execute_string_keep_state (index_line, NULL);
+ free (index_line);
+ }
+
+ if (which < 0)
+ {
+ line_error (_("Unknown index `%s'"), name);
+ free (index_entry);
+ }
+ else
+ {
+ INDEX_ELT *new = xmalloc (sizeof (INDEX_ELT));
+ new->next = the_indices[which];
+ new->entry_text = index_entry;
+ new->entry = NULL;
+ new->node = current_node ? current_node : xstrdup ("");
+ new->code = tem->code;
+ new->defining_line = line_number - 1;
+ /* We need to make a copy since input_filename may point to
+ something that goes away, for example, inside a macro.
+ (see the findexerr test). */
+ new->defining_file = xstrdup (input_filename);
+ the_indices[which] = new;
+ }
+}
+
+/* The function which user defined index commands call. */
+static void
+gen_index ()
+{
+ char *name = xstrdup (command);
+ if (strlen (name) >= strlen ("index"))
+ name[strlen (name) - strlen ("index")] = 0;
+ index_add_arg (name);
+ free (name);
+}
+
+/* Define an index known as NAME. We assign the slot number.
+ If CODE is nonzero, make this a code index. */
+static void
+defindex (name, code)
+ char *name;
+ int code;
+{
+ int i, slot;
+
+ /* If it already exists, flush it. */
+ undefindex (name);
+
+ /* Try to find an empty slot. */
+ slot = -1;
+ for (i = 0; i < defined_indices; i++)
+ if (!name_index_alist[i])
+ {
+ slot = i;
+ break;
+ }
+
+ if (slot < 0)
+ { /* No such luck. Make space for another index. */
+ slot = defined_indices;
+ defined_indices++;
+
+ name_index_alist = (INDEX_ALIST **)
+ xrealloc (name_index_alist, (1 + defined_indices)
+ * sizeof (INDEX_ALIST *));
+ the_indices = (INDEX_ELT **)
+ xrealloc (the_indices, (1 + defined_indices) * sizeof (INDEX_ELT *));
+ }
+
+ /* We have a slot. Start assigning. */
+ name_index_alist[slot] = xmalloc (sizeof (INDEX_ALIST));
+ name_index_alist[slot]->name = xstrdup (name);
+ name_index_alist[slot]->read_index = slot;
+ name_index_alist[slot]->write_index = slot;
+ name_index_alist[slot]->code = code;
+
+ the_indices[slot] = NULL;
+}
+
+/* Define an index NAME, implicitly @code if CODE is nonzero. */
+static void
+top_defindex (name, code)
+ char *name;
+ int code;
+{
+ char *temp;
+
+ temp = xmalloc (1 + strlen (name) + strlen ("index"));
+ sprintf (temp, "%sindex", name);
+ define_user_command (temp, gen_index, 0);
+ defindex (name, code);
+ free (temp);
+}
+
+/* Set up predefined indices. */
+void
+init_indices ()
+{
+ int i;
+
+ /* Create the default data structures. */
+
+ /* Initialize data space. */
+ if (!the_indices)
+ {
+ the_indices = xmalloc ((1 + defined_indices) * sizeof (INDEX_ELT *));
+ the_indices[defined_indices] = NULL;
+
+ name_index_alist = xmalloc ((1 + defined_indices)
+ * sizeof (INDEX_ALIST *));
+ name_index_alist[defined_indices] = NULL;
+ }
+
+ /* If there were existing indices, get rid of them now. */
+ for (i = 0; i < defined_indices; i++)
+ {
+ undefindex (name_index_alist[i]->name);
+ if (name_index_alist[i])
+ { /* Suppose we're called with two input files, and the first
+ does a @synindex pg cp. Then, when we get here to start
+ the second file, the "pg" element won't get freed by
+ undefindex (because it's pointing to "cp"). So free it
+ here; otherwise, when we try to define the pg index again
+ just below, it will still point to cp. */
+ free (name_index_alist[i]->name);
+ free (name_index_alist[i]);
+ name_index_alist[i] = NULL;
+ }
+ }
+
+ /* Add the default indices. */
+ top_defindex ("cp", 0); /* cp is the only non-code index. */
+ top_defindex ("fn", 1);
+ top_defindex ("ky", 1);
+ top_defindex ("pg", 1);
+ top_defindex ("tp", 1);
+ top_defindex ("vr", 1);
+}
+
+/* Given an index name, return the offset in the_indices of this index,
+ or -1 if there is no such index. */
+int
+translate_index (name)
+ char *name;
+{
+ INDEX_ALIST *which = find_index (name);
+
+ if (which)
+ return which->read_index;
+ else
+ return -1;
+}
+
+/* Return the index list which belongs to NAME. */
+INDEX_ELT *
+index_list (name)
+ char *name;
+{
+ int which = translate_index (name);
+ if (which < 0)
+ return (INDEX_ELT *) -1;
+ else
+ return the_indices[which];
+}
+
+/* Define a new index command. Arg is name of index. */
+static void
+gen_defindex (code)
+ int code;
+{
+ char *name;
+ get_rest_of_line (0, &name);
+
+ if (find_index (name))
+ {
+ line_error (_("Index `%s' already exists"), name);
+ }
+ else
+ {
+ char *temp = xmalloc (strlen (name) + sizeof ("index"));
+ sprintf (temp, "%sindex", name);
+ define_user_command (temp, gen_index, 0);
+ defindex (name, code);
+ free (temp);
+ }
+
+ free (name);
+}
+
+void
+cm_defindex ()
+{
+ gen_defindex (0);
+}
+
+void
+cm_defcodeindex ()
+{
+ gen_defindex (1);
+}
+
+/* Expects 2 args, on the same line. Both are index abbreviations.
+ Make the first one be a synonym for the second one, i.e. make the
+ first one have the same index as the second one. */
+void
+cm_synindex ()
+{
+ int source, target;
+ char *abbrev1, *abbrev2;
+
+ skip_whitespace ();
+ get_until_in_line (0, " ", &abbrev1);
+ target = find_index_offset (abbrev1);
+ skip_whitespace ();
+ get_until_in_line (0, " ", &abbrev2);
+ source = find_index_offset (abbrev2);
+ if (source < 0 || target < 0)
+ {
+ line_error (_("Unknown index `%s' and/or `%s' in @synindex"),
+ abbrev1, abbrev2);
+ }
+ else
+ {
+ name_index_alist[target]->write_index
+ = name_index_alist[source]->write_index;
+ }
+
+ free (abbrev1);
+ free (abbrev2);
+}
+
+void
+cm_pindex () /* Pinhead index. */
+{
+ index_add_arg ("pg");
+}
+
+void
+cm_vindex () /* Variable index. */
+{
+ index_add_arg ("vr");
+}
+
+void
+cm_kindex () /* Key index. */
+{
+ index_add_arg ("ky");
+}
+
+void
+cm_cindex () /* Concept index. */
+{
+ index_add_arg ("cp");
+}
+
+void
+cm_findex () /* Function index. */
+{
+ index_add_arg ("fn");
+}
+
+void
+cm_tindex () /* Data Type index. */
+{
+ index_add_arg ("tp");
+}
+
+int
+index_element_compare (element1, element2)
+ INDEX_ELT **element1, **element2;
+{
+ return index_compare_fn ((*element1)->entry, (*element2)->entry);
+}
+
+/* Force all index entries to be unique. */
+void
+make_index_entries_unique (array, count)
+ INDEX_ELT **array;
+ int count;
+{
+ int i, j;
+ INDEX_ELT **copy;
+ int counter = 1;
+
+ copy = xmalloc ((1 + count) * sizeof (INDEX_ELT *));
+
+ for (i = 0, j = 0; i < count; i++)
+ {
+ if (i == (count - 1)
+ || array[i]->node != array[i + 1]->node
+ || !STREQ (array[i]->entry, array[i + 1]->entry))
+ copy[j++] = array[i];
+ else
+ {
+ free (array[i]->entry);
+ free (array[i]->entry_text);
+ free (array[i]);
+ }
+ }
+ copy[j] = NULL;
+
+ /* Now COPY contains only unique entries. Duplicated entries in the
+ original array have been freed. Replace the current array with
+ the copy, fixing the NEXT pointers. */
+ for (i = 0; copy[i]; i++)
+ {
+ copy[i]->next = copy[i + 1];
+
+ /* Fix entry names which are the same. They point to different nodes,
+ so we make the entry name unique. */
+ if (copy[i+1]
+ && STREQ (copy[i]->entry, copy[i + 1]->entry)
+ && !html)
+ {
+ char *new_entry_name;
+
+ new_entry_name = xmalloc (10 + strlen (copy[i]->entry));
+ sprintf (new_entry_name, "%s <%d>", copy[i]->entry, counter);
+ free (copy[i]->entry);
+ copy[i]->entry = new_entry_name;
+ counter++;
+ }
+ else
+ counter = 1;
+
+ array[i] = copy[i];
+ }
+ array[i] = NULL;
+
+ /* Free the storage used only by COPY. */
+ free (copy);
+}
+
+/* Sort the index passed in INDEX, returning an array of
+ pointers to elements. The array is terminated with a NULL
+ pointer. We call qsort because it's supposed to be fast.
+ I think this looks bad. */
+INDEX_ELT **
+sort_index (index)
+ INDEX_ELT *index;
+{
+ INDEX_ELT **array;
+ INDEX_ELT *temp = index;
+ int count = 0;
+ int save_line_number = line_number;
+ char *save_input_filename = input_filename;
+ int save_html = html;
+
+ /* Pretend we are in non-HTML mode, for the purpose of getting the
+ expanded index entry that lacks any markup and other HTML escape
+ characters which could produce a wrong sort order. */
+ /* fixme: html: this still causes some markup, such as non-ASCII
+ characters @AE{} etc., to sort incorrectly. */
+ html = 0;
+
+ while (temp)
+ {
+ count++;
+ temp = temp->next;
+ }
+
+ /* We have the length. Make an array. */
+
+ array = xmalloc ((count + 1) * sizeof (INDEX_ELT *));
+ count = 0;
+ temp = index;
+
+ while (temp)
+ {
+ array[count++] = temp;
+
+ /* Set line number and input filename to the source line for this
+ index entry, as this expansion finds any errors. */
+ line_number = array[count - 1]->defining_line;
+ input_filename = array[count - 1]->defining_file;
+
+ /* If this particular entry should be printed as a "code" index,
+ then expand it as @code{entry}, i.e. as in fixed-width font. */
+ array[count-1]->entry = expansion (temp->entry_text,
+ array[count-1]->code);
+
+ temp = temp->next;
+ }
+ array[count] = NULL; /* terminate the array. */
+ line_number = save_line_number;
+ input_filename = save_input_filename;
+ html = save_html;
+
+#ifdef HAVE_STRCOLL
+ /* This is not perfect. We should set (then restore) the locale to the
+ documentlanguage, so strcoll operates according to the document's
+ locale, not the user's. For now, I'm just going to assume that
+ those few new documents which use @documentlanguage will be
+ processed in the appropriate locale. In any case, don't use
+ strcoll in the C (aka POSIX) locale, that is the ASCII ordering. */
+ if (language_code != en)
+ {
+ char *lang_env = getenv ("LANG");
+ if (lang_env && !STREQ (lang_env, "C") && !STREQ (lang_env, "POSIX"))
+ index_compare_fn = strcoll;
+ }
+#endif /* HAVE_STRCOLL */
+
+ /* Sort the array. */
+ qsort (array, count, sizeof (INDEX_ELT *), index_element_compare);
+ make_index_entries_unique (array, count);
+ return array;
+}
+
+/* Nonzero means that we are in the middle of printing an index. */
+int printing_index = 0;
+
+/* Takes one arg, a short name of an index to print.
+ Outputs a menu of the sorted elements of the index. */
+void
+cm_printindex ()
+{
+ int item;
+ INDEX_ELT *index;
+ INDEX_ELT *last_index = 0;
+ INDEX_ELT **array;
+ char *index_name;
+ unsigned line_length;
+ char *line;
+ int saved_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
+ int saved_filling_enabled = filling_enabled;
+ int saved_line_number = line_number;
+ char *saved_input_filename = input_filename;
+
+ close_paragraph ();
+ get_rest_of_line (0, &index_name);
+
+ index = index_list (index_name);
+ if (index == (INDEX_ELT *)-1)
+ {
+ line_error (_("Unknown index `%s' in @printindex"), index_name);
+ free (index_name);
+ return;
+ }
+
+ /* Do this before sorting, so execute_string in index_element_compare
+ will give the same results as when we actually print. */
+ printing_index = 1;
+ filling_enabled = 0;
+ inhibit_paragraph_indentation = 1;
+ array = sort_index (index);
+
+ close_paragraph ();
+ if (html)
+ add_word ("<ul compact>");
+ else if (!no_headers)
+ add_word ("* Menu:\n\n");
+
+ me_inhibit_expansion++;
+
+ /* This will probably be enough. */
+ line_length = 100;
+ line = xmalloc (line_length);
+
+ for (item = 0; (index = array[item]); item++)
+ {
+ /* A pathological document might have an index entry outside of any
+ node. Don't crash; try using the section name instead. */
+ char *index_node = index->node;
+
+ line_number = index->defining_line;
+ input_filename = index->defining_file;
+
+ if ((!index_node || !*index_node) && html)
+ index_node = toc_find_section_of_node (index_node);
+
+ if (!index_node || !*index_node)
+ {
+ line_error (_("Entry for index `%s' outside of any node"),
+ index_name);
+ if (html || !no_headers)
+ index_node = _("(outside of any node)");
+ }
+
+ if (html)
+ /* fixme: html: we should use specific index anchors pointing
+ to the actual location of the indexed position (but then we
+ have to find something to wrap the anchor around). */
+ {
+ if (last_index
+ && STREQ (last_index->entry_text, index->entry_text))
+ add_word (", "); /* Don't repeat the previous entry. */
+ else
+ {
+ /* In the HTML case, the expanded index entry is not
+ good for us, since it was expanded for non-HTML mode
+ inside sort_index. So we need to HTML-escape and
+ expand the original entry text here. */
+ char *escaped_entry = xstrdup (index->entry_text);
+ char *expanded_entry;
+
+ /* expansion() doesn't HTML-escape the argument, so need
+ to do it separately. */
+ escaped_entry = escape_string (escaped_entry);
+ expanded_entry = expansion (escaped_entry, index->code);
+ add_word_args ("\n<li>%s: ", expanded_entry);
+ free (escaped_entry);
+ free (expanded_entry);
+ }
+ add_word ("<a href=\"");
+ if (index->node && *index->node)
+ {
+ /* Make sure any non-macros in the node name are expanded. */
+ in_fixed_width_font++;
+ index_node = expansion (index_node, 0);
+ in_fixed_width_font--;
+ add_anchor_name (index_node, 1);
+ add_word_args ("\">%s</a>", index_node);
+ free (index_node);
+ }
+ else if (STREQ (index_node, _("(outside of any node)")))
+ {
+ add_anchor_name (index_node, 1);
+ add_word_args ("\">%s</a>", index_node);
+ }
+ else
+ /* If we use the section instead of the (missing) node, then
+ index_node already includes all we need except the #. */
+ add_word_args ("#%s</a>", index_node);
+ }
+ else
+ {
+ unsigned new_length = strlen (index->entry);
+
+ if (new_length < 50) /* minimum length used below */
+ new_length = 50;
+ new_length += strlen (index_node) + 7; /* * : .\n\0 */
+
+ if (new_length > line_length)
+ {
+ line_length = new_length;
+ line = xrealloc (line, line_length);
+ }
+ /* Print the entry, nicely formatted. We've already
+ expanded any commands in index->entry, including any
+ implicit @code. Thus, can't call execute_string, since
+ @@ has turned into @. */
+ if (!no_headers)
+ {
+ sprintf (line, "* %-37s ", index->entry);
+ line[2 + strlen (index->entry)] = ':';
+ insert_string (line);
+ /* Make sure any non-macros in the node name are expanded. */
+ in_fixed_width_font++;
+ execute_string ("%s.\n", index_node);
+ in_fixed_width_font--;
+ }
+ else
+ {
+ /* With --no-headers, the @node lines are gone, so
+ there's little sense in referring to them in the
+ index. Instead, output the number or name of the
+ section that corresponds to that node. */
+ char *section_name = toc_find_section_of_node (index_node);
+
+ sprintf (line, "%-*s ", number_sections ? 50 : 1, index->entry);
+ line[strlen (index->entry)] = ':';
+ insert_string (line);
+ if (section_name)
+ {
+ int idx = 0;
+ unsigned ref_len = strlen (section_name) + 30;
+
+ if (ref_len > line_length)
+ {
+ line_length = ref_len;
+ line = xrealloc (line, line_length);
+ }
+
+ if (number_sections)
+ {
+ while (section_name[idx]
+ && (isdigit (section_name[idx])
+ || (idx && section_name[idx] == '.')))
+ idx++;
+ }
+ if (idx)
+ sprintf (line, " See %.*s.\n", idx, section_name);
+ else
+ sprintf (line, "\n See ``%s''.\n", section_name);
+ insert_string (line);
+ }
+ else
+ {
+ insert_string (" "); /* force a blank */
+ execute_string ("See node %s.\n", index_node);
+ }
+ }
+ }
+
+ /* Prevent `output_paragraph' from growing to the size of the
+ whole index. */
+ flush_output ();
+ last_index = index;
+ }
+
+ free (line);
+ free (index_name);
+
+ me_inhibit_expansion--;
+
+ printing_index = 0;
+ free (array);
+ close_single_paragraph ();
+ filling_enabled = saved_filling_enabled;
+ inhibit_paragraph_indentation = saved_inhibit_paragraph_indentation;
+ input_filename = saved_input_filename;
+ line_number = saved_line_number;
+
+ if (html)
+ add_word ("</ul>");
+}
diff --git a/contrib/texinfo/makeinfo/index.h b/contrib/texinfo/makeinfo/index.h
new file mode 100644
index 0000000..ed8583a
--- /dev/null
+++ b/contrib/texinfo/makeinfo/index.h
@@ -0,0 +1,36 @@
+/* index.h -- declarations for index.c.
+ $Id: index.h,v 1.4 1999/04/19 18:12:17 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef INDEX_H
+#define INDEX_H
+
+#include "makeinfo.h"
+#include "cmds.h"
+
+/* User commands are only new indices. (Macros are handled separately.) */
+extern COMMAND **user_command_array;
+extern int user_command_array_len;
+
+/* Initialize all indices. */
+extern void init_indices ();
+
+/* Function to compare index entries for sorting. */
+extern int (*index_compare_fn) ();
+
+#endif /* !INDEX_H */
diff --git a/contrib/texinfo/makeinfo/insertion.c b/contrib/texinfo/makeinfo/insertion.c
new file mode 100644
index 0000000..11b9089
--- /dev/null
+++ b/contrib/texinfo/makeinfo/insertion.c
@@ -0,0 +1,1368 @@
+/* insertion.c -- insertions for Texinfo.
+ $Id: insertion.c,v 1.27 1999/07/06 23:12:53 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "cmds.h"
+#include "defun.h"
+#include "insertion.h"
+#include "macro.h"
+#include "makeinfo.h"
+
+/* Must match list in insertion.h. */
+static char *insertion_type_names[] =
+{
+ "cartouche", "defcv", "deffn", "defivar", "defmac", "defmethod",
+ "defop", "defopt", "defspec", "deftp", "deftypefn", "deftypefun",
+ "deftypeivar", "deftypemethod", "deftypeop", "deftypevar",
+ "deftypevr", "defun", "defvar", "defvr", "detailmenu", "direntry",
+ "display", "enumerate", "example", "flushleft", "flushright",
+ "format", "ftable", "group", "ifclear", "ifhtml", "ifinfo",
+ "ifnothtml", "ifnotinfo", "ifnottex", "ifset", "iftex", "itemize",
+ "lisp", "menu", "multitable", "quotation", "rawhtml", "rawtex",
+ "smalldisplay", "smallexample", "smallformat", "smalllisp", "table",
+ "tex", "vtable", "bad_type"
+};
+
+/* All nested environments. */
+INSERTION_ELT *insertion_stack = NULL;
+
+/* How deeply we're nested. */
+int insertion_level = 0;
+
+/* Whether to examine menu lines. */
+int in_menu = 0;
+
+/* How to examine menu lines. */
+int in_detailmenu = 0;
+
+/* Set to 1 if we've processed (commentary) text in a @menu that
+ wasn't part of a menu item. */
+int had_menu_commentary;
+
+/* Set to 1 if <p> is written in normal context.
+ Used for menu and itemize. */
+int in_paragraph = 0;
+
+static const char dl_tag[] = "<dl>\n";
+
+void
+init_insertion_stack ()
+{
+ insertion_stack = NULL;
+}
+
+/* Return the type of the current insertion. */
+static enum insertion_type
+current_insertion_type ()
+{
+ return insertion_level ? insertion_stack->insertion : bad_type;
+}
+
+/* Return the string which is the function to wrap around items, or NULL
+ if we're not in an environment where @item is ok. */
+static char *
+current_item_function ()
+{
+ int done = 0;
+ INSERTION_ELT *elt = insertion_stack;
+
+ /* Skip down through the stack until we find an insertion with an
+ itemize function defined, i.e., skip conditionals, @cartouche, etc. */
+ while (!done && elt)
+ {
+ switch (elt->insertion)
+ {
+ /* This list should match the one in cm_item. */
+ case ifclear:
+ case ifhtml:
+ case ifinfo:
+ case ifnothtml:
+ case ifnotinfo:
+ case ifnottex:
+ case ifset:
+ case iftex:
+ case rawhtml:
+ case rawtex:
+ case tex:
+ case cartouche:
+ elt = elt->next;
+ break;
+
+ default:
+ done = 1;
+ }
+ }
+
+ /* item_function usually gets assigned the empty string. */
+ return done && (*elt->item_function) ? elt->item_function : NULL;
+}
+
+/* Parse the item marker function off the input. If result is just "@",
+ change it to "@ ", since "@" by itself is not a command. This makes
+ "@ ", "@\t", and "@\n" all the same, but their default meanings are
+ the same anyway, and let's not worry about supporting redefining them. */
+char *
+get_item_function ()
+{
+ char *item_function;
+ get_rest_of_line (0, &item_function);
+
+ /* If we hit the end of text in get_rest_of_line, backing up
+ input pointer will cause the last character of the last line
+ be pushed back onto the input, which is wrong. */
+ if (input_text_offset < input_text_length)
+ backup_input_pointer ();
+
+ if (STREQ (item_function, "@"))
+ {
+ free (item_function);
+ item_function = xstrdup ("@ ");
+ }
+
+ return item_function;
+}
+
+ /* Push the state of the current insertion on the stack. */
+void
+push_insertion (type, item_function)
+ enum insertion_type type;
+ char *item_function;
+{
+ INSERTION_ELT *new = xmalloc (sizeof (INSERTION_ELT));
+
+ new->item_function = item_function;
+ new->filling_enabled = filling_enabled;
+ new->indented_fill = indented_fill;
+ new->insertion = type;
+ new->line_number = line_number;
+ new->filename = xstrdup (input_filename);
+ new->inhibited = inhibit_paragraph_indentation;
+ new->in_fixed_width_font = in_fixed_width_font;
+ new->next = insertion_stack;
+ insertion_stack = new;
+ insertion_level++;
+}
+
+ /* Pop the value on top of the insertion stack into the
+ global variables. */
+void
+pop_insertion ()
+{
+ INSERTION_ELT *temp = insertion_stack;
+
+ if (temp == NULL)
+ return;
+
+ in_fixed_width_font = temp->in_fixed_width_font;
+ inhibit_paragraph_indentation = temp->inhibited;
+ filling_enabled = temp->filling_enabled;
+ indented_fill = temp->indented_fill;
+ free_and_clear (&(temp->item_function));
+ free_and_clear (&(temp->filename));
+ insertion_stack = insertion_stack->next;
+ free (temp);
+ insertion_level--;
+}
+
+ /* Return a pointer to the print name of this
+ enumerated type. */
+char *
+insertion_type_pname (type)
+ enum insertion_type type;
+{
+ if ((int) type < (int) bad_type)
+ return insertion_type_names[(int) type];
+ else
+ return _("Broken-Type in insertion_type_pname");
+}
+
+/* Return the insertion_type associated with NAME.
+ If the type is not one of the known ones, return BAD_TYPE. */
+enum insertion_type
+find_type_from_name (name)
+ char *name;
+{
+ int index = 0;
+ while (index < (int) bad_type)
+ {
+ if (STREQ (name, insertion_type_names[index]))
+ return (enum insertion_type) index;
+ if (index == rawhtml && STREQ (name, "html"))
+ return rawhtml;
+ if (index == rawtex && STREQ (name, "tex"))
+ return rawtex;
+ index++;
+ }
+ return bad_type;
+}
+
+int
+defun_insertion (type)
+ enum insertion_type type;
+{
+ return 0
+ || (type == defcv)
+ || (type == deffn)
+ || (type == defivar)
+ || (type == defmac)
+ || (type == defmethod)
+ || (type == defop)
+ || (type == defopt)
+ || (type == defspec)
+ || (type == deftp)
+ || (type == deftypefn)
+ || (type == deftypefun)
+ || (type == deftypeivar)
+ || (type == deftypemethod)
+ || (type == deftypeop)
+ || (type == deftypevar)
+ || (type == deftypevr)
+ || (type == defun)
+ || (type == defvar)
+ || (type == defvr)
+ ;
+}
+
+/* MAX_NS is the maximum nesting level for enumerations. I picked 100
+ which seemed reasonable. This doesn't control the number of items,
+ just the number of nested lists. */
+#define max_stack_depth 100
+#define ENUM_DIGITS 1
+#define ENUM_ALPHA 2
+typedef struct {
+ int enumtype;
+ int enumval;
+} DIGIT_ALPHA;
+
+DIGIT_ALPHA enumstack[max_stack_depth];
+int enumstack_offset = 0;
+int current_enumval = 1;
+int current_enumtype = ENUM_DIGITS;
+char *enumeration_arg = NULL;
+
+void
+start_enumerating (at, type)
+ int at, type;
+{
+ if ((enumstack_offset + 1) == max_stack_depth)
+ {
+ line_error (_("Enumeration stack overflow"));
+ return;
+ }
+ enumstack[enumstack_offset].enumtype = current_enumtype;
+ enumstack[enumstack_offset].enumval = current_enumval;
+ enumstack_offset++;
+ current_enumval = at;
+ current_enumtype = type;
+}
+
+void
+stop_enumerating ()
+{
+ --enumstack_offset;
+ if (enumstack_offset < 0)
+ enumstack_offset = 0;
+
+ current_enumval = enumstack[enumstack_offset].enumval;
+ current_enumtype = enumstack[enumstack_offset].enumtype;
+}
+
+/* Place a letter or digits into the output stream. */
+void
+enumerate_item ()
+{
+ char temp[10];
+
+ if (current_enumtype == ENUM_ALPHA)
+ {
+ if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
+ {
+ current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
+ warning (_("lettering overflow, restarting at %c"), current_enumval);
+ }
+ sprintf (temp, "%c. ", current_enumval);
+ }
+ else
+ sprintf (temp, "%d. ", current_enumval);
+
+ indent (output_column += (current_indent - strlen (temp)));
+ add_word (temp);
+ current_enumval++;
+}
+
+static void
+enum_html ()
+{
+ char type;
+ int start;
+
+ if (isdigit (*enumeration_arg))
+ {
+ type = '1';
+ start = atoi (enumeration_arg);
+ }
+ else if (isupper (*enumeration_arg))
+ {
+ type = 'A';
+ start = *enumeration_arg - 'A' + 1;
+ }
+ else
+ {
+ type = 'a';
+ start = *enumeration_arg - 'a' + 1;
+ }
+
+ add_word_args ("<ol type=%c start=%d>\n", type, start);
+}
+
+/* Conditionally parse based on the current command name. */
+void
+command_name_condition ()
+{
+ char *discarder = xmalloc (8 + strlen (command));
+
+ sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
+ discard_until (discarder);
+ discard_until ("\n");
+
+ free (discarder);
+}
+
+/* This is where the work for all the "insertion" style
+ commands is done. A huge switch statement handles the
+ various setups, and generic code is on both sides. */
+void
+begin_insertion (type)
+ enum insertion_type type;
+{
+ int no_discard = 0;
+
+ if (defun_insertion (type))
+ {
+ push_insertion (type, xstrdup (""));
+ no_discard++;
+ }
+ else
+ push_insertion (type, get_item_function ());
+
+ switch (type)
+ {
+ case menu:
+ if (!no_headers)
+ close_paragraph ();
+
+ filling_enabled = no_indent = 0;
+ inhibit_paragraph_indentation = 1;
+
+ if (html)
+ {
+ had_menu_commentary = 1;
+ }
+ else if (!no_headers)
+ add_word ("* Menu:\n");
+
+ in_menu++;
+ in_fixed_width_font++;
+ no_discard++;
+ break;
+
+ case detailmenu:
+ if (!in_menu)
+ {
+ if (!no_headers)
+ close_paragraph ();
+
+ filling_enabled = no_indent = 0;
+ inhibit_paragraph_indentation = 1;
+
+ no_discard++;
+ }
+
+ in_fixed_width_font++;
+ in_detailmenu++;
+ break;
+
+ case direntry:
+ if (html)
+ command_name_condition ();
+ else
+ {
+ close_single_paragraph ();
+ filling_enabled = no_indent = 0;
+ inhibit_paragraph_indentation = 1;
+ insert_string ("START-INFO-DIR-ENTRY\n");
+ }
+ break;
+
+ case quotation:
+ /* @quotation does filling (@display doesn't). */
+ if (html)
+ add_word ("<blockquote>\n");
+ else
+ {
+ close_single_paragraph ();
+ last_char_was_newline = no_indent = 0;
+ indented_fill = filling_enabled = 1;
+ inhibit_paragraph_indentation = 1;
+ }
+ current_indent += default_indentation_increment;
+ break;
+
+ case display:
+ case smalldisplay:
+ case example:
+ case smallexample:
+ case lisp:
+ case smalllisp:
+ /* Like @display but without indentation. */
+ case smallformat:
+ case format:
+ close_single_paragraph ();
+ inhibit_paragraph_indentation = 1;
+ in_fixed_width_font++;
+ filling_enabled = 0;
+ last_char_was_newline = 0;
+
+ if (html)
+ /* Kludge alert: if <pre> is followed by a newline, IE3
+ renders an extra blank line before the pre-formatted block.
+ Other browsers seem to not mind one way or the other. */
+ add_word ("<pre>");
+
+ if (type != format && type != smallformat)
+ current_indent += default_indentation_increment;
+ break;
+
+ case multitable:
+ do_multitable ();
+ break;
+
+ case table:
+ case ftable:
+ case vtable:
+ case itemize:
+ close_single_paragraph ();
+ current_indent += default_indentation_increment;
+ filling_enabled = indented_fill = 1;
+#if defined (INDENT_PARAGRAPHS_IN_TABLE)
+ inhibit_paragraph_indentation = 0;
+#else
+ inhibit_paragraph_indentation = 1;
+#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
+
+ /* Make things work for losers who forget the itemize syntax. */
+ if (type == itemize)
+ {
+ if (!(*insertion_stack->item_function))
+ {
+ free (insertion_stack->item_function);
+ insertion_stack->item_function = xstrdup ("@bullet");
+ }
+ }
+
+ if (!*insertion_stack->item_function)
+ {
+ line_error (_("%s requires an argument: the formatter for %citem"),
+ insertion_type_pname (type), COMMAND_PREFIX);
+ }
+
+ if (html)
+ {
+ if (type == itemize)
+ {
+ add_word ("<ul>\n");
+ in_paragraph = 0;
+ }
+ else
+ add_word (dl_tag);
+ }
+ break;
+
+ case enumerate:
+ close_single_paragraph ();
+ no_indent = 0;
+#if defined (INDENT_PARAGRAPHS_IN_TABLE)
+ inhibit_paragraph_indentation = 0;
+#else
+ inhibit_paragraph_indentation = 1;
+#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
+
+ current_indent += default_indentation_increment;
+ filling_enabled = indented_fill = 1;
+
+ if (html)
+ enum_html ();
+
+ if (isdigit (*enumeration_arg))
+ start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
+ else
+ start_enumerating (*enumeration_arg, ENUM_ALPHA);
+ break;
+
+ /* @group does nothing special in makeinfo. */
+ case group:
+ /* Only close the paragraph if we are not inside of an
+ @example-like environment. */
+ if (!insertion_stack->next
+ || (insertion_stack->next->insertion != display
+ && insertion_stack->next->insertion != smalldisplay
+ && insertion_stack->next->insertion != example
+ && insertion_stack->next->insertion != smallexample
+ && insertion_stack->next->insertion != lisp
+ && insertion_stack->next->insertion != smalllisp
+ && insertion_stack->next->insertion != format
+ && insertion_stack->next->insertion != smallformat
+ && insertion_stack->next->insertion != flushleft
+ && insertion_stack->next->insertion != flushright))
+ close_single_paragraph ();
+ break;
+
+ /* Insertions that are no-ops in info, but do something in TeX. */
+ case cartouche:
+ case ifclear:
+ case ifhtml:
+ case ifinfo:
+ case ifnothtml:
+ case ifnotinfo:
+ case ifnottex:
+ case ifset:
+ case iftex:
+ case rawtex:
+ if (in_menu)
+ no_discard++;
+ break;
+
+ case rawhtml:
+ escape_html = 0;
+ break;
+
+ case defcv:
+ case deffn:
+ case defivar:
+ case defmac:
+ case defmethod:
+ case defop:
+ case defopt:
+ case defspec:
+ case deftp:
+ case deftypefn:
+ case deftypefun:
+ case deftypeivar:
+ case deftypemethod:
+ case deftypeop:
+ case deftypevar:
+ case deftypevr:
+ case defun:
+ case defvar:
+ case defvr:
+ inhibit_paragraph_indentation = 1;
+ filling_enabled = indented_fill = 1;
+ current_indent += default_indentation_increment;
+ no_indent = 0;
+ break;
+
+ case flushleft:
+ close_single_paragraph ();
+ inhibit_paragraph_indentation = 1;
+ filling_enabled = indented_fill = no_indent = 0;
+ break;
+
+ case flushright:
+ close_single_paragraph ();
+ filling_enabled = indented_fill = no_indent = 0;
+ inhibit_paragraph_indentation = 1;
+ force_flush_right++;
+ break;
+
+ default:
+ line_error ("begin_insertion internal error: type=%d", type);
+
+ }
+
+ if (!no_discard)
+ discard_until ("\n");
+}
+
+/* Try to end the insertion with the specified TYPE. With a value of
+ `bad_type', TYPE gets translated to match the value currently on top
+ of the stack. Otherwise, if TYPE doesn't match the top of the
+ insertion stack, give error. */
+void
+end_insertion (type)
+ enum insertion_type type;
+{
+ enum insertion_type temp_type;
+
+ if (!insertion_level)
+ return;
+
+ temp_type = current_insertion_type ();
+
+ if (type == bad_type)
+ type = temp_type;
+
+ if (type != temp_type)
+ {
+ line_error
+ (_("`@end' expected `%s', but saw `%s'"),
+ insertion_type_pname (temp_type), insertion_type_pname (type));
+ return;
+ }
+
+ pop_insertion ();
+
+ switch (type)
+ {
+ /* Insertions which have no effect on paragraph formatting. */
+ case ifclear:
+ case ifhtml:
+ case ifinfo:
+ case ifnothtml:
+ case ifnotinfo:
+ case ifnottex:
+ case ifset:
+ case iftex:
+ case rawtex:
+ break;
+
+ case rawhtml:
+ escape_html = 1;
+ break;
+
+ case direntry: /* Eaten if html. */
+ insert_string ("END-INFO-DIR-ENTRY\n\n");
+ close_insertion_paragraph ();
+ break;
+
+ case detailmenu:
+ in_detailmenu--; /* No longer hacking menus. */
+ if (!in_menu)
+ {
+ if (!no_headers)
+ close_insertion_paragraph ();
+ }
+ break;
+
+ case menu:
+ in_menu--; /* No longer hacking menus. */
+ if (html)
+ add_word ("</ul>\n");
+ else if (!no_headers)
+ close_insertion_paragraph ();
+ break;
+
+ case multitable:
+ end_multitable ();
+ break;
+
+ case enumerate:
+ stop_enumerating ();
+ close_insertion_paragraph ();
+ current_indent -= default_indentation_increment;
+ if (html)
+ add_word ("</ol>\n");
+ break;
+
+ case flushleft:
+ case group:
+ case cartouche:
+ close_insertion_paragraph ();
+ break;
+
+ case format:
+ case smallformat:
+ case display:
+ case smalldisplay:
+ case example:
+ case smallexample:
+ case lisp:
+ case smalllisp:
+ case quotation:
+ /* @format and @smallformat are the only fixed_width insertion
+ without a change in indentation. */
+ if (type != format && type != smallformat)
+ current_indent -= default_indentation_increment;
+
+ if (html)
+ add_word (type == quotation ? "</blockquote>\n" : "</pre>\n");
+
+ /* The ending of one of these insertions always marks the
+ start of a new paragraph. */
+ close_insertion_paragraph ();
+ break;
+
+ case table:
+ case ftable:
+ case vtable:
+ current_indent -= default_indentation_increment;
+ if (html)
+ add_word ("</dl>\n");
+ break;
+
+ case itemize:
+ current_indent -= default_indentation_increment;
+ if (html)
+ add_word ("</ul>\n");
+ close_insertion_paragraph ();
+ break;
+
+ case flushright:
+ force_flush_right--;
+ close_insertion_paragraph ();
+ break;
+
+ /* Handle the @defun insertions with this default clause. */
+ default:
+ {
+ enum insertion_type base_type;
+
+ if (type < defcv || type > defvr)
+ line_error ("end_insertion internal error: type=%d", type);
+
+ base_type = get_base_type (type);
+ switch (base_type)
+ {
+ case deffn:
+ case defvr:
+ case deftp:
+ case deftypefn:
+ case deftypevr:
+ case defcv:
+ case defop:
+ case deftypemethod:
+ case deftypeop:
+ case deftypeivar:
+ if (html)
+ /* close the tables which has been opened in defun.c */
+ add_word ("</TD></TR>\n</TABLE>\n");
+ break;
+ } /* switch (base_type)... */
+
+ current_indent -= default_indentation_increment;
+ close_insertion_paragraph ();
+ }
+ break;
+
+ }
+
+ if (current_indent < 0)
+ line_error ("end_insertion internal error: current indent=%d",
+ current_indent);
+}
+
+/* Insertions cannot cross certain boundaries, such as node beginnings. In
+ code that creates such boundaries, you should call `discard_insertions'
+ before doing anything else. It prints the errors for you, and cleans up
+ the insertion stack.
+
+ With nonzero SPECIALS_OK argument, allows unmatched
+ @if... conditionals, otherwise not. This is because conditionals can
+ cross node boundaries. Always happens with the @top node, for example. */
+void
+discard_insertions (specials_ok)
+ int specials_ok;
+{
+ int real_line_number = line_number;
+ while (insertion_stack)
+ {
+ if (specials_ok
+ && ((ifclear <= insertion_stack->insertion
+ && insertion_stack->insertion <= iftex)
+ || insertion_stack->insertion == rawhtml
+ || insertion_stack->insertion == rawtex))
+ break;
+ else
+ {
+ char *offender = insertion_type_pname (insertion_stack->insertion);
+ char *current_filename = input_filename;
+
+ input_filename = insertion_stack->filename;
+ line_number = insertion_stack->line_number;
+ line_error (_("No matching `%cend %s'"), COMMAND_PREFIX, offender);
+ input_filename = current_filename;
+ pop_insertion ();
+ }
+ }
+ line_number = real_line_number;
+}
+
+/* Insertion (environment) commands. */
+
+void
+cm_quotation ()
+{
+ begin_insertion (quotation);
+}
+
+void
+cm_example ()
+{
+ begin_insertion (example);
+}
+
+void
+cm_smallexample ()
+{
+ begin_insertion (smallexample);
+}
+
+void
+cm_lisp ()
+{
+ begin_insertion (lisp);
+}
+
+void
+cm_smalllisp ()
+{
+ begin_insertion (smalllisp);
+}
+
+/* @cartouche/@end cartouche draws box with rounded corners in
+ TeX output. Right now, just a no-op insertion. */
+void
+cm_cartouche ()
+{
+ begin_insertion (cartouche);
+}
+
+void
+cm_format ()
+{
+ begin_insertion (format);
+}
+
+void
+cm_smallformat ()
+{
+ begin_insertion (smallformat);
+}
+
+void
+cm_display ()
+{
+ begin_insertion (display);
+}
+
+void
+cm_smalldisplay ()
+{
+ begin_insertion (smalldisplay);
+}
+
+void
+cm_direntry ()
+{
+ if (no_headers || html)
+ command_name_condition ();
+ else
+ begin_insertion (direntry);
+}
+
+void
+cm_itemize ()
+{
+ begin_insertion (itemize);
+}
+
+/* Start an enumeration insertion of type TYPE. If the user supplied
+ no argument on the line, then use DEFAULT_STRING as the initial string. */
+static void
+do_enumeration (type, default_string)
+ int type;
+ char *default_string;
+{
+ get_until_in_line (0, ".", &enumeration_arg);
+ canon_white (enumeration_arg);
+
+ if (!*enumeration_arg)
+ {
+ free (enumeration_arg);
+ enumeration_arg = xstrdup (default_string);
+ }
+
+ if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
+ {
+ warning (_("%s requires letter or digit"), insertion_type_pname (type));
+
+ switch (type)
+ {
+ case enumerate:
+ default_string = "1";
+ break;
+ }
+ enumeration_arg = xstrdup (default_string);
+ }
+ begin_insertion (type);
+}
+
+void
+cm_enumerate ()
+{
+ do_enumeration (enumerate, "1");
+}
+
+void
+cm_table ()
+{
+ begin_insertion (table);
+}
+
+void
+cm_multitable ()
+{
+ begin_insertion (multitable); /* @@ */
+}
+
+void
+cm_ftable ()
+{
+ begin_insertion (ftable);
+}
+
+void
+cm_vtable ()
+{
+ begin_insertion (vtable);
+}
+
+void
+cm_group ()
+{
+ begin_insertion (group);
+}
+
+void
+cm_ifinfo ()
+{
+ if (process_info)
+ begin_insertion (ifinfo);
+ else
+ command_name_condition ();
+}
+
+void
+cm_ifnotinfo ()
+{
+ if (!process_info)
+ begin_insertion (ifnotinfo);
+ else
+ command_name_condition ();
+}
+
+
+/* Insert raw HTML (no escaping of `<' etc.). */
+void
+cm_html ()
+{
+ if (process_html)
+ begin_insertion (rawhtml);
+ else
+ command_name_condition ();
+}
+
+void
+cm_ifhtml ()
+{
+ if (process_html)
+ begin_insertion (ifhtml);
+ else
+ command_name_condition ();
+}
+
+void
+cm_ifnothtml ()
+{
+ if (!process_html)
+ begin_insertion (ifnothtml);
+ else
+ command_name_condition ();
+}
+
+
+void
+cm_tex ()
+{
+ if (process_tex)
+ begin_insertion (rawtex);
+ else
+ command_name_condition ();
+}
+
+void
+cm_iftex ()
+{
+ if (process_tex)
+ begin_insertion (iftex);
+ else
+ command_name_condition ();
+}
+
+void
+cm_ifnottex ()
+{
+ if (!process_tex)
+ begin_insertion (ifnottex);
+ else
+ command_name_condition ();
+}
+
+/* Begin an insertion where the lines are not filled or indented. */
+void
+cm_flushleft ()
+{
+ begin_insertion (flushleft);
+}
+
+/* Begin an insertion where the lines are not filled, and each line is
+ forced to the right-hand side of the page. */
+void
+cm_flushright ()
+{
+ begin_insertion (flushright);
+}
+
+void
+cm_menu ()
+{
+ if (current_node == NULL)
+ {
+ warning (_("@menu seen before first @node, creating `Top' node"));
+ warning (_("perhaps your @top node should be wrapped in @ifnottex rather than @ifinfo?"));
+ /* Include @top command so we can construct the implicit node tree. */
+ execute_string ("@node top\n@top Top\n");
+ }
+ begin_insertion (menu);
+}
+
+void
+cm_detailmenu ()
+{
+ if (current_node == NULL)
+ { /* Problems anyway, @detailmenu should always be inside @menu. */
+ warning (_("@detailmenu seen before first node, creating `Top' node"));
+ execute_string ("@node top\n@top Top\n");
+ }
+ begin_insertion (detailmenu);
+}
+
+/* End existing insertion block. */
+void
+cm_end ()
+{
+ char *temp;
+ enum insertion_type type;
+
+ if (!insertion_level)
+ {
+ line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command);
+ return;
+ }
+
+ get_rest_of_line (0, &temp);
+
+ if (temp[0] == 0)
+ line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command);
+
+ type = find_type_from_name (temp);
+
+ if (type == bad_type)
+ {
+ line_error (_("Bad argument to `%s', `%s', using `%s'"),
+ command, temp, insertion_type_pname (current_insertion_type ()));
+ }
+ end_insertion (type);
+ free (temp);
+}
+
+/* @itemx, @item. */
+
+static int itemx_flag = 0;
+
+/* Return whether CMD takes a brace-delimited {arg}. */
+static int
+command_needs_braces (cmd)
+ char *cmd;
+{
+ int i;
+ for (i = 0; command_table[i].name; i++)
+ {
+ if (STREQ (command_table[i].name, cmd))
+ return command_table[i].argument_in_braces == BRACE_ARGS;
+ }
+
+ return 0; /* macro or alias */
+}
+
+
+void
+cm_item ()
+{
+ char *rest_of_line, *item_func;
+
+ /* Can only hack "@item" while inside of an insertion. */
+ if (insertion_level)
+ {
+ INSERTION_ELT *stack = insertion_stack;
+ int original_input_text_offset;
+
+ skip_whitespace ();
+ original_input_text_offset = input_text_offset;
+
+ get_rest_of_line (0, &rest_of_line);
+ item_func = current_item_function ();
+
+ /* Do the right thing depending on which insertion function is active. */
+ switch_top:
+ switch (stack->insertion)
+ {
+ case multitable:
+ multitable_item ();
+ /* Support text directly after the @item. */
+ if (*rest_of_line)
+ {
+ line_number--;
+ input_text_offset = original_input_text_offset;
+ }
+ break;
+
+ case ifclear:
+ case ifhtml:
+ case ifinfo:
+ case ifnothtml:
+ case ifnotinfo:
+ case ifnottex:
+ case ifset:
+ case iftex:
+ case rawhtml:
+ case rawtex:
+ case tex:
+ case cartouche:
+ stack = stack->next;
+ if (!stack)
+ goto no_insertion;
+ else
+ goto switch_top;
+ break;
+
+ case menu:
+ case quotation:
+ case example:
+ case smallexample:
+ case lisp:
+ case smalllisp:
+ case format:
+ case smallformat:
+ case display:
+ case smalldisplay:
+ case group:
+ line_error (_("@%s not meaningful inside `@%s' block"),
+ command,
+ insertion_type_pname (current_insertion_type ()));
+ break;
+
+ case itemize:
+ case enumerate:
+ if (itemx_flag)
+ {
+ line_error (_("@itemx not meaningful inside `%s' block"),
+ insertion_type_pname (current_insertion_type ()));
+ }
+ else
+ {
+ if (html)
+ {
+ if (in_paragraph)
+ {
+ add_word ("</p>");
+ in_paragraph = 0;
+ }
+ add_word ("<li>");
+ }
+ else
+ {
+ start_paragraph ();
+ kill_self_indent (-1);
+ filling_enabled = indented_fill = 1;
+
+ if (current_item_function ())
+ {
+ output_column = current_indent - 2;
+ indent (output_column);
+
+ /* The item marker can be given with or without
+ braces -- @bullet and @bullet{} are both ok.
+ Or it might be something that doesn't take
+ braces at all, such as "o" or "#" or "@ ".
+ Thus, only supply braces if the item marker is
+ a command, they haven't supplied braces
+ themselves, and we know it needs them. */
+ if (item_func && *item_func)
+ {
+ if (*item_func == COMMAND_PREFIX
+ && item_func[strlen (item_func) - 1] != '}'
+ && command_needs_braces (item_func + 1))
+ execute_string ("%s{}", item_func);
+ else
+ execute_string ("%s", item_func);
+ }
+ insert (' ');
+ output_column++;
+ }
+ else
+ enumerate_item ();
+
+ /* Special hack. This makes `close_paragraph' a no-op until
+ `start_paragraph' has been called. */
+ must_start_paragraph = 1;
+ }
+
+ /* Handle text directly after the @item. */
+ if (*rest_of_line)
+ {
+ line_number--;
+ input_text_offset = original_input_text_offset;
+ }
+ }
+ break;
+
+ case table:
+ case ftable:
+ case vtable:
+ if (html)
+ {
+ static int last_html_output_position = 0;
+
+ /* If nothing has been output since the last <dd>,
+ remove the empty <dd> element. Some browsers render
+ an extra empty line for <dd><dt>, which makes @itemx
+ conversion look ugly. */
+ if (last_html_output_position == output_position
+ && strncmp ((char *) output_paragraph, "<dd>",
+ output_paragraph_offset) == 0)
+ output_paragraph_offset = 0;
+
+ /* Force the browser to render one blank line before
+ each new @item in a table. But don't do that unless
+ this is the first <dt> after the <dl>, or if we are
+ converting @itemx.
+
+ Note that there are some browsers which ignore <br>
+ in this context, but I cannot find any way to force
+ them all render exactly one blank line. */
+ if (!itemx_flag
+ && strncmp ((char *) output_paragraph
+ + output_paragraph_offset - sizeof (dl_tag) + 1,
+ dl_tag, sizeof (dl_tag) - 1) != 0)
+ add_word ("<br>");
+
+ add_word ("<dt>");
+ if (item_func && *item_func)
+ execute_string ("%s{%s}", item_func, rest_of_line);
+ else
+ execute_string ("%s", rest_of_line);
+
+ if (current_insertion_type () == ftable)
+ execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
+
+ if (current_insertion_type () == vtable)
+ execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
+ /* Make sure output_position is updated, so we could
+ remember it. */
+ close_single_paragraph ();
+ last_html_output_position = output_position;
+ add_word ("<dd>");
+ }
+ else
+ {
+ /* We need this to determine if we have two @item's in a row
+ (see test just below). */
+ static int last_item_output_position = 0;
+
+ /* Get rid of extra characters. */
+ kill_self_indent (-1);
+
+ /* If we have one @item followed directly by another @item,
+ we need to insert a blank line. This is not true for
+ @itemx, though. */
+ if (!itemx_flag && last_item_output_position == output_position)
+ insert ('\n');
+
+ /* `close_paragraph' almost does what we want. The problem
+ is when paragraph_is_open, and last_char_was_newline, and
+ the last newline has been turned into a space, because
+ filling_enabled. I handle it here. */
+ if (last_char_was_newline && filling_enabled &&
+ paragraph_is_open)
+ insert ('\n');
+ close_paragraph ();
+
+#if defined (INDENT_PARAGRAPHS_IN_TABLE)
+ /* Indent on a new line, but back up one indentation level. */
+ {
+ int save = inhibit_paragraph_indentation;
+ inhibit_paragraph_indentation = 1;
+ /* At this point, inserting any non-whitespace character will
+ force the existing indentation to be output. */
+ add_char ('i');
+ inhibit_paragraph_indentation = save;
+ }
+#else /* !INDENT_PARAGRAPHS_IN_TABLE */
+ add_char ('i');
+#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
+
+ output_paragraph_offset--;
+ kill_self_indent (default_indentation_increment + 1);
+
+ /* Add item's argument to the line. */
+ filling_enabled = 0;
+ if (item_func && *item_func)
+ execute_string ("%s{%s}", item_func, rest_of_line);
+ else
+ execute_string ("%s", rest_of_line);
+
+ if (current_insertion_type () == ftable)
+ execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
+ else if (current_insertion_type () == vtable)
+ execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
+
+ /* Start a new line, and let start_paragraph ()
+ do the indenting of it for you. */
+ close_single_paragraph ();
+ indented_fill = filling_enabled = 1;
+ last_item_output_position = output_position;
+ }
+ }
+ free (rest_of_line);
+ }
+ else
+ {
+ no_insertion:
+ line_error (_("%c%s found outside of an insertion block"),
+ COMMAND_PREFIX, command);
+ }
+}
+
+void
+cm_itemx ()
+{
+ itemx_flag++;
+ cm_item ();
+ itemx_flag--;
+}
diff --git a/contrib/texinfo/makeinfo/insertion.h b/contrib/texinfo/makeinfo/insertion.h
new file mode 100644
index 0000000..6f4a24b
--- /dev/null
+++ b/contrib/texinfo/makeinfo/insertion.h
@@ -0,0 +1,61 @@
+/* insertion.h -- declarations for insertion.c.
+ $Id: insertion.h,v 1.6 1999/07/06 23:12:58 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef INSERTION_H
+#define INSERTION_H
+
+/* Must match list in insertion.c. */
+enum insertion_type
+{
+ cartouche, defcv, deffn, defivar, defmac, defmethod, defop, defopt,
+ defspec, deftp, deftypefn, deftypefun, deftypeivar, deftypemethod,
+ deftypeop, deftypevar, deftypevr, defun, defvar, defvr, detailmenu,
+ direntry, display, enumerate, example, flushleft, flushright, format,
+ ftable, group, ifclear, ifhtml, ifinfo, ifnothtml, ifnotinfo,
+ ifnottex, ifset, iftex, itemize, lisp, menu, multitable, quotation,
+ rawhtml, rawtex, smalldisplay, smallexample, smallformat, smalllisp,
+ table, tex, vtable, bad_type
+};
+
+typedef struct istack_elt
+{
+ struct istack_elt *next;
+ char *item_function;
+ char *filename;
+ int line_number;
+ int filling_enabled;
+ int indented_fill;
+ enum insertion_type insertion;
+ int inhibited;
+ int in_fixed_width_font;
+} INSERTION_ELT;
+
+
+extern int insertion_level;
+extern INSERTION_ELT *insertion_stack;
+extern int in_menu;
+extern int in_detailmenu;
+extern int had_menu_commentary;
+extern int in_paragraph;
+
+extern void command_name_condition ();
+extern void cm_ifnothtml (), cm_ifhtml(), cm_html ();
+extern void cm_ifinfo (), cm_ifnotinfo ();
+extern void cm_ifnottex (), cm_iftex (), cm_tex ();
+#endif /* !INSERTION_H */
diff --git a/contrib/texinfo/makeinfo/lang.c b/contrib/texinfo/makeinfo/lang.c
new file mode 100644
index 0000000..eeb9ef5
--- /dev/null
+++ b/contrib/texinfo/makeinfo/lang.c
@@ -0,0 +1,415 @@
+/* lang.c -- language depend behaviour (startpoint)
+ $Id: lang.c,v 1.11 1999/07/13 21:16:29 karl Exp $
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written by Karl Heinz Marbaise <kama@hippo.fido.de>. */
+
+#include "system.h"
+#include "cmds.h"
+#include "lang.h"
+#include "makeinfo.h"
+
+/* Current document encoding. */
+char *document_encoding = NULL;
+
+/* Current language code; default is English. */
+language_code_type language_code = en;
+
+language_struct language_table[] = {
+ { aa, "aa", "Afar" },
+ { ab, "ab", "Abkhazian" },
+ { af, "af", "Afrikaans" },
+ { am, "am", "Amharic" },
+ { ar, "ar", "Arabic" },
+ { as, "as", "Assamese" },
+ { ay, "ay", "Aymara" },
+ { az, "az", "Azerbaijani" },
+ { ba, "ba", "Bashkir" },
+ { be, "be", "Byelorussian" },
+ { bg, "bg", "Bulgarian" },
+ { bh, "bh", "Bihari" },
+ { bi, "bi", "Bislama" },
+ { bn, "bn", "Bengali; Bangla" },
+ { bo, "bo", "Tibetan" },
+ { br, "br", "Breton" },
+ { ca, "ca", "Catalan" },
+ { co, "co", "Corsican" },
+ { cs, "cs", "Czech" },
+ { cy, "cy", "Welsh" },
+ { da, "da", "Danish" },
+ { de, "de", "German" },
+ { dz, "dz", "Bhutani" },
+ { el, "el", "Greek" },
+ { en, "en", "English" },
+ { eo, "eo", "Esperanto" },
+ { es, "es", "Spanish" },
+ { et, "et", "Estonian" },
+ { eu, "eu", "Basque" },
+ { fa, "fa", "Persian" },
+ { fi, "fi", "Finnish" },
+ { fj, "fj", "Fiji" },
+ { fo, "fo", "Faroese" },
+ { fr, "fr", "French" },
+ { fy, "fy", "Frisian" },
+ { ga, "ga", "Irish" },
+ { gd, "gd", "Scots Gaelic" },
+ { gl, "gl", "Galician" },
+ { gn, "gn", "Guarani" },
+ { gu, "gu", "Gujarati" },
+ { ha, "ha", "Hausa" },
+ { he, "he", "Hebrew" } /* (formerly iw) */,
+ { hi, "hi", "Hindi" },
+ { hr, "hr", "Croatian" },
+ { hu, "hu", "Hungarian" },
+ { hy, "hy", "Armenian" },
+ { ia, "ia", "Interlingua" },
+ { id, "id", "Indonesian" } /* (formerly in) */,
+ { ie, "ie", "Interlingue" },
+ { ik, "ik", "Inupiak" },
+ { is, "is", "Icelandic" },
+ { it, "it", "Italian" },
+ { iu, "iu", "Inuktitut" },
+ { ja, "ja", "Japanese" },
+ { jw, "jw", "Javanese" },
+ { ka, "ka", "Georgian" },
+ { kk, "kk", "Kazakh" },
+ { kl, "kl", "Greenlandic" },
+ { km, "km", "Cambodian" },
+ { kn, "kn", "Kannada" },
+ { ko, "ko", "Korean" },
+ { ks, "ks", "Kashmiri" },
+ { ku, "ku", "Kurdish" },
+ { ky, "ky", "Kirghiz" },
+ { la, "la", "Latin" },
+ { ln, "ln", "Lingala" },
+ { lo, "lo", "Laothian" },
+ { lt, "lt", "Lithuanian" },
+ { lv, "lv", "Latvian, Lettish" },
+ { mg, "mg", "Malagasy" },
+ { mi, "mi", "Maori" },
+ { mk, "mk", "Macedonian" },
+ { ml, "ml", "Malayalam" },
+ { mn, "mn", "Mongolian" },
+ { mo, "mo", "Moldavian" },
+ { mr, "mr", "Marathi" },
+ { ms, "ms", "Malay" },
+ { mt, "mt", "Maltese" },
+ { my, "my", "Burmese" },
+ { na, "na", "Nauru" },
+ { ne, "ne", "Nepali" },
+ { nl, "nl", "Dutch" },
+ { no, "no", "Norwegian" },
+ { oc, "oc", "Occitan" },
+ { om, "om", "(Afan) Oromo" },
+ { or, "or", "Oriya" },
+ { pa, "pa", "Punjabi" },
+ { pl, "pl", "Polish" },
+ { ps, "ps", "Pashto, Pushto" },
+ { pt, "pt", "Portuguese" },
+ { qu, "qu", "Quechua" },
+ { rm, "rm", "Rhaeto-Romance" },
+ { rn, "rn", "Kirundi" },
+ { ro, "ro", "Romanian" },
+ { ru, "ru", "Russian" },
+ { rw, "rw", "Kinyarwanda" },
+ { sa, "sa", "Sanskrit" },
+ { sd, "sd", "Sindhi" },
+ { sg, "sg", "Sangro" },
+ { sh, "sh", "Serbo-Croatian" },
+ { si, "si", "Sinhalese" },
+ { sk, "sk", "Slovak" },
+ { sl, "sl", "Slovenian" },
+ { sm, "sm", "Samoan" },
+ { sn, "sn", "Shona" },
+ { so, "so", "Somali" },
+ { sq, "sq", "Albanian" },
+ { sr, "sr", "Serbian" },
+ { ss, "ss", "Siswati" },
+ { st, "st", "Sesotho" },
+ { su, "su", "Sundanese" },
+ { sv, "sv", "Swedish" },
+ { sw, "sw", "Swahili" },
+ { ta, "ta", "Tamil" },
+ { te, "te", "Telugu" },
+ { tg, "tg", "Tajik" },
+ { th, "th", "Thai" },
+ { ti, "ti", "Tigrinya" },
+ { tk, "tk", "Turkmen" },
+ { tl, "tl", "Tagalog" },
+ { tn, "tn", "Setswana" },
+ { to, "to", "Tonga" },
+ { tr, "tr", "Turkish" },
+ { ts, "ts", "Tsonga" },
+ { tt, "tt", "Tatar" },
+ { tw, "tw", "Twi" },
+ { ug, "ug", "Uighur" },
+ { uk, "uk", "Ukrainian" },
+ { ur, "ur", "Urdu" },
+ { uz, "uz", "Uzbek" },
+ { vi, "vi", "Vietnamese" },
+ { vo, "vo", "Volapuk" },
+ { wo, "wo", "Wolof" },
+ { xh, "xh", "Xhosa" },
+ { yi, "yi", "Yiddish" } /* (formerly ji) */,
+ { yo, "yo", "Yoruba" },
+ { za, "za", "Zhuang" },
+ { zh, "zh", "Chinese" },
+ { zu, "zu", "Zulu" },
+ { last_language_code, NULL, NULL }
+};
+
+/* @documentlanguage. Maybe we'll do something useful with this in the
+ future. For now, we just recognize it. */
+void
+cm_documentlanguage ()
+{
+ language_code_type c;
+ char *lang_arg;
+
+ /* Read the line with the language code on it. */
+ get_rest_of_line (1, &lang_arg);
+
+ /* Linear search is fine these days. */
+ for (c = aa; c != last_language_code; c++)
+ {
+ if (strcmp (lang_arg, language_table[c].abbrev) == 0)
+ { /* Set current language code. */
+ language_code = c;
+ break;
+ }
+ }
+
+ /* If we didn't find this code, complain. */
+ if (c == last_language_code)
+ warning (_("%s is not a valid ISO 639 language code"), lang_arg);
+
+ free (lang_arg);
+}
+
+
+
+/* @documentencoding. Set global. */
+void
+cm_documentencoding ()
+{
+ get_rest_of_line (1, &document_encoding);
+}
+
+
+
+/* Accent commands that take explicit arguments and don't have any
+ special HTML support. */
+
+void
+cm_accent (arg)
+ int arg;
+{
+ if (arg == START)
+ {
+ /* Must come first to avoid ambiguity with overdot. */
+ if (strcmp (command, "udotaccent") == 0) /* underdot */
+ add_char ('.');
+ }
+ else if (arg == END)
+ {
+ if (strcmp (command, "=") == 0) /* macron */
+ add_word (html ? "&macr;" : "=");
+ else if (strcmp (command, "H") == 0) /* Hungarian umlaut */
+ add_word ("''");
+ else if (strcmp (command, "dotaccent") == 0) /* overdot */
+ add_meta_char ('.');
+ else if (strcmp (command, "ringaccent") == 0) /* ring */
+ add_char ('*');
+ else if (strcmp (command, "tieaccent") == 0) /* long tie */
+ add_char ('[');
+ else if (strcmp (command, "u") == 0) /* breve */
+ add_char ('(');
+ else if (strcmp (command, "ubaraccent") == 0) /* underbar */
+ add_char ('_');
+ else if (strcmp (command, "v") == 0) /* hacek/check */
+ add_word (html ? "&lt;" : "<");
+ }
+}
+
+/* Common routine for the accent characters that have support in HTML.
+ If the character being accented is in the HTML_SUPPORTED set, then
+ produce &CHTML_SOLO;, for example, &Auml; for an A-umlaut. If not in
+ HTML_SUPPORTED, just produce &HTML_SOLO;X for the best we can do with
+ at an X-umlaut. Finally, if not producing HTML, just use SINGLE, a
+ character such as " which is the best plain text representation we
+ can manage. If HTML_SOLO_STANDALONE is zero the given HTML_SOLO
+ does not exist as valid standalone character in HTML. */
+
+static void
+cm_accent_generic (arg, start, end, html_supported, single,
+ html_solo_standalone, html_solo)
+ int arg, start, end;
+ char *html_supported;
+ int single;
+ int html_solo_standalone;
+ char *html_solo;
+{
+ if (html)
+ {
+ static int valid_html_accent;
+
+ if (arg == START)
+ { /* If HTML has good support for this character, use it. */
+ if (strchr (html_supported, curchar ()))
+ { /* Yes; start with an ampersand. The character itself
+ will be added later in read_command (makeinfo.c). */
+ add_char ('&');
+ valid_html_accent = 1;
+ }
+ else
+ { /* No special HTML support, so produce standalone char. */
+ valid_html_accent = 0;
+ if (html_solo_standalone)
+ {
+ add_char ('&');
+ add_word (html_solo);
+ add_char (';');
+ }
+ else
+ /* If the html_solo does not exist as standalone character
+ (namely &circ; &grave; &tilde;), then we use
+ the single character version instead. */
+ add_char (single);
+ }
+ }
+ else if (arg == END)
+ { /* Only if we saw a valid_html_accent can we use the full
+ HTML accent (umlaut, grave ...). */
+ if (valid_html_accent)
+ {
+ add_word (html_solo);
+ add_char (';');
+ }
+ }
+ }
+ else if (arg == END)
+ { /* Not producing HTML, so just use the normal character. */
+ add_char (single);
+ }
+}
+
+void
+cm_accent_umlaut (arg, start, end)
+ int arg, start, end;
+{
+ cm_accent_generic (arg, start, end, "aouAOUEeIiy", '"', 1, "uml");
+}
+
+void
+cm_accent_acute (arg, start, end)
+ int arg, start, end;
+{
+ cm_accent_generic (arg, start, end, "AEIOUYaeiouy", '\'', 1, "acute");
+}
+
+void
+cm_accent_cedilla (arg, start, end)
+ int arg, start, end;
+{
+ cm_accent_generic (arg, start, end, "Cc", ',', 1, "cedil");
+}
+
+void
+cm_accent_hat (arg, start, end)
+ int arg, start, end;
+{
+ cm_accent_generic (arg, start, end, "AEIOUaeiou", '^', 0, "circ");
+}
+
+void
+cm_accent_grave (arg, start, end)
+ int arg, start, end;
+{
+ cm_accent_generic (arg, start, end, "AEIOUaeiou", '`', 0, "grave");
+}
+
+void
+cm_accent_tilde (arg, start, end)
+ int arg, start, end;
+{
+ cm_accent_generic (arg, start, end, "AOano", '~', 0, "tilde");
+}
+
+
+
+/* Non-English letters/characters that don't insert themselves. */
+void
+cm_special_char (arg)
+{
+ if (arg == START)
+ {
+ if ((*command == 'L' || *command == 'l'
+ || *command == 'O' || *command == 'o')
+ && command[1] == 0)
+ { /* Lslash lslash Oslash oslash.
+ Lslash and lslash aren't supported in HTML. */
+ if (html && (command[0] == 'O' || command[0] == 'o'))
+ add_word_args ("&%cslash;", command[0]);
+ else
+ add_word_args ("/%c", command[0]);
+ }
+ else if (strcmp (command, "exclamdown") == 0)
+ add_word (html ? "&iexcl;" : "!");
+ else if (strcmp (command, "pounds") == 0)
+ add_word (html ? "&pound;" : "#");
+ else if (strcmp (command, "questiondown") == 0)
+ add_word (html ? "&iquest;" : "?");
+ else if (strcmp (command, "AE") == 0)
+ add_word (html ? "&AElig;" : command);
+ else if (strcmp (command, "ae") == 0)
+ add_word (html ? "&aelig;" : command);
+ else if (strcmp (command, "OE") == 0)
+ add_word (html ? "&#140;" : command);
+ else if (strcmp (command, "oe") == 0)
+ add_word (html ? "&#156;" : command);
+ else if (strcmp (command, "AA") == 0)
+ add_word (html ? "&Aring;" : command);
+ else if (strcmp (command, "aa") == 0)
+ add_word (html ? "&aring;" : command);
+ else if (strcmp (command, "ss") == 0)
+ add_word (html ? "&szlig;" : command);
+ else
+ line_error ("cm_special_char internal error: command=@%s", command);
+ }
+}
+
+/* Dotless i or j. */
+void
+cm_dotless (arg, start, end)
+ int arg, start, end;
+{
+ if (arg == END)
+ {
+ if (output_paragraph[start] != 'i' && output_paragraph[start] != 'j')
+ /* This error message isn't perfect if the argument is multiple
+ characters, but it doesn't seem worth getting right. */
+ line_error (_("%c%s expects `i' or `j' as argument, not `%c'"),
+ COMMAND_PREFIX, command, output_paragraph[start]);
+
+ else if (end - start != 1)
+ line_error (_("%c%s expects a single character `i' or `j' as argument"),
+ COMMAND_PREFIX, command);
+
+ /* We've already inserted the `i' or `j', so nothing to do. */
+ }
+}
diff --git a/contrib/texinfo/makeinfo/lang.h b/contrib/texinfo/makeinfo/lang.h
new file mode 100644
index 0000000..25bf0bd
--- /dev/null
+++ b/contrib/texinfo/makeinfo/lang.h
@@ -0,0 +1,86 @@
+/* lang.h -- declarations for language codes etc.
+ $Id: lang.h,v 1.6 1999/03/22 20:07:34 karl Exp $
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written by Karl Heinz Marbaise <kama@hippo.fido.de>. */
+
+#ifndef LANG_H
+#define LANG_H
+
+/* The langauge code which can be changed through @documentlanguage
+ * Actualy Info does not support this (may be in the future) ;-)
+ * Default for language code is en (english!) kama
+ * These code should ISO 639 two letter codes.
+ */
+typedef enum
+{
+ aa, ab, af, am, ar, as, ay, az,
+ ba, be, bg, bh, bi, bn, bo, br,
+ ca, co, cs, cy,
+ da, de, dz,
+ el, en, eo, es, et, eu,
+ fa, fi, fj, fo, fr, fy,
+ ga, gd, gl, gn, gu,
+ ha, he, hi, hr, hu, hy,
+ ia, id, ie, ik, is, it, iu,
+ ja, jw,
+ ka, kk, kl, km, kn, ko, ks, ku, ky,
+ la, ln, lo, lt, lv,
+ mg, mi, mk, ml, mn, mo, mr, ms, mt, my,
+ na, ne, nl, no,
+ oc, om, or,
+ pa, pl, ps, pt,
+ qu,
+ rm, rn, ro, ru, rw,
+ sa, sd, sg, sh, si, sk, sl, sm, sn, so, sq, sr, ss, st, su, sv, sw,
+ ta, te, tg, th, ti, tk, tl, tn, to, tr, ts, tt, tw,
+ ug, uk, ur, uz,
+ vi, vo,
+ wo,
+ xh,
+ yi, yo,
+ za, zh, zu,
+ last_language_code
+} language_code_type;
+
+/* The current language code. */
+extern language_code_type language_code;
+
+/* Information about all valid languages. */
+typedef struct
+{
+ language_code_type lc; /* language code as enum type */
+ char *abbrev; /* two letter language code */
+ char *desc; /* full name for language code */
+} language_struct;
+extern language_struct language_table[];
+
+/* The encoding, or null if not set. */
+extern char *document_encoding;
+
+
+/* The commands. */
+extern void cm_documentlanguage (), cm_documentencoding ();
+
+/* Accents, other non-English characters. */
+void cm_accent (), cm_special_char (), cm_dotless ();
+
+extern void cm_accent_umlaut (), cm_accent_acute (), cm_accent_cedilla (),
+ cm_accent_hat (), cm_accent_grave (), cm_accent_tilde ();
+
+#endif /* not LANG_H */
diff --git a/contrib/texinfo/makeinfo/macro.c b/contrib/texinfo/makeinfo/macro.c
new file mode 100644
index 0000000..8c89da2
--- /dev/null
+++ b/contrib/texinfo/makeinfo/macro.c
@@ -0,0 +1,1114 @@
+/* macro.c -- user-defined macros for Texinfo.
+ $Id: macro.c,v 1.10 1999/08/17 21:06:35 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "cmds.h"
+#include "macro.h"
+#include "makeinfo.h"
+#include "insertion.h"
+
+/* If non-NULL, this is an output stream to write the full macro expansion
+ of the input text to. The result is another texinfo file, but
+ missing @include, @infoinclude, @macro, and macro invocations. Instead,
+ all of the text is placed within the file. */
+FILE *macro_expansion_output_stream = NULL;
+
+/* Output file for -E. */
+char *macro_expansion_filename;
+
+/* Nonzero means a macro string is in execution, as opposed to a file. */
+int me_executing_string = 0;
+
+/* Nonzero means we want only to expand macros and
+ leave everything else intact. */
+int only_macro_expansion = 0;
+
+static ITEXT **itext_info = NULL;
+static int itext_size = 0;
+
+/* Return the arglist on the current line. This can behave in two different
+ ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */
+int braces_required_for_macro_args = 0;
+
+/* Array of macros and definitions. */
+MACRO_DEF **macro_list = NULL;
+
+int macro_list_len = 0; /* Number of elements. */
+int macro_list_size = 0; /* Number of slots in total. */
+
+/* Return the length of the array in ARRAY. */
+int
+array_len (array)
+ char **array;
+{
+ int i = 0;
+
+ if (array)
+ for (i = 0; array[i]; i++);
+
+ return i;
+}
+
+void
+free_array (array)
+ char **array;
+{
+ if (array)
+ {
+ int i;
+ for (i = 0; array[i]; i++)
+ free (array[i]);
+
+ free (array);
+ }
+}
+
+/* Return the macro definition of NAME or NULL if NAME is not defined. */
+MACRO_DEF *
+find_macro (name)
+ char *name;
+{
+ int i;
+ MACRO_DEF *def;
+
+ def = NULL;
+ for (i = 0; macro_list && (def = macro_list[i]); i++)
+ {
+ if ((!def->inhibited) && (strcmp (def->name, name) == 0))
+ break;
+ }
+ return def;
+}
+
+/* Add the macro NAME with ARGLIST and BODY to the list of defined macros.
+ SOURCE_FILE is the name of the file where this definition can be found,
+ and SOURCE_LINENO is the line number within that file. If a macro already
+ exists with NAME, then a warning is produced, and that previous
+ definition is overwritten. */
+void
+add_macro (name, arglist, body, source_file, source_lineno, flags)
+ char *name;
+ char **arglist;
+ char *body;
+ char *source_file;
+ int source_lineno, flags;
+{
+ MACRO_DEF *def;
+
+ def = find_macro (name);
+
+ if (!def)
+ {
+ if (macro_list_len + 2 >= macro_list_size)
+ macro_list = xrealloc
+ (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
+
+ macro_list[macro_list_len] = xmalloc (sizeof (MACRO_DEF));
+ macro_list[macro_list_len + 1] = NULL;
+
+ def = macro_list[macro_list_len];
+ macro_list_len += 1;
+ def->name = name;
+ }
+ else
+ {
+ char *temp_filename = input_filename;
+ int temp_line = line_number;
+
+ warning (_("macro `%s' previously defined"), name);
+
+ input_filename = def->source_file;
+ line_number = def->source_lineno;
+ warning (_("here is the previous definition of `%s'"), name);
+
+ input_filename = temp_filename;
+ line_number = temp_line;
+
+ if (def->arglist)
+ {
+ int i;
+
+ for (i = 0; def->arglist[i]; i++)
+ free (def->arglist[i]);
+
+ free (def->arglist);
+ }
+ free (def->source_file);
+ free (def->body);
+ }
+
+ def->source_file = xstrdup (source_file);
+ def->source_lineno = source_lineno;
+ def->body = body;
+ def->arglist = arglist;
+ def->inhibited = 0;
+ def->flags = flags;
+}
+
+
+char **
+get_brace_args (quote_single)
+ int quote_single;
+{
+ char **arglist, *word;
+ int arglist_index, arglist_size;
+ int character, escape_seen, start;
+ int depth = 1;
+
+ /* There is an arglist in braces here, so gather the args inside of it. */
+ skip_whitespace_and_newlines ();
+ input_text_offset++;
+ arglist = NULL;
+ arglist_index = arglist_size = 0;
+
+ get_arg:
+ skip_whitespace_and_newlines ();
+ start = input_text_offset;
+ escape_seen = 0;
+
+ while ((character = curchar ()))
+ {
+ if (character == '\\')
+ {
+ input_text_offset += 2;
+ escape_seen = 1;
+ }
+ else if (character == '{')
+ {
+ depth++;
+ input_text_offset++;
+ }
+ else if ((character == ',' && !quote_single) ||
+ ((character == '}') && depth == 1))
+ {
+ int len = input_text_offset - start;
+
+ if (len || (character != '}'))
+ {
+ word = xmalloc (1 + len);
+ memcpy (word, input_text + start, len);
+ word[len] = 0;
+
+ /* Clean up escaped characters. */
+ if (escape_seen)
+ {
+ int i;
+ for (i = 0; word[i]; i++)
+ if (word[i] == '\\')
+ memmove (word + i, word + i + 1,
+ 1 + strlen (word + i + 1));
+ }
+
+ if (arglist_index + 2 >= arglist_size)
+ arglist = xrealloc
+ (arglist, (arglist_size += 10) * sizeof (char *));
+
+ arglist[arglist_index++] = word;
+ arglist[arglist_index] = NULL;
+ }
+
+ input_text_offset++;
+ if (character == '}')
+ break;
+ else
+ goto get_arg;
+ }
+ else if (character == '}')
+ {
+ depth--;
+ input_text_offset++;
+ }
+ else
+ {
+ input_text_offset++;
+ if (character == '\n') line_number++;
+ }
+ }
+ return arglist;
+}
+
+char **
+get_macro_args (def)
+ MACRO_DEF *def;
+{
+ int i;
+ char *word;
+
+ /* Quickly check to see if this macro has been invoked with any arguments.
+ If not, then don't skip any of the following whitespace. */
+ for (i = input_text_offset; i < input_text_length; i++)
+ if (!cr_or_whitespace (input_text[i]))
+ break;
+
+ if (input_text[i] != '{')
+ {
+ if (braces_required_for_macro_args)
+ {
+ return NULL;
+ }
+ else
+ {
+ /* Braces are not required to fill out the macro arguments. If
+ this macro takes one argument, it is considered to be the
+ remainder of the line, sans whitespace. */
+ if (def->arglist && def->arglist[0] && !def->arglist[1])
+ {
+ char **arglist;
+
+ get_rest_of_line (0, &word);
+ if (input_text[input_text_offset - 1] == '\n')
+ {
+ input_text_offset--;
+ line_number--;
+ }
+ /* canon_white (word); */
+ arglist = xmalloc (2 * sizeof (char *));
+ arglist[0] = word;
+ arglist[1] = NULL;
+ return arglist;
+ }
+ else
+ {
+ /* The macro either took no arguments, or took more than
+ one argument. In that case, it must be invoked with
+ arguments surrounded by braces. */
+ return NULL;
+ }
+ }
+ }
+ return get_brace_args (def->flags & ME_QUOTE_ARG);
+}
+
+/* Substitute actual parameters for named parameters in body.
+ The named parameters which appear in BODY must by surrounded
+ reverse slashes, as in \foo\. */
+char *
+apply (named, actuals, body)
+ char **named, **actuals, *body;
+{
+ int i;
+ int new_body_index, new_body_size;
+ char *new_body, *text;
+ int length_of_actuals;
+
+ length_of_actuals = array_len (actuals);
+ new_body_size = strlen (body);
+ new_body = xmalloc (1 + new_body_size);
+
+ /* Copy chars from BODY into NEW_BODY. */
+ i = 0;
+ new_body_index = 0;
+
+ while (body[i])
+ { /* Anything but a \ is easy. */
+ if (body[i] != '\\')
+ new_body[new_body_index++] = body[i++];
+ else
+ { /* Snarf parameter name, check against named parameters. */
+ char *param;
+ int param_start, which, len;
+
+ param_start = ++i;
+ while (body[i] && body[i] != '\\')
+ i++;
+
+ len = i - param_start;
+ param = xmalloc (1 + len);
+ memcpy (param, body + param_start, len);
+ param[len] = 0;
+
+ if (body[i]) /* move past \ */
+ i++;
+
+ /* Now check against named parameters. */
+ for (which = 0; named && named[which]; which++)
+ if (STREQ (named[which], param))
+ break;
+
+ if (named && named[which])
+ {
+ text = which < length_of_actuals ? actuals[which] : NULL;
+ if (!text)
+ text = "";
+ len = strlen (text);
+ }
+ else
+ { /* not a parameter, either it's \\ (if len==0) or an
+ error. In either case, restore one \ at least. */
+ if (len) {
+ warning (_("\\ in macro expansion followed by `%s' instead of \\ or parameter name"),
+ param);
+ }
+ len++;
+ text = xmalloc (1 + len);
+ sprintf (text, "\\%s", param);
+ }
+
+ if (strlen (param) + 2 < len)
+ {
+ new_body_size += len + 1;
+ new_body = xrealloc (new_body, new_body_size);
+ }
+
+ free (param);
+
+ strcpy (new_body + new_body_index, text);
+ new_body_index += len;
+
+ if (!named || !named[which])
+ free (text);
+ }
+ }
+
+ new_body[new_body_index] = 0;
+ return new_body;
+}
+
+/* Expand macro passed in DEF, a pointer to a MACRO_DEF, and
+ return its expansion as a string. */
+char *
+expand_macro (def)
+ MACRO_DEF *def;
+{
+ char **arglist;
+ int num_args;
+ char *execution_string = NULL;
+ int start_line = line_number;
+
+ /* Find out how many arguments this macro definition takes. */
+ num_args = array_len (def->arglist);
+
+ /* Gather the arguments present on the line if there are any. */
+ arglist = get_macro_args (def);
+
+ if (num_args < array_len (arglist))
+ {
+ free_array (arglist);
+ line_error (_("Macro `%s' called on line %d with too many args"),
+ def->name, start_line);
+ return execution_string;
+ }
+
+ if (def->body)
+ execution_string = apply (def->arglist, arglist, def->body);
+
+ free_array (arglist);
+ return execution_string;
+}
+
+/* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */
+void
+execute_macro (def)
+ MACRO_DEF *def;
+{
+ char *execution_string;
+ int start_line = line_number, end_line;
+
+ if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
+ me_append_before_this_command ();
+
+ execution_string = expand_macro (def);
+ if (!execution_string)
+ return;
+
+ if (def->body)
+ {
+ /* Reset the line number to where the macro arguments began.
+ This makes line numbers reported in error messages correct in
+ case the macro arguments span several lines and the expanded
+ arguments invoke other commands. */
+ end_line = line_number;
+ line_number = start_line;
+
+ if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
+ {
+ remember_itext (input_text, input_text_offset);
+ me_execute_string (execution_string);
+ }
+ else
+ execute_string ("%s", execution_string);
+
+ free (execution_string);
+ line_number = end_line;
+ }
+}
+
+
+/* Read and remember the definition of a macro. If RECURSIVE is set,
+ set the ME_RECURSE flag. MACTYPE is either "macro" or "rmacro", and
+ tells us what the matching @end should be. */
+static void
+define_macro (mactype, recursive)
+ char *mactype;
+ int recursive;
+{
+ int i;
+ char *name, **arglist, *body, *line, *last_end;
+ int body_size, body_index;
+ int depth = 1;
+ int defining_line = line_number;
+ int flags = 0;
+
+ arglist = NULL;
+ body = NULL;
+ body_size = 0;
+ body_index = 0;
+
+ if (macro_expansion_output_stream && !executing_string)
+ me_append_before_this_command ();
+
+ skip_whitespace ();
+
+ /* Get the name of the macro. This is the set of characters which are
+ not whitespace and are not `{' immediately following the @macro. */
+ {
+ int start = input_text_offset;
+ int len;
+
+ for (i = start;
+ (i < input_text_length) &&
+ (input_text[i] != '{') &&
+ (!cr_or_whitespace (input_text[i]));
+ i++);
+
+ len = i - start;
+ name = xmalloc (1 + len);
+ memcpy (name, input_text + start, len);
+ name[len] = 0;
+ input_text_offset = i;
+ }
+
+ skip_whitespace ();
+
+ /* It is not required that the definition of a macro includes an arglist.
+ If not, don't try to get the named parameters, just use a null list. */
+ if (curchar () == '{')
+ {
+ int character;
+ int arglist_index = 0, arglist_size = 0;
+ int gathering_words = 1;
+ char *word = NULL;
+
+ /* Read the words inside of the braces which determine the arglist.
+ These words will be replaced within the body of the macro at
+ execution time. */
+
+ input_text_offset++;
+ skip_whitespace_and_newlines ();
+
+ while (gathering_words)
+ {
+ int len;
+
+ for (i = input_text_offset;
+ (character = input_text[i]);
+ i++)
+ {
+ switch (character)
+ {
+ case '\n':
+ line_number++;
+ case ' ':
+ case '\t':
+ case ',':
+ case '}':
+ /* Found the end of the current arglist word. Save it. */
+ len = i - input_text_offset;
+ word = xmalloc (1 + len);
+ memcpy (word, input_text + input_text_offset, len);
+ word[len] = 0;
+ input_text_offset = i;
+
+ /* Advance to the comma or close-brace that signified
+ the end of the argument. */
+ while ((character = curchar ())
+ && character != ','
+ && character != '}')
+ {
+ input_text_offset++;
+ if (character == '\n')
+ line_number++;
+ }
+
+ /* Add the word to our list of words. */
+ if (arglist_index + 2 >= arglist_size)
+ {
+ arglist_size += 10;
+ arglist = xrealloc (arglist,
+ arglist_size * sizeof (char *));
+ }
+
+ arglist[arglist_index++] = word;
+ arglist[arglist_index] = NULL;
+ break;
+ }
+
+ if (character == '}')
+ {
+ input_text_offset++;
+ gathering_words = 0;
+ break;
+ }
+
+ if (character == ',')
+ {
+ input_text_offset++;
+ skip_whitespace_and_newlines ();
+ i = input_text_offset - 1;
+ }
+ }
+ }
+
+ /* If we have exactly one argument, do @quote-arg implicitly. Not
+ only does this match TeX's behavior (which can't feasibly be
+ changed), but it's a good idea. */
+ if (arglist_index == 1)
+ flags |= ME_QUOTE_ARG;
+ }
+
+ /* Read the text carefully until we find an "@end macro" which
+ matches this one. The text in between is the body of the macro. */
+ skip_whitespace_and_newlines ();
+
+ while (depth)
+ {
+ if ((input_text_offset + 9) > input_text_length)
+ {
+ int temp_line = line_number;
+ line_number = defining_line;
+ line_error (_("%cend macro not found"), COMMAND_PREFIX);
+ line_number = temp_line;
+ return;
+ }
+
+ get_rest_of_line (0, &line);
+
+ /* Handle commands only meaningful within a macro. */
+ if ((*line == COMMAND_PREFIX) && (depth == 1) &&
+ (strncmp (line + 1, "allow-recursion", 15) == 0) &&
+ (line[16] == 0 || whitespace (line[16])))
+ {
+ for (i = 16; whitespace (line[i]); i++);
+ strcpy (line, line + i);
+ flags |= ME_RECURSE;
+ if (!*line)
+ {
+ free (line);
+ continue;
+ }
+ }
+
+ if ((*line == COMMAND_PREFIX) && (depth == 1) &&
+ (strncmp (line + 1, "quote-arg", 9) == 0) &&
+ (line[10] == 0 || whitespace (line[10])))
+ {
+ for (i = 10; whitespace (line[i]); i++);
+ strcpy (line, line + i);
+
+ if (arglist && arglist[0] && !arglist[1])
+ {
+ flags |= ME_QUOTE_ARG;
+ if (!*line)
+ {
+ free (line);
+ continue;
+ }
+ }
+ else
+ line_error (_("@quote-arg only useful for single-argument macros"));
+ }
+
+ if (*line == COMMAND_PREFIX
+ && (strncmp (line + 1, "macro ", 6) == 0
+ || strncmp (line + 1, "rmacro ", 7) == 0))
+ depth++;
+
+ /* Incorrect implementation of nesting -- just check that the last
+ @end matches what we started with. Since nested macros don't
+ work in TeX anyway, this isn't worth the trouble to get right. */
+ if (*line == COMMAND_PREFIX && strncmp (line + 1, "end macro", 9) == 0)
+ {
+ depth--;
+ last_end = "macro";
+ }
+ if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 9) == 0)
+ {
+ depth--;
+ last_end = "rmacro";
+ }
+
+ if (depth)
+ {
+ if ((body_index + strlen (line) + 3) >= body_size)
+ body = xrealloc (body, body_size += 3 + strlen (line));
+ strcpy (body + body_index, line);
+ body_index += strlen (line);
+ body[body_index++] = '\n';
+ body[body_index] = 0;
+ }
+ free (line);
+ }
+
+ /* Check that @end matched the macro command. */
+ if (!STREQ (last_end, mactype))
+ warning (_("mismatched @end %s with @%s"), last_end, mactype);
+
+ /* If it was an empty macro like
+ @macro foo
+ @end macro
+ create an empty body. (Otherwise, the macro is not expanded.) */
+ if (!body)
+ {
+ body = (char *)malloc(1);
+ *body = 0;
+ }
+
+ /* We now have the name, the arglist, and the body. However, BODY
+ includes the final newline which preceded the `@end macro' text.
+ Delete it. */
+ if (body && strlen (body))
+ body[strlen (body) - 1] = 0;
+
+ if (recursive)
+ flags |= ME_RECURSE;
+
+ add_macro (name, arglist, body, input_filename, defining_line, flags);
+
+ if (macro_expansion_output_stream && !executing_string)
+ remember_itext (input_text, input_text_offset);
+}
+
+void
+cm_macro ()
+{
+ define_macro ("macro", 0);
+}
+
+void
+cm_rmacro ()
+{
+ define_macro ("rmacro", 1);
+}
+
+/* Delete the macro with name NAME. The macro is deleted from the list,
+ but it is also returned. If there was no macro defined, NULL is
+ returned. */
+
+static MACRO_DEF *
+delete_macro (name)
+ char *name;
+{
+ int i;
+ MACRO_DEF *def;
+
+ def = NULL;
+
+ for (i = 0; macro_list && (def = macro_list[i]); i++)
+ if (strcmp (def->name, name) == 0)
+ {
+ memmove (macro_list + i, macro_list + i + 1,
+ ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
+ macro_list_len--;
+ break;
+ }
+ return def;
+}
+
+void
+cm_unmacro ()
+{
+ int i;
+ char *line, *name;
+ MACRO_DEF *def;
+
+ if (macro_expansion_output_stream && !executing_string)
+ me_append_before_this_command ();
+
+ get_rest_of_line (0, &line);
+
+ for (i = 0; line[i] && !whitespace (line[i]); i++);
+ name = xmalloc (i + 1);
+ memcpy (name, line, i);
+ name[i] = 0;
+
+ def = delete_macro (name);
+
+ if (def)
+ {
+ free (def->source_file);
+ free (def->name);
+ free (def->body);
+
+ if (def->arglist)
+ {
+ int i;
+
+ for (i = 0; def->arglist[i]; i++)
+ free (def->arglist[i]);
+
+ free (def->arglist);
+ }
+
+ free (def);
+ }
+
+ free (line);
+ free (name);
+
+ if (macro_expansion_output_stream && !executing_string)
+ remember_itext (input_text, input_text_offset);
+}
+
+/* How to output sections of the input file verbatim. */
+
+/* Set the value of POINTER's offset to OFFSET. */
+ITEXT *
+remember_itext (pointer, offset)
+ char *pointer;
+ int offset;
+{
+ int i;
+ ITEXT *itext = NULL;
+
+ /* If we have no info, initialize a blank list. */
+ if (!itext_info)
+ {
+ itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *));
+ for (i = 0; i < itext_size; i++)
+ itext_info[i] = NULL;
+ }
+
+ /* If the pointer is already present in the list, then set the offset. */
+ for (i = 0; i < itext_size; i++)
+ if ((itext_info[i]) &&
+ (itext_info[i]->pointer == pointer))
+ {
+ itext = itext_info[i];
+ itext_info[i]->offset = offset;
+ break;
+ }
+
+ if (i == itext_size)
+ {
+ /* Find a blank slot (or create a new one), and remember the
+ pointer and offset. */
+ for (i = 0; i < itext_size; i++)
+ if (itext_info[i] == NULL)
+ break;
+
+ /* If not found, then add some slots. */
+ if (i == itext_size)
+ {
+ int j;
+
+ itext_info = xrealloc
+ (itext_info, (itext_size += 10) * sizeof (ITEXT *));
+
+ for (j = i; j < itext_size; j++)
+ itext_info[j] = NULL;
+ }
+
+ /* Now add the pointer and the offset. */
+ itext_info[i] = xmalloc (sizeof (ITEXT));
+ itext_info[i]->pointer = pointer;
+ itext_info[i]->offset = offset;
+ itext = itext_info[i];
+ }
+ return itext;
+}
+
+/* Forget the input text associated with POINTER. */
+void
+forget_itext (pointer)
+ char *pointer;
+{
+ int i;
+
+ for (i = 0; i < itext_size; i++)
+ if (itext_info[i] && (itext_info[i]->pointer == pointer))
+ {
+ free (itext_info[i]);
+ itext_info[i] = NULL;
+ break;
+ }
+}
+
+/* Append the text which appeared in input_text from the last offset to
+ the character just before the command that we are currently executing. */
+void
+me_append_before_this_command ()
+{
+ int i;
+
+ for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--)
+ ;
+ maybe_write_itext (input_text, i);
+}
+
+/* Similar to execute_string, but only takes a single string argument,
+ and remembers the input text location, etc. */
+void
+me_execute_string (execution_string)
+ char *execution_string;
+{
+ int saved_escape_html = escape_html;
+ int saved_in_paragraph = in_paragraph;
+ escape_html = me_executing_string == 0;
+ in_paragraph = 0;
+
+ pushfile ();
+ input_text_offset = 0;
+ /* The following xstrdup is so we can relocate input_text at will. */
+ input_text = xstrdup (execution_string);
+ input_filename = xstrdup (input_filename);
+ input_text_length = strlen (execution_string);
+
+ remember_itext (input_text, 0);
+
+ me_executing_string++;
+ reader_loop ();
+ free (input_text);
+ free (input_filename);
+ popfile ();
+ me_executing_string--;
+
+ in_paragraph = saved_in_paragraph;
+ escape_html = saved_escape_html;
+}
+
+/* A wrapper around me_execute_string which saves and restores
+ variables important for output generation. This is called
+ when we need to produce macro-expanded output for input which
+ leaves no traces in the Info output. */
+void
+me_execute_string_keep_state (execution_string, append_string)
+ char *execution_string, *append_string;
+{
+ int op_orig, opcol_orig, popen_orig;
+ int fill_orig, newline_orig, indent_orig, meta_pos_orig;
+
+ remember_itext (input_text, input_text_offset);
+ op_orig = output_paragraph_offset;
+ meta_pos_orig = meta_char_pos;
+ opcol_orig = output_column;
+ popen_orig = paragraph_is_open;
+ fill_orig = filling_enabled;
+ newline_orig = last_char_was_newline;
+ filling_enabled = 0;
+ indent_orig = no_indent;
+ no_indent = 1;
+ me_execute_string (execution_string);
+ if (append_string)
+ write_region_to_macro_output (append_string, 0, strlen (append_string));
+ output_paragraph_offset = op_orig;
+ meta_char_pos = meta_pos_orig;
+ output_column = opcol_orig;
+ paragraph_is_open = popen_orig;
+ filling_enabled = fill_orig;
+ last_char_was_newline = newline_orig;
+ no_indent = indent_orig;
+}
+
+/* Append the text which appears in input_text from the last offset to
+ the current OFFSET. */
+void
+append_to_expansion_output (offset)
+ int offset;
+{
+ int i;
+ ITEXT *itext = NULL;
+
+ for (i = 0; i < itext_size; i++)
+ if (itext_info[i] && itext_info[i]->pointer == input_text)
+ {
+ itext = itext_info[i];
+ break;
+ }
+
+ if (!itext)
+ return;
+
+ if (offset > itext->offset)
+ {
+ write_region_to_macro_output (input_text, itext->offset, offset);
+ remember_itext (input_text, offset);
+ }
+}
+
+/* Only write this input text iff it appears in our itext list. */
+void
+maybe_write_itext (pointer, offset)
+ char *pointer;
+ int offset;
+{
+ int i;
+ ITEXT *itext = NULL;
+
+ for (i = 0; i < itext_size; i++)
+ if (itext_info[i] && (itext_info[i]->pointer == pointer))
+ {
+ itext = itext_info[i];
+ break;
+ }
+
+ if (itext && (itext->offset < offset))
+ {
+ write_region_to_macro_output (itext->pointer, itext->offset, offset);
+ remember_itext (pointer, offset);
+ }
+}
+
+void
+write_region_to_macro_output (string, start, end)
+ char *string;
+ int start, end;
+{
+ if (macro_expansion_output_stream)
+ fwrite (string + start, 1, end - start, macro_expansion_output_stream);
+}
+
+/* Aliases. */
+
+typedef struct alias_struct
+{
+ char *alias;
+ char *mapto;
+ struct alias_struct *next;
+} alias_type;
+
+static alias_type *aliases;
+
+/* @alias */
+void
+cm_alias ()
+{
+ alias_type *a = xmalloc (sizeof (alias_type));
+
+ skip_whitespace ();
+ get_until_in_line (1, "=", &(a->alias));
+ discard_until ("=");
+ skip_whitespace ();
+ get_until_in_line (0, " ", &(a->mapto));
+
+ a->next = aliases;
+ aliases = a;
+}
+
+/* Perform an alias expansion. Called from read_command. */
+char *
+alias_expand (tok)
+ char *tok;
+{
+ alias_type *findit = aliases;
+
+ while (findit)
+ if (strcmp (findit->alias, tok) == 0)
+ {
+ free (tok);
+ return alias_expand (xstrdup (findit->mapto));
+ }
+ else
+ findit = findit->next;
+
+ return tok;
+}
+
+/* definfoenclose implementation. */
+
+/* This structure is used to track enclosure macros. When an enclosure
+ macro is recognized, a pointer to the enclosure block corresponding
+ to its name is saved in the brace element for its argument. */
+typedef struct enclose_struct
+{
+ char *enclose;
+ char *before;
+ char *after;
+ struct enclose_struct *next;
+} enclosure_type;
+
+static enclosure_type *enclosures;
+
+typedef struct enclosure_stack_struct
+{
+ enclosure_type *current;
+ struct enclosure_stack_struct *next;
+} enclosure_stack_type;
+
+static enclosure_stack_type *enclosure_stack;
+
+/* @definfoenclose */
+void
+cm_definfoenclose ()
+{
+ enclosure_type *e = xmalloc (sizeof (enclosure_type));
+
+ skip_whitespace ();
+ get_until_in_line (1, ",", &(e->enclose));
+ discard_until (",");
+ get_until_in_line (0, ",", &(e->before));
+ discard_until (",");
+ get_until_in_line (0, "\n", &(e->after));
+
+ e->next = enclosures;
+ enclosures = e;
+}
+
+/* If TOK is an enclosure command, push it on the enclosure stack and
+ return 1. Else return 0. */
+
+int
+enclosure_command (tok)
+ char *tok;
+{
+ enclosure_type *findit = enclosures;
+
+ while (findit)
+ if (strcmp (findit->enclose, tok) == 0)
+ {
+ enclosure_stack_type *new = xmalloc (sizeof (enclosure_stack_type));
+ new->current = findit;
+ new->next = enclosure_stack;
+ enclosure_stack = new;
+
+ return 1;
+ }
+ else
+ findit = findit->next;
+
+ return 0;
+}
+
+/* actually perform the enclosure expansion */
+void
+enclosure_expand (arg, start, end)
+ int arg, start, end;
+{
+ if (arg == START)
+ add_word (enclosure_stack->current->before);
+ else
+ {
+ enclosure_stack_type *temp;
+
+ add_word (enclosure_stack->current->after);
+
+ temp = enclosure_stack;
+ enclosure_stack = enclosure_stack->next;
+ free (temp);
+ }
+}
diff --git a/contrib/texinfo/makeinfo/macro.h b/contrib/texinfo/makeinfo/macro.h
new file mode 100644
index 0000000..a64c613
--- /dev/null
+++ b/contrib/texinfo/makeinfo/macro.h
@@ -0,0 +1,71 @@
+/* macro.h -- declarations for macro.c.
+ $Id: macro.h,v 1.5 1999/07/15 00:00:46 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MACRO_H
+#define MACRO_H
+
+extern FILE *macro_expansion_output_stream;
+extern char *macro_expansion_filename;
+extern int me_executing_string;
+extern int only_macro_expansion;
+
+/* Here is a structure used to remember input text strings and offsets
+ within them. */
+typedef struct {
+ char *pointer; /* Pointer to the input text. */
+ int offset; /* Offset of the last character output. */
+} ITEXT;
+
+/* Macro definitions for user-defined commands. */
+typedef struct {
+ char *name; /* Name of the macro. */
+ char **arglist; /* Args to replace when executing. */
+ char *body; /* Macro body. */
+ char *source_file; /* File where this macro is defined. */
+ int source_lineno; /* Line number within FILENAME. */
+ int inhibited; /* Nonzero means make find_macro () fail. */
+ int flags; /* ME_RECURSE, ME_QUOTE_ARG, etc. */
+} MACRO_DEF;
+
+/* flags for MACRO_DEF */
+#define ME_RECURSE 0x01
+#define ME_QUOTE_ARG 0x02
+
+extern void execute_macro ();
+extern MACRO_DEF *find_macro ();
+extern char *expand_macro ();
+
+extern ITEXT *remember_itext ();
+extern void forget_itext ();
+extern void maybe_write_itext ();
+extern void write_region_to_macro_output ();
+extern void append_to_expansion_output ();
+extern void me_append_before_this_command ();
+extern void me_execute_string ();
+
+extern char *alias_expand ();
+extern int enclosure_command ();
+extern void enclosure_expand ();
+
+/* The @commands. */
+extern void cm_macro (), cm_rmacro (), cm_unmacro ();
+extern void cm_alias (), cm_definfoenclose ();
+
+#endif /* not MACRO_H */
diff --git a/contrib/texinfo/makeinfo/makeinfo.c b/contrib/texinfo/makeinfo/makeinfo.c
index bfd142e..5f042bc 100644
--- a/contrib/texinfo/makeinfo/makeinfo.c
+++ b/contrib/texinfo/makeinfo/makeinfo.c
@@ -1,7 +1,7 @@
-/* Makeinfo -- convert Texinfo source files into Info files.
- $Id: makeinfo.c,v 1.60 1998/02/25 20:36:22 karl Exp $
+/* makeinfo -- convert Texinfo source into other formats.
+ $Id: makeinfo.c,v 1.171 1999/09/19 15:24:44 karl Exp $
- Copyright (C) 1987, 92, 93, 94, 95, 96, 97, 98
+ Copyright (C) 1987, 92, 93, 94, 95, 96, 97, 98, 99
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
@@ -20,35 +20,20 @@
Makeinfo was authored by Brian Fox (bfox@ai.mit.edu). */
-/* Indent #pragma so that older Cpp's don't try to parse it. */
-#ifdef _AIX
- #pragma alloca
-#endif /* _AIX */
-
-int major_version = 1;
-int minor_version = 68;
-
#include "system.h"
#include "getopt.h"
-#ifdef TM_IN_SYS_TIME
-#include <sys/time.h>
-#else
-#include <time.h>
-#endif /* !TM_IN_SYS_TIME */
-
-#ifdef __GNUC__
-# undef alloca
-# define alloca __builtin_alloca
-#else
-# ifdef HAVE_ALLOCA_H
-# include <alloca.h>
-# else
-# ifndef _AIX
-char *alloca ();
-# endif
-# endif
-#endif
+#define COMPILING_MAKEINFO
+#include "makeinfo.h"
+#include "cmds.h"
+#include "files.h"
+#include "footnote.h"
+#include "html.h"
+#include "index.h"
+#include "insertion.h"
+#include "macro.h"
+#include "node.h"
+#include "toc.h"
/* We'd like to take advantage of _doprnt if it's around, a la error.c,
but then we'd have no VA_SPRINTF. */
@@ -69,6 +54,15 @@ char *alloca ();
# define va_end(args)
#endif
+/* DJGPP supports /dev/null, which is okay for Unix aficionados,
+ shell scripts and Makefiles, but interactive DOS die-hards
+ would probably want to have NUL as well. */
+#ifdef __DJGPP__
+# define ALSO_NULL_DEVICE "NUL"
+#else
+# define ALSO_NULL_DEVICE ""
+#endif
+
/* You can change some of the behavior of Makeinfo by changing the
following defines: */
@@ -78,11 +72,6 @@ char *alloca ();
no starting indentation. */
/* #define INDENT_PARAGRAPHS_IN_TABLE */
-/* Define DEFAULT_INDENTATION_INCREMENT as an integer which is the amount
- that @example should increase indentation by. This incremement is used
- for all insertions which indent the enclosed text. */
-#define DEFAULT_INDENTATION_INCREMENT 5
-
/* Define PARAGRAPH_START_INDENT to be the amount of indentation that
the first lines of paragraphs receive by default, where no other
value has been specified. Users can change this value on the command
@@ -95,103 +84,23 @@ char *alloca ();
line between paragraphs. Paragraphs are defined by 2 or more consecutive
newlines in the input file (i.e., one or more blank lines). */
#define DEFAULT_PARAGRAPH_SPACING 1
-
-/* Define HAVE_MACROS to enable the macro facility of Texinfo. Using this
- facility, users can create their own command procedures with
- arguments. Must always be defined. */
-#define HAVE_MACROS
-
-
-#define COMPILING_MAKEINFO
-#include "makeinfo.h"
-
-/* Nonzero means that we are currently hacking the insides of an
- insertion which would use a fixed width font. */
-static int in_fixed_width_font = 0;
-
-/* Nonzero means that start_paragraph () MUST be called before we pay
- any attention to close_paragraph () calls. */
-int must_start_paragraph = 0;
-
-/* Nonzero means a string is in execution, as opposed to a file. */
-static int executing_string = 0;
-
-/* Nonzero means a macro string is in execution, as opposed to a file. */
-static int me_executing_string = 0;
-
-#if defined (HAVE_MACROS)
-/* If non-NULL, this is an output stream to write the full macro expansion
- of the input text to. The result is another texinfo file, but
- missing @include, @infoinclude, @macro, and macro invocations. Instead,
- all of the text is placed within the file. */
-FILE *macro_expansion_output_stream = (FILE *)NULL;
-char *macro_expansion_filename;
-
-/* Here is a structure used to remember input text strings and offsets
- within them. */
-typedef struct {
- char *pointer; /* Pointer to the input text. */
- int offset; /* Offset of the last character output. */
-} ITEXT;
-
-static ITEXT **itext_info = (ITEXT **)NULL;
-static int itext_size = 0;
-
-/* Nonzero means to inhibit writing macro expansions to the output
- stream, because it has already been written. */
-int me_inhibit_expansion = 0;
-
-ITEXT *remember_itext ();
-void forget_itext (), me_append_before_this_command ();
-void append_to_expansion_output (), write_region_to_macro_output ();
-void maybe_write_itext (), me_execute_string ();
-#endif /* HAVE_MACROS */
-
-/* **************************************************************** */
-/* */
-/* Global Variables */
-/* */
-/* **************************************************************** */
-
-/* Global pointer to argv[0]. */
-char *progname;
-
-/* Return nonzero if STRING is the text at input_text + input_text_offset,
- else zero. */
-#define looking_at(string) \
- (strncmp (input_text + input_text_offset, string, strlen (string)) == 0)
-
-/* And writing to the output. */
+/* Global variables. */
/* The output file name. */
-char *output_filename = (char *)NULL;
-char *pretty_output_filename;
+char *output_filename = NULL;
/* Name of the output file that the user elected to pass on the command line.
Such a name overrides any name found with the @setfilename command. */
-char *command_output_filename = (char *)NULL;
-
-/* A colon separated list of directories to search for files included
- with @include. This can be controlled with the `-I' option to makeinfo. */
-char *include_files_path = (char *)NULL;
+char *command_output_filename = NULL;
-/* Position in the output file. */
-int output_position;
+/* Flags which control initial output string for xrefs. */
+int px_ref_flag = 0;
+int ref_flag = 0;
#define INITIAL_PARAGRAPH_SPACE 5000
int paragraph_buffer_len = INITIAL_PARAGRAPH_SPACE;
-/* Nonzero indicates that filling will take place on long lines. */
-int filling_enabled = 1;
-
-/* Nonzero means that words are not to be split, even in long lines. This
- gets changed for cm_w (). */
-int non_splitting_words = 0;
-
-/* Nonzero indicates that filling a line also indents the new line. */
-int indented_fill = 0;
-
/* The amount of indentation to add at the starts of paragraphs.
0 means don't change existing indentation at paragraph starts.
> 0 is amount to indent new paragraphs by.
@@ -202,170 +111,26 @@ int indented_fill = 0;
this is 3. */
int paragraph_start_indent = PARAGRAPH_START_INDENT;
-/* Nonzero means that the use of paragraph_start_indent is inhibited.
- @example uses this to line up the left columns of the example text.
- A negative value for this variable is incremented each time it is used.
- @noindent uses this to inhibit indentation for a single paragraph. */
-int inhibit_paragraph_indentation = 0;
-
/* Indentation that is pending insertion. We have this for hacking lines
which look blank, but contain whitespace. We want to treat those as
blank lines. */
int pending_indent = 0;
-/* The amount that indentation increases/decreases by. */
-int default_indentation_increment = DEFAULT_INDENTATION_INCREMENT;
-
-/* Nonzero indicates that indentation is temporarily turned off. */
-int no_indent = 1;
-
-/* Nonzero means forcing output text to be flushright. */
-int force_flush_right = 0;
-
-/* Nonzero means that the footnote style for this document was set on
- the command line, which overrides any other settings. */
-int footnote_style_preset = 0;
-
-/* Nonzero means that we automatically number footnotes that have no
- specified marker. */
-int number_footnotes = 1;
-
-/* The current footnote number in this node. Each time a new node is
- started this is reset to 1. */
-int current_footnote_number = 1;
-
-/* Command name in the process of being hacked. */
-char *command;
-
/* The index in our internal command table of the currently
executing command. */
int command_index;
-/* A search string which is used to find a line defining a node. */
-char node_search_string[] =
- { '\n', COMMAND_PREFIX, 'n', 'o', 'd', 'e', ' ', 0 };
-
-/* A search string which is used to find a line defining a menu. */
-char menu_search_string[] =
- { '\n', COMMAND_PREFIX, 'm', 'e', 'n', 'u', 0 };
-
/* A search string which is used to find the first @setfilename. */
char setfilename_search[] =
{ COMMAND_PREFIX,
's', 'e', 't', 'f', 'i', 'l', 'e', 'n', 'a', 'm', 'e', 0 };
-/* A stack of file information records. If a new file is read in with
- "@input", we remember the old input file state on this stack. */
-typedef struct fstack
-{
- struct fstack *next;
- char *filename;
- char *text;
- int size;
- int offset;
- int line_number;
-} FSTACK;
-
-FSTACK *filestack = (FSTACK *) NULL;
-
-/* Stuff for nodes. */
-/* The current nodes node name. */
-char *current_node = (char *)NULL;
-
-/* The current nodes section level. */
-int current_section = 0;
-
-/* The filename of the current input file. This is never freed. */
-char *node_filename = (char *)NULL;
-
-/* What we remember for each node. */
-typedef struct tentry
-{
- struct tentry *next_ent;
- char *node; /* name of this node. */
- char *prev; /* name of "Prev:" for this node. */
- char *next; /* name of "Next:" for this node. */
- char *up; /* name of "Up:" for this node. */
- int position; /* output file position of this node. */
- int line_no; /* defining line in source file. */
- char *filename; /* The file that this node was found in. */
- int touched; /* Nonzero means this node has been referenced. */
- int flags; /* Room for growth. Right now, contains 1 bit. */
-} TAG_ENTRY;
-
-/* If node-a has a "Next" for node-b, but node-b has no "Prev" for node-a,
- we turn on this flag bit in node-b's tag entry. This means that when
- it is time to validate node-b, we don't report an additional error
- if there was no "Prev" field. */
-#define PREV_ERROR 0x1
-#define NEXT_ERROR 0x2
-#define UP_ERROR 0x4
-#define NO_WARN 0x8
-#define IS_TOP 0x10
-
-TAG_ENTRY *tag_table = (TAG_ENTRY *) NULL;
-
/* Values for calling handle_variable_internal (). */
#define SET 1
#define CLEAR 2
#define IFSET 3
#define IFCLEAR 4
-#if defined (HAVE_MACROS)
-#define ME_RECURSE 0x01
-#define ME_QUOTE_ARG 0x02
-
-/* Macro definitions for user-defined commands. */
-typedef struct {
- char *name; /* Name of the macro. */
- char **arglist; /* Args to replace when executing. */
- char *body; /* Macro body. */
- char *source_file; /* File where this macro is defined. */
- int source_lineno; /* Line number within FILENAME. */
- int inhibited; /* Nonzero means make find_macro () fail. */
- int flags; /* ME_RECURSE, ME_QUOTE_ARG, etc. */
-} MACRO_DEF;
-
-void add_macro (), execute_macro ();
-MACRO_DEF *find_macro (), *delete_macro ();
-#endif /* HAVE_MACROS */
-
-/* Menu reference, *note reference, and validation hacking. */
-
-/* The various references that we know about. */
-enum reftype
-{
- menu_reference, followed_reference
-};
-
-/* A structure to remember references with. A reference to a node is
- either an entry in a menu, or a cross-reference made with [px]ref. */
-typedef struct node_ref
-{
- struct node_ref *next;
- char *node; /* Name of node referred to. */
- char *containing_node; /* Name of node containing this reference. */
- int line_no; /* Line number where the reference occurs. */
- int section; /* Section level where the reference occurs. */
- char *filename; /* Name of file where the reference occurs. */
- enum reftype type; /* Type of reference, either menu or note. */
-} NODE_REF;
-
-/* The linked list of such structures. */
-NODE_REF *node_references = (NODE_REF *) NULL;
-
-/* Flag which tells us whether to examine menu lines or not. */
-int in_menu = 0;
-
-/* Flag which tells us how to examine menu lines. */
-int in_detailmenu = 0;
-
-/* Nonzero means that we have seen "@top" once already. */
-int top_node_seen = 0;
-
-/* Nonzero means that we have seen a non-"@top" node already. */
-int non_top_node_seen = 0;
-
/* Flags controlling the operation of the program. */
/* Default is to remove output if there were errors. */
@@ -374,81 +139,78 @@ int force = 0;
/* Default is to notify users of bad choices. */
int print_warnings = 1;
-/* Default is to check node references. */
-int validating = 1;
-
-/* Nonzero means do not output "Node: Foo" for node separations. */
-int no_headers = 0;
-
/* Number of errors that we tolerate on a given fileset. */
int max_error_level = 100;
-/* Maximum number of references to a single node before complaining. */
-int reference_warning_limit = 1000;
-
-/* Nonzero means print out information about what is going on when it
- is going on. */
-int verbose_mode = 0;
+/* The actual last inserted character. Note that this may be something
+ other than NEWLINE even if last_char_was_newline is 1. */
+int last_inserted_character = 0;
-/* Nonzero means to be relaxed about the input file. This is useful when
- we can successfully format the input, but it doesn't strictly match our
- somewhat pedantic ideas of correctness. Right now, it affects what
- @table and @itemize do without arguments. */
-int allow_lax_format = 0;
+/* Nonzero means that a newline character has already been
+ inserted, so close_paragraph () should insert one less. */
+int line_already_broken = 0;
-/* The list of commands that we hack in texinfo. Each one
- has an associated function. When the command is encountered in the
- text, the associated function is called with START as the argument.
- If the function expects arguments in braces, it remembers itself on
- the stack. When the corresponding close brace is encountered, the
- function is called with END as the argument. */
+/* When nonzero we have finished an insertion (see end_insertion ()) and we
+ want to ignore false continued paragraph closings. */
+int insertion_paragraph_closed = 0;
-#define START 0
-#define END 1
+/* Nonzero means attempt to make all of the lines have fill_column width. */
+int do_justification = 0;
typedef struct brace_element
{
struct brace_element *next;
COMMAND_FUNCTION *proc;
+ char *command;
int pos, line;
int in_fixed_width_font;
} BRACE_ELEMENT;
-BRACE_ELEMENT *brace_stack = (BRACE_ELEMENT *) NULL;
+BRACE_ELEMENT *brace_stack = NULL;
-extern void do_multitable ();
+extern void do_multitable (), end_multitable ();
-void print_version_info ();
-void usage ();
void push_node_filename (), pop_node_filename ();
-void remember_error (), flush_file_stack ();
+void remember_error ();
void convert_from_stream (), convert_from_file (), convert_from_loaded_file ();
void init_internals (), init_paragraph (), init_brace_stack ();
void init_insertion_stack (), init_indices ();
void init_tag_table (), write_tag_table (), write_tag_table_internal ();
void validate_file (), validate_other_references (), split_file ();
-void free_node_references (), do_enumeration (), handle_variable ();
+void free_node_references (), handle_variable ();
void handle_variable_internal ();
void normalize_node_name ();
-void undefindex (), top_defindex (), gen_defindex ();
-void define_user_command ();
-void free_pending_notes (), output_pending_notes ();
+void add_anchor_name ();
+void free_node_node_references (), remember_node_node_reference ();
char **get_brace_args ();
-char *expansion ();
int array_len ();
void free_array ();
static int end_of_sentence_p ();
static void isolate_nodename ();
-void reader_loop (), read_command ();
+void reader_loop ();
void remember_brace (), remember_brace_1 ();
void pop_and_call_brace (), discard_braces ();
void add_word (), add_char (), insert (), flush_output ();
void insert_string ();
-void close_paragraph_with_lines (), close_paragraph ();
+void close_paragraph ();
void ignore_blank_line ();
void do_flush_right_indentation (), discard_insertions ();
void start_paragraph (), indent ();
+void inhibit_output_flushing (), uninhibit_output_flushing ();
+int set_paragraph_indent ();
+int self_delimiting (), search_forward ();
+int multitable_item (), number_of_node ();
+extern void add_link (), add_escaped_anchor_name ();
+
+void me_execute_string_keep_state ();
+void maybe_update_execution_strings ();
+
+extern char *escape_string ();
+extern void insert_html_tag ();
+extern void sectioning_html ();
+extern void add_link ();
+
#if defined (VA_FPRINTF) && __STDC__
/* Unfortunately we must use prototypes if we are to use <stdarg.h>. */
void add_word_args (char *, ...);
@@ -456,356 +218,9 @@ void execute_string (char *, ...);
#else
void add_word_args ();
void execute_string ();
-#endif /* will not use prototypes */
-
-void insert_self (), insert_space (), cm_ignore_line ();
-
-void
- cm_TeX (), cm_asterisk (), cm_bullet (), cm_cite (),
- cm_code (), cm_copyright (), cm_ctrl (), cm_dfn (), cm_dircategory (),
- cm_direntry (), cm_dots (), cm_emph (), cm_enddots (),
- cm_kbd (), cm_key (), cm_no_op (), cm_no_op_line_arg (),
- cm_not_fixed_width (), cm_strong (), cm_var_sc (), cm_w (), cm_image ();
-
-/* Sectioning. */
-void
- cm_chapter (), cm_unnumbered (), cm_appendix (), cm_top (),
- cm_section (), cm_unnumberedsec (), cm_appendixsec (),
- cm_subsection (), cm_unnumberedsubsec (), cm_appendixsubsec (),
- cm_subsubsection (), cm_unnumberedsubsubsec (), cm_appendixsubsubsec (),
- cm_heading (), cm_chapheading (), cm_subheading (), cm_subsubheading (),
- cm_majorheading (), cm_raisesections (), cm_lowersections ();
-
-/* All @def... commands map to cm_defun, most accent commands map to
- cm_accent, most non-English letters map to cm_special_char. */
-void cm_defun (), cm_accent (), cm_special_char (), cm_dotless ();
-
-void
- cm_node (), cm_menu (), cm_xref (), cm_ftable (), cm_vtable (), cm_pxref (),
- cm_inforef (), cm_uref (), cm_email (), cm_quotation (),
- cm_display (), cm_itemize (),
- cm_enumerate (), cm_tab (), cm_table (), cm_itemx (), cm_noindent (),
- cm_setfilename (), cm_br (), cm_sp (), cm_page (), cm_group (),
- cm_center (), cm_include (), cm_bye (), cm_item (), cm_end (),
- cm_ifinfo (), cm_ifnothtml (), cm_ifnottex (), cm_kindex (), cm_cindex (),
- cm_findex (), cm_pindex (), cm_vindex (), cm_tindex (),
- cm_synindex (), cm_printindex (), cm_minus (), cm_footnote (),
- cm_example (), cm_smallexample (), cm_lisp (), cm_format (), cm_exdent (),
- cm_defindex (), cm_defcodeindex (), cm_result (), cm_expansion (),
- cm_equiv (), cm_print (), cm_error (), cm_point (), cm_today (),
- cm_flushleft (), cm_flushright (), cm_smalllisp (), cm_finalout (),
- cm_cartouche (), cm_detailmenu (), cm_multitable ();
-
-/* Conditionals. */
-void cm_set (), cm_clear (), cm_ifset (), cm_ifclear ();
-void cm_value (), cm_ifeq ();
-
-#if defined (HAVE_MACROS)
-/* Define a user-defined command which is simple substitution. */
-void cm_macro (), cm_unmacro ();
-#endif /* HAVE_MACROS */
-
-/* Options. */
-void cm_paragraphindent (), cm_footnotestyle ();
-
-/* Internals. */
-void command_name_condition (), misplaced_brace (), cm_obsolete (),
- cm_ideprecated ();
-
-typedef struct
-{
- char *name;
- COMMAND_FUNCTION *proc;
- int argument_in_braces;
-} COMMAND;
-
-/* Stuff for defining commands on the fly. */
-COMMAND **user_command_array = (COMMAND **) NULL;
-int user_command_array_len = 0;
-
-#define NO_BRACE_ARGS 0
-#define BRACE_ARGS 1
-
-static COMMAND command_table[] = {
- { "\t", insert_space, NO_BRACE_ARGS },
- { "\n", insert_space, NO_BRACE_ARGS },
- { " ", insert_self, NO_BRACE_ARGS },
- { "!", insert_self, NO_BRACE_ARGS },
- { "\"", insert_self, NO_BRACE_ARGS },
- { "'", insert_self, NO_BRACE_ARGS },
- { "*", cm_asterisk, NO_BRACE_ARGS },
- { ",", cm_accent, BRACE_ARGS },
- { "-", cm_no_op, NO_BRACE_ARGS },
- { ".", insert_self, NO_BRACE_ARGS },
- { ":", cm_no_op, NO_BRACE_ARGS },
- { "=", insert_self, NO_BRACE_ARGS },
- { "?", insert_self, NO_BRACE_ARGS },
- { "@", insert_self, NO_BRACE_ARGS },
- { "^", insert_self, NO_BRACE_ARGS },
- { "`", insert_self, NO_BRACE_ARGS },
- { "{", insert_self, NO_BRACE_ARGS },
- { "|", cm_no_op, NO_BRACE_ARGS },
- { "}", insert_self, NO_BRACE_ARGS },
- { "~", insert_self, NO_BRACE_ARGS },
- { "AA", insert_self, BRACE_ARGS },
- { "AE", insert_self, BRACE_ARGS },
- { "H", cm_accent, BRACE_ARGS },
- { "L", cm_special_char, BRACE_ARGS },
- { "O", cm_special_char, BRACE_ARGS },
- { "OE", insert_self, BRACE_ARGS },
- { "TeX", cm_TeX, BRACE_ARGS },
- { "aa", insert_self, BRACE_ARGS },
- { "ae", insert_self, BRACE_ARGS },
- { "appendix", cm_appendix, NO_BRACE_ARGS },
- { "appendixsection", cm_appendixsec, NO_BRACE_ARGS },
- { "appendixsec", cm_appendixsec, NO_BRACE_ARGS },
- { "appendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS },
- { "appendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS },
- { "asis", cm_no_op, BRACE_ARGS },
- { "b", cm_not_fixed_width, BRACE_ARGS },
- { "bullet", cm_bullet, BRACE_ARGS },
- { "bye", cm_bye, NO_BRACE_ARGS },
- { "c", cm_ignore_line, NO_BRACE_ARGS },
- { "cartouche", cm_cartouche, NO_BRACE_ARGS },
- { "center", cm_center, NO_BRACE_ARGS },
- { "centerchap", cm_unnumbered, NO_BRACE_ARGS },
- { "chapheading", cm_chapheading, NO_BRACE_ARGS },
- { "chapter", cm_chapter, NO_BRACE_ARGS },
- { "cindex", cm_cindex, NO_BRACE_ARGS },
- { "cite", cm_cite, BRACE_ARGS },
- { "clear", cm_clear, NO_BRACE_ARGS },
- { "code", cm_code, BRACE_ARGS },
- { "comment", cm_ignore_line, NO_BRACE_ARGS },
- { "contents", cm_no_op, NO_BRACE_ARGS },
- { "copyright", cm_copyright, BRACE_ARGS },
- { "ctrl", cm_obsolete, BRACE_ARGS },
- { "defcodeindex", cm_defcodeindex, NO_BRACE_ARGS },
- { "defindex", cm_defindex, NO_BRACE_ARGS },
-/* The `def' commands. */
- { "defcv", cm_defun, NO_BRACE_ARGS },
- { "defcvx", cm_defun, NO_BRACE_ARGS },
- { "deffn", cm_defun, NO_BRACE_ARGS },
- { "deffnx", cm_defun, NO_BRACE_ARGS },
- { "defivar", cm_defun, NO_BRACE_ARGS },
- { "defivarx", cm_defun, NO_BRACE_ARGS },
- { "defmac", cm_defun, NO_BRACE_ARGS },
- { "defmacx", cm_defun, NO_BRACE_ARGS },
- { "defmethod", cm_defun, NO_BRACE_ARGS },
- { "defmethodx", cm_defun, NO_BRACE_ARGS },
- { "defop", cm_defun, NO_BRACE_ARGS },
- { "defopt", cm_defun, NO_BRACE_ARGS },
- { "defoptx", cm_defun, NO_BRACE_ARGS },
- { "defopx", cm_defun, NO_BRACE_ARGS },
- { "defspec", cm_defun, NO_BRACE_ARGS },
- { "defspecx", cm_defun, NO_BRACE_ARGS },
- { "deftp", cm_defun, NO_BRACE_ARGS },
- { "deftpx", cm_defun, NO_BRACE_ARGS },
- { "deftypefn", cm_defun, NO_BRACE_ARGS },
- { "deftypefnx", cm_defun, NO_BRACE_ARGS },
- { "deftypefun", cm_defun, NO_BRACE_ARGS },
- { "deftypefunx", cm_defun, NO_BRACE_ARGS },
- { "deftypemethod", cm_defun, NO_BRACE_ARGS },
- { "deftypemethodx", cm_defun, NO_BRACE_ARGS },
- { "deftypevar", cm_defun, NO_BRACE_ARGS },
- { "deftypevarx", cm_defun, NO_BRACE_ARGS },
- { "deftypevr", cm_defun, NO_BRACE_ARGS },
- { "deftypevrx", cm_defun, NO_BRACE_ARGS },
- { "defun", cm_defun, NO_BRACE_ARGS },
- { "defunx", cm_defun, NO_BRACE_ARGS },
- { "defvar", cm_defun, NO_BRACE_ARGS },
- { "defvarx", cm_defun, NO_BRACE_ARGS },
- { "defvr", cm_defun, NO_BRACE_ARGS },
- { "defvrx", cm_defun, NO_BRACE_ARGS },
-/* The end of the `def' commands. */
- { "detailmenu", cm_detailmenu, NO_BRACE_ARGS },
- { "dfn", cm_dfn, BRACE_ARGS },
- { "dircategory", cm_dircategory, NO_BRACE_ARGS },
- { "direntry", cm_direntry, NO_BRACE_ARGS },
- { "display", cm_display, NO_BRACE_ARGS },
- { "dmn", cm_no_op, BRACE_ARGS },
- { "dotaccent", cm_accent, BRACE_ARGS },
- { "dotless", cm_dotless, BRACE_ARGS },
- { "dots", cm_dots, BRACE_ARGS },
- { "email", cm_email, BRACE_ARGS },
- { "emph", cm_emph, BRACE_ARGS },
- { "end", cm_end, NO_BRACE_ARGS },
- { "enddots", cm_enddots, BRACE_ARGS },
- { "enumerate", cm_enumerate, NO_BRACE_ARGS },
- { "equiv", cm_equiv, BRACE_ARGS },
- { "error", cm_error, BRACE_ARGS },
- { "example", cm_example, NO_BRACE_ARGS },
- { "exclamdown", cm_special_char, BRACE_ARGS },
- { "exdent", cm_exdent, NO_BRACE_ARGS },
- { "expansion", cm_expansion, BRACE_ARGS },
- { "file", cm_code, BRACE_ARGS },
- { "finalout", cm_no_op, NO_BRACE_ARGS },
- { "findex", cm_findex, NO_BRACE_ARGS },
- { "flushleft", cm_flushleft, NO_BRACE_ARGS },
- { "flushright", cm_flushright, NO_BRACE_ARGS },
- { "footnote", cm_footnote, NO_BRACE_ARGS}, /* self-arg eater */
- { "footnotestyle", cm_footnotestyle, NO_BRACE_ARGS },
- { "format", cm_format, NO_BRACE_ARGS },
- { "ftable", cm_ftable, NO_BRACE_ARGS },
- { "group", cm_group, NO_BRACE_ARGS },
- { "heading", cm_heading, NO_BRACE_ARGS },
- { "headings", cm_ignore_line, NO_BRACE_ARGS },
- { "html", command_name_condition, NO_BRACE_ARGS },
- { "hyphenation", cm_no_op, BRACE_ARGS },
- { "i", cm_not_fixed_width, BRACE_ARGS },
- { "ifclear", cm_ifclear, NO_BRACE_ARGS },
- { "ifeq", cm_ifeq, NO_BRACE_ARGS },
- { "ifhtml", command_name_condition, NO_BRACE_ARGS },
- { "ifinfo", cm_ifinfo, NO_BRACE_ARGS },
- { "ifnothtml", cm_ifnothtml, NO_BRACE_ARGS },
- { "ifnotinfo", command_name_condition, NO_BRACE_ARGS },
- { "ifnottex", cm_ifnottex, NO_BRACE_ARGS },
- { "ifset", cm_ifset, NO_BRACE_ARGS },
- { "iftex", command_name_condition, NO_BRACE_ARGS },
- { "ignore", command_name_condition, NO_BRACE_ARGS },
- { "image", cm_image, BRACE_ARGS },
- { "include", cm_include, NO_BRACE_ARGS },
- { "inforef", cm_inforef, BRACE_ARGS },
- { "item", cm_item, NO_BRACE_ARGS },
- { "itemize", cm_itemize, NO_BRACE_ARGS },
- { "itemx", cm_itemx, NO_BRACE_ARGS },
- { "kbd", cm_kbd, BRACE_ARGS },
- { "kbdinputstyle", cm_no_op_line_arg, NO_BRACE_ARGS },
- { "key", cm_key, BRACE_ARGS },
- { "kindex", cm_kindex, NO_BRACE_ARGS },
- { "l", cm_special_char, BRACE_ARGS },
- { "lisp", cm_lisp, NO_BRACE_ARGS },
- { "lowersections", cm_lowersections, NO_BRACE_ARGS },
- { "macro", cm_macro, NO_BRACE_ARGS },
- { "majorheading", cm_majorheading, NO_BRACE_ARGS },
- { "math", cm_no_op, BRACE_ARGS },
- { "menu", cm_menu, NO_BRACE_ARGS },
- { "minus", cm_minus, BRACE_ARGS },
- { "multitable", cm_multitable, NO_BRACE_ARGS },
- { "need", cm_ignore_line, NO_BRACE_ARGS },
- { "node", cm_node, NO_BRACE_ARGS },
- { "noindent", cm_noindent, NO_BRACE_ARGS },
- { "nwnode", cm_node, NO_BRACE_ARGS },
- { "o", cm_special_char, BRACE_ARGS },
- { "oe", insert_self, BRACE_ARGS },
- { "page", cm_no_op, NO_BRACE_ARGS },
- { "paragraphindent", cm_paragraphindent, NO_BRACE_ARGS },
- { "pindex", cm_pindex, NO_BRACE_ARGS },
- { "point", cm_point, BRACE_ARGS },
- { "pounds", cm_special_char, BRACE_ARGS },
- { "print", cm_print, BRACE_ARGS },
- { "printindex", cm_printindex, NO_BRACE_ARGS },
- { "pxref", cm_pxref, BRACE_ARGS },
- { "questiondown", cm_special_char, BRACE_ARGS },
- { "quotation", cm_quotation, NO_BRACE_ARGS },
- { "r", cm_not_fixed_width, BRACE_ARGS },
- { "raisesections", cm_raisesections, NO_BRACE_ARGS },
- { "ref", cm_xref, BRACE_ARGS },
- { "refill", cm_no_op, NO_BRACE_ARGS },
- { "result", cm_result, BRACE_ARGS },
- { "ringaccent", cm_accent, BRACE_ARGS },
- { "samp", cm_code, BRACE_ARGS },
- { "sc", cm_var_sc, BRACE_ARGS },
- { "section", cm_section, NO_BRACE_ARGS },
- { "set", cm_set, NO_BRACE_ARGS },
- { "setchapternewpage", cm_ignore_line, NO_BRACE_ARGS },
- { "setchapterstyle", cm_obsolete, NO_BRACE_ARGS },
- { "setfilename", cm_setfilename, NO_BRACE_ARGS },
- { "settitle", cm_ignore_line, NO_BRACE_ARGS },
- { "shortcontents", cm_no_op, NO_BRACE_ARGS },
- { "shorttitlepage", cm_ignore_line, NO_BRACE_ARGS },
- { "smallbook", cm_ignore_line, NO_BRACE_ARGS },
- { "smallexample", cm_smallexample, NO_BRACE_ARGS },
- { "smalllisp", cm_smalllisp, NO_BRACE_ARGS },
- { "sp", cm_sp, NO_BRACE_ARGS },
- { "ss", insert_self, BRACE_ARGS },
- { "strong", cm_strong, BRACE_ARGS },
- { "subheading", cm_subheading, NO_BRACE_ARGS },
- { "subsection", cm_subsection, NO_BRACE_ARGS },
- { "subsubheading", cm_subsubheading, NO_BRACE_ARGS },
- { "subsubsection", cm_subsubsection, NO_BRACE_ARGS },
- { "summarycontents", cm_no_op, NO_BRACE_ARGS },
- { "syncodeindex", cm_synindex, NO_BRACE_ARGS },
- { "synindex", cm_synindex, NO_BRACE_ARGS },
- { "t", cm_no_op, BRACE_ARGS },
- { "tab", cm_tab, NO_BRACE_ARGS },
- { "table", cm_table, NO_BRACE_ARGS },
- { "tex", command_name_condition, NO_BRACE_ARGS },
- { "tieaccent", cm_accent, BRACE_ARGS },
- { "tindex", cm_tindex, NO_BRACE_ARGS },
- { "titlefont", cm_not_fixed_width, BRACE_ARGS },
- { "titlepage", command_name_condition, NO_BRACE_ARGS },
- { "today", cm_today, BRACE_ARGS },
- { "top", cm_top, NO_BRACE_ARGS },
- { "u", cm_accent, BRACE_ARGS },
- { "ubaraccent", cm_accent, BRACE_ARGS },
- { "udotaccent", cm_accent, BRACE_ARGS },
-#if defined (HAVE_MACROS)
- { "unmacro", cm_unmacro, NO_BRACE_ARGS },
-#endif
- { "unnumbered", cm_unnumbered, NO_BRACE_ARGS },
- { "unnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS },
- { "unnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS },
- { "unnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS },
- { "uref", cm_uref, BRACE_ARGS },
- { "url", cm_code, BRACE_ARGS },
- { "v", cm_accent, BRACE_ARGS },
- { "value", cm_value, BRACE_ARGS },
- { "var", cm_var_sc, BRACE_ARGS },
- { "vindex", cm_vindex, NO_BRACE_ARGS },
- { "vtable", cm_vtable, NO_BRACE_ARGS },
- { "w", cm_w, BRACE_ARGS },
- { "xref", cm_xref, BRACE_ARGS },
-
- /* Deprecated commands. These used to be for italics. */
- { "iappendix", cm_ideprecated, NO_BRACE_ARGS },
- { "iappendixsec", cm_ideprecated, NO_BRACE_ARGS },
- { "iappendixsection", cm_ideprecated, NO_BRACE_ARGS },
- { "iappendixsubsec", cm_ideprecated, NO_BRACE_ARGS },
- { "iappendixsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
- { "ichapter", cm_ideprecated, NO_BRACE_ARGS },
- { "isection", cm_ideprecated, NO_BRACE_ARGS },
- { "isubsection", cm_ideprecated, NO_BRACE_ARGS },
- { "isubsubsection", cm_ideprecated, NO_BRACE_ARGS },
- { "iunnumbered", cm_ideprecated, NO_BRACE_ARGS },
- { "iunnumberedsec", cm_ideprecated, NO_BRACE_ARGS },
- { "iunnumberedsubsec", cm_ideprecated, NO_BRACE_ARGS },
- { "iunnumberedsubsubsec", cm_ideprecated, NO_BRACE_ARGS },
-
- /* Now @include does what this was used to. */
- { "infoinclude", cm_obsolete, NO_BRACE_ARGS },
- { "titlespec", cm_obsolete, NO_BRACE_ARGS },
-
- { NULL, NULL, NO_BRACE_ARGS }
-};
-
-struct option long_options[] =
-{
- { "error-limit", 1, 0, 'e' }, /* formerly -el */
- { "fill-column", 1, 0, 'f' }, /* formerly -fc */
- { "footnote-style", 1, 0, 's' }, /* formerly -ft */
- { "force", 0, 0, 'F' }, /* do not remove output */
- { "no-headers", 0, &no_headers, 1 }, /* do not output Node: foo */
- { "no-pointer-validate", 0, &validating, 0 }, /* formerly -nv */
- { "no-validate", 0, &validating, 0 }, /* formerly -nv */
- { "no-split", 0, &splitting, 0 }, /* formerly -ns */
- { "no-warn", 0, &print_warnings, 0 }, /* formerly -nw */
- { "macro-expand", 1, 0, 'E' },
- { "number-footnotes", 0, &number_footnotes, 1 },
- { "no-number-footnotes", 0, &number_footnotes, 0 },
- { "output", 1, 0, 'o' },
- { "paragraph-indent", 1, 0, 'p' }, /* formerly -pi */
- { "reference-limit", 1, 0, 'r' }, /* formerly -rl */
- { "verbose", 0, &verbose_mode, 1 }, /* formerly -verbose */
- { "help", 0, 0, 'h' },
- { "version", 0, 0, 'V' },
- {NULL, 0, NULL, 0}
-};
+#endif /* no prototypes */
-/* **************************************************************** */
-/* */
-/* Error Handling */
-/* */
-/* **************************************************************** */
+/* Error handling. */
/* Number of errors encountered. */
int errors_printed = 0;
@@ -817,7 +232,7 @@ fs_error (filename)
{
remember_error ();
perror (filename);
- return (0);
+ return 0;
}
/* Print an error message, and return false. */
@@ -916,15 +331,136 @@ remember_error ()
fprintf (stderr, _("Too many errors! Gave up.\n"));
flush_file_stack ();
cm_bye ();
- exit (FATAL);
+ xexit (1);
}
}
+
+/* The other side of a malformed expression. */
+void
+misplaced_brace ()
+{
+ line_error (_("Misplaced %c"), '}');
+}
-/* **************************************************************** */
-/* */
-/* Main () Start of code */
-/* */
-/* **************************************************************** */
+/* Main. */
+
+/* Display the version info of this invocation of Makeinfo. */
+static void
+print_version_info ()
+{
+ printf ("makeinfo (GNU %s) %s\n", PACKAGE, VERSION);
+}
+
+/* If EXIT_VALUE is zero, print the full usage message to stdout.
+ Otherwise, just say to use --help for more info.
+ Then exit with EXIT_VALUE. */
+static void
+usage (exit_value)
+ int exit_value;
+{
+ if (exit_value != 0)
+ fprintf (stderr, _("Try `%s --help' for more information.\n"), progname);
+ else
+ {
+ printf (_("Usage: %s [OPTION]... TEXINFO-FILE...\n\
+\n\
+Translate Texinfo source documentation to various other formats:\n\
+Info files suitable for reading online with Emacs or standalone GNU Info\n\
+(by default); plain text (with --no-headers); or HTML (with --html).\n\
+\n\
+Options:\n\
+ --commands-in-node-names allow @ commands in node names.\n\
+ -D VAR define a variable, as with @set.\n\
+ -E, --macro-expand FILE output macro-expanded source to FILE.\n\
+ --error-limit=NUM quit after NUM errors (default %d).\n\
+ --fill-column=NUM break Info lines at NUM characters (default %d).\n\
+ --footnote-style=STYLE output footnotes according to STYLE:\n\
+ `separate' to place footnotes in their own node,\n\
+ `end' to place the footnotes at the end of the\n\
+ node in which they are defined (the default).\n\
+ --force preserve output even if errors.\n\
+ --help display this help and exit.\n\
+ --html output HTML rather than Info format;\n\
+ -I DIR append DIR to the @include search path.\n\
+ --ifhtml process @ifhtml and @html text even when not\n\
+ generating HTML.\n\
+ --ifinfo process @ifinfo text even when generating HTML.\n\
+ --iftex process @iftex and @tex text.\n\
+ implies --no-split.\n"),
+ progname, max_error_level, fill_column);
+ printf (_("\
+ --no-headers suppress Info node separators and Node: lines and\n\
+ write to standard output without --output.\n\
+ --no-ifhtml do not process @ifhtml and @html text.\n\
+ --no-ifinfo do not process @ifinfo text.\n\
+ --no-iftex do not process @iftex and @tex text.\n\
+ --no-split suppress splitting of large Info output files or\n\
+ generation of one HTML file per node.\n\
+ --no-validate suppress node cross-reference validation.\n\
+ --no-warn suppress warnings (but not errors).\n\
+ --number-sections include chapter, section, etc. numbers in output.\n\
+ -o, --output=FILE output to FILE, ignoring any @setfilename.\n\
+ -P DIR prepend DIR to the @include search path.\n\
+ --paragraph-indent=VAL indent Info paragraphs by VAL spaces (default %d).\n\
+ if VAL is `none', do not indent;\n\
+ if VAL is `asis', preserve existing indentation.\n\
+ --reference-limit=NUM warn about at most NUM references (default %d).\n\
+ -U VAR undefine a variable, as with @clear.\n\
+ -v, --verbose explain what is being done.\n\
+ --version display version information and exit.\n\
+"),
+ paragraph_start_indent, reference_warning_limit);
+ }
+
+ puts (_("\n\
+The defaults for the @if... conditionals depend on the output format:\n\
+if generating HTML, --ifhtml is on and the others are off;\n\
+if generating Info or plain text, --ifinfo is on and the others are off.\n\
+\n\
+Examples:\n\
+ makeinfo foo.texi write Info to foo's @setfilename\n\
+ makeinfo --html foo.texi write HTML to foo's @setfilename\n\
+ makeinfo --no-headers -o - foo.texi write plain text to standard output\n\
+ makeinfo --number-sections foo.texi write Info with numbered sections\n\
+ makeinfo --no-split foo.texi write one Info file however big\n\
+\n\
+Email bug reports to bug-texinfo@gnu.org,\n\
+general questions and discussion to help-texinfo@gnu.org."));
+ xexit (exit_value);
+}
+
+struct option long_options[] =
+{
+ { "commands-in-node-names", 0, &expensive_validation, 1 },
+ { "error-limit", 1, 0, 'e' },
+ { "fill-column", 1, 0, 'f' },
+ { "footnote-style", 1, 0, 's' },
+ { "force", 0, &force, 1 },
+ { "help", 0, 0, 'h' },
+ { "html", 0, 0, 'w' },
+ { "ifhtml", 0, &process_html, 1 },
+ { "ifinfo", 0, &process_info, 1 },
+ { "iftex", 0, &process_tex, 1 },
+ { "macro-expand", 1, 0, 'E' },
+ { "no-headers", 0, &no_headers, 1 },
+ { "no-ifhtml", 0, &process_html, 0 },
+ { "no-ifinfo", 0, &process_info, 0 },
+ { "no-iftex", 0, &process_tex, 0 },
+ { "no-number-footnotes", 0, &number_footnotes, 0 },
+ { "no-number-sections", 0, &number_sections, 0 },
+ { "no-pointer-validate", 0, &validating, 0 },
+ { "no-split", 0, &splitting, 0 },
+ { "no-validate", 0, &validating, 0 },
+ { "no-warn", 0, &print_warnings, 0 },
+ { "number-footnotes", 0, &number_footnotes, 1 },
+ { "number-sections", 0, &number_sections, 1 },
+ { "output", 1, 0, 'o' },
+ { "paragraph-indent", 1, 0, 'p' },
+ { "reference-limit", 1, 0, 'r' },
+ { "verbose", 0, &verbose_mode, 1 },
+ { "version", 0, 0, 'V' },
+ {NULL, 0, NULL, 0}
+};
/* For each file mentioned in the command line, process it, turning
Texinfo commands into wonderfully formatted output text. */
@@ -934,18 +470,16 @@ main (argc, argv)
char **argv;
{
extern int errors_printed;
- char *filename_part ();
int c, ind;
int reading_from_stdin = 0;
- /* The name of this program is the last filename in argv[0]. */
- progname = filename_part (argv[0]);
-
#ifdef HAVE_SETLOCALE
/* Do not use LC_ALL, because LC_NUMERIC screws up the scanf parsing
of the argument to @multicolumn. */
setlocale (LC_TIME, "");
setlocale (LC_MESSAGES, "");
+ setlocale (LC_CTYPE, "");
+ setlocale (LC_COLLATE, "");
#endif
/* Set the text message domain. */
@@ -953,7 +487,7 @@ main (argc, argv)
textdomain (PACKAGE);
/* Parse argument flags from the input line. */
- while ((c = getopt_long (argc, argv, "D:e:E:f:I:o:p:P:r:s:U:V",
+ while ((c = getopt_long (argc, argv, "D:e:E:f:hI:o:p:P:r:s:U:vV:w",
long_options, &ind)) != EOF)
{
if (c == 0 && long_options[ind].flag == 0)
@@ -967,19 +501,17 @@ main (argc, argv)
handle_variable_internal ((c == 'D') ? SET : CLEAR, optarg);
break;
- case 'e':
- /* User specified error level. */
+ case 'e': /* --error-limit */
if (sscanf (optarg, "%d", &max_error_level) != 1)
{
fprintf (stderr,
_("%s: %s arg must be numeric, not `%s'.\n"),
"--error-limit", progname, optarg);
- usage (stderr, FATAL);
+ usage (stderr, 1);
}
break;
- case 'E':
- /* User specified a macro expansion output file. */
+ case 'E': /* --macro-expand */
if (!macro_expansion_output_stream)
{
macro_expansion_filename = optarg;
@@ -992,23 +524,18 @@ main (argc, argv)
error (_("Cannot specify more than one macro expansion output"));
break;
- case 'f':
- /* User specified fill_column. */
+ case 'f': /* --fill-column */
if (sscanf (optarg, "%d", &fill_column) != 1)
{
fprintf (stderr,
- _("%s: %s arg must be numeric, not `%s'.\n"),
+ _("%s: %s arg must be numeric, not `%s'.\n"),
"--fill-column", progname, optarg);
- usage (FATAL);
+ usage (1);
}
break;
- case 'F':
- force++; /* Do not remove erroneous output. */
- break;
-
- case 'h':
- usage (NO_ERROR);
+ case 'h': /* --help */
+ usage (0);
break;
case 'I':
@@ -1019,23 +546,21 @@ main (argc, argv)
include_files_path = (char *)
xrealloc (include_files_path,
2 + strlen (include_files_path) + strlen (optarg));
- strcat (include_files_path, ":");
+ strcat (include_files_path, PATH_SEP);
strcat (include_files_path, optarg);
break;
- case 'o':
- /* User specified output file. */
+ case 'o': /* --output */
command_output_filename = xstrdup (optarg);
break;
- case 'p':
- /* User specified paragraph indent (paragraph_start_index). */
+ case 'p': /* --paragraph-indent */
if (set_paragraph_indent (optarg) < 0)
{
fprintf (stderr,
- _("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"),
+ _("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"),
progname, optarg);
- usage (FATAL);
+ usage (1);
}
break;
@@ -1044,14 +569,14 @@ main (argc, argv)
if (!include_files_path)
{
include_files_path = xstrdup (optarg);
- include_files_path = (char *) xrealloc (include_files_path,
+ include_files_path = xrealloc (include_files_path,
strlen (include_files_path) + 3); /* 3 for ":.\0" */
- strcat (include_files_path, ":.");
+ strcat (strcat (include_files_path, PATH_SEP), ".");
}
else
{
char *tmp = xstrdup (include_files_path);
- include_files_path = (char *) xrealloc (include_files_path,
+ include_files_path = xrealloc (include_files_path,
strlen (include_files_path) + strlen (optarg) + 2); /* 2 for ":\0" */
strcpy (include_files_path, optarg);
strcat (include_files_path, ":");
@@ -1059,47 +584,59 @@ main (argc, argv)
free (tmp);
}
break;
-
- case 'r':
- /* User specified reference warning limit. */
+
+ case 'r': /* --reference-limit */
if (sscanf (optarg, "%d", &reference_warning_limit) != 1)
{
fprintf (stderr,
- _("%s: %s arg must be numeric, not `%s'.\n"),
+ _("%s: %s arg must be numeric, not `%s'.\n"),
"--reference-limit", progname, optarg);
- usage (FATAL);
+ usage (1);
}
break;
- case 's':
- /* User specified footnote style. */
+ case 's': /* --footnote-style */
if (set_footnote_style (optarg) < 0)
{
fprintf (stderr,
- _("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"),
+ _("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"),
progname, optarg);
- usage (FATAL);
+ usage (1);
}
footnote_style_preset = 1;
break;
- case 'V':
- /* User requested version info. */
+ case 'v':
+ verbose_mode++;
+ break;
+
+ case 'V': /* --version */
print_version_info ();
- printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
+ puts ("");
+ printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
There is NO warranty. You may redistribute this software\n\
under the terms of the GNU General Public License.\n\
For more information about these matters, see the files named COPYING.\n"),
- "1998");
- exit (NO_ERROR);
+ "1999");
+ exit (0);
+ break;
+
+ case 'w': /* --html */
+ html = 1;
+ process_html = 1;
+ process_info = 0;
+ splitting = 0; /* too complicated for now */
break;
case '?':
- usage (FATAL);
+ usage (1);
break;
}
}
+ if (!validating)
+ expensive_validation = 0;
+
if (optind == argc)
{
/* Check to see if input is a file. If so, process that. */
@@ -1108,19 +645,24 @@ For more information about these matters, see the files named COPYING.\n"),
else
{
fprintf (stderr, _("%s: missing file argument.\n"), progname);
- usage (FATAL);
+ usage (1);
}
}
- /* If the user has specified --no-headers, this should imply --no-split.
- Do that here. I think it might also imply that we should ignore the
- setfilename at the top of the file, but this might break some FSF things,
- so I will hold off on that. */
if (no_headers)
{
+ if (html && splitting)
+ { /* --no-headers --no-split --html indicates confusion. */
+ fprintf (stderr,
+ "%s: --no-headers conflicts with --no-split for --html.\n",
+ progname);
+ usage (1);
+ }
+
+ /* --no-headers implies --no-split. */
splitting = 0;
- /* If the user has not specified an output file, use stdout. */
+ /* If the user did not specify an output file, use stdout. */
if (!command_output_filename)
command_output_filename = xstrdup ("-");
}
@@ -1138,491 +680,11 @@ For more information about these matters, see the files named COPYING.\n"),
else
convert_from_stream (stdin, "stdin");
- if (errors_printed)
- return (SYNTAX);
- else
- return (NO_ERROR);
-}
-
-/* Display the version info of this invocation of Makeinfo. */
-void
-print_version_info ()
-{
- printf ("makeinfo (GNU %s %s) %d.%d\n", PACKAGE, VERSION,
- major_version, minor_version);
-}
-
-/* If EXIT_VALUE is zero, print the full usage message to stdout.
- Otherwise, just say to use --help for more info.
- Then exit with EXIT_VALUE. */
-void
-usage (exit_value)
- int exit_value;
-{
- if (exit_value != 0)
- fprintf (stderr, _("Try `%s --help' for more information.\n"), progname);
- else
- printf (_("Usage: %s [OPTION]... TEXINFO-FILE...\n\
-\n\
-Translate Texinfo source documentation to a format suitable for reading\n\
-with GNU Info.\n\
-\n\
-Options:\n\
--D VAR define a variable, as with @set.\n\
--E MACRO-OFILE process macros only, output texinfo source.\n\
--I DIR append DIR to the @include directory search path.\n\
--P DIR prepend DIR to the @include directory search path.\n\
--U VAR undefine a variable, as with @clear.\n\
---error-limit NUM quit after NUM errors (default %d).\n\
---fill-column NUM break lines at NUM characters (default %d).\n\
---footnote-style STYLE output footnotes according to STYLE:\n\
- `separate' to place footnotes in their own node,\n\
- `end' to place the footnotes at the end of\n\
- the node in which they are defined (the default).\n\
---force preserve output even if errors.\n\
---help display this help and exit.\n\
---no-validate suppress node cross-reference validation.\n\
---no-warn suppress warnings (but not errors).\n\
---no-split suppress splitting of large files.\n\
---no-headers suppress node separators and Node: Foo headers.\n\
---output FILE, -o FILE output to FILE, and ignore any @setfilename.\n\
---paragraph-indent VAL indent paragraphs with VAL spaces (default %d).\n\
- if VAL is `none', do not indent; if VAL is `asis',\n\
- preserve any existing indentation.\n\
---reference-limit NUM complain about at most NUM references (default %d).\n\
---verbose report about what is being done.\n\
---version display version information and exit.\n\
-\n\
-Email bug reports to bug-texinfo@gnu.org.\n\
-"),
- progname, max_error_level, fill_column,
- paragraph_start_indent, reference_warning_limit);
- exit (exit_value);
-}
-
-/* Manipulating Lists */
-
-typedef struct generic_list {
- struct generic_list *next;
-} GENERIC_LIST;
-
-/* Reverse the chain of structures in LIST. Output the new head
- of the chain. You should always assign the output value of this
- function to something, or you will lose the chain. */
-GENERIC_LIST *
-reverse_list (list)
- register GENERIC_LIST *list;
-{
- register GENERIC_LIST *next;
- register GENERIC_LIST *prev = (GENERIC_LIST *) NULL;
-
- while (list)
- {
- next = list->next;
- list->next = prev;
- prev = list;
- list = next;
- }
- return (prev);
-}
-
-/* Pushing and Popping Files */
-
-/* Find and load the file named FILENAME. Return a pointer to
- the loaded file, or NULL if it can't be loaded. */
-char *
-find_and_load (filename)
- char *filename;
-{
- struct stat fileinfo;
- long file_size;
- int file = -1, count = 0;
- char *fullpath, *result, *get_file_info_in_path ();
-
- result = fullpath = (char *)NULL;
-
- fullpath = get_file_info_in_path (filename, include_files_path, &fileinfo);
-
- if (!fullpath)
- goto error_exit;
-
- filename = fullpath;
- file_size = (long) fileinfo.st_size;
-
- file = open (filename, O_RDONLY);
- if (file < 0)
- goto error_exit;
-
- /* Load the file, with enough room for a newline and a null. */
- result = xmalloc (file_size + 2);
-
- /* VMS stat lies about the st_size value. The actual number of
- readable bytes is always less than this value. The arcane
- mysteries of VMS/RMS are too much to probe, so this hack
- suffices to make things work. */
-#if defined (VMS) || defined (WIN32)
-#ifdef VMS
- while ((n = read (file, result + count, file_size)) > 0)
-#else /* WIN32 */
- while ((n = read (file, result + count, 1)) > 0)
-#endif /* WIN32 */
- count += n;
- if (n == -1)
-#else /* !VMS && !WIN32 */
- count = file_size;
- if (read (file, result, file_size) != file_size)
-#endif /* !VMS && !WIN32 */
- error_exit:
- {
- if (result)
- free (result);
-
- if (fullpath)
- free (fullpath);
-
- if (file != -1)
- close (file);
-
- return ((char *) NULL);
- }
- close (file);
-
- /* Set the globals to the new file. */
- input_text = result;
- size_of_input_text = count;
- input_filename = fullpath;
- node_filename = xstrdup (fullpath);
- input_text_offset = 0;
- line_number = 1;
- /* Not strictly necessary. This magic prevents read_token () from doing
- extra unnecessary work each time it is called (that is a lot of times).
- SIZE_OF_INPUT_TEXT is one past the actual end of the text. */
- input_text[size_of_input_text] = '\n';
- /* This, on the other hand, is always necessary. */
- input_text[size_of_input_text+1] = 0;
- return (result);
-}
-
-/* Save the state of the current input file. */
-void
-pushfile ()
-{
- FSTACK *newstack = (FSTACK *) xmalloc (sizeof (FSTACK));
- newstack->filename = input_filename;
- newstack->text = input_text;
- newstack->size = size_of_input_text;
- newstack->offset = input_text_offset;
- newstack->line_number = line_number;
- newstack->next = filestack;
-
- filestack = newstack;
- push_node_filename ();
-}
-
-/* Make the current file globals be what is on top of the file stack. */
-void
-popfile ()
-{
- FSTACK *tos = filestack;
-
- if (!tos)
- abort (); /* My fault. I wonder what I did? */
-
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream)
- {
- maybe_write_itext (input_text, input_text_offset);
- forget_itext (input_text);
- }
-#endif /* HAVE_MACROS */
-
- /* Pop the stack. */
- filestack = filestack->next;
-
- /* Make sure that commands with braces have been satisfied. */
- if (!executing_string && !me_executing_string)
- discard_braces ();
-
- /* Get the top of the stack into the globals. */
- input_filename = tos->filename;
- input_text = tos->text;
- size_of_input_text = tos->size;
- input_text_offset = tos->offset;
- line_number = tos->line_number;
- free (tos);
-
- /* Go back to the (now) current node. */
- pop_node_filename ();
-}
-
-/* Flush all open files on the file stack. */
-void
-flush_file_stack ()
-{
- while (filestack)
- {
- char *fname = input_filename;
- char *text = input_text;
- popfile ();
- free (fname);
- free (text);
- }
-}
-
-int node_filename_stack_index = 0;
-int node_filename_stack_size = 0;
-char **node_filename_stack = (char **)NULL;
-
-void
-push_node_filename ()
-{
- if (node_filename_stack_index + 1 > node_filename_stack_size)
- node_filename_stack = (char **)xrealloc
- (node_filename_stack, (node_filename_stack_size += 10) * sizeof (char *));
-
- node_filename_stack[node_filename_stack_index] = node_filename;
- node_filename_stack_index++;
-}
-
-void
-pop_node_filename ()
-{
- node_filename = node_filename_stack[--node_filename_stack_index];
-}
-
-/* Return just the simple part of the filename; i.e. the
- filename without the path information, or extensions.
- This conses up a new string. */
-char *
-filename_part (filename)
- char *filename;
-{
- char *basename;
-
- basename = strrchr (filename, '/');
- if (!basename)
- basename = filename;
- else
- basename++;
-
- basename = xstrdup (basename);
-#if defined (REMOVE_OUTPUT_EXTENSIONS)
-
- /* See if there is an extension to remove. If so, remove it. */
- {
- char *temp;
-
- temp = strrchr (basename, '.');
- if (temp)
- *temp = 0;
- }
-#endif /* REMOVE_OUTPUT_EXTENSIONS */
- return (basename);
-}
-
-/* Return the pathname part of filename. This can be NULL. */
-char *
-pathname_part (filename)
- char *filename;
-{
- char *expand_filename ();
- char *result = (char *) NULL;
- register int i;
-
- filename = expand_filename (filename, "");
-
- i = strlen (filename) - 1;
-
- while (i && filename[i] != '/')
- i--;
- if (filename[i] == '/')
- i++;
-
- if (i)
- {
- result = (char *)xmalloc (1 + i);
- strncpy (result, filename, i);
- result[i] = 0;
- }
- free (filename);
- return (result);
-}
-
-char *
-filename_non_directory (name)
- char *name;
-{
- register int i;
-
- for (i = strlen (name) - 1; i; i--)
- if (name[i] == '/')
- return (xstrdup (name + i + 1));
-
- return (xstrdup (name));
+ return errors_printed ? 2 : 0;
}
-/* Return the expansion of FILENAME. */
-char *
-expand_filename (filename, input_name)
- char *filename, *input_name;
-{
- register int i;
- char *full_pathname ();
-
- if (filename)
- filename = full_pathname (filename);
- else
- {
- filename = filename_non_directory (input_name);
-
- if (!*filename)
- {
- free (filename);
- filename = xstrdup ("noname.texi");
- }
-
- for (i = strlen (filename) - 1; i; i--)
- if (filename[i] == '.')
- break;
-
- if (!i)
- i = strlen (filename);
-
- if (i + 6 > (strlen (filename)))
- filename = (char *)xrealloc (filename, i + 6);
- strcpy (filename + i, ".info");
- return (filename);
- }
-
- if (filename[0] == '.' || filename[0] == '/')
- return (filename);
-
- if (filename[0] != '/' && input_name[0] == '/')
- {
- /* Make it so that relative names work. */
- char *result;
-
- i = strlen (input_name) - 1;
-
- result = (char *)xmalloc (1 + strlen (input_name) + strlen (filename));
- strcpy (result, input_name);
-
- while (result[i] != '/' && i)
- i--;
-
- if (result[i] == '/')
- i++;
-
- strcpy (&result[i], filename);
- free (filename);
- return (result);
- }
- return (filename);
-}
-
-/* Return the full path to FILENAME. */
-char *
-full_pathname (filename)
- char *filename;
-{
- int initial_character;
- char *result;
-
- /* No filename given? */
- if (!filename || !(initial_character = *filename))
- return (xstrdup (""));
-
- /* Already absolute? */
- if ((initial_character == '/') ||
- ((strncmp (filename, "./", 2) == 0) ||
- (strncmp (filename, "../", 3) == 0)))
- return (xstrdup (filename));
-
- if (initial_character != '~')
- {
- char *localdir;
-
- localdir = (char *)xmalloc (1025);
-#if defined (HAVE_GETCWD)
- if (!getcwd (localdir, 1024))
-#else /* !HAVE_GETCWD */
- if (!getwd (localdir))
-#endif /* !HAVE_GETCWD */
- {
- fprintf (stderr, _("%s: getwd: %s, %s\n"),
- progname, filename, localdir);
- exit (1);
- }
-
- strcat (localdir, "/");
- strcat (localdir, filename);
- result = xstrdup (localdir);
- free (localdir);
- }
- else
- {
-#ifndef WIN32
- if (filename[1] == '/')
- {
- /* Return the concatenation of the environment variable HOME
- and the rest of the string. */
- char *temp_home;
-
- temp_home = (char *) getenv ("HOME");
- result = (char *)xmalloc (strlen (&filename[1])
- + 1
- + temp_home ? strlen (temp_home)
- : 0);
- *result = 0;
-
- if (temp_home)
- strcpy (result, temp_home);
-
- strcat (result, &filename[1]);
- }
- else
- {
- struct passwd *user_entry;
- int i, c;
- char *username = (char *)xmalloc (257);
-
- for (i = 1; (c = filename[i]); i++)
- {
- if (c == '/')
- break;
- else
- username[i - 1] = c;
- }
- if (c)
- username[i - 1] = 0;
-
- user_entry = getpwnam (username);
-
- if (!user_entry)
- return (xstrdup (filename));
-
- result = (char *)xmalloc (1 + strlen (user_entry->pw_dir)
- + strlen (&filename[i]));
- strcpy (result, user_entry->pw_dir);
- strcat (result, &filename[i]);
- }
- }
-#endif /* not WIN32 */
- return (result);
-}
-
-char *
-output_name_from_input_name (name)
- char *name;
-{
- return (expand_filename ((char *)NULL, name));
-}
-/* **************************************************************** */
-/* */
-/* Hacking Tokens and Strings */
-/* */
-/* **************************************************************** */
+/* Hacking tokens and strings. */
/* Return the next token as a string pointer. We cons the string. */
char *
@@ -1643,17 +705,17 @@ read_token ()
result = xstrdup (" ");
*result = character;
- return (result);
+ return result;
}
- for (i = 0; ((input_text_offset != size_of_input_text)
+ for (i = 0; ((input_text_offset != input_text_length)
&& (character = curchar ())
&& command_char (character));
i++, input_text_offset++);
- result = (char *)xmalloc (i + 1);
+ result = xmalloc (i + 1);
memcpy (result, &input_text[input_text_offset - i], i);
result[i] = 0;
- return (result);
+ return result;
}
/* Return nonzero if CHARACTER is self-delimiting. */
@@ -1663,7 +725,7 @@ self_delimiting (character)
{
/* @; and @\ are not Texinfo commands, but they are listed here
anyway. I don't know why. --karl, 10aug96. */
- return member (character, "~{|}`^\\@?=;:.-,*\'\" !\n\t");
+ return strchr ("~{|}`^\\@?=;:.-,*\'\" !\n\t", character) != NULL;
}
/* Clear whitespace from the front and end of string. */
@@ -1698,7 +760,7 @@ void
fix_whitespace (string)
char *string;
{
- char *temp = (char *)xmalloc (strlen (string) + 1);
+ char *temp = xmalloc (strlen (string) + 1);
int string_index = 0;
int temp_index = 0;
int c;
@@ -1731,7 +793,7 @@ discard_until (string)
{
int temp = search_forward (string, input_text_offset);
- int tt = (temp < 0) ? size_of_input_text : temp + strlen (string);
+ int tt = (temp < 0) ? input_text_length : temp + strlen (string);
int from = input_text_offset;
/* Find out what line we are on. */
@@ -1741,7 +803,7 @@ discard_until (string)
if (temp < 0)
{
- input_text_offset = size_of_input_text - strlen (string);
+ input_text_offset = input_text_length - strlen (string);
if (strcmp (string, "\n") != 0)
{
@@ -1769,7 +831,7 @@ get_until (match, string)
new_point = search_forward (match, input_text_offset);
if (new_point < 0)
- new_point = size_of_input_text;
+ new_point = input_text_length;
len = new_point - current_point;
/* Keep track of which line number we are at. */
@@ -1778,7 +840,7 @@ get_until (match, string)
if (input_text[x++] == '\n')
line_number++;
- *string = (char *)xmalloc (len + 1);
+ *string = xmalloc (len + 1);
memcpy (*string, &input_text[current_point], len);
(*string)[len] = 0;
@@ -1786,86 +848,144 @@ get_until (match, string)
/* Now leave input_text_offset in a consistent state. */
input_text_offset = tem;
- if (input_text_offset > size_of_input_text)
- input_text_offset = size_of_input_text;
+ if (input_text_offset > input_text_length)
+ input_text_offset = input_text_length;
+
+ return new_point;
+}
+
+/* Replace input_text[FROM .. TO] with its expansion. */
+void
+replace_with_expansion (from, to)
+ int from, *to;
+{
+ char *xp;
+ unsigned xp_len, new_len;
+ char *old_input = input_text;
+ unsigned raw_len = *to - from;
+ char *str;
+
+ /* The rest of the code here moves large buffers, so let's
+ not waste time if the input cannot possibly expand
+ into anything. Unfortunately, we cannot avoid expansion
+ when we see things like @code etc., even if they only
+ asked for expansion of macros, since any Texinfo command
+ can be potentially redefined with a macro. */
+ if (only_macro_expansion &&
+ memchr (input_text + from, COMMAND_PREFIX, raw_len) == 0)
+ return;
- return (new_point);
+ /* Get original string from input. */
+ str = xmalloc (raw_len + 1);
+ memcpy (str, input_text + from, raw_len);
+ str[raw_len] = 0;
+
+ /* We are going to relocate input_text, so we had better output
+ pending portion of input_text now, before the pointer changes. */
+ if (macro_expansion_output_stream && !executing_string
+ && !me_inhibit_expansion)
+ append_to_expansion_output (from);
+
+ /* Expand it. */
+ xp = expansion (str, 0);
+ xp_len = strlen (xp);
+ free (str);
+
+ /* Plunk the expansion into the middle of `input_text' --
+ which is terminated by a newline, not a null. Avoid
+ expensive move of the rest of the input if the expansion
+ has the same length as the original string. */
+ if (xp_len != raw_len)
+ {
+ new_len = from + xp_len + input_text_length - *to + 1;
+ if (executing_string)
+ { /* If we are in execute_string, we might need to update
+ the relevant element in the execution_strings[] array,
+ since it could have to be relocated from under our
+ feet. (input_text is reallocated here as well, if needed.) */
+ maybe_update_execution_strings (&input_text, new_len);
+ }
+ else if (new_len > input_text_length + 1)
+ /* Don't bother to realloc if we have enough space. */
+ input_text = xrealloc (input_text, new_len);
+
+ memmove (input_text + from + xp_len,
+ input_text + *to, input_text_length - *to + 1);
+
+ *to += xp_len - raw_len;
+ /* Since we change input_text_length here, the comparison above
+ isn't really valid, but it seems the worst that might happen is
+ an extra xrealloc or two, so let's not worry. */
+ input_text_length += xp_len - raw_len;
+ }
+ memcpy (input_text + from, xp, xp_len);
+ free (xp);
+
+ /* Synchronize the macro-expansion pointers with our new input_text. */
+ if (input_text != old_input)
+ forget_itext (old_input);
+ if (macro_expansion_output_stream && !executing_string)
+ remember_itext (input_text, from);
}
/* Read characters from the file until we are at MATCH or end of line.
- Place the characters read into STRING. */
+ Place the characters read into STRING. If EXPAND is nonzero,
+ expand the text before looking for MATCH for those cases where
+ MATCH might be produced by some macro. */
void
get_until_in_line (expand, match, string)
int expand;
char *match, **string;
{
- int real_bottom = size_of_input_text;
+ int real_bottom = input_text_length;
int limit = search_forward ("\n", input_text_offset);
if (limit < 0)
- limit = size_of_input_text;
+ limit = input_text_length;
- /* Replace input_text[input_text_offset .. limit-1] with its macro
- expansion (actually, we expand all commands). This allows the node
- names themselves to be constructed via a macro, as in:
+ /* Replace input_text[input_text_offset .. limit-1] with its expansion.
+ This allows the node names and menu entries themselves to be
+ constructed via a macro, as in:
@macro foo{p, q}
Together: \p\ & \q\.
@end macro
@node @foo{A,B}, next, prev, top
-
+
Otherwise, the `,' separating the macro args A and B is taken as
the node argument separator, so the node name is `@foo{A'. This
expansion is only necessary on the first call, since we expand the
- whole line then.
-
- Furthermore, if we're executing a string, don't do it -- we'll end
- up shrinking the execution string which is currently aliased to
- `input_text', so it might get moved, and not updated in the
- `execution_strings' array. This happens when processing the
- (synthetic) Overview-Footnotes node in the Texinfo manual. */
-
- if (expand && !executing_string && !me_executing_string)
+ whole line then. */
+ if (expand)
{
- char *xp;
- unsigned xp_len, new_len;
-
- /* Get original string from input. */
- unsigned raw_len = limit - input_text_offset;
- char *str = xmalloc (raw_len + 1);
- strncpy (str, input_text + input_text_offset, raw_len);
- str[raw_len] = 0;
-
- /* Expand it. */
- xp = expansion (str, 0);
- xp_len = strlen (xp);
- free (str);
-
- /* Plunk the expansion into the middle of `input_text' --
- which is terminated by a newline, not a null. */
- str = xmalloc (real_bottom - limit + 1);
- strncpy (str, input_text + limit, real_bottom - limit + 1);
- new_len = input_text_offset + xp_len + real_bottom - limit + 1;
- input_text = xrealloc (input_text, new_len);
- strcpy (input_text + input_text_offset, xp);
- strncpy (input_text + input_text_offset + xp_len, str,
- real_bottom - limit + 1);
- free (str);
- free (xp);
-
- limit += xp_len - raw_len;
- real_bottom += xp_len - raw_len;
+ replace_with_expansion (input_text_offset, &limit);
}
- size_of_input_text = limit;
+ real_bottom = input_text_length;
+ input_text_length = limit;
get_until (match, string);
- size_of_input_text = real_bottom;
+ input_text_length = real_bottom;
}
void
-get_rest_of_line (string)
+get_rest_of_line (expand, string)
+ int expand;
char **string;
{
- get_until ("\n", string);
+ if (expand)
+ {
+ char *tem;
+
+ /* Don't expand non-macros in input, since we want them
+ intact in the macro-expanded output. */
+ only_macro_expansion++;
+ get_until_in_line (1, "\n", &tem);
+ only_macro_expansion--;
+ *string = expansion (tem, 0);
+ free (tem);
+ }
+ else
+ get_until_in_line (0, "\n", string);
+
canon_white (*string);
if (curchar () == '\n') /* as opposed to the end of the file... */
@@ -1898,7 +1018,7 @@ get_until_in_braces (match, string)
int i, brace = 0;
int match_len = strlen (match);
- for (i = input_text_offset; i < size_of_input_text; i++)
+ for (i = input_text_offset; i < input_text_length; i++)
{
if (input_text[i] == '{')
brace++;
@@ -1913,27 +1033,27 @@ get_until_in_braces (match, string)
}
match_len = i - input_text_offset;
- temp = (char *)xmalloc (2 + match_len);
- strncpy (temp, input_text + input_text_offset, match_len);
+ temp = xmalloc (2 + match_len);
+ memcpy (temp, input_text + input_text_offset, match_len);
temp[match_len] = 0;
input_text_offset = i;
*string = temp;
}
-/* **************************************************************** */
-/* */
-/* Converting the File */
-/* */
-/* **************************************************************** */
+/* Converting a file. */
/* Convert the file named by NAME. The output is saved on the file
named as the argument to the @setfilename command. */
static char *suffixes[] = {
+ /* ".txi" is checked first so that on 8+3 DOS filesystems, if they
+ have "texinfo.txi" and "texinfo.tex" in the same directory, the
+ former is used rather than the latter, due to file name truncation. */
+ ".txi",
".texinfo",
".texi",
".txinfo",
"",
- (char *)NULL
+ NULL
};
void
@@ -1951,6 +1071,30 @@ initialize_conversion ()
output_position = 0;
}
+typedef struct generic_list {
+ struct generic_list *next;
+} GENERIC_LIST;
+
+/* Reverse the chain of structures in LIST. Output the new head
+ of the chain. You should always assign the output value of this
+ function to something, or you will lose the chain. */
+GENERIC_LIST *
+reverse_list (list)
+ GENERIC_LIST *list;
+{
+ GENERIC_LIST *next;
+ GENERIC_LIST *prev = NULL;
+
+ while (list)
+ {
+ next = list->next;
+ list->next = prev;
+ prev = list;
+ list = next;
+ }
+ return prev;
+}
+
/* We read in multiples of 4k, simply because it is a typical pipe size
on unix systems. */
#define READ_BUFFER_GROWTH (4 * 4096)
@@ -1962,7 +1106,7 @@ convert_from_stream (stream, name)
FILE *stream;
char *name;
{
- char *buffer = (char *)NULL;
+ char *buffer = NULL;
int buffer_offset = 0, buffer_size = 0;
initialize_conversion ();
@@ -1983,7 +1127,7 @@ convert_from_stream (stream, name)
if (count < 0)
{
perror (name);
- exit (FATAL);
+ xexit (1);
}
buffer_offset += count;
@@ -1993,7 +1137,7 @@ convert_from_stream (stream, name)
/* Set the globals to the new file. */
input_text = buffer;
- size_of_input_text = buffer_offset;
+ input_text_length = buffer_offset;
input_filename = xstrdup (name);
node_filename = xstrdup (name);
input_text_offset = 0;
@@ -2001,8 +1145,8 @@ convert_from_stream (stream, name)
/* Not strictly necessary. This magic prevents read_token () from doing
extra unnecessary work each time it is called (that is a lot of times).
- The SIZE_OF_INPUT_TEXT is one past the actual end of the text. */
- input_text[size_of_input_text] = '\n';
+ The INPUT_TEXT_LENGTH is one past the actual end of the text. */
+ input_text[input_text_length] = '\n';
convert_from_loaded_file (name);
}
@@ -2011,8 +1155,8 @@ void
convert_from_file (name)
char *name;
{
- register int i;
- char *filename = (char *)xmalloc (strlen (name) + 50);
+ int i;
+ char *filename = xmalloc (strlen (name) + 50);
initialize_conversion ();
@@ -2046,29 +1190,32 @@ convert_from_file (name)
convert_from_loaded_file (name);
}
-
+
void
convert_from_loaded_file (name)
char *name;
{
- char *expand_filename (), *filename_part ();
- char *real_output_filename = (char *)NULL;
+ char *real_output_filename = NULL;
-#if defined (HAVE_MACROS)
remember_itext (input_text, 0);
-#endif /* HAVE_MACROS */
+
+ input_text_offset = 0;
+
+ /* Avoid the `\input texinfo' line in HTML output (assuming it starts
+ the file). */
+ if (looking_at ("\\input"))
+ discard_until ("\n");
/* Search this file looking for the special string which starts conversion.
Once found, we may truly begin. */
- input_text_offset = 0;
while (input_text_offset >= 0)
{
input_text_offset =
search_forward (setfilename_search, input_text_offset);
- if ((input_text_offset == 0) ||
- ((input_text_offset > 0) &&
- (input_text[input_text_offset -1] == '\n')))
+ if (input_text_offset == 0
+ || (input_text_offset > 0
+ && input_text[input_text_offset -1] == '\n'))
break;
else if (input_text_offset > 0)
input_text_offset++;
@@ -2082,35 +1229,62 @@ convert_from_loaded_file (name)
error (_("No `%s' found in `%s'"), setfilename_search, name);
goto finished;
#else
- register int i, end_of_first_line;
-
- /* Find the end of the first line in the file. */
- for (i = 0; i < size_of_input_text - 1; i++)
- if (input_text[i] == '\n')
- break;
-
- end_of_first_line = i + 1;
-
- input_text_offset = 0;
-
- for (i = 0; i < end_of_first_line; i++)
- {
- if ((input_text[i] == '\\') &&
- (strncmp (input_text + i + 1, "include", 7) == 0))
- {
- input_text_offset = end_of_first_line;
- break;
- }
- }
command_output_filename = output_name_from_input_name (name);
#endif /* !REQUIRE_SETFILENAME */
}
+
+ {
+ int i, end_of_first_line;
+
+ /* Find the end of the first line in the file. */
+ for (i = 0; i < input_text_length - 1; i++)
+ if (input_text[i] == '\n')
+ break;
+
+ end_of_first_line = i + 1;
+
+ for (i = 0; i < end_of_first_line; i++)
+ {
+ if ((input_text[i] == '\\') &&
+ (strncmp (input_text + i + 1, "input", 5) == 0))
+ {
+ input_text_offset = i;
+ break;
+ }
+ }
+ }
}
else
input_text_offset += strlen (setfilename_search);
if (!command_output_filename)
- get_until ("\n", &output_filename);
+ {
+ get_until ("\n", &output_filename); /* read rest of line */
+ if (html)
+ { /* Change any extension to .html. */
+ char *html_name, *directory_part, *basename_part, *temp;
+
+ canon_white (output_filename);
+ directory_part = pathname_part (output_filename);
+ basename_part = filename_part (output_filename);
+
+ /* Zap any existing extension. */
+ temp = strrchr (basename_part, '.');
+ if (temp)
+ *temp = 0;
+
+ /* Construct new filename. */
+ html_name = xmalloc (strlen (directory_part)
+ + strlen (basename_part) + 6);
+ strcpy (html_name, directory_part);
+ strcat (html_name, basename_part);
+ strcat (html_name, ".html");
+
+ /* Replace name from @setfilename with the html name. */
+ free (output_filename);
+ output_filename = html_name;
+ }
+ }
else
{
if (input_text_offset != -1)
@@ -2119,7 +1293,7 @@ convert_from_loaded_file (name)
input_text_offset = 0;
real_output_filename = output_filename = command_output_filename;
- command_output_filename = (char *)NULL;
+ command_output_filename = NULL;
}
canon_white (output_filename);
@@ -2147,9 +1321,12 @@ convert_from_loaded_file (name)
output_stream = fopen (real_output_filename, "w");
}
- if (output_stream != stdout)
+ set_current_output_filename (real_output_filename);
+
+ if (verbose_mode)
printf (_("Making %s file `%s' from `%s'.\n"),
- no_headers ? "text" : "info", output_filename, input_filename);
+ no_headers ? "text" : (html ? "HTML" : "info"),
+ output_filename, input_filename);
if (output_stream == NULL)
{
@@ -2176,12 +1353,10 @@ convert_from_loaded_file (name)
line_number++;
}
- if (!no_headers)
- {
- add_word_args (_("This is Info file %s, produced by Makeinfo version %d.%d"),
- output_filename, major_version, minor_version);
- add_word_args (_(" from the input file %s.\n"), input_filename);
- }
+ /* html fixxme: should output this as trailer on first page. */
+ if (!no_headers && !html)
+ add_word_args (_("This is %s, produced by makeinfo version %s from %s.\n"),
+ output_filename, VERSION, input_filename);
close_paragraph ();
reader_loop ();
@@ -2191,13 +1366,13 @@ finished:
close_paragraph ();
flush_file_stack ();
-#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
{
fclose (macro_expansion_output_stream);
if (errors_printed && !force
&& strcmp (macro_expansion_filename, "-") != 0
- && strcmp (macro_expansion_filename, "/dev/null") != 0)
+ && FILENAME_CMP (macro_expansion_filename, NULL_DEVICE) != 0
+ && FILENAME_CMP (macro_expansion_filename, ALSO_NULL_DEVICE) != 0)
{
fprintf (stderr, _("%s: Removing macro output file `%s' due to errors; use --force to preserve.\n"),
progname, macro_expansion_filename);
@@ -2205,19 +1380,24 @@ finished:
perror (macro_expansion_filename);
}
}
-#endif /* HAVE_MACROS */
if (output_stream)
{
output_pending_notes ();
- free_pending_notes ();
- if (tag_table != NULL)
+ if (tag_table)
{
tag_table = (TAG_ENTRY *) reverse_list (tag_table);
- if (!no_headers)
+ if (!no_headers && !html)
write_tag_table ();
}
+ if (html)
+ {
+ start_paragraph ();
+ add_word ("</body></html>\n");
+ close_paragraph ();
+ }
+
if (output_stream != stdout)
fclose (output_stream);
@@ -2225,11 +1405,17 @@ finished:
if (validating)
validate_file (tag_table);
- if (splitting && (!errors_printed || force))
+ /* If we need to output the table of contents, do it now. */
+ if (contents_filename || shortcontents_filename)
+ toc_update ();
+
+ if (splitting && !html && (!errors_printed || force))
split_file (real_output_filename, 0);
- else if (errors_printed && !force
+ else if (errors_printed
+ && !force
&& strcmp (real_output_filename, "-") != 0
- && strcmp (real_output_filename, "/dev/null") != 0)
+ && FILENAME_CMP (real_output_filename, NULL_DEVICE) != 0
+ && FILENAME_CMP (real_output_filename, ALSO_NULL_DEVICE) != 0)
{ /* If there were errors, and no --force, remove the output. */
fprintf (stderr, _("%s: Removing output file `%s' due to errors; use --force to preserve.\n"),
progname, real_output_filename);
@@ -2247,7 +1433,7 @@ free_and_clear (pointer)
if (*pointer)
{
free (*pointer);
- *pointer = (char *) NULL;
+ *pointer = NULL;
}
}
@@ -2259,6 +1445,8 @@ init_internals ()
free_and_clear (&command);
free_and_clear (&input_filename);
free_node_references ();
+ free_node_node_references ();
+ toc_free ();
init_insertion_stack ();
init_brace_stack ();
current_node = NULL; /* sometimes already freed */
@@ -2267,171 +1455,140 @@ init_internals ()
in_detailmenu = 0;
top_node_seen = 0;
non_top_node_seen = 0;
+ node_number = -1;
}
void
init_paragraph ()
{
free_and_clear (&output_paragraph);
- output_paragraph = (unsigned char *)xmalloc (paragraph_buffer_len);
+ output_paragraph = xmalloc (paragraph_buffer_len);
output_paragraph[0] = 0;
output_paragraph_offset = 0;
output_column = 0;
paragraph_is_open = 0;
current_indent = 0;
+ meta_char_pos = 0;
}
+
+/* This is called from `reader_loop' when we are at the * beginning a
+ menu line. */
-/* Okay, we are ready to start the conversion. Call the reader on
- some text, and fill the text as it is output. Handle commands by
- remembering things like open braces and the current file position on a
- stack, and when the corresponding close brace is found, you can call
- the function with the proper arguments. */
-void
-reader_loop ()
+static void
+handle_menu_entry ()
{
- int character;
- int done = 0;
- int dash_count = 0;
+ char *tem;
+
+ /* Ugh, glean_node_from_menu wants to read the * itself. */
+ input_text_offset--;
+
+ /* Find node name in menu entry and save it in references list for
+ later validation. Use followed_reference type for detailmenu
+ references since we don't want to use them for default node pointers. */
+ tem = glean_node_from_menu (1, in_detailmenu
+ ? followed_reference : menu_reference);
- while (!done)
- {
- if (input_text_offset >= size_of_input_text)
- break;
+ if (html && tem)
+ { /* Start a menu item with the cleaned-up line. Put an anchor
+ around the start text (before `:' or the node name). */
+ char *string;
- character = curchar ();
+ discard_until ("* ");
- if (!in_fixed_width_font &&
- (character == '\'' || character == '`') &&
- input_text[input_text_offset + 1] == character)
- {
- input_text_offset++;
- character = '"';
- }
+ /* The line number was already incremented in reader_loop when we
+ saw the newline, and discard_until has now incremented again. */
+ line_number--;
- if (character == '-')
- {
- dash_count++;
- if (dash_count == 2 && !in_fixed_width_font)
- {
- input_text_offset++;
- continue;
- }
- }
- else
+ if (had_menu_commentary)
{
- dash_count = 0;
+ add_word ("<ul>\n");
+ had_menu_commentary = 0;
+ in_paragraph = 0;
}
-
- /* If this is a whitespace character, then check to see if the line
- is blank. If so, advance to the carriage return. */
- if (whitespace (character))
+ else if (!in_paragraph && !paragraph_is_open)
{
- register int i = input_text_offset + 1;
-
- while (i < size_of_input_text && whitespace (input_text[i]))
- i++;
-
- if (i == size_of_input_text || input_text[i] == '\n')
- {
- if (i == size_of_input_text)
- i--;
-
- input_text_offset = i;
- character = curchar ();
- }
+ add_word ("<p>\n");
+ in_paragraph = 1;
}
-
- if (character == '\n')
+
+ if (in_paragraph)
{
- line_number++;
-
- /* Check for a menu entry here, since the "escape sequence"
- that begins menu entries is "\n* ". */
- if (in_menu && input_text_offset + 1 < size_of_input_text)
- {
- char *glean_node_from_menu (), *tem;
-
- /* Note that the value of TEM is discarded, since it is
- gauranteed to be NULL when glean_node_from_menu () is
- called with a Nonzero argument. */
- if (!in_detailmenu)
- tem = glean_node_from_menu (1);
- }
+ add_word ("</p>");
+ in_paragraph = 0;
}
- switch (character)
- {
- case COMMAND_PREFIX:
- read_command ();
- break;
-
- case '{':
- /* Special case. I'm not supposed to see this character by itself.
- If I do, it means there is a syntax error in the input text.
- Report the error here, but remember this brace on the stack so
- you can ignore its partner. */
+ add_word ("<li><a href=\"");
+ string = expansion (tem, 0);
+ add_anchor_name (string, 1);
+ add_word ("\">");
+ free (string);
- line_error (_("Misplaced %c"), '{');
- remember_brace (misplaced_brace);
+ /* The menu item may use macros, so expand them now. */
+ only_macro_expansion++;
+ get_until_in_line (1, ":", &string);
+ only_macro_expansion--;
+ execute_string ("%s", string); /* get escaping done */
+ free (string);
- /* Don't advance input_text_offset since this happens in
- remember_brace ().
- input_text_offset++;
- */
- break;
+ add_word ("</a>");
- case '}':
- pop_and_call_brace ();
- input_text_offset++;
- break;
-
- default:
- add_char (character);
- input_text_offset++;
+ if (looking_at ("::"))
+ discard_until (":");
+ else
+ { /* discard the node name */
+ get_until_in_line (0, ".", &string);
+ free (string);
}
+ input_text_offset++; /* discard the second colon or the period */
+ add_word (": ");
+ }
+ else if (tem)
+ { /* For Info output, we can just use the input and the main case in
+ reader_loop where we output what comes in. Just move off the *
+ so the next time through reader_loop we don't end up back here. */
+ add_char ('*');
+ input_text_offset += 2; /* undo the pointer back-up above. */
}
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream)
- maybe_write_itext (input_text, input_text_offset);
-#endif /* HAVE_MACROS */
-}
-/* Find the command corresponding to STRING. If the command
- is found, return a pointer to the data structure. Otherwise
- return (-1). */
-COMMAND *
+ if (tem)
+ free (tem);
+}
+
+/* Find the command corresponding to STRING. If the command is found,
+ return a pointer to the data structure. Otherwise return -1. */
+static COMMAND *
get_command_entry (string)
char *string;
{
- register int i;
+ int i;
for (i = 0; command_table[i].name; i++)
if (strcmp (command_table[i].name, string) == 0)
- return (&command_table[i]);
+ return &command_table[i];
/* This command is not in our predefined command table. Perhaps
it is a user defined command. */
for (i = 0; i < user_command_array_len; i++)
if (user_command_array[i] &&
(strcmp (user_command_array[i]->name, string) == 0))
- return (user_command_array[i]);
+ return user_command_array[i];
/* We never heard of this command. */
- return ((COMMAND *) -1);
+ return (COMMAND *) -1;
}
-
+
/* input_text_offset is right at the command prefix character.
- Read the next token to determine what to do. */
-void
+ Read the next token to determine what to do. Return zero
+ if there's no known command or macro after the prefix character. */
+static int
read_command ()
{
COMMAND *entry;
+ int old_text_offset = input_text_offset++;
- input_text_offset++;
free_and_clear (&command);
command = read_token ();
-#if defined (HAVE_MACROS)
/* Check to see if this command is a macro. If so, execute it here. */
{
MACRO_DEF *def;
@@ -2450,41 +1607,227 @@ read_command ()
if (!(def->flags & ME_RECURSE))
def->inhibited = 0;
- return;
+ return 1;
}
}
-#endif /* HAVE_MACROS */
+
+ if (only_macro_expansion)
+ {
+ /* Back up to the place where we were called, so the
+ caller will have a chance to process this non-macro. */
+ input_text_offset = old_text_offset;
+ return 0;
+ }
+
+ /* Perform alias expansion */
+ command = alias_expand (command);
+
+ if (enclosure_command (command))
+ {
+ remember_brace (enclosure_expand);
+ enclosure_expand (START, output_paragraph_offset, 0);
+ return 0;
+ }
entry = get_command_entry (command);
if (entry == (COMMAND *)-1)
{
line_error (_("Unknown command `%s'"), command);
- return;
+ return 0;
}
- if (entry->argument_in_braces)
+ if (entry->argument_in_braces == BRACE_ARGS)
remember_brace (entry->proc);
+ else if (entry->argument_in_braces == MAYBE_BRACE_ARGS)
+ {
+ if (curchar () == '{')
+ remember_brace (entry->proc);
+ else
+ { /* No braces, so arg is next char. */
+ int ch;
+ int saved_offset = output_paragraph_offset;
+ (*(entry->proc)) (START, output_paragraph_offset, 0);
+
+ /* Possibilities left for the next character: @ (error), }
+ (error), whitespace (skip) anything else (normal char). */
+ skip_whitespace ();
+ ch = curchar ();
+ if (ch == '@')
+ {
+ line_error (_("Use braces to give a command as an argument to @%s"),
+ entry->name);
+ return 0;
+ }
+ else if (ch == '}')
+ {
+ /* Our caller will give the error message, because this }
+ won't match anything. */
+ return 0;
+ }
+ add_char (ch);
+ input_text_offset++;
+ (*(entry->proc)) (END, saved_offset, output_paragraph_offset);
+ return 1;
+ }
+ }
+
+ /* Get here if we have BRACE_ARGS, NO_BRACE_ARGS, or MAYBE_BRACE_ARGS
+ with braces. */
(*(entry->proc)) (START, output_paragraph_offset, 0);
+ return 1;
}
-/* Return the string which invokes PROC; a pointer to a function. */
-char *
-find_proc_name (proc)
- COMMAND_FUNCTION *proc;
+/* Okay, we are ready to start the conversion. Call the reader on
+ some text, and fill the text as it is output. Handle commands by
+ remembering things like open braces and the current file position on a
+ stack, and when the corresponding close brace is found, you can call
+ the function with the proper arguments. Although the filling isn't
+ necessary for HTML, it should do no harm. */
+void
+reader_loop ()
{
- register int i;
+ int character;
+ int done = 0;
+ int dash_count = 0;
- for (i = 0; command_table[i].name; i++)
- if (proc == command_table[i].proc)
- return command_table[i].name;
- return _("NO_NAME!");
-}
+ while (!done)
+ {
+ if (input_text_offset >= input_text_length)
+ break;
+
+ character = curchar ();
+
+ /* If only_macro_expansion, only handle macros and leave
+ everything else intact. */
+ if (!only_macro_expansion && !in_fixed_width_font
+ && (character == '\'' || character == '`')
+ && input_text[input_text_offset + 1] == character)
+ {
+ input_text_offset++;
+ character = '"'; /* html fixxme */
+ }
+
+ /* Convert --- to --. */
+ if (!only_macro_expansion && character == '-')
+ {
+ dash_count++;
+ if (dash_count == 2 && !in_fixed_width_font)
+ {
+ input_text_offset++;
+ continue;
+ }
+ }
+ else if (dash_count > 0)
+ dash_count = 0;
+
+ /* If this is a whitespace character, then check to see if the line
+ is blank. If so, advance to the carriage return. */
+ if (!only_macro_expansion && whitespace (character))
+ {
+ int i = input_text_offset + 1;
+
+ while (i < input_text_length && whitespace (input_text[i]))
+ i++;
+
+ if (i == input_text_length || input_text[i] == '\n')
+ {
+ if (i == input_text_length)
+ i--;
+
+ input_text_offset = i;
+ character = curchar ();
+ }
+ }
+
+ if (character == '\n')
+ line_number++;
+
+ switch (character)
+ {
+ case '*': /* perhaps we are at a menu */
+ /* We used to check for this in the \n case but an @c in a
+ menu swallows its newline, so check here instead. */
+ if (!only_macro_expansion && in_menu
+ && input_text_offset + 1 < input_text_length
+ && input_text[input_text_offset-1] == '\n')
+ handle_menu_entry ();
+ else
+ { /* Duplicate code from below, but not worth twisting the
+ fallthroughs to get down there. */
+ add_char (character);
+ input_text_offset++;
+ }
+ break;
+
+ /* Escapes for HTML unless we're outputting raw HTML. Do
+ this always, even if SGML rules don't require it since
+ that's easier and safer for non-conforming browsers. */
+ case '&':
+ if (html && escape_html)
+ add_word ("&amp;");
+ else
+ add_char (character);
+ input_text_offset++;
+ break;
+
+ case '<':
+ if (html && escape_html)
+ add_word ("&lt;");
+ else
+ add_char (character);
+ input_text_offset++;
+ break;
+
+ case '>':
+ if (html && escape_html)
+ add_word ("&gt;");
+ else
+ add_char (character);
+ input_text_offset++;
+ break;
+ case COMMAND_PREFIX: /* @ */
+ if (read_command () || !only_macro_expansion)
+ break;
+
+ /* FALLTHROUGH (usually) */
+ case '{':
+ /* Special case. We're not supposed to see this character by itself.
+ If we do, it means there is a syntax error in the input text.
+ Report the error here, but remember this brace on the stack so
+ we can ignore its partner. */
+ if (!only_macro_expansion)
+ {
+ line_error (_("Misplaced %c"), '{');
+ remember_brace (misplaced_brace);
+ /* remember_brace advances input_text_offset. */
+ break;
+ }
+
+ /* FALLTHROUGH (usually) */
+ case '}':
+ if (!only_macro_expansion)
+ {
+ pop_and_call_brace ();
+ input_text_offset++;
+ break;
+ }
+
+ /* FALLTHROUGH (usually) */
+ default:
+ add_char (character);
+ input_text_offset++;
+ }
+ }
+ if (macro_expansion_output_stream && !only_macro_expansion)
+ maybe_write_itext (input_text, input_text_offset);
+}
+
void
init_brace_stack ()
{
- brace_stack = (BRACE_ELEMENT *) NULL;
+ brace_stack = NULL;
}
void
@@ -2505,9 +1848,10 @@ remember_brace_1 (proc, position)
COMMAND_FUNCTION *proc;
int position;
{
- BRACE_ELEMENT *new = (BRACE_ELEMENT *) xmalloc (sizeof (BRACE_ELEMENT));
+ BRACE_ELEMENT *new = xmalloc (sizeof (BRACE_ELEMENT));
new->next = brace_stack;
new->proc = proc;
+ new->command = xstrdup (command);
new->pos = position;
new->line = line_number;
new->in_fixed_width_font = in_fixed_width_font;
@@ -2519,24 +1863,29 @@ remember_brace_1 (proc, position)
void
pop_and_call_brace ()
{
- BRACE_ELEMENT *temp;
- COMMAND_FUNCTION *proc;
- int pos;
-
- if (brace_stack == (BRACE_ELEMENT *) NULL)
+ if (brace_stack == NULL)
{
line_error (_("Unmatched }"));
return;
}
- pos = brace_stack->pos;
- proc = brace_stack->proc;
- in_fixed_width_font = brace_stack->in_fixed_width_font;
- temp = brace_stack->next;
- free (brace_stack);
- brace_stack = temp;
+ {
+ BRACE_ELEMENT *temp;
+
+ int pos = brace_stack->pos;
+ COMMAND_FUNCTION *proc = brace_stack->proc;
+ in_fixed_width_font = brace_stack->in_fixed_width_font;
+
+ /* Reset current command, so the proc can know who it is. This is
+ used in cm_accent. */
+ command = brace_stack->command;
- (*proc) (END, pos, output_paragraph_offset);
+ temp = brace_stack->next;
+ free (brace_stack);
+ brace_stack = temp;
+
+ (*proc) (END, pos, output_paragraph_offset);
+ }
}
/* Shift all of the markers in `brace_stack' by AMOUNT. */
@@ -2544,7 +1893,7 @@ void
adjust_braces_following (here, amount)
int here, amount;
{
- register BRACE_ELEMENT *stack = brace_stack;
+ BRACE_ELEMENT *stack = brace_stack;
while (stack)
{
@@ -2554,6 +1903,21 @@ adjust_braces_following (here, amount)
}
}
+/* Return the string which invokes PROC; a pointer to a function.
+ Always returns the first function in the command table if more than
+ one matches PROC. */
+static char *
+find_proc_name (proc)
+ COMMAND_FUNCTION *proc;
+{
+ int i;
+
+ for (i = 0; command_table[i].name; i++)
+ if (proc == command_table[i].proc)
+ return command_table[i].name;
+ return _("NO_NAME!");
+}
+
/* You call discard_braces () when you shouldn't have any braces on the stack.
I used to think that this happens for commands that don't take arguments
in braces, but that was wrong because of things like @code{foo @@}. So now
@@ -2618,9 +1982,9 @@ get_char_len (character)
else
len = 1;
}
- return (len);
+ return len;
}
-
+
void
#if defined (VA_FPRINTF) && __STDC__
add_word_args (char *format, ...)
@@ -2630,7 +1994,7 @@ add_word_args (format, va_alist)
va_dcl
#endif
{
- char buffer[1000];
+ char buffer[2000]; /* xx no fixed limits */
#ifdef VA_FPRINTF
va_list ap;
#endif
@@ -2639,7 +2003,7 @@ add_word_args (format, va_alist)
#ifdef VA_SPRINTF
VA_SPRINTF (buffer, format, ap);
#else
- sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8);
+ sprintf (buffer, format, a1, a2, a3, a4, a5, a6, a7, a8);
#endif /* not VA_SPRINTF */
va_end (ap);
add_word (buffer);
@@ -2654,24 +2018,6 @@ add_word (string)
add_char (*string++);
}
-/* Nonzero if the last character inserted has the syntax class of NEWLINE. */
-int last_char_was_newline = 1;
-
-/* The actual last inserted character. Note that this may be something
- other than NEWLINE even if last_char_was_newline is 1. */
-int last_inserted_character = 0;
-
-/* Nonzero means that a newline character has already been
- inserted, so close_paragraph () should insert one less. */
-int line_already_broken = 0;
-
-/* When nonzero we have finished an insertion (see `end_insertion') and we
- want to ignore false continued paragraph closings. */
-int insertion_paragraph_closed = 0;
-
-/* Nonzero means attempt to make all of the lines have fill_column width. */
-int do_justification = 0;
-
/* Add the character to the current paragraph. If filling_enabled is
nonzero, then do filling as well. */
void
@@ -2679,8 +2025,10 @@ add_char (character)
int character;
{
/* If we are avoiding outputting headers, and we are currently
- in a menu, then simply return. */
- if (no_headers && (in_menu || in_detailmenu))
+ in a menu, then simply return. But if we're only expanding macros,
+ then we're being called from glean_node_from_menu to try to
+ remember a menu reference, and we need that so we can do defaulting. */
+ if (no_headers && !only_macro_expansion && (in_menu || in_detailmenu))
return;
/* If we are adding a character now, then we don't have to
@@ -2696,15 +2044,23 @@ add_char (character)
}
}
- if (non_splitting_words && member (character, " \t\n"))
- character = ' ' | 0x80;
+ if (non_splitting_words && strchr (" \t\n", character))
+ {
+ if (html)
+ { /* Seems cleaner to use &nbsp; than an 8-bit char. */
+ add_word ("&nbsp");
+ character = ';';
+ }
+ else
+ character = META (' '); /* unmeta-d in flush_output */
+ }
insertion_paragraph_closed = 0;
switch (character)
{
case '\n':
- if (!filling_enabled)
+ if (!filling_enabled && ! (html && (in_menu || in_detailmenu)))
{
insert ('\n');
@@ -2721,30 +2077,33 @@ add_char (character)
indent (output_column = current_indent);
break;
}
- else /* CHARACTER is newline, and filling is enabled. */
+ else if (end_of_sentence_p ())
+ /* CHARACTER is newline, and filling is enabled. */
{
- if (end_of_sentence_p ())
- {
- insert (' ');
- output_column++;
- last_inserted_character = character;
- }
+ insert (' ');
+ output_column++;
+ last_inserted_character = character;
}
if (last_char_was_newline)
{
+ if (html)
+ last_char_was_newline++;
close_paragraph ();
pending_indent = 0;
}
else
{
last_char_was_newline = 1;
- insert (' ');
+ if (html)
+ insert ('\n');
+ else
+ insert (' ');
output_column++;
}
break;
- default:
+ default: /* not at newline */
{
int len = get_char_len (character);
int suppress_insert = 0;
@@ -2761,18 +2120,29 @@ add_char (character)
if (!paragraph_is_open)
{
start_paragraph ();
-
- /* If the paragraph is supposed to be indented a certain way,
- then discard all of the pending whitespace. Otherwise, we
- let the whitespace stay. */
+ /* If the paragraph is supposed to be indented a certain
+ way, then discard all of the pending whitespace.
+ Otherwise, we let the whitespace stay. */
if (!paragraph_start_indent)
indent (pending_indent);
pending_indent = 0;
+
+ /* This horrible kludge of checking for a < prevents <p>
+ from being inserted when we already have html markup
+ starting a paragraph, as with <ul> and <h1> and the like. */
+ if (html && escape_html && character != '<'
+ && (!in_fixed_width_font || in_menu || in_detailmenu))
+ {
+ insert_string ("<p>");
+ in_paragraph = 1;
+ adjust_braces_following (0, 3); /* adjust for <p> */
+ }
}
- if ((output_column += len) > fill_column)
+ output_column += len;
+ if (output_column > fill_column)
{
- if (filling_enabled)
+ if (filling_enabled && !html)
{
int temp = output_paragraph_offset;
while (--temp > 0 && output_paragraph[temp] != '\n')
@@ -2785,7 +2155,15 @@ add_char (character)
while (temp && whitespace (output_paragraph[temp - 1]))
temp--;
- output_paragraph[temp++] = '\n';
+ /* If we went back all the way to the newline of the
+ preceding line, it probably means that the word we
+ are adding is itself wider than the space that the
+ indentation and the fill_column let us use. In
+ that case, do NOT insert another newline, since it
+ won't help. Just indent to current_indent and
+ leave it alone, since that's the most we can do. */
+ if (temp && output_paragraph[temp - 1] != '\n')
+ output_paragraph[temp++] = '\n';
/* We have correctly broken the line where we want
to. What we don't want is spaces following where
@@ -2817,11 +2195,11 @@ add_char (character)
}
/* Filled, but now indent if that is right. */
- if (indented_fill && current_indent)
+ if (indented_fill && current_indent > 0)
{
int buffer_len = ((output_paragraph_offset - temp)
+ current_indent);
- char *temp_buffer = (char *)xmalloc (buffer_len);
+ char *temp_buffer = xmalloc (buffer_len);
int indentation = 0;
/* We have to shift any markers that are in
@@ -2832,7 +2210,7 @@ add_char (character)
indentation != current_indent)
temp_buffer[indentation++] = ' ';
- strncpy ((char *) &temp_buffer[current_indent],
+ memcpy ((char *) &temp_buffer[current_indent],
(char *) &output_paragraph[temp],
buffer_len - current_indent);
@@ -2844,7 +2222,7 @@ add_char (character)
(paragraph_buffer_len += buffer_len));
output_paragraph = tt;
}
- strncpy ((char *) &output_paragraph[temp],
+ memcpy ((char *) &output_paragraph[temp],
temp_buffer, buffer_len);
output_paragraph_offset += current_indent;
free (temp_buffer);
@@ -2871,11 +2249,27 @@ add_char (character)
}
}
+/* Add a character and store its position in meta_char_pos. */
+void
+add_meta_char (character)
+ int character;
+{
+ meta_char_pos = output_paragraph_offset;
+ add_char (character);
+}
+
/* Insert CHARACTER into `output_paragraph'. */
void
insert (character)
int character;
{
+ /* This is sad, but it seems desirable to not force any particular
+ order on the front matter commands. This way, the document can do
+ @settitle, @documentlanguage, etc, in any order and with any
+ omissions, and we'll still output the html <head> `just in time'. */
+ if (!executing_string && html && !html_output_head_p)
+ html_output_head ();
+
output_paragraph[output_paragraph_offset++] = character;
if (output_paragraph_offset == paragraph_buffer_len)
{
@@ -2895,7 +2289,7 @@ insert_string (string)
/* Sentences might have these characters after the period (or whatever). */
-#define post_sentence(c) ((c) == ')' || (c) == '\'' || (c) == '"' \
+#define POST_SENTENCE(c) ((c) == ')' || (c) == '\'' || (c) == '"' \
|| (c) == ']')
/* Return true if at an end-of-sentence character, possibly followed by
@@ -2904,9 +2298,19 @@ static int
end_of_sentence_p ()
{
int loc = output_paragraph_offset - 1;
- while (loc > 0 && post_sentence (output_paragraph[loc]))
+
+ /* If nothing has been output, don't check output_paragraph[-1]. */
+ if (loc < 0)
+ return 0;
+
+ /* A post-sentence character that is at meta_char_pos is not really
+ a post-sentence character; it was produced by a markup such as
+ @samp. We don't want the period inside @samp to be treated as a
+ sentence ender. */
+ while (loc > 0
+ && loc != meta_char_pos && POST_SENTENCE (output_paragraph[loc]))
loc--;
- return sentence_ender (output_paragraph[loc]);
+ return loc != meta_char_pos && sentence_ender (output_paragraph[loc]);
}
@@ -2959,16 +2363,19 @@ uninhibit_output_flushing ()
void
flush_output ()
{
- register int i;
+ int i;
if (!output_paragraph_offset || flushing_ignored)
return;
for (i = 0; i < output_paragraph_offset; i++)
{
- /* If we turned on the 8th bit for a space
- inside @w, turn it back off for output. */
- if (output_paragraph[i] & meta_character_bit)
+ /* If we turned on the 8th bit for a space inside @w, turn it
+ back off for output. This might be problematic, since the
+ 0x80 character may be used in 8-bit character sets. Sigh.
+ In any case, don't do this for HTML, since the nbsp character
+ is valid input and must be passed along to the browser. */
+ if (!html && (output_paragraph[i] & meta_character_bit))
{
int temp = UNMETA (output_paragraph[i]);
if (temp == ' ')
@@ -2980,6 +2387,7 @@ flush_output ()
output_position += output_paragraph_offset;
output_paragraph_offset = 0;
+ meta_char_pos = 0;
}
/* How to close a paragraph controlling the number of lines between
@@ -2990,6 +2398,16 @@ flush_output ()
1 creates a single blank line between paragraphs. */
int paragraph_spacing = DEFAULT_PARAGRAPH_SPACING;
+static void
+close_paragraph_with_lines (lines)
+ int lines;
+{
+ int old_spacing = paragraph_spacing;
+ paragraph_spacing = lines;
+ close_paragraph ();
+ paragraph_spacing = old_spacing;
+}
+
/* Close the current paragraph, leaving no blank lines between them. */
void
close_single_paragraph ()
@@ -3033,28 +2451,18 @@ close_insertion_paragraph ()
insertion_paragraph_closed = 1;
}
-void
-close_paragraph_with_lines (lines)
- int lines;
-{
- int old_spacing = paragraph_spacing;
- paragraph_spacing = lines;
- close_paragraph ();
- paragraph_spacing = old_spacing;
-}
-
/* Close the currently open paragraph. */
void
close_paragraph ()
{
- register int i;
+ int i;
/* The insertion paragraph is no longer closed. */
insertion_paragraph_closed = 0;
if (paragraph_is_open && !must_start_paragraph)
{
- register int tindex, c;
+ int tindex, c;
tindex = output_paragraph_offset;
@@ -3083,7 +2491,13 @@ close_paragraph ()
if (!force_flush_right)
{
for (i = 0; i < (paragraph_spacing - line_already_broken); i++)
- insert ('\n');
+ {
+ insert ('\n');
+ /* Don't need anything extra for HTML in usual case of no
+ extra paragraph spacing. */
+ if (html && i > 0)
+ insert_string ("<br>");
+ }
}
/* If we are doing flush right indentation, then do it now
@@ -3096,6 +2510,7 @@ close_paragraph ()
no_indent = 0;
output_column = 0;
}
+
ignore_blank_line ();
}
@@ -3122,7 +2537,7 @@ do_flush_right_indentation ()
if (output_paragraph_offset < fill_column)
{
- register int i;
+ int i;
if (fill_column >= paragraph_buffer_len)
output_paragraph =
@@ -3130,7 +2545,7 @@ do_flush_right_indentation ()
(paragraph_buffer_len += fill_column));
temp_len = strlen ((char *)output_paragraph);
- temp = (char *)xmalloc (temp_len + 1);
+ temp = xmalloc (temp_len + 1);
memcpy (temp, (char *)output_paragraph, temp_len);
for (i = 0; i < fill_column - output_paragraph_offset; i++)
@@ -3139,6 +2554,7 @@ do_flush_right_indentation ()
memcpy ((char *)output_paragraph + i, temp, temp_len);
free (temp);
output_paragraph_offset = fill_column;
+ adjust_braces_following (0, i);
}
}
}
@@ -3195,16 +2611,12 @@ void
indent (amount)
int amount;
{
- register BRACE_ELEMENT *elt = brace_stack;
+ if (html)
+ return;
/* For every START_POS saved within the brace stack which will be affected
by this indentation, bump that start pos forward. */
- while (elt)
- {
- if (elt->pos >= output_paragraph_offset)
- elt->pos += amount;
- elt = elt->next;
- }
+ adjust_braces_following (output_paragraph_offset, amount);
while (--amount >= 0)
insert (' ');
@@ -3219,2492 +2631,62 @@ search_forward (string, from)
{
int len = strlen (string);
- while (from < size_of_input_text)
+ while (from < input_text_length)
{
if (strncmp (input_text + from, string, len) == 0)
- return (from);
+ return from;
from++;
}
- return (-1);
-}
-
-/* Whoops, Unix doesn't have strcasecmp. */
-
-/* Case independent string compare. */
-#if !defined (HAVE_STRCASECMP)
-int
-strcasecmp (string1, string2)
- char *string1, *string2;
-{
- char ch1, ch2;
-
- for (;;)
- {
- ch1 = *string1++;
- ch2 = *string2++;
-
- if (!(ch1 | ch2))
- return (0);
-
- ch1 = coerce_to_upper (ch1);
- ch2 = coerce_to_upper (ch2);
-
- if (ch1 != ch2)
- return (ch1 - ch2);
- }
-}
-#endif /* !HAVE_STRCASECMP */
-
-void
-init_insertion_stack ()
-{
- insertion_stack = (INSERTION_ELT *) NULL;
-}
-
-/* Return the type of the current insertion. */
-enum insertion_type
-current_insertion_type ()
-{
- if (!insertion_level)
- return (bad_type);
- else
- return (insertion_stack->insertion);
-}
-
-/* Return a pointer to the string which is the function to wrap around
- items. */
-char *
-current_item_function ()
-{
- register int level, done;
- register INSERTION_ELT *elt;
-
- level = insertion_level;
- elt = insertion_stack;
- done = 0;
-
- /* Skip down through the stack until we find a non-conditional insertion. */
- while (!done && (elt != NULL))
- {
- switch (elt->insertion)
- {
- case ifinfo:
- case ifnothtml:
- case ifnottex:
- case ifset:
- case ifclear:
- case cartouche:
- elt = elt->next;
- level--;
- break;
-
- default:
- done = 1;
- }
- }
-
- if (!level)
- return ((char *) NULL);
- else
- return (elt->item_function);
-}
-
-char *
-get_item_function ()
-{
- char *item_function;
- get_rest_of_line (&item_function);
- backup_input_pointer ();
- return (item_function);
-}
-
- /* Push the state of the current insertion on the stack. */
-void
-push_insertion (type, item_function)
- enum insertion_type type;
- char *item_function;
-{
- INSERTION_ELT *new = (INSERTION_ELT *) xmalloc (sizeof (INSERTION_ELT));
-
- new->item_function = item_function;
- new->filling_enabled = filling_enabled;
- new->indented_fill = indented_fill;
- new->insertion = type;
- new->line_number = line_number;
- new->filename = xstrdup (input_filename);
- new->inhibited = inhibit_paragraph_indentation;
- new->in_fixed_width_font = in_fixed_width_font;
- new->next = insertion_stack;
- insertion_stack = new;
- insertion_level++;
-}
-
- /* Pop the value on top of the insertion stack into the
- global variables. */
-void
-pop_insertion ()
-{
- INSERTION_ELT *temp = insertion_stack;
-
- if (temp == (INSERTION_ELT *) NULL)
- return;
-
- in_fixed_width_font = temp->in_fixed_width_font;
- inhibit_paragraph_indentation = temp->inhibited;
- filling_enabled = temp->filling_enabled;
- indented_fill = temp->indented_fill;
- free_and_clear (&(temp->item_function));
- free_and_clear (&(temp->filename));
- insertion_stack = insertion_stack->next;
- free (temp);
- insertion_level--;
-}
-
- /* Return a pointer to the print name of this
- enumerated type. */
-char *
-insertion_type_pname (type)
- enum insertion_type type;
-{
- if ((int) type < (int) bad_type)
- return (insertion_type_names[(int) type]);
- else
- return (_("Broken-Type in insertion_type_pname"));
-}
-
-/* Return the insertion_type associated with NAME.
- If the type is not one of the known ones, return BAD_TYPE. */
-enum insertion_type
-find_type_from_name (name)
- char *name;
-{
- int index = 0;
- while (index < (int) bad_type)
- {
- if (strcmp (name, insertion_type_names[index]) == 0)
- return (enum insertion_type) index;
- index++;
- }
- return (bad_type);
-}
-
-int
-defun_insertion (type)
- enum insertion_type type;
-{
- return
- ((type == deffn)
- || (type == defun)
- || (type == defmac)
- || (type == defspec)
- || (type == defvr)
- || (type == defvar)
- || (type == defopt)
- || (type == deftypefn)
- || (type == deftypefun)
- || (type == deftypevr)
- || (type == deftypevar)
- || (type == defcv)
- || (type == defivar)
- || (type == defop)
- || (type == defmethod)
- || (type == deftypemethod)
- || (type == deftp));
-}
-
-/* MAX_NS is the maximum nesting level for enumerations. I picked 100
- which seemed reasonable. This doesn't control the number of items,
- just the number of nested lists. */
-#define max_stack_depth 100
-#define ENUM_DIGITS 1
-#define ENUM_ALPHA 2
-typedef struct {
- int enumtype;
- int enumval;
-} DIGIT_ALPHA;
-
-DIGIT_ALPHA enumstack[max_stack_depth];
-int enumstack_offset = 0;
-int current_enumval = 1;
-int current_enumtype = ENUM_DIGITS;
-char *enumeration_arg = (char *)NULL;
-
-void
-start_enumerating (at, type)
- int at, type;
-{
- if ((enumstack_offset + 1) == max_stack_depth)
- {
- line_error (_("Enumeration stack overflow"));
- return;
- }
- enumstack[enumstack_offset].enumtype = current_enumtype;
- enumstack[enumstack_offset].enumval = current_enumval;
- enumstack_offset++;
- current_enumval = at;
- current_enumtype = type;
-}
-
-void
-stop_enumerating ()
-{
- --enumstack_offset;
- if (enumstack_offset < 0)
- enumstack_offset = 0;
-
- current_enumval = enumstack[enumstack_offset].enumval;
- current_enumtype = enumstack[enumstack_offset].enumtype;
-}
-
-/* Place a letter or digits into the output stream. */
-void
-enumerate_item ()
-{
- char temp[10];
-
- if (current_enumtype == ENUM_ALPHA)
- {
- if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
- {
- current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
- warning (_("lettering overflow, restarting at %c"), current_enumval);
- }
- sprintf (temp, "%c. ", current_enumval);
- }
- else
- sprintf (temp, "%d. ", current_enumval);
-
- indent (output_column += (current_indent - strlen (temp)));
- add_word (temp);
- current_enumval++;
-}
-
-/* This is where the work for all the "insertion" style
- commands is done. A huge switch statement handles the
- various setups, and generic code is on both sides. */
-void
-begin_insertion (type)
- enum insertion_type type;
-{
- int no_discard = 0;
-
- if (defun_insertion (type))
- {
- push_insertion (type, xstrdup (""));
- no_discard++;
- }
- else
- push_insertion (type, get_item_function ());
-
- switch (type)
- {
- case menu:
- if (!no_headers)
- close_paragraph ();
-
- filling_enabled = no_indent = 0;
- inhibit_paragraph_indentation = 1;
-
- if (!no_headers)
- add_word (_("* Menu:\n"));
-
- in_menu++;
- no_discard++;
- break;
-
- case detailmenu:
- if (!in_menu)
- {
- if (!no_headers)
- close_paragraph ();
-
- filling_enabled = no_indent = 0;
- inhibit_paragraph_indentation = 1;
-
- no_discard++;
- }
-
- in_detailmenu++;
- break;
-
- case direntry:
- close_single_paragraph ();
- filling_enabled = no_indent = 0;
- inhibit_paragraph_indentation = 1;
- insert_string ("START-INFO-DIR-ENTRY\n");
- break;
-
- /* I think @quotation is meant to do filling.
- If you don't want filling, then use @display. */
- case quotation:
- close_single_paragraph ();
- last_char_was_newline = no_indent = 0;
- indented_fill = filling_enabled = 1;
- inhibit_paragraph_indentation = 1;
- current_indent += default_indentation_increment;
- break;
-
- case display:
- case example:
- case smallexample:
- case lisp:
- case smalllisp:
- /* Just like @example, but no indentation. */
- case format:
- close_single_paragraph ();
- inhibit_paragraph_indentation = 1;
- in_fixed_width_font++;
- filling_enabled = 0;
- last_char_was_newline = 0;
- if (type != format)
- current_indent += default_indentation_increment;
- break;
-
- case multitable:
- do_multitable ();
- break;
-
- case table:
- case ftable:
- case vtable:
- case itemize:
- close_single_paragraph ();
- current_indent += default_indentation_increment;
- filling_enabled = indented_fill = 1;
-#if defined (INDENT_PARAGRAPHS_IN_TABLE)
- inhibit_paragraph_indentation = 0;
-#else
- inhibit_paragraph_indentation = 1;
-#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
-
- /* Make things work for losers who forget the itemize syntax. */
- if (allow_lax_format && (type == itemize))
- {
- if (!(*insertion_stack->item_function))
- {
- free (insertion_stack->item_function);
- insertion_stack->item_function = xstrdup ("@bullet");
- insertion_stack->item_function[0] = COMMAND_PREFIX;
- }
- }
-
- if (!*insertion_stack->item_function)
- {
- line_error (_("%s requires an argument: the formatter for %citem"),
- insertion_type_pname (type), COMMAND_PREFIX);
- }
- break;
-
- case enumerate:
- close_single_paragraph ();
- no_indent = 0;
-#if defined (INDENT_PARAGRAPHS_IN_TABLE)
- inhibit_paragraph_indentation = 0;
-#else
- inhibit_paragraph_indentation = 1;
-#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
-
- current_indent += default_indentation_increment;
- filling_enabled = indented_fill = 1;
-
- if (isdigit (*enumeration_arg))
- start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
- else
- start_enumerating (*enumeration_arg, ENUM_ALPHA);
- break;
-
- /* Does nothing special in makeinfo. */
- case group:
- /* Only close the paragraph if we are not inside of an @example. */
- if (!insertion_stack->next ||
- insertion_stack->next->insertion != example)
- close_single_paragraph ();
- break;
-
- /* Insertions that are no-ops in info, but do something in TeX. */
- case ifinfo:
- case ifnothtml:
- case ifnottex:
- case ifset:
- case ifclear:
- case cartouche:
- if (in_menu)
- no_discard++;
- break;
-
- case deffn:
- case defun:
- case defmac:
- case defspec:
- case defvr:
- case defvar:
- case defopt:
- case deftypefn:
- case deftypefun:
- case deftypevr:
- case deftypevar:
- case defcv:
- case defivar:
- case defop:
- case defmethod:
- case deftypemethod:
- case deftp:
- inhibit_paragraph_indentation = 1;
- filling_enabled = indented_fill = 1;
- current_indent += default_indentation_increment;
- no_indent = 0;
- break;
-
- case flushleft:
- close_single_paragraph ();
- inhibit_paragraph_indentation = 1;
- filling_enabled = indented_fill = no_indent = 0;
- break;
-
- case flushright:
- close_single_paragraph ();
- filling_enabled = indented_fill = no_indent = 0;
- inhibit_paragraph_indentation = 1;
- force_flush_right++;
- break;
- }
-
- if (!no_discard)
- discard_until ("\n");
-}
-
-/* Try to end the insertion with the specified TYPE. With a value of
- `bad_type', TYPE gets translated to match the value currently on top
- of the stack. Otherwise, if TYPE doesn't match the top of the
- insertion stack, give error. */
-void
-end_insertion (type)
- enum insertion_type type;
-{
- enum insertion_type temp_type;
-
- if (!insertion_level)
- return;
-
- temp_type = current_insertion_type ();
-
- if (type == bad_type)
- type = temp_type;
-
- if (type != temp_type)
- {
- line_error
- (_("`%cend' expected `%s', but saw `%s'"), COMMAND_PREFIX,
- insertion_type_pname (temp_type), insertion_type_pname (type));
- return;
- }
-
- pop_insertion ();
-
- switch (type)
- {
- /* Insertions which have no effect on paragraph formatting. */
- case ifnothtml:
- case ifnottex:
- case ifinfo:
- case ifset:
- case ifclear:
- break;
-
- case direntry:
- insert_string ("END-INFO-DIR-ENTRY\n\n");
- close_insertion_paragraph ();
- break;
-
- case detailmenu:
- in_detailmenu--; /* No longer hacking menus. */
- if (!in_menu)
- {
- if (!no_headers)
- close_insertion_paragraph ();
- }
- break;
-
- case menu:
- in_menu--; /* No longer hacking menus. */
- if (!no_headers)
- close_insertion_paragraph ();
- break;
-
- case multitable:
- end_multitable ();
- break;
-
- case enumerate:
- stop_enumerating ();
- close_insertion_paragraph ();
- current_indent -= default_indentation_increment;
- break;
-
- case flushleft:
- case group:
- case cartouche:
- close_insertion_paragraph ();
- break;
-
- case format:
- case display:
- case example:
- case smallexample:
- case lisp:
- case smalllisp:
- case quotation:
- /* @format is the only fixed_width insertion without a change
- in indentation. */
- if (type != format)
- current_indent -= default_indentation_increment;
-
- /* The ending of one of these insertions always marks the
- start of a new paragraph. */
- close_insertion_paragraph ();
- break;
-
- case table:
- case ftable:
- case vtable:
- case itemize:
- current_indent -= default_indentation_increment;
- break;
-
- case flushright:
- force_flush_right--;
- close_insertion_paragraph ();
- break;
-
- /* Handle the @defun style insertions with a default clause. */
- default:
- current_indent -= default_indentation_increment;
- close_insertion_paragraph ();
- break;
- }
-}
-
-/* Insertions cannot cross certain boundaries, such as node beginnings. In
- code that creates such boundaries, you should call `discard_insertions'
- before doing anything else. It prints the errors for you, and cleans up
- the insertion stack. With nonzero SPECIALS_OK, allows unmatched
- ifinfo, ifset, ifclear, otherwise not. */
-void
-discard_insertions (specials_ok)
- int specials_ok;
-{
- int real_line_number = line_number;
- while (insertion_stack)
- {
- if (specials_ok && (insertion_stack->insertion == ifinfo
- || insertion_stack->insertion == ifset
- || insertion_stack->insertion == ifclear))
- break;
- else
- {
- char *offender = insertion_type_pname (insertion_stack->insertion);
- char *current_filename = input_filename;
-
- input_filename = insertion_stack->filename;
- line_number = insertion_stack->line_number;
- line_error (_("No matching `%cend %s'"), COMMAND_PREFIX, offender);
- input_filename = current_filename;
- pop_insertion ();
- }
- }
- line_number = real_line_number;
+ return -1;
}
-/* The Texinfo commands. */
-
-/* Commands which insert their own names. */
-void
-insert_self (arg)
- int arg;
-{
- if (arg == START)
- add_word (command);
-}
-
-void
-insert_space (arg)
- int arg;
-{
- if (arg == START)
- add_char (' ');
-}
-
-/* Force a line break in the output. */
-void
-cm_asterisk ()
-{
- close_single_paragraph ();
- cm_noindent ();
-}
-
-/* Insert ellipsis. */
-void
-cm_dots (arg)
- int arg;
-{
- if (arg == START)
- add_word ("...");
-}
-
-/* Insert ellipsis for sentence end. */
-void
-cm_enddots (arg)
- int arg;
-{
- if (arg == START)
- add_word ("....");
-}
-
-void
-cm_bullet (arg)
- int arg;
-{
- if (arg == START)
- add_char ('*');
-}
-
-void
-cm_minus (arg)
- int arg;
-{
- if (arg == START)
- add_char ('-');
-}
-
-/* Insert "TeX". */
-void
-cm_TeX (arg)
- int arg;
-{
- if (arg == START)
- add_word ("TeX");
-}
-
-/* Copyright symbol. */
-void
-cm_copyright (arg)
- int arg;
-{
- if (arg == START)
- add_word ("(C)");
-}
-
-/* Accent commands that take explicit arguments. */
-void
-cm_accent (arg)
- int arg;
-{
- if (arg == START)
- {
- if (strcmp (command, "dotaccent") == 0) /* overdot */
- add_char ('.');
- else if (strcmp (command, "H") == 0) /* Hungarian umlaut */
- add_word ("''");
- else if (strcmp (command, "ringaccent") == 0)
- add_char ('*');
- else if (strcmp (command, "tieaccent") == 0)
- add_char ('[');
- else if (strcmp (command, "u") == 0) /* breve */
- add_char ('(');
- else if (strcmp (command, "v") == 0) /* hacek/check */
- add_char ('<');
- }
- else if (arg == END)
- {
- if (strcmp (command, "ubaraccent") == 0) /* underbar */
- add_char ('_');
- else if (strcmp (command, "udotaccent") == 0) /* underdot */
- add_word ("-.");
- else if (strcmp (command, ",") == 0) /* cedilla */
- add_word (",");
- }
-}
-
-/* Non-English letters/characters that don't insert themselves. */
-void
-cm_special_char (arg)
-{
- if (arg == START)
- {
- if ((*command == 'L' || *command == 'l'
- || *command == 'O' || *command == 'o')
- && command[1] == 0)
- {
- /* Lslash lslash Oslash oslash */
- add_char (*command);
- add_char ('/');
- }
- else if (strcmp (command, "exclamdown") == 0)
- add_char ('!');
- else if (strcmp (command, "pounds") == 0)
- add_char ('#');
- else if (strcmp (command, "questiondown") == 0)
- add_char ('?');
- else
- fprintf (stderr, _("How did @%s end up in cm_special_char?\n"), command);
- }
-}
-
-/* Dotless i or j. */
-void
-cm_dotless (arg, start, end)
- int arg, start, end;
-{
- if (arg == END)
- {
- if (output_paragraph[start] != 'i' && output_paragraph[start] != 'j')
- /* This error message isn't perfect if the argument is multiple
- characters, but it doesn't seem worth getting right. */
- line_error (_("%c%s expects `i' or `j' as argument, not `%c'"),
- COMMAND_PREFIX, command, output_paragraph[start]);
-
- else if (end - start != 1)
- line_error (_("%c%s expects a single character `i' or `j' as argument"),
- COMMAND_PREFIX, command);
-
- /* We've already inserted the `i' or `j', so nothing to do. */
- }
-}
-
-void
-cm_today (arg)
- int arg;
-{
- static char *months [12] =
- { N_("January"), N_("February"), N_("March"), N_("April"), N_("May"),
- N_("June"), N_("July"), N_("August"), N_("September"), N_("October"),
- N_("November"), N_("December") };
- if (arg == START)
- {
- time_t timer = time (0);
- struct tm *ts = localtime (&timer);
- add_word_args ("%d %s %d", ts->tm_mday, _(months[ts->tm_mon]),
- ts->tm_year + 1900);
- }
-}
-
-void
-cm_code (arg)
- int arg;
-{
- extern int printing_index;
-
- if (arg == START)
- {
- in_fixed_width_font++;
-
- if (!printing_index)
- add_char ('`');
- }
- else
- {
- if (!printing_index)
- add_char ('\'');
- }
-}
-
-void
-cm_kbd (arg)
- int arg;
-{
- /* People use @kbd in an example to get the "user input" font.
- We don't want quotes in that case. */
- if (!in_fixed_width_font)
- cm_code (arg);
-}
-
-void
-cm_key (arg)
- int arg;
-{
- add_char (arg == START ? '<' : '>');
-}
-
-/* Convert the character at position into a true control character. */
-void
-cm_ctrl (arg, start, end)
- int arg, start, end;
-{
- /* Should we allow multiple character arguments? I think yes. */
- if (arg == END)
- {
- register int i, character;
-#if defined (NO_MULTIPLE_CTRL)
- if ((end - start) != 1)
- line_error (_("%c%s expects a single character as an argument"),
- COMMAND_PREFIX, command);
- else
-#endif
- for (i = start; i < end; i++)
- {
- character = output_paragraph[i];
-
- if (isletter (character))
- output_paragraph[i] = CTL (coerce_to_upper (character));
- }
- }
-}
-
-/* Handle a command that switches to a non-fixed-width font. */
-void
-not_fixed_width (arg)
- int arg;
-{
- if (arg == START)
- in_fixed_width_font = 0;
-}
-
-/* Small caps and @var in makeinfo just uppercase the text. */
-void
-cm_var_sc (arg, start_pos, end_pos)
- int arg, start_pos, end_pos;
-{
- not_fixed_width (arg);
-
- if (arg == END)
- {
- while (start_pos < end_pos)
- {
- output_paragraph[start_pos] =
- coerce_to_upper (output_paragraph[start_pos]);
- start_pos++;
- }
- }
-}
-
-void
-cm_dfn (arg, position)
- int arg, position;
-{
- add_char ('"');
-}
-
-void
-cm_emph (arg)
- int arg;
-{
- add_char ('*');
-}
-
-void
-cm_strong (arg, position)
- int arg, position;
-{
- cm_emph (arg);
-}
-
-void
-cm_cite (arg, position)
- int arg, position;
-{
- if (arg == START)
- add_word ("`");
- else
- add_word ("'");
-}
-
-/* No highlighting, but argument switches fonts. */
-void
-cm_not_fixed_width (arg, start, end)
- int arg, start, end;
-{
- not_fixed_width (arg);
-}
-
-/* Various commands are no-op's. */
-void
-cm_no_op ()
-{
-}
-
-/* No-op that eats its argument on same line. */
-void
-cm_no_op_line_arg ()
-{
- char *temp;
- get_rest_of_line (&temp);
- free (temp);
-}
-
-/* Prevent the argument from being split across two lines. */
-void
-cm_w (arg, start, end)
- int arg, start, end;
-{
- if (arg == START)
- non_splitting_words++;
- else
- non_splitting_words--;
-}
-
-
-/* Explain that this command is obsolete, thus the user shouldn't
- do anything with it. */
-void
-cm_obsolete (arg, start, end)
- int arg, start, end;
-{
- if (arg == START)
- warning (_("%c%s is obsolete"), COMMAND_PREFIX, command);
-}
-
-/* Insert the text following input_text_offset up to the end of the line
- in a new, separate paragraph. Directly underneath it, insert a
- line of WITH_CHAR, the same length of the inserted text. */
-void
-insert_and_underscore (with_char)
- int with_char;
-{
- register int i, len;
- int old_no_indent, starting_pos, ending_pos;
- char *temp;
-
- close_paragraph ();
- filling_enabled = indented_fill = 0;
- old_no_indent = no_indent;
- no_indent = 1;
-
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- append_to_expansion_output (input_text_offset + 1);
-#endif /* HAVE_MACROS */
-
- get_rest_of_line (&temp);
-
- starting_pos = output_position + output_paragraph_offset;
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- {
- char *temp1 = (char *) xmalloc (2 + strlen (temp));
- sprintf (temp1, "%s\n", temp);
- remember_itext (input_text, input_text_offset);
- me_execute_string (temp1);
- free (temp1);
- }
- else
-#endif /* HAVE_MACROS */
- execute_string ("%s\n", temp);
-
- ending_pos = output_position + output_paragraph_offset;
- free (temp);
-
- len = (ending_pos - starting_pos) - 1;
- for (i = 0; i < len; i++)
- add_char (with_char);
- insert ('\n');
- close_paragraph ();
- filling_enabled = 1;
- no_indent = old_no_indent;
-}
-
-/* Here is a structure which associates sectioning commands with
- an integer, hopefully to reflect the `depth' of the current
- section. */
-struct {
- char *name;
- int level;
-} section_alist[] = {
- { "unnumberedsubsubsec", 5 },
- { "unnumberedsubsec", 4 },
- { "unnumberedsec", 3 },
- { "unnumbered", 2 },
- { "appendixsubsubsec", 5 },
- { "appendixsubsec", 4 },
- { "appendixsec", 3 },
- { "appendixsection", 3 },
- { "appendix", 2 },
- { "subsubsec", 5 },
- { "subsubsection", 5 },
- { "subsection", 4 },
- { "section", 3 },
- { "chapter", 2 },
- { "top", 1 },
-
- { (char *)NULL, 0 }
-};
-
-/* Amount to offset the name of sectioning commands to levels by. */
-int section_alist_offset = 0;
-
-/* Shift the meaning of @section to @chapter. */
-void
-cm_raisesections ()
-{
- discard_until ("\n");
- section_alist_offset--;
-}
-
-/* Shift the meaning of @chapter to @section. */
-void
-cm_lowersections ()
-{
- discard_until ("\n");
- section_alist_offset++;
-}
-
-/* Return an integer which identifies the type section present in TEXT. */
-int
-what_section (text)
- char *text;
-{
- register int i, j;
- char *t;
-
- find_section_command:
- for (j = 0; text[j] && cr_or_whitespace (text[j]); j++);
- if (text[j] != COMMAND_PREFIX)
- return (-1);
-
- text = text + j + 1;
-
- /* We skip @c, @comment, and @?index commands. */
- if ((strncmp (text, "comment", strlen ("comment")) == 0) ||
- (text[0] == 'c' && cr_or_whitespace (text[1])) ||
- (strcmp (text + 1, "index") == 0))
- {
- while (*text++ != '\n');
- goto find_section_command;
- }
-
- /* Handle italicized sectioning commands. */
- if (*text == 'i')
- text++;
-
- for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++);
-
- for (i = 0; (t = section_alist[i].name); i++)
- {
- if (j == strlen (t) && strncmp (t, text, j) == 0)
- {
- int return_val;
-
- return_val = (section_alist[i].level + section_alist_offset);
-
- if (return_val < 0)
- return_val = 0;
- else if (return_val > 5)
- return_val = 5;
- return (return_val);
- }
- }
- return (-1);
-}
-
-/* Set the level of @top to LEVEL. Return the old level of @top. */
-int
-set_top_section_level (level)
- int level;
-{
- register int i, result = -1;
-
- for (i = 0; section_alist[i].name; i++)
- if (strcmp (section_alist[i].name, "top") == 0)
- {
- result = section_alist[i].level;
- section_alist[i].level = level;
- break;
- }
- return (result);
-}
-
-/* Treat this just like @unnumbered. The only difference is
- in node defaulting. */
-void
-cm_top ()
-{
- /* It is an error to have more than one @top. */
- if (top_node_seen)
- {
- TAG_ENTRY *tag = tag_table;
-
- line_error (_("Node with %ctop as a section already exists"),
- COMMAND_PREFIX);
-
- while (tag != (TAG_ENTRY *)NULL)
- {
- if ((tag->flags & IS_TOP))
- {
- int old_line_number = line_number;
- char *old_input_filename = input_filename;
-
- line_number = tag->line_no;
- input_filename = tag->filename;
- line_error (_("Here is the %ctop node"), COMMAND_PREFIX);
- input_filename = old_input_filename;
- line_number = old_line_number;
- return;
- }
- tag = tag->next_ent;
- }
- }
- else
- {
- top_node_seen = 1;
-
- /* It is an error to use @top before you have used @node. */
- if (!tag_table)
- {
- char *top_name;
-
- get_rest_of_line (&top_name);
- free (top_name);
- line_error (_("%ctop used before %cnode, defaulting to %s"),
- COMMAND_PREFIX, COMMAND_PREFIX, top_name);
- execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name);
- return;
- }
-
- cm_unnumbered ();
-
- /* The most recently defined node is the top node. */
- tag_table->flags |= IS_TOP;
-
- /* Now set the logical hierarchical level of the Top node. */
- {
- int orig_offset = input_text_offset;
-
- input_text_offset = search_forward (node_search_string, orig_offset);
-
- if (input_text_offset > 0)
- {
- int this_section;
-
- /* We have encountered a non-top node, so mark that one exists. */
- non_top_node_seen = 1;
-
- /* Move to the end of this line, and find out what the
- sectioning command is here. */
- while (input_text[input_text_offset] != '\n')
- input_text_offset++;
-
- if (input_text_offset < size_of_input_text)
- input_text_offset++;
-
- this_section = what_section (input_text + input_text_offset);
-
- /* If we found a sectioning command, then give the top section
- a level of this section - 1. */
- if (this_section != -1)
- set_top_section_level (this_section - 1);
- }
- input_text_offset = orig_offset;
- }
- }
-}
-
-/* Organized by level commands. That is, "*" == chapter, "=" == section. */
-char *scoring_characters = "*=-.";
-
-void
-sectioning_underscore (command)
- char *command;
-{
- char character;
- char *temp;
- int level;
-
- temp = (char *)xmalloc (2 + strlen (command));
- temp[0] = COMMAND_PREFIX;
- strcpy (&temp[1], command);
- level = what_section (temp);
- free (temp);
- level -= 2;
-
- if (level < 0)
- level = 0;
-
- character = scoring_characters[level];
-
- insert_and_underscore (character);
-}
-
-/* The command still works, but prints a warning message in addition. */
-void
-cm_ideprecated (arg, start, end)
- int arg, start, end;
-{
- warning (_("%c%s is obsolete; use %c%s instead"),
- COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1);
- sectioning_underscore (command + 1);
-}
-
-/* The remainder of the text on this line is a chapter heading. */
-void
-cm_chapter ()
-{
- sectioning_underscore ("chapter");
-}
-
-/* The remainder of the text on this line is a section heading. */
-void
-cm_section ()
-{
- sectioning_underscore ("section");
-}
-
-/* The remainder of the text on this line is a subsection heading. */
-void
-cm_subsection ()
-{
- sectioning_underscore ("subsection");
-}
-
-/* The remainder of the text on this line is a subsubsection heading. */
-void
-cm_subsubsection ()
-{
- sectioning_underscore ("subsubsection");
-}
-
-/* The remainder of the text on this line is an unnumbered heading. */
-void
-cm_unnumbered ()
-{
- cm_chapter ();
-}
-
-/* The remainder of the text on this line is an unnumbered section heading. */
-void
-cm_unnumberedsec ()
-{
- cm_section ();
-}
-
-/* The remainder of the text on this line is an unnumbered
- subsection heading. */
-void
-cm_unnumberedsubsec ()
-{
- cm_subsection ();
-}
-
-/* The remainder of the text on this line is an unnumbered
- subsubsection heading. */
-void
-cm_unnumberedsubsubsec ()
-{
- cm_subsubsection ();
-}
-
-/* The remainder of the text on this line is an appendix heading. */
-void
-cm_appendix ()
-{
- cm_chapter ();
-}
-
-/* The remainder of the text on this line is an appendix section heading. */
-void
-cm_appendixsec ()
-{
- cm_section ();
-}
-
-/* The remainder of the text on this line is an appendix subsection heading. */
-void
-cm_appendixsubsec ()
-{
- cm_subsection ();
-}
-
-/* The remainder of the text on this line is an appendix
- subsubsection heading. */
-void
-cm_appendixsubsubsec ()
-{
- cm_subsubsection ();
-}
-
-/* Compatibility functions substitute for chapter, section, etc. */
-void
-cm_majorheading ()
-{
- cm_chapheading ();
-}
-
-void
-cm_chapheading ()
-{
- cm_chapter ();
-}
-
-void
-cm_heading ()
-{
- cm_section ();
-}
-
-void
-cm_subheading ()
-{
- cm_subsection ();
-}
-
-void
-cm_subsubheading ()
-{
- cm_subsubsection ();
-}
-
-/* **************************************************************** */
-/* */
-/* Adding nodes, and making tags */
-/* */
-/* **************************************************************** */
-
-/* Start a new tag table. */
-void
-init_tag_table ()
-{
- while (tag_table != (TAG_ENTRY *) NULL)
- {
- TAG_ENTRY *temp = tag_table;
- free (temp->node);
- free (temp->prev);
- free (temp->next);
- free (temp->up);
- tag_table = tag_table->next_ent;
- free (temp);
- }
-}
-
-void
-write_tag_table ()
-{
- write_tag_table_internal (0); /* Not indirect. */
-}
-
-void
-write_tag_table_indirect ()
-{
- write_tag_table_internal (1);
-}
-
-/* Write out the contents of the existing tag table.
- INDIRECT_P says how to format the output. */
-void
-write_tag_table_internal (indirect_p)
- int indirect_p;
-{
- TAG_ENTRY *node = tag_table;
- int old_indent = no_indent;
-
- no_indent = 1;
- filling_enabled = 0;
- must_start_paragraph = 0;
- close_paragraph ();
-
- if (!indirect_p)
- {
- no_indent = 1;
- insert ('\n');
- }
-
- add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : "");
-
- while (node != (TAG_ENTRY *) NULL)
- {
- execute_string ("Node: %s", node->node);
- add_word_args ("\177%d\n", node->position);
- node = node->next_ent;
- }
-
- add_word ("\037\nEnd Tag Table\n");
- flush_output ();
- no_indent = old_indent;
-}
+/* Cross references. */
+/* Return next comma-delimited argument, but do not cross a close-brace
+ boundary. Clean up whitespace, too. If EXPAND is nonzero, replace
+ the entire brace-delimited argument list with its expansion before
+ looking for the next comma. */
char *
-get_node_token (expand)
- int expand;
+get_xref_token (expand)
+ int expand;
{
char *string;
- get_until_in_line (expand, ",", &string);
-
- if (curchar () == ',')
- input_text_offset++;
-
- canon_white (string);
-
- /* Force all versions of "top" to be "Top". */
- normalize_node_name (string);
-
- return (string);
-}
-
-/* Convert "top" and friends into "Top". */
-void
-normalize_node_name (string)
- char *string;
-{
- if (strcasecmp (string, "Top") == 0)
- strcpy (string, "Top");
-}
-
-/* Look up NAME in the tag table, and return the associated
- tag_entry. If the node is not in the table return NULL. */
-TAG_ENTRY *
-find_node (name)
- char *name;
-{
- TAG_ENTRY *tag = tag_table;
-
- while (tag != (TAG_ENTRY *) NULL)
- {
- if (strcmp (tag->node, name) == 0)
- return (tag);
- tag = tag->next_ent;
- }
- return ((TAG_ENTRY *) NULL);
-}
-
-/* Remember NODE and associates. */
-void
-remember_node (node, prev, next, up, position, line_no, no_warn)
- char *node, *prev, *next, *up;
- int position, line_no, no_warn;
-{
- /* Check for existence of this tag already. */
- if (validating)
- {
- register TAG_ENTRY *tag = find_node (node);
- if (tag)
- {
- line_error (
- _("Node `%s' multiply defined (line %d is first definition at)"),
- node, tag->line_no);
- return;
- }
- }
-
- /* First, make this the current node. */
- current_node = node;
-
- /* Now add it to the list. */
- {
- TAG_ENTRY *new = (TAG_ENTRY *) xmalloc (sizeof (TAG_ENTRY));
- new->node = node;
- new->prev = prev;
- new->next = next;
- new->up = up;
- new->position = position;
- new->line_no = line_no;
- new->filename = node_filename;
- new->touched = 0; /* not yet referenced. */
- new->flags = 0;
- if (no_warn)
- new->flags |= NO_WARN;
- new->next_ent = tag_table;
- tag_table = new;
- }
-}
-
-/* The order is: nodename, nextnode, prevnode, upnode.
- If all of the NEXT, PREV, and UP fields are empty, they are defaulted.
- You must follow a node command which has those fields defaulted
- with a sectioning command (e.g. @chapter) giving the "level" of that node.
- It is an error not to do so.
- The defaults come from the menu in this node's parent. */
-void
-cm_node ()
-{
- char *node, *prev, *next, *up;
- int new_node_pos, defaulting, this_section, no_warn = 0;
- extern int already_outputting_pending_notes;
-
- if (strcmp (command, "nwnode") == 0)
- no_warn = 1;
-
- /* Get rid of unmatched brace arguments from previous commands. */
- discard_braces ();
-
- /* There also might be insertions left lying around that haven't been
- ended yet. Do that also. */
- discard_insertions (1);
-
- if (!already_outputting_pending_notes)
- {
- close_paragraph ();
- output_pending_notes ();
- free_pending_notes ();
- }
-
- filling_enabled = indented_fill = 0;
- new_node_pos = output_position;
- current_footnote_number = 1;
-
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- append_to_expansion_output (input_text_offset + 1);
-#endif /* HAVE_MACROS */
-
- node = get_node_token (1);
- next = get_node_token (0);
- prev = get_node_token (0);
- up = get_node_token (0);
-
- if (verbose_mode)
- printf (_("Formatting node %s...\n"), node);
-
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- remember_itext (input_text, input_text_offset);
-#endif /* HAVE_MACROS */
-
- no_indent = 1;
- if (!no_headers)
- {
- add_word_args ("\037\nFile: %s, Node: ", pretty_output_filename);
-
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- me_execute_string (node);
- else
-#endif /* HAVE_MACROS */
- execute_string ("%s", node);
- filling_enabled = indented_fill = 0;
- }
-
- /* Check for defaulting of this node's next, prev, and up fields. */
- defaulting = (*next == 0 && *prev == 0 && *up == 0);
-
- this_section = what_section (input_text + input_text_offset);
-
- /* If we are defaulting, then look at the immediately following
- sectioning command (error if none) to determine the node's
- level. Find the node that contains the menu mentioning this node
- that is one level up (error if not found). That node is the "Up"
- of this node. Default the "Next" and "Prev" from the menu. */
- if (defaulting)
- {
- NODE_REF *last_ref = (NODE_REF *)NULL;
- NODE_REF *ref = node_references;
-
- if ((this_section < 0) && (strcmp (node, "Top") != 0))
- {
- char *polite_section_name = "top";
- int i;
-
- for (i = 0; section_alist[i].name; i++)
- if (section_alist[i].level == current_section + 1)
- {
- polite_section_name = section_alist[i].name;
- break;
- }
-
- line_error
- (_("Node `%s' requires a sectioning command (e.g. %c%s)"),
- node, COMMAND_PREFIX, polite_section_name);
- }
- else
- {
- if (strcmp (node, "Top") == 0)
- {
- /* Default the NEXT pointer to be the first menu item in
- this node, if there is a menu in this node. We have to
- try very hard to find the menu, as it may be obscured
- by execution_strings which are on the filestack. For
- every member of the filestack which has a FILENAME
- member which is identical to the current INPUT_FILENAME,
- search forward from that offset. */
- int saved_input_text_offset = input_text_offset;
- int saved_size_of_input_text = size_of_input_text;
- char *saved_input_text = input_text;
- FSTACK *next_file = filestack;
-
- int orig_offset, orig_size;
- char *glean_node_from_menu ();
-
- /* No matter what, make this file point back at `(dir)'. */
- free (up); up = xstrdup ("(dir)");
-
- while (1)
- {
- orig_offset = input_text_offset;
- orig_size =
- search_forward (node_search_string, orig_offset);
-
- if (orig_size < 0)
- orig_size = size_of_input_text;
-
- input_text_offset =
- search_forward (menu_search_string, orig_offset);
-
- if (input_text_offset > -1)
- {
- char *nodename_from_menu = (char *)NULL;
-
- input_text_offset =
- search_forward ("\n* ", input_text_offset);
-
- if (input_text_offset != -1)
- nodename_from_menu = glean_node_from_menu (0);
-
- if (nodename_from_menu)
- {
- free (next); next = nodename_from_menu;
- break;
- }
- }
-
- /* We got here, so it hasn't been found yet. Try
- the next file on the filestack if there is one. */
- if (next_file &&
- (strcmp (next_file->filename, input_filename) == 0))
- {
- input_text = next_file->text;
- input_text_offset = next_file->offset;
- size_of_input_text = next_file->size;
- next_file = next_file->next;
- }
- else
- {
- /* No more input files to check. */
- break;
- }
- }
-
- input_text = saved_input_text;
- input_text_offset = saved_input_text_offset;
- size_of_input_text = saved_size_of_input_text;
- }
- }
-
- /* Fix the level of the menu references in the Top node, iff it
- was declared with @top, and no subsequent reference was found. */
- if (top_node_seen && !non_top_node_seen)
- {
- /* Then this is the first non-@top node seen. */
- int level;
-
- level = set_top_section_level (this_section - 1);
- non_top_node_seen = 1;
-
- while (ref)
- {
- if (ref->section == level)
- ref->section = this_section - 1;
- ref = ref->next;
- }
-
- ref = node_references;
- }
-
- while (ref)
- {
- if (ref->section == (this_section - 1) &&
- ref->type == menu_reference &&
- strcmp (ref->node, node) == 0)
- {
- char *containing_node = ref->containing_node;
-
- free (up);
- up = xstrdup (containing_node);
-
- if (last_ref &&
- last_ref->type == menu_reference &&
- (strcmp (last_ref->containing_node,
- containing_node) == 0))
- {
- free (next);
- next = xstrdup (last_ref->node);
- }
-
- while ((ref->section == this_section - 1) &&
- (ref->next) &&
- (ref->next->type != menu_reference))
- ref = ref->next;
-
- if (ref->next && ref->type == menu_reference &&
- (strcmp (ref->next->containing_node,
- containing_node) == 0))
- {
- free (prev);
- prev = xstrdup (ref->next->node);
- }
- else if (!ref->next &&
- strcasecmp (ref->containing_node, "Top") == 0)
- {
- free (prev);
- prev = xstrdup (ref->containing_node);
- }
- break;
- }
- last_ref = ref;
- ref = ref->next;
- }
- }
-
-#if defined (HAVE_MACROS)
- /* Insert the correct args if we are expanding macros, and the node's
- pointers weren't defaulted. */
- if (macro_expansion_output_stream && !executing_string && !defaulting)
- {
- char *temp;
- int op_orig = output_paragraph_offset;
-
- temp = (char *)xmalloc (3 + strlen (next));
- sprintf (temp, ", %s", next);
- me_execute_string (temp);
- free (temp);
-
- temp = (char *)xmalloc (3 + strlen (prev));
- sprintf (temp, ", %s", prev);
- me_execute_string (temp);
- free (temp);
-
- temp = (char *)xmalloc (4 + strlen (up));
- sprintf (temp, ", %s", up);
- me_execute_string (temp);
- free (temp);
-
- output_paragraph_offset = op_orig;
- }
-#endif /* HAVE_MACROS */
-
- if (!no_headers)
- {
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream)
- me_inhibit_expansion++;
-#endif /* HAVE_MACROS */
-
- if (*next)
- {
- execute_string (", Next: %s", next);
- filling_enabled = indented_fill = 0;
- }
-
- if (*prev)
- {
- execute_string (", Prev: %s", prev);
- filling_enabled = indented_fill = 0;
- }
-
- if (*up)
- {
- execute_string (", Up: %s", up);
- filling_enabled = indented_fill = 0;
- }
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream)
- me_inhibit_expansion--;
-#endif /* HAVE_MACROS */
- }
-
- close_paragraph ();
- no_indent = 0;
-
- if (!*node)
- {
- line_error ("No node name specified for `%c%s' command",
- COMMAND_PREFIX, command);
- free (node);
- free (next);
- free (prev);
- free (up);
- }
- else
- {
- if (!*next) { free (next); next = (char *)NULL; }
- if (!*prev) { free (prev); prev = (char *)NULL; }
- if (!*up) { free (up); up = (char *)NULL; }
- remember_node (node, prev, next, up, new_node_pos, line_number, no_warn);
- }
-
- /* Change the section only if there was a sectioning command. */
- if (this_section >= 0)
- current_section = this_section;
-
- filling_enabled = 1;
-}
-
-/* Validation of an info file.
- Scan through the list of tag entries touching the Prev, Next, and Up
- elements of each. It is an error not to be able to touch one of them,
- except in the case of external node references, such as "(DIR)".
-
- If the Prev is different from the Up,
- then the Prev node must have a Next pointing at this node.
-
- Every node except Top must have an Up.
- The Up node must contain some sort of reference, other than a Next,
- to this node.
-
- If the Next is different from the Next of the Up,
- then the Next node must have a Prev pointing at this node. */
-void
-validate_file (tag_table)
- TAG_ENTRY *tag_table;
-{
- char *old_input_filename = input_filename;
- TAG_ENTRY *tags = tag_table;
-
- while (tags != (TAG_ENTRY *) NULL)
- {
- register TAG_ENTRY *temp_tag;
-
- input_filename = tags->filename;
- line_number = tags->line_no;
-
- /* If this is a "no warn" node, don't validate it in any way. */
- if (tags->flags & NO_WARN)
- {
- tags = tags->next_ent;
- continue;
- }
-
- /* If this node has a Next, then make sure that the Next exists. */
- if (tags->next)
- {
- validate (tags->next, tags->line_no, "Next");
-
- /* If the Next node exists, and there is no Up, then make
- sure that the Prev of the Next points back. */
- temp_tag = find_node (tags->next);
- if (temp_tag)
- {
- char *prev;
-
- if (temp_tag->flags & NO_WARN)
- {
- /* Do nothing if we aren't supposed to issue warnings
- about this node. */
- }
- else
- {
- prev = temp_tag->prev;
- if (!prev || (strcmp (prev, tags->node) != 0))
- {
- line_error (_("Node `%s''s Next field not pointed back to"),
- tags->node);
- line_number = temp_tag->line_no;
- input_filename = temp_tag->filename;
- line_error
- (_("This node (`%s') is the one with the bad `Prev'"),
- temp_tag->node);
- input_filename = tags->filename;
- line_number = tags->line_no;
- temp_tag->flags |= PREV_ERROR;
- }
- }
- }
- }
-
- /* Validate the Prev field if there is one, and we haven't already
- complained about it in some way. You don't have to have a Prev
- field at this stage. */
- if (!(tags->flags & PREV_ERROR) && tags->prev)
- {
- int valid_p = validate (tags->prev, tags->line_no, "Prev");
-
- if (!valid_p)
- tags->flags |= PREV_ERROR;
- else
- {
- /* If the Prev field is not the same as the Up field,
- then the node pointed to by the Prev field must have
- a Next field which points to this node. */
- if (tags->up && (strcmp (tags->prev, tags->up) != 0))
- {
- temp_tag = find_node (tags->prev);
-
- /* If we aren't supposed to issue warnings about the
- target node, do nothing. */
- if (!temp_tag || (temp_tag->flags & NO_WARN))
- {
- /* Do nothing. */
- }
- else
- {
- if (!temp_tag->next ||
- (strcmp (temp_tag->next, tags->node) != 0))
- {
- line_error
- (_("Node `%s's Prev field not pointed back to"),
- tags->node);
- line_number = temp_tag->line_no;
- input_filename = temp_tag->filename;
- line_error (_("This node (`%s') has the bad Next"),
- temp_tag->node);
- input_filename = tags->filename;
- line_number = tags->line_no;
- temp_tag->flags |= NEXT_ERROR;
- }
- }
- }
- }
- }
-
- if (!tags->up && (strcasecmp (tags->node, _("Top")) != 0))
- line_error (_("Node `%s' missing Up field"), tags->node);
- else if (tags->up)
- {
- int valid_p = validate (tags->up, tags->line_no, "Up");
-
- /* If node X has Up: Y, then warn if Y fails to have a menu item
- or note pointing at X, if Y isn't of the form "(Y)". */
- if (valid_p && *tags->up != '(')
- {
- NODE_REF *nref, *tref, *list;
- NODE_REF *find_node_reference ();
-
- tref = (NODE_REF *) NULL;
- list = node_references;
-
- for (;;)
- {
- if (!(nref = find_node_reference (tags->node, list)))
- break;
-
- if (strcmp (nref->containing_node, tags->up) == 0)
- {
- if (nref->type != menu_reference)
- {
- tref = nref;
- list = nref->next;
- }
- else
- break;
- }
- list = nref->next;
- }
-
- if (!nref)
- {
- temp_tag = find_node (tags->up);
- line_number = temp_tag->line_no;
- input_filename = temp_tag->filename;
- if (!tref)
- line_error (
-_("`%s' has an Up field of `%s', but `%s' has no menu item for `%s'"),
- tags->node, tags->up, tags->up, tags->node);
- line_number = tags->line_no;
- input_filename = tags->filename;
- }
- }
- }
- tags = tags->next_ent;
- }
-
- validate_other_references (node_references);
- /* We have told the user about the references which didn't exist.
- Now tell him about the nodes which aren't referenced. */
-
- tags = tag_table;
- while (tags != (TAG_ENTRY *) NULL)
- {
- /* If this node is a "no warn" node, do nothing. */
- if (tags->flags & NO_WARN)
- {
- tags = tags->next_ent;
- continue;
- }
-
- /* Special hack. If the node in question appears to have
- been referenced more than REFERENCE_WARNING_LIMIT times,
- give a warning. */
- if (tags->touched > reference_warning_limit)
- {
- input_filename = tags->filename;
- line_number = tags->line_no;
- warning (_("node `%s' has been referenced %d times"),
- tags->node, tags->touched);
- }
-
- if (tags->touched == 0)
- {
- input_filename = tags->filename;
- line_number = tags->line_no;
-
- /* Notice that the node "Top" is special, and doesn't have to
- be referenced. */
- if (strcasecmp (tags->node, _("Top")) != 0)
- warning (_("unreferenced node `%s'"), tags->node);
- }
- tags = tags->next_ent;
- }
- input_filename = old_input_filename;
-}
-
-/* Return 1 if tag correctly validated, or 0 if not. */
-int
-validate (tag, line, label)
- char *tag;
- int line;
- char *label;
-{
- TAG_ENTRY *result;
-
- /* If there isn't a tag to verify, or if the tag is in another file,
- then it must be okay. */
- if (!tag || !*tag || *tag == '(')
- return (1);
-
- /* Otherwise, the tag must exist. */
- result = find_node (tag);
-
- if (!result)
- {
- line_number = line;
- line_error (_("%s reference to nonexistent node `%s'"), label, tag);
- return (0);
- }
- result->touched++;
- return (1);
-}
-
-/* Split large output files into a series of smaller files. Each file
- is pointed to in the tag table, which then gets written out as the
- original file. The new files have the same name as the original file
- with a "-num" attached. SIZE is the largest number of bytes to allow
- in any single split file. */
-void
-split_file (filename, size)
- char *filename;
- int size;
-{
- char *root_filename, *root_pathname;
- char *the_file, *filename_part ();
- struct stat fileinfo;
- long file_size;
- char *the_header;
- int header_size;
-
- /* Can only do this to files with tag tables. */
- if (!tag_table)
- return;
-
- if (size == 0)
- size = DEFAULT_SPLIT_SIZE;
-
- if ((stat (filename, &fileinfo) != 0) ||
- (((long) fileinfo.st_size) < SPLIT_SIZE_THRESHOLD))
- return;
- file_size = (long) fileinfo.st_size;
-
- the_file = find_and_load (filename);
- if (!the_file)
- return;
-
- root_filename = filename_part (filename);
- root_pathname = pathname_part (filename);
-
- if (!root_pathname)
- root_pathname = xstrdup ("");
-
- /* Start splitting the file. Walk along the tag table
- outputting sections of the file. When we have written
- all of the nodes in the tag table, make the top-level
- pointer file, which contains indirect pointers and
- tags for the nodes. */
- {
- int which_file = 1;
- TAG_ENTRY *tags = tag_table;
- char *indirect_info = (char *)NULL;
-
- /* Remember the `header' of this file. The first tag in the file is
- the bottom of the header; the top of the file is the start. */
- the_header = (char *)xmalloc (1 + (header_size = tags->position));
- memcpy (the_header, the_file, header_size);
-
- while (tags)
- {
- int file_top, file_bot, limit;
-
- /* Have to include the Control-_. */
- file_top = file_bot = tags->position;
- limit = file_top + size;
-
- /* If the rest of this file is only one node, then
- that is the entire subfile. */
- if (!tags->next_ent)
- {
- int i = tags->position + 1;
- char last_char = the_file[i];
-
- while (i < file_size)
- {
- if ((the_file[i] == '\037') &&
- ((last_char == '\n') ||
- (last_char == '\014')))
- break;
- else
- last_char = the_file[i];
- i++;
- }
- file_bot = i;
- tags = tags->next_ent;
- goto write_region;
- }
-
- /* Otherwise, find the largest number of nodes that can fit in
- this subfile. */
- for (; tags; tags = tags->next_ent)
- {
- if (!tags->next_ent)
- {
- /* This entry is the last node. Search forward for the end
- of this node, and that is the end of this file. */
- int i = tags->position + 1;
- char last_char = the_file[i];
-
- while (i < file_size)
- {
- if ((the_file[i] == '\037') &&
- ((last_char == '\n') ||
- (last_char == '\014')))
- break;
- else
- last_char = the_file[i];
- i++;
- }
- file_bot = i;
-
- if (file_bot < limit)
- {
- tags = tags->next_ent;
- goto write_region;
- }
- else
- {
- /* Here we want to write out everything before the last
- node, and then write the last node out in a file
- by itself. */
- file_bot = tags->position;
- goto write_region;
- }
- }
-
- if (tags->next_ent->position > limit)
- {
- if (tags->position == file_top)
- tags = tags->next_ent;
-
- file_bot = tags->position;
-
- write_region:
- {
- int fd;
- char *split_filename;
-
- split_filename = (char *) xmalloc
- (10 + strlen (root_pathname) + strlen (root_filename));
- sprintf
- (split_filename,
- "%s%s-%d", root_pathname, root_filename, which_file);
-
- fd = open
- (split_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
-
- if ((fd < 0) ||
- (write (fd, the_header, header_size) != header_size) ||
- (write (fd, the_file + file_top, file_bot - file_top)
- != (file_bot - file_top)) ||
- ((close (fd)) < 0))
- {
- perror (split_filename);
- if (fd != -1)
- close (fd);
- exit (FATAL);
- }
-
- if (!indirect_info)
- {
- indirect_info = the_file + file_top;
- sprintf (indirect_info, "\037\nIndirect:\n");
- indirect_info += strlen (indirect_info);
- }
-
- sprintf (indirect_info, "%s-%d: %d\n",
- root_filename, which_file, file_top);
-
- free (split_filename);
- indirect_info += strlen (indirect_info);
- which_file++;
- break;
- }
- }
- }
- }
-
- /* We have sucessfully created the subfiles. Now write out the
- original again. We must use `output_stream', or
- write_tag_table_indirect () won't know where to place the output. */
- output_stream = fopen (filename, "w");
- if (!output_stream)
- {
- perror (filename);
- exit (FATAL);
- }
-
- {
- int distance = indirect_info - the_file;
- fwrite (the_file, 1, distance, output_stream);
-
- /* Inhibit newlines. */
- paragraph_is_open = 0;
-
- write_tag_table_indirect ();
- fclose (output_stream);
- free (the_header);
- free (the_file);
- return;
- }
- }
-}
-
-/* The strings here are followed in the message by `reference to...' in
- the `validate' routine. */
-char *
-reftype_type_string (type)
- enum reftype type;
-{
- switch (type)
- {
- case menu_reference:
- return ("Menu");
- case followed_reference:
- return ("Cross");
- default:
- return ("Internal-bad-reference-type");
- }
-}
-
-/* Remember this node name for later validation use. This is used to
- remember menu references while reading the input file. After the
- output file has been written, if validation is on, then we use the
- contents of `node_references' as a list of nodes to validate. */
-void
-remember_node_reference (node, line, type)
- char *node;
- int line;
- enum reftype type;
-{
- NODE_REF *temp = (NODE_REF *) xmalloc (sizeof (NODE_REF));
-
- temp->next = node_references;
- temp->node = xstrdup (node);
- temp->line_no = line;
- temp->section = current_section;
- temp->type = type;
- temp->containing_node = xstrdup (current_node ? current_node : "");
- temp->filename = node_filename;
-
- node_references = temp;
-}
-
-void
-validate_other_references (ref_list)
- register NODE_REF *ref_list;
-{
- char *old_input_filename = input_filename;
-
- while (ref_list != (NODE_REF *) NULL)
- {
- input_filename = ref_list->filename;
- validate (ref_list->node, ref_list->line_no,
- reftype_type_string (ref_list->type));
- ref_list = ref_list->next;
- }
- input_filename = old_input_filename;
-}
-
-/* Find NODE in REF_LIST. */
-NODE_REF *
-find_node_reference (node, ref_list)
- char *node;
- register NODE_REF *ref_list;
-{
- while (ref_list)
- {
- if (strcmp (node, ref_list->node) == 0)
- break;
- ref_list = ref_list->next;
- }
- return (ref_list);
-}
-
-void
-free_node_references ()
-{
- register NODE_REF *list, *temp;
-
- list = node_references;
-
- while (list)
+ if (expand)
{
- temp = list;
- free (list->node);
- free (list->containing_node);
- list = list->next;
- free (temp);
- }
- node_references = (NODE_REF *) NULL;
-}
+ int old_offset = input_text_offset;
+ int old_lineno = line_number;
- /* This function gets called at the start of every line while inside of
- a menu. It checks to see if the line starts with "* ", and if so,
- remembers the node reference that this menu refers to.
- input_text_offset is at the \n just before the line start. */
-#define menu_starter "* "
-char *
-glean_node_from_menu (remember_reference)
- int remember_reference;
-{
- int i, orig_offset = input_text_offset;
- char *nodename;
-
- if (strncmp (&input_text[input_text_offset + 1],
- menu_starter,
- strlen (menu_starter)) != 0)
- return ((char *)NULL);
- else
- input_text_offset += strlen (menu_starter) + 1;
-
- get_until_in_line (0, ":", &nodename);
- if (curchar () == ':')
- input_text_offset++;
- canon_white (nodename);
-
- if (curchar () == ':')
- goto save_node;
-
- free (nodename);
- get_rest_of_line (&nodename);
-
- /* Special hack: If the nodename follows the menu item name,
- then we have to read the rest of the line in order to find
- out what the nodename is. But we still have to read the
- line later, in order to process any formatting commands that
- might be present. So un-count the carriage return that has just
- been counted. */
- line_number--;
-
- isolate_nodename (nodename);
-
-save_node:
- input_text_offset = orig_offset;
- normalize_node_name (nodename);
- i = strlen (nodename);
- if (i && nodename[i - 1] == ':')
- nodename[i - 1] = 0;
-
- if (remember_reference)
- {
- remember_node_reference (nodename, line_number, menu_reference);
- free (nodename);
- return ((char *)NULL);
- }
- else
- return (nodename);
-}
-
-static void
-isolate_nodename (nodename)
- char *nodename;
-{
- register int i, c;
- int paren_seen, paren;
-
- if (!nodename)
- return;
-
- canon_white (nodename);
- paren_seen = paren = i = 0;
-
- if (*nodename == '.' || !*nodename)
- {
- *nodename = 0;
- return;
- }
-
- if (*nodename == '(')
- {
- paren++;
- paren_seen++;
- i++;
- }
-
- for (; (c = nodename[i]); i++)
- {
- if (paren)
+ get_until_in_braces ("}", &string);
+ if (curchar () == '}') /* as opposed to end of text */
+ input_text_offset++;
+ if (input_text_offset > old_offset)
{
- if (c == '(')
- paren++;
- else if (c == ')')
- paren--;
+ int limit = input_text_offset;
- continue;
+ input_text_offset = old_offset;
+ line_number = old_lineno;
+ only_macro_expansion++;
+ replace_with_expansion (input_text_offset, &limit);
+ only_macro_expansion--;
}
-
- /* If the character following the close paren is a space, then this
- node has no more characters associated with it. */
- if (c == '\t' ||
- c == '\n' ||
- c == ',' ||
- ((paren_seen && nodename[i - 1] == ')') &&
- (c == ' ' || c == '.')) ||
- (c == '.' &&
- ((!nodename[i + 1] ||
- (cr_or_whitespace (nodename[i + 1])) ||
- (nodename[i + 1] == ')')))))
- break;
- }
- nodename[i] = 0;
-}
-
-void
-cm_menu ()
-{
- if (current_node == (char *)NULL)
- {
- warning (_("%cmenu seen before first node"), COMMAND_PREFIX);
- warning (_("creating `Top' node"));
- execute_string ("@node Top");
+ free (string);
}
- begin_insertion (menu);
-}
-
-void
-cm_detailmenu ()
-{
- if (current_node == (char *)NULL)
- {
- warning (_("%cmenu seen before first node"), COMMAND_PREFIX);
- warning (_("creating `Top' node"));
- execute_string ("@node Top");
- }
- begin_insertion (detailmenu);
-}
-
-/* **************************************************************** */
-/* */
-/* Cross Reference Hacking */
-/* */
-/* **************************************************************** */
-
-/* Return next comma-delimited argument, but do not cross a close-brace
- boundary. Clean up whitespace, too. */
-char *
-get_xref_token ()
-{
- char *string;
get_until_in_braces (",", &string);
if (curchar () == ',')
input_text_offset++;
fix_whitespace (string);
- return (string);
+ return string;
}
-int px_ref_flag = 0; /* Controls initial output string. */
+/* NOTE: If you wonder why the HTML output is produced with such a
+ peculiar mix of calls to add_word and execute_string, here's the
+ reason. get_xref_token (1) expands all macros in a reference, but
+ any other commands, like @value, @@, etc., are left intact. To
+ expand them, we need to run the arguments through execute_string.
+ However, characters like <, &, > and others cannot be let into
+ execute_string, because they will be escaped. See the mess? */
/* Make a cross reference. */
void
@@ -5712,15 +2694,20 @@ cm_xref (arg)
{
if (arg == START)
{
- char *arg1, *arg2, *arg3, *arg4, *arg5;
-
- arg1 = get_xref_token ();
- arg2 = get_xref_token ();
- arg3 = get_xref_token ();
- arg4 = get_xref_token ();
- arg5 = get_xref_token ();
+ char *arg1 = get_xref_token (1); /* expands all macros in xref */
+ char *arg2 = get_xref_token (0);
+ char *arg3 = get_xref_token (0);
+ char *arg4 = get_xref_token (0);
+ char *arg5 = get_xref_token (0);
+ char *tem;
- add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
+ if (html)
+ {
+ if (!ref_flag)
+ add_word_args ("%s", px_ref_flag ? _("see ") : _("See "));
+ }
+ else
+ add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
if (*arg5 || *arg4)
{
@@ -5736,7 +2723,30 @@ cm_xref (arg)
else
node_name = arg2;
- execute_string ("%s: (%s)%s", node_name, arg4, arg1);
+ if (html)
+ {
+ /* html fixxme: revisit this; external node name not
+ much use to us with numbered nodes. */
+ add_word ("<a href=");
+ execute_string ("\"%s.html#", arg4);
+ /* Do not collapse -- to -, etc., in references. */
+ in_fixed_width_font++;
+ tem = expansion (node_name, 0);
+ in_fixed_width_font--;
+ add_escaped_anchor_name (tem);
+ free (tem);
+ add_word ("\">");
+ execute_string ("%s", arg1);
+ add_word ("</a>");
+ }
+ else
+ {
+ execute_string ("%s:", node_name);
+ in_fixed_width_font++;
+ execute_string (" (%s)%s%s", arg4, arg1, px_ref_flag ? "." : "");
+ in_fixed_width_font--;
+ }
+
/* Free all of the arguments found. */
if (arg1) free (arg1);
if (arg2) free (arg2);
@@ -5750,17 +2760,56 @@ cm_xref (arg)
if (*arg3)
{
- if (!*arg2)
- execute_string ("%s: %s", arg3, arg1);
+ if (html)
+ {
+ add_word ("<a href=\"");
+ in_fixed_width_font++;
+ tem = expansion (arg1, 0);
+ in_fixed_width_font--;
+ add_anchor_name (tem, 1);
+ free (tem);
+ add_word ("\">");
+ execute_string ("%s", *arg2 ? arg2 : arg3);
+ add_word ("</a>");
+ }
else
- execute_string ("%s: %s", arg2, arg1);
+ {
+ execute_string ("%s:", *arg2 ? arg2 : arg3);
+ in_fixed_width_font++;
+ execute_string (" %s%s", arg1, px_ref_flag ? "." : "");
+ in_fixed_width_font--;
+ }
}
else
{
- if (*arg2)
- execute_string ("%s: %s", arg2, arg1);
+ if (html)
+ {
+ add_word ("<a href=\"");
+ in_fixed_width_font++;
+ tem = expansion (arg1, 0);
+ in_fixed_width_font--;
+ add_anchor_name (tem, 1);
+ free (tem);
+ add_word ("\">");
+ execute_string ("%s", *arg2 ? arg2 : arg1);
+ add_word ("</a>");
+ }
else
- execute_string ("%s::", arg1);
+ {
+ if (*arg2)
+ {
+ execute_string ("%s:", arg2);
+ in_fixed_width_font++;
+ execute_string (" %s%s", arg1, px_ref_flag ? "." : "");
+ in_fixed_width_font--;
+ }
+ else
+ {
+ in_fixed_width_font++;
+ execute_string ("%s::", arg1);
+ in_fixed_width_font--;
+ }
+ }
}
/* Free all of the arguments found. */
@@ -5771,29 +2820,21 @@ cm_xref (arg)
if (arg5) free (arg5);
}
else
- {
- /* Check to make sure that the next non-whitespace character is either
- a period or a comma. input_text_offset is pointing at the "}" which
- ended the xref or pxref command. */
- int temp = input_text_offset + 1;
+ { /* Check to make sure that the next non-whitespace character is
+ valid to follow an xref (so info readers can find the node
+ names). `input_text_offset' is pointing at the "}" which ended
+ the xref or ref command. */
+ int temp;
- if (output_paragraph[output_paragraph_offset - 2] == ':' &&
- output_paragraph[output_paragraph_offset - 1] == ':')
- return;
- while (temp < size_of_input_text)
+ for (temp = input_text_offset + 1; temp < input_text_length; )
{
if (cr_or_whitespace (input_text[temp]))
temp++;
else
{
- if (input_text[temp] != '.'
- && input_text[temp] != ','
- && input_text[temp] != '\t')
- {
- line_error (
- _("`.' or `,' must follow cross reference, not %c"),
- input_text[temp]);
- }
+ if (input_text[temp] != '.' && input_text[temp] != ',')
+ warning (_("`.' or `,' must follow cross reference, not %c"),
+ input_text[temp]);
break;
}
}
@@ -5810,8 +2851,22 @@ cm_pxref (arg)
cm_xref (arg);
px_ref_flag--;
}
- else
- add_char ('.');
+ /* Note that cm_xref isn't called with arg == END, which disables
+ the code near the end of cm_xref that checks for `.' or `,'
+ after the cross-reference. This is because @pxref{} generates
+ the required character itself, when needed. */
+}
+
+void
+cm_ref (arg)
+ int arg;
+{
+ if (arg == START)
+ {
+ ref_flag++;
+ cm_xref (arg);
+ ref_flag--;
+ }
}
void
@@ -5820,14 +2875,27 @@ cm_inforef (arg)
{
if (arg == START)
{
- char *node = get_xref_token ();
- char *pname = get_xref_token ();
- char *file = get_xref_token ();
+ char *node = get_xref_token (1); /* expands all macros in inforef */
+ char *pname = get_xref_token (0);
+ char *file = get_xref_token (0);
- if (*pname)
- execute_string ("*note %s: (%s)%s", pname, file, node);
+ if (html)
+ {
+ add_word (_("see "));
+ /* html fixxme: revisit this */
+ add_word ("<a href=");
+ execute_string ("\"%s.html\"", file);
+ add_word (">");
+ execute_string ("%s", pname);
+ add_word ("</a>");
+ }
else
- execute_string ("*note (%s)%s::", file, node);
+ {
+ if (*pname)
+ execute_string ("*note %s: (%s)%s", pname, file, node);
+ else
+ execute_string ("*note (%s)%s::", file, node);
+ }
free (node);
free (pname);
@@ -5837,76 +2905,88 @@ cm_inforef (arg)
/* A URL reference. */
void
-cm_uref (arg, start_pos, end_pos)
- int arg, start_pos, end_pos;
+cm_uref (arg)
+ int arg;
{
- if (arg == END)
+ if (arg == START)
{
- char *comma;
- char *arg = (char *) &output_paragraph[start_pos];
-
- output_paragraph[end_pos] = 0;
- output_column -= end_pos - start_pos;
- output_paragraph_offset = start_pos;
-
- arg = xstrdup (arg);
- comma = strchr (arg, ','); /* let's hope for no commas in the url */
- if (comma)
- {
- *comma = 0;
- /* Ignore spaces at beginning of second arg. */
- for (comma++; isspace (*comma); comma++)
- ;
- add_word (comma);
- add_char (' ');
- add_char ('(');
- add_word (arg);
- add_char (')');
- }
- else
- {
- extern int printing_index;
-
- if (!printing_index)
- add_char ('`');
-
- add_word (arg);
-
- if (!printing_index)
- add_char ('\'');
- }
- free (arg);
- }
+ extern int printing_index;
+ char *url = get_xref_token (1); /* expands all macros in uref */
+ char *desc = get_xref_token (0);
+ char *replacement = get_xref_token (0);
+
+ if (html)
+ { /* never need to show the url */
+ add_word ("<a href=");
+ /* don't collapse `--' etc. in the url */
+ in_fixed_width_font++;
+ execute_string ("\"%s\"", url);
+ in_fixed_width_font--;
+ add_word (">");
+ execute_string ("%s", *replacement ? replacement
+ : (*desc ? desc : url));
+ add_word ("</a>");
+ }
+ else if (*replacement) /* do not show the url */
+ execute_string ("%s", replacement);
+ else if (*desc) /* show both text and url */
+ {
+ execute_string ("%s ", desc);
+ in_fixed_width_font++;
+ execute_string ("(%s)", url);
+ in_fixed_width_font--;
+ }
+ else /* no text at all, so have the url to show */
+ {
+ in_fixed_width_font++;
+ execute_string ("%s%s%s",
+ printing_index ? "" : "`",
+ url,
+ printing_index ? "" : "'");
+ in_fixed_width_font--;
+ }
+ if (url)
+ free (url);
+ if (desc)
+ free (desc);
+ if (replacement)
+ free (replacement);
+ }
}
/* An email reference. */
void
-cm_email (arg, start_pos, end_pos)
- int arg, start_pos, end_pos;
+cm_email (arg)
+ int arg;
{
- if (arg == END)
+ if (arg == START)
{
- char *comma;
- char *arg = (char *) &output_paragraph[start_pos];
+ char *addr = get_xref_token (1); /* expands all macros in email */
+ char *name = get_xref_token (0);
- output_paragraph[end_pos] = 0;
- output_column -= end_pos - start_pos;
- output_paragraph_offset = start_pos;
-
- arg = xstrdup (arg);
- comma = strchr (arg, ',');
- if (comma)
+ if (html)
+ {
+ add_word ("<a href=");
+ /* don't collapse `--' etc. in the address */
+ in_fixed_width_font++;
+ execute_string ("\"mailto:%s\"", addr);
+ in_fixed_width_font--;
+ add_word (">");
+ execute_string ("%s", *name ? name : addr);
+ add_word ("</a>");
+ }
+ else
{
- *comma = 0;
- for (comma++; isspace (*comma); comma++)
- ;
- add_word (comma);
- add_char (' ');
+ execute_string ("%s%s", name, *name ? " " : "");
+ in_fixed_width_font++;
+ execute_string ("<%s>", addr);
+ in_fixed_width_font--;
}
- add_char ('<');
- add_word (arg);
- add_char ('>');
- free (arg);
+
+ if (addr)
+ free (addr);
+ if (name)
+ free (name);
}
}
@@ -5916,264 +2996,84 @@ void
cm_image (arg)
int arg;
{
- if (arg == START)
+ char *name_arg, *rest;
+
+ if (arg == END)
+ return;
+
+ name_arg = get_xref_token (1); /* expands all macros in image */
+ /* We don't (yet) care about any other args, but read them so they
+ don't end up in the text. */
+ rest = get_xref_token (0);
+ if (rest)
+ free (rest);
+ rest = get_xref_token (0);
+ if (rest)
+ free (rest);
+
+ if (*name_arg)
{
- char *name_arg = get_xref_token ();
- /* We don't yet care about any other args, but read them so they
- don't end up in the text. */
- char *arg = get_xref_token ();
- if (arg) free (arg);
- arg = get_xref_token ();
- if (arg) free (arg);
-
- if (*name_arg)
- {
- /* Try to open foo.txt. */
+ char *fullname = xmalloc (strlen (name_arg) + 4 + 1);
+
+ if (html)
+ { /* fixxme It would be nice to insert more useful alt text. */
+ sprintf (fullname, "%s.png", name_arg);
+ if (access (fullname, R_OK) != 0)
+ {
+ sprintf (fullname, "%s.jpg", name_arg);
+ if (access (fullname, R_OK) != 0)
+ {
+ line_error (_("No .png or .jpg for `%s'"), name_arg);
+ return;
+ }
+ }
+
+ add_word_args ("<img src=\"%s\" alt=\"%s\">", fullname, fullname);
+ }
+ else
+ { /* Try to open foo.txt. */
FILE *image_file;
- char *name = xmalloc (strlen (name_arg) + 4);
- strcpy (name, name_arg);
- strcat (name, ".txt");
- image_file = fopen (name, "r");
+ strcpy (fullname, name_arg);
+ strcat (fullname, ".txt");
+ image_file = fopen (fullname, "r");
if (image_file)
{
int ch;
int save_inhibit_indentation = inhibit_paragraph_indentation;
int save_filling_enabled = filling_enabled;
-
+
inhibit_paragraph_indentation = 1;
filling_enabled = 0;
last_char_was_newline = 0;
-
+
/* Maybe we need to remove the final newline if the image
file is only one line to allow in-line images. On the
other hand, they could just make the file without a
final newline. */
while ((ch = getc (image_file)) != EOF)
add_char (ch);
-
+
inhibit_paragraph_indentation = save_inhibit_indentation;
filling_enabled = save_filling_enabled;
-
- if (fclose (image_file) != 0) {
- perror (name);
- }
+
+ if (fclose (image_file) != 0)
+ perror (fullname);
}
else
- warning (_("@image file `%s' unreadable: %s"), name,
- strerror (errno));
+ warning (_("@image file `%s' unreadable: %s"), fullname,
+ strerror (errno));
}
- else
- line_error (_("@image missing filename argument"));
- if (name_arg) free (name_arg);
+ free (fullname);
}
-}
-
-/* **************************************************************** */
-/* */
-/* Insertion Command Stubs */
-/* */
-/* **************************************************************** */
-
-void
-cm_quotation ()
-{
- begin_insertion (quotation);
-}
-
-void
-cm_example ()
-{
- begin_insertion (example);
-}
-
-void
-cm_smallexample ()
-{
- begin_insertion (smallexample);
-}
-
-void
-cm_lisp ()
-{
- begin_insertion (lisp);
-}
-
-void
-cm_smalllisp ()
-{
- begin_insertion (smalllisp);
-}
-
-/* @cartouche/@end cartouche draws box with rounded corners in
- TeX output. Right now, just a no-op insertion. */
-void
-cm_cartouche ()
-{
- begin_insertion (cartouche);
-}
-
-void
-cm_format ()
-{
- begin_insertion (format);
-}
-
-void
-cm_display ()
-{
- begin_insertion (display);
-}
-
-void
-cm_direntry ()
-{
- if (no_headers)
- command_name_condition ();
else
- begin_insertion (direntry);
-}
-
-void
-cm_itemize ()
-{
- begin_insertion (itemize);
-}
+ line_error (_("@image missing filename argument"));
-void
-cm_enumerate ()
-{
- do_enumeration (enumerate, "1");
-}
-
-/* Start an enumeration insertion of type TYPE. If the user supplied
- no argument on the line, then use DEFAULT_STRING as the initial string. */
-void
-do_enumeration (type, default_string)
- int type;
- char *default_string;
-{
- get_until_in_line (0, ".", &enumeration_arg);
- canon_white (enumeration_arg);
-
- if (!*enumeration_arg)
- {
- free (enumeration_arg);
- enumeration_arg = xstrdup (default_string);
- }
-
- if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
- {
- warning (_("%s requires letter or digit"), insertion_type_pname (type));
-
- switch (type)
- {
- case enumerate:
- default_string = "1";
- break;
- }
- enumeration_arg = xstrdup (default_string);
- }
- begin_insertion (type);
-}
-
-void
-cm_table ()
-{
- begin_insertion (table);
-}
-
-void
-cm_multitable ()
-{
- begin_insertion (multitable); /* @@ */
-}
-
-void
-cm_ftable ()
-{
- begin_insertion (ftable);
-}
-
-void
-cm_vtable ()
-{
- begin_insertion (vtable);
-}
-
-void
-cm_group ()
-{
- begin_insertion (group);
-}
-
-void
-cm_ifinfo ()
-{
- begin_insertion (ifinfo);
-}
-
-void
-cm_ifnothtml ()
-{
- begin_insertion (ifnothtml);
-}
-
-void
-cm_ifnottex ()
-{
- begin_insertion (ifnottex);
-}
-
-/* Begin an insertion where the lines are not filled or indented. */
-void
-cm_flushleft ()
-{
- begin_insertion (flushleft);
-}
-
-/* Begin an insertion where the lines are not filled, and each line is
- forced to the right-hand side of the page. */
-void
-cm_flushright ()
-{
- begin_insertion (flushright);
-}
-
-/* End existing insertion block. */
-void
-cm_end ()
-{
- char *temp;
- enum insertion_type type;
-
- if (!insertion_level)
- {
- line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command);
- return;
- }
-
- get_rest_of_line (&temp);
-
- if (temp[0] == 0)
- line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command);
-
- type = find_type_from_name (temp);
-
- if (type == bad_type)
- {
- line_error (_("Bad argument to `%s', `%s', using `%s'"),
- command, temp, insertion_type_pname (current_insertion_type ()));
- }
- end_insertion (type);
- free (temp);
+ if (name_arg)
+ free (name_arg);
}
-/* **************************************************************** */
-/* */
-/* Conditional Handling */
-/* */
-/* **************************************************************** */
+/* Conditionals. */
/* A structure which contains `defined' variables. */
typedef struct defines {
@@ -6183,7 +3083,7 @@ typedef struct defines {
} DEFINE;
/* The linked list of `set' defines. */
-DEFINE *defines = (DEFINE *)NULL;
+DEFINE *defines = NULL;
/* Add NAME to the list of `set' defines. */
void
@@ -6201,7 +3101,7 @@ set (name, value)
return;
}
- temp = (DEFINE *)xmalloc (sizeof (DEFINE));
+ temp = xmalloc (sizeof (DEFINE));
temp->next = defines;
temp->name = xstrdup (name);
temp->value = xstrdup (value);
@@ -6213,9 +3113,9 @@ void
clear (name)
char *name;
{
- register DEFINE *temp, *last;
+ DEFINE *temp, *last;
- last = (DEFINE *)NULL;
+ last = NULL;
temp = defines;
while (temp)
@@ -6242,28 +3142,13 @@ char *
set_p (name)
char *name;
{
- register DEFINE *temp;
+ DEFINE *temp;
for (temp = defines; temp; temp = temp->next)
if (strcmp (temp->name, name) == 0)
- return (temp->value);
+ return temp->value;
- return ((char *)NULL);
-}
-
-/* Conditionally parse based on the current command name. */
-void
-command_name_condition ()
-{
- char *discarder;
-
- discarder = (char *)xmalloc (8 + strlen (command));
-
- sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
- discard_until (discarder);
- discard_until ("\n");
-
- free (discarder);
+ return NULL;
}
/* Create a variable whose name appears as the first word on this line. */
@@ -6310,7 +3195,7 @@ cm_ifeq ()
if (array_len (arglist) > 1)
{
if ((strcasecmp (arglist[0], arglist[1]) == 0) &&
- (arglist[2] != (char *)NULL))
+ (arglist[2]))
execute_string ("%s\n", arglist[2]);
}
@@ -6322,7 +3207,27 @@ void
cm_value (arg, start_pos, end_pos)
int arg, start_pos, end_pos;
{
- if (arg == END)
+ static int value_level = 0, saved_meta_pos = -1;
+
+ /* All the text after @value{ upto the matching } will eventually
+ disappear from output_paragraph, when this function is called
+ with ARG == END. If the text produced until then sets
+ meta_char_pos, we will need to restore it to the value it had
+ before @value was seen. So we need to save the previous value
+ of meta_char_pos here. */
+ if (arg == START)
+ {
+ /* If we are already inside some outer @value, don't overwrite
+ the value saved in saved_meta_pos. */
+ if (!value_level)
+ saved_meta_pos = meta_char_pos;
+ value_level++;
+ /* While the argument of @value is processed, we need to inhibit
+ textual transformations like "--" into "-", since @set didn't
+ do that when it grabbed the name of the variable. */
+ in_fixed_width_font++;
+ }
+ else
{
char *name = (char *) &output_paragraph[start_pos];
char *value;
@@ -6332,10 +3237,26 @@ cm_value (arg, start_pos, end_pos)
output_column -= end_pos - start_pos;
output_paragraph_offset = start_pos;
+ /* Restore the previous value of meta_char_pos if the stuff
+ inside this @value{} moved it. */
+ if (saved_meta_pos == -1) /* can't happen inside @value{} */
+ abort ();
+ if (value_level == 1
+ && meta_char_pos >= start_pos && meta_char_pos < end_pos)
+ {
+ meta_char_pos = saved_meta_pos;
+ saved_meta_pos = -1;
+ }
+ value_level--;
+ /* No need to decrement in_fixed_width_font, since before
+ we are called with arg == END, the reader loop already
+ popped the brace stack, which restored in_fixed_width_font,
+ among other things. */
+
if (value)
execute_string ("%s", value);
else
- add_word_args (_("{No Value For \"%s\"}"), name);
+ add_word_args (_("{No value for `%s'}"), name);
free (name);
}
@@ -6348,8 +3269,12 @@ handle_variable (action)
{
char *name;
- get_rest_of_line (&name);
- backup_input_pointer ();
+ get_rest_of_line (0, &name);
+ /* If we hit the end of text in get_rest_of_line, backing up
+ input pointer will cause the last character of the last line
+ be pushed back onto the input, which is wrong. */
+ if (input_text_offset < input_text_length)
+ backup_input_pointer ();
handle_variable_internal (action, name);
free (name);
}
@@ -6452,11 +3377,11 @@ handle_variable_internal (action, name)
{
int level = 0, done = 0;
- while (!done && input_text_offset < size_of_input_text)
+ while (!done && input_text_offset < input_text_length)
{
char *freeable_line, *line;
- get_rest_of_line (&freeable_line);
+ get_rest_of_line (0, &freeable_line);
for (line = freeable_line; whitespace (*line); line++);
@@ -6488,7 +3413,7 @@ handle_variable_internal (action, name)
}
free (freeable_line);
}
-
+
if (!done)
{
int save = line_number;
@@ -6497,7 +3422,7 @@ handle_variable_internal (action, name)
condition);
line_number = save;
}
-
+
/* We found the end of a false @ifset/ifclear. If we are
in a menu, back up over the newline that ends the ifset,
since that newline may also begin the next menu entry. */
@@ -6524,7 +3449,7 @@ typedef struct {
int in_use; /* Nonzero means string currently in use. */
} EXECUTION_STRING;
-static EXECUTION_STRING **execution_strings = (EXECUTION_STRING **)NULL;
+static EXECUTION_STRING **execution_strings = NULL;
static int execution_strings_index = 0;
static int execution_strings_slots = 0;
@@ -6532,8 +3457,8 @@ EXECUTION_STRING *
get_execution_string (initial_size)
int initial_size;
{
- register int i = 0;
- EXECUTION_STRING *es = (EXECUTION_STRING *)NULL;
+ int i = 0;
+ EXECUTION_STRING *es = NULL;
if (execution_strings)
{
@@ -6549,29 +3474,64 @@ get_execution_string (initial_size)
{
if (execution_strings_index + 1 >= execution_strings_slots)
{
- execution_strings = (EXECUTION_STRING **)xrealloc
+ execution_strings = xrealloc
(execution_strings,
(execution_strings_slots += 3) * sizeof (EXECUTION_STRING *));
for (; i < execution_strings_slots; i++)
- execution_strings[i] = (EXECUTION_STRING *)NULL;
+ execution_strings[i] = NULL;
}
execution_strings[execution_strings_index] =
- (EXECUTION_STRING *)xmalloc (sizeof (EXECUTION_STRING));
+ xmalloc (sizeof (EXECUTION_STRING));
es = execution_strings[execution_strings_index];
execution_strings_index++;
es->size = 0;
- es->string = (char *)NULL;
+ es->string = NULL;
es->in_use = 0;
}
if (initial_size > es->size)
{
- es->string = (char *) xrealloc (es->string, initial_size);
+ es->string = xrealloc (es->string, initial_size);
es->size = initial_size;
}
- return (es);
+ return es;
+}
+
+/* Given a pointer to TEXT and its desired length NEW_LEN, find TEXT's
+ entry in the execution_strings[] array and change the .STRING and
+ .SIZE members of that entry as appropriate. */
+void
+maybe_update_execution_strings (text, new_len)
+ char **text;
+ unsigned new_len;
+{
+ int i = 0;
+
+ if (execution_strings)
+ {
+ for (i = 0; i < execution_strings_index; i++)
+ if (execution_strings[i] && (execution_strings[i]->in_use == 1) &&
+ execution_strings[i]->string == *text)
+ {
+ /* Don't ever shrink the string storage in execution_strings[]!
+ execute_string assumes that it is always big enough to store
+ every possible execution_string, and will break if that's
+ not true. So we only enlarge the string storage if the
+ current size isn't big enough. */
+ if (execution_strings[i]->size < new_len)
+ {
+ execution_strings[i]->string =
+ *text = xrealloc (*text, new_len + 1);
+ execution_strings[i]->size = new_len + 1;
+ }
+ return;
+ }
+ }
+ /* We should *never* end up here, since if we are inside
+ execute_string, TEXT is always in execution_strings[]. */
+ abort ();
}
/* Execute the string produced by formatting the ARGs with FORMAT. This
@@ -6607,7 +3567,7 @@ execute_string (format, va_alist)
input_text_offset = 0;
input_text = temp_string;
input_filename = xstrdup (input_filename);
- size_of_input_text = strlen (temp_string);
+ input_text_length = strlen (temp_string);
executing_string++;
reader_loop ();
@@ -6619,8 +3579,8 @@ execute_string (format, va_alist)
}
-/* Return what would be output for STR, i.e., expand Texinfo commands.
- If IMPLICIT_CODE is set, expand @code{STR}. */
+/* Return what would be output for STR (in newly-malloced memory), i.e.,
+ expand Texinfo commands. If IMPLICIT_CODE is set, expand @code{STR}. */
char *
expansion (str, implicit_code)
@@ -6633,6 +3593,29 @@ expansion (str, implicit_code)
/* Inhibit any real output. */
int start = output_paragraph_offset;
int saved_paragraph_is_open = paragraph_is_open;
+ int saved_output_column = output_column;
+
+ /* Inhibit indentation and filling, so that extra newlines
+ are not added to the expansion. (This is undesirable if
+ we write the expanded text to macro_expansion_output_stream.) */
+ int saved_filling_enabled = filling_enabled;
+ int saved_indented_fill = indented_fill;
+ int saved_no_indent = no_indent;
+ int saved_escape_html = escape_html;
+ int saved_meta_pos = meta_char_pos;
+ int saved_last_char = last_inserted_character;
+ int saved_last_nl = last_char_was_newline;
+
+ /* If we are called in the middle of processing a command, we need
+ to dup and save the global variable `command' (which holds the
+ name of this command), since the recursive reader loop will free
+ it from under our feet if it finds any macros in STR. */
+ char *saved_command = command ? xstrdup (command) : NULL;
+
+ filling_enabled = 0;
+ indented_fill = 0;
+ no_indent = 1;
+ escape_html = 0;
inhibit_output_flushing ();
paragraph_is_open = 1;
@@ -6644,998 +3627,43 @@ expansion (str, implicit_code)
result = xmalloc (1 + length);
memcpy (result, (char *) (output_paragraph + start), length);
result[length] = 0;
-
+
/* Pretend it never happened. */
+ free_and_clear (&command);
+ command = saved_command;
output_paragraph_offset = start;
paragraph_is_open = saved_paragraph_is_open;
+ output_column = saved_output_column;
+ filling_enabled = saved_filling_enabled;
+ indented_fill = saved_indented_fill;
+ no_indent = saved_no_indent;
+ escape_html = saved_escape_html;
+ meta_char_pos = saved_meta_pos;
+ last_inserted_character = saved_last_char;
+ last_char_was_newline = saved_last_nl;
return result;
}
-
-/* @itemx, @item. */
-
-static int itemx_flag = 0;
-
-void
-cm_itemx ()
-{
- itemx_flag++;
- cm_item ();
- itemx_flag--;
-}
-
-void
-cm_item ()
-{
- char *rest_of_line, *item_func;
-
- /* Can only hack "@item" while inside of an insertion. */
- if (insertion_level)
- {
- INSERTION_ELT *stack = insertion_stack;
- int original_input_text_offset;
-
- skip_whitespace ();
- original_input_text_offset = input_text_offset;
-
- get_rest_of_line (&rest_of_line);
- item_func = current_item_function ();
-
- /* Okay, do the right thing depending on which insertion function
- is active. */
-
- switch_top:
- switch (stack->insertion)
- {
- case multitable:
- multitable_item ();
- /* Ultra special hack. It appears that some people incorrectly
- place text directly after the @item, instead of on a new line
- by itself. This happens to work in TeX, so I make it work
- here. */
- if (*rest_of_line)
- {
- line_number--;
- input_text_offset = original_input_text_offset;
- }
- break;
-
- case ifinfo:
- case ifset:
- case ifclear:
- case cartouche:
- stack = stack->next;
- if (!stack)
- goto no_insertion;
- else
- goto switch_top;
- break;
-
- case menu:
- case quotation:
- case example:
- case smallexample:
- case lisp:
- case format:
- case display:
- case group:
- line_error (_("The `%c%s' command is meaningless within a `@%s' block"),
- COMMAND_PREFIX, command,
- insertion_type_pname (current_insertion_type ()));
- break;
-
- case itemize:
- case enumerate:
- if (itemx_flag)
- {
- line_error (_("%citemx is not meaningful inside of a `%s' block"),
- COMMAND_PREFIX,
- insertion_type_pname (current_insertion_type ()));
- }
- else
- {
- start_paragraph ();
- kill_self_indent (-1);
- filling_enabled = indented_fill = 1;
-
- if (current_insertion_type () == itemize)
- {
- indent (output_column = current_indent - 2);
-
- /* I need some way to determine whether this command
- takes braces or not. I believe the user can type
- either "@bullet" or "@bullet{}". Of course, they
- can also type "o" or "#" or whatever else they want. */
- if (item_func && *item_func)
- {
- if (*item_func == COMMAND_PREFIX)
- if (item_func[strlen (item_func) - 1] != '}')
- execute_string ("%s{}", item_func);
- else
- execute_string ("%s", item_func);
- else
- execute_string ("%s", item_func);
- }
- insert (' ');
- output_column++;
- }
- else
- enumerate_item ();
-
- /* Special hack. This makes `close_paragraph' a no-op until
- `start_paragraph' has been called. */
- must_start_paragraph = 1;
-
- /* Handle text directly after the @item. */
- if (*rest_of_line)
- {
- line_number--;
- input_text_offset = original_input_text_offset;
- }
- }
- break;
-
- case table:
- case ftable:
- case vtable:
- {
- /* We need this to determine if we have two @item's in a row
- (see test just below). */
- static int last_item_output_position = 0;
-
- /* Get rid of extra characters. */
- kill_self_indent (-1);
-
- /* If we have one @item followed directly by another @item,
- we need to insert a blank line. This is not true for
- @itemx, though. */
- if (!itemx_flag && last_item_output_position == output_position)
- insert ('\n');
-
- /* `close_paragraph' almost does what we want. The problem
- is when paragraph_is_open, and last_char_was_newline, and
- the last newline has been turned into a space, because
- filling_enabled. I handle it here. */
- if (last_char_was_newline && filling_enabled && paragraph_is_open)
- insert ('\n');
- close_paragraph ();
-
-#if defined (INDENT_PARAGRAPHS_IN_TABLE)
- /* Indent on a new line, but back up one indentation level. */
- {
- int save = inhibit_paragraph_indentation;
- inhibit_paragraph_indentation = 1;
- /* At this point, inserting any non-whitespace character will
- force the existing indentation to be output. */
- add_char ('i');
- inhibit_paragraph_indentation = save;
- }
-#else /* !INDENT_PARAGRAPHS_IN_TABLE */
- add_char ('i');
-#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
-
- output_paragraph_offset--;
- kill_self_indent (default_indentation_increment + 1);
-
- /* Add item's argument to the line. */
- filling_enabled = 0;
- if (item_func && *item_func)
- execute_string ("%s{%s}", item_func, rest_of_line);
- else
- execute_string ("%s", rest_of_line);
-
- if (current_insertion_type () == ftable)
- execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line);
- else if (current_insertion_type () == vtable)
- execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line);
-
- /* Start a new line, and let start_paragraph ()
- do the indenting of it for you. */
- close_single_paragraph ();
- indented_fill = filling_enabled = 1;
- last_item_output_position = output_position;
- }
- }
- free (rest_of_line);
- }
- else
- {
- no_insertion:
- line_error (_("%c%s found outside of an insertion block"),
- COMMAND_PREFIX, command);
- }
-}
-
-/* **************************************************************** */
-/* */
-/* Defun and Friends */
-/* */
-/* **************************************************************** */
-
-#define DEFUN_SELF_DELIMITING(c) \
- (((c) == '(') \
- || ((c) == ')') \
- || ((c) == '[') \
- || ((c) == ']'))
-
-struct token_accumulator
-{
- unsigned int length;
- unsigned int index;
- char **tokens;
-};
-
-void
-initialize_token_accumulator (accumulator)
- struct token_accumulator *accumulator;
-{
- (accumulator->length) = 0;
- (accumulator->index) = 0;
- (accumulator->tokens) = NULL;
-}
-
-void
-accumulate_token (accumulator, token)
- struct token_accumulator *accumulator;
- char *token;
-{
- if ((accumulator->index) >= (accumulator->length))
- {
- (accumulator->length) += 10;
- (accumulator->tokens) = (char **) xrealloc
- (accumulator->tokens, (accumulator->length * sizeof (char *)));
- }
- accumulator->tokens[accumulator->index] = token;
- accumulator->index += 1;
-}
-
-char *
-copy_substring (start, end)
- char *start;
- char *end;
-{
- char *result, *scan, *scan_result;
-
- result = (char *) xmalloc ((end - start) + 1);
- scan_result = result;
- scan = start;
-
- while (scan < end)
- *scan_result++ = *scan++;
-
- *scan_result = 0;
- return (result);
-}
-/* Given `string' pointing at an open brace, skip forward and return a
- pointer to just past the matching close brace. */
-int
-scan_group_in_string (string_pointer)
- char **string_pointer;
-{
- register int c;
- register char *scan_string;
- register unsigned int level = 1;
-
- scan_string = (*string_pointer) + 1;
-
- while (1)
- {
- if (level == 0)
- {
- (*string_pointer) = scan_string;
- return (1);
- }
- c = (*scan_string++);
- if (c == 0)
- {
- /* Tweak line_number to compensate for fact that
- we gobbled the whole line before coming here. */
- line_number -= 1;
- line_error (_("Missing `}' in %cdef arg"), COMMAND_PREFIX);
- line_number += 1;
- (*string_pointer) = (scan_string - 1);
- return (0);
- }
- if (c == '{')
- level += 1;
- if (c == '}')
- level -= 1;
- }
-}
-/* Return a list of tokens from the contents of `string'.
- Commands and brace-delimited groups count as single tokens.
- Contiguous whitespace characters are converted to a token
- consisting of a single space. */
-char **
-args_from_string (string)
- char *string;
-{
- struct token_accumulator accumulator;
- register char *scan_string = string;
- char *token_start, *token_end;
-
- initialize_token_accumulator (&accumulator);
-
- while ((*scan_string) != 0)
- {
- /* Replace arbitrary whitespace by a single space. */
- if (whitespace (*scan_string))
- {
- scan_string += 1;
- while (whitespace (*scan_string))
- scan_string += 1;
- accumulate_token ((&accumulator), (xstrdup (" ")));
- continue;
- }
-
- /* Commands count as single tokens. */
- if ((*scan_string) == COMMAND_PREFIX)
- {
- token_start = scan_string;
- scan_string += 1;
- if (self_delimiting (*scan_string))
- scan_string += 1;
- else
- {
- register int c;
- while (1)
- {
- c = *scan_string++;
-
- if ((c == 0) || (c == '{') || (whitespace (c)))
- {
- scan_string -= 1;
- break;
- }
- }
-
- if (*scan_string == '{')
- {
- char *s = scan_string;
- (void) scan_group_in_string (&s);
- scan_string = s;
- }
- }
- token_end = scan_string;
- }
-
- /* Parentheses and brackets are self-delimiting. */
- else if (DEFUN_SELF_DELIMITING (*scan_string))
- {
- token_start = scan_string;
- scan_string += 1;
- token_end = scan_string;
- }
-
- /* Open brace introduces a group that is a single token. */
- else if (*scan_string == '{')
- {
- char *s = scan_string;
- int balanced = scan_group_in_string (&s);
-
- token_start = scan_string + 1;
- scan_string = s;
- token_end = balanced ? (scan_string - 1) : scan_string;
- }
-
- /* Otherwise a token is delimited by whitespace, parentheses,
- brackets, or braces. A token is also ended by a command. */
- else
- {
- token_start = scan_string;
-
- while (1)
- {
- register int c;
-
- c = *scan_string++;
-
- /* Do not back up if we're looking at a }; since the only
- valid }'s are those matched with {'s, we want to give
- an error. If we back up, we go into an infinite loop. */
- if (!c || whitespace (c) || DEFUN_SELF_DELIMITING (c)
- || c == '{')
- {
- scan_string--;
- break;
- }
-
- /* If we encounter a command embedded within a token,
- then end the token. */
- if (c == COMMAND_PREFIX)
- {
- scan_string--;
- break;
- }
- }
- token_end = scan_string;
- }
-
- accumulate_token
- (&accumulator, copy_substring (token_start, token_end));
- }
- accumulate_token (&accumulator, NULL);
- return (accumulator.tokens);
-}
-
-void
-process_defun_args (defun_args, auto_var_p)
- char **defun_args;
- int auto_var_p;
-{
- int pending_space = 0;
-
- while (1)
- {
- char *defun_arg = *defun_args++;
-
- if (defun_arg == NULL)
- break;
-
- if (defun_arg[0] == ' ')
- {
- pending_space = 1;
- continue;
- }
-
- if (pending_space)
- {
- add_char (' ');
- pending_space = 0;
- }
-
- if (DEFUN_SELF_DELIMITING (defun_arg[0]))
- add_char (defun_arg[0]);
- else if (defun_arg[0] == '&')
- add_word (defun_arg);
- else if (defun_arg[0] == COMMAND_PREFIX)
- execute_string ("%s", defun_arg);
- else if (auto_var_p)
- execute_string ("%cvar{%s}", COMMAND_PREFIX, defun_arg);
- else
- add_word (defun_arg);
- }
-}
+/* Return text (info) expansion of STR no matter what the current output
+ format is. */
char *
-next_nonwhite_defun_arg (arg_pointer)
- char ***arg_pointer;
-{
- char **scan = (*arg_pointer);
- char *arg = (*scan++);
-
- if ((arg != 0) && (*arg == ' '))
- arg = *scan++;
-
- if (arg == 0)
- scan -= 1;
-
- *arg_pointer = scan;
-
- return ((arg == 0) ? "" : arg);
-}
-
-/* Make the defun type insertion.
- TYPE says which insertion this is.
- X_P, if nonzero, says not to start a new insertion. */
-void
-defun_internal (type, x_p)
- enum insertion_type type;
- int x_p;
+text_expansion (str)
+ char *str;
{
- enum insertion_type base_type;
- char **defun_args, **scan_args;
- char *category, *defined_name, *type_name, *type_name2;
-
- {
- char *line;
- get_rest_of_line (&line);
- defun_args = (args_from_string (line));
- free (line);
- }
-
- scan_args = defun_args;
-
- switch (type)
- {
- case defun:
- category = _("Function");
- base_type = deffn;
- break;
- case defmac:
- category = _("Macro");
- base_type = deffn;
- break;
- case defspec:
- category = _("Special Form");
- base_type = deffn;
- break;
- case defvar:
- category = _("Variable");
- base_type = defvr;
- break;
- case defopt:
- category = _("User Option");
- base_type = defvr;
- break;
- case deftypefun:
- category = _("Function");
- base_type = deftypefn;
- break;
- case deftypevar:
- category = _("Variable");
- base_type = deftypevr;
- break;
- case defivar:
- category = _("Instance Variable");
- base_type = defcv;
- break;
- case defmethod:
- category = _("Method");
- base_type = defop;
- break;
- case deftypemethod:
- category = _("Method");
- base_type = deftypemethod;
- break;
- default:
- category = next_nonwhite_defun_arg (&scan_args);
- base_type = type;
- break;
- }
-
- if ((base_type == deftypefn)
- || (base_type == deftypevr)
- || (base_type == defcv)
- || (base_type == defop)
- || (base_type == deftypemethod))
- type_name = next_nonwhite_defun_arg (&scan_args);
-
- if (base_type == deftypemethod)
- type_name2 = next_nonwhite_defun_arg (&scan_args);
-
- defined_name = next_nonwhite_defun_arg (&scan_args);
-
- /* This hack exists solely for the purposes of formatting the texinfo
- manual. I couldn't think of a better way. The token might be
- a simple @@ followed immediately by more text. If this is the case,
- then the next defun arg is part of this one, and we should concatenate
- them. */
- if (*scan_args && **scan_args && !whitespace (**scan_args) &&
- (strcmp (defined_name, "@@") == 0))
- {
- char *tem = (char *)xmalloc (3 + strlen (scan_args[0]));
-
- sprintf (tem, "@@%s", scan_args[0]);
-
- free (scan_args[0]);
- scan_args[0] = tem;
- scan_args++;
- defined_name = tem;
- }
-
- if (!x_p)
- begin_insertion (type);
-
- /* Write the definition header line.
- This should start at the normal indentation. */
- current_indent -= default_indentation_increment;
- start_paragraph ();
-
- switch (base_type)
- {
- case deffn:
- case defvr:
- case deftp:
- execute_string (" -- %s: %s", category, defined_name);
- break;
- case deftypefn:
- case deftypevr:
- execute_string (" -- %s: %s %s", category, type_name, defined_name);
- break;
- case defcv:
- execute_string (" -- %s of %s: %s", category, type_name, defined_name);
- break;
- case defop:
- execute_string (" -- %s on %s: %s", category, type_name, defined_name);
- break;
- case deftypemethod:
- execute_string (" -- %s on %s: %s %s", category, type_name, type_name2,
- defined_name);
- break;
- }
- current_indent += default_indentation_increment;
-
- /* Now process the function arguments, if any.
- If these carry onto the next line, they should be indented by two
- increments to distinguish them from the body of the definition,
- which is indented by one increment. */
- current_indent += default_indentation_increment;
-
- switch (base_type)
- {
- case deffn:
- case defop:
- process_defun_args (scan_args, 1);
- break;
-
- /* Through Makeinfo 1.67 we processed remaining args only for deftp,
- deftypefn, and deftypemethod. But the libc manual, for example,
- needs to say:
- @deftypevar {char *} tzname[2]
- And simply allowing the extra text seems far simpler than trying
- to invent yet more defn commands. In any case, we should either
- output it or give an error, not silently ignore it. */
- default:
- process_defun_args (scan_args, 0);
- break;
- }
- current_indent -= default_indentation_increment;
- close_single_paragraph ();
-
- /* Make an entry in the appropriate index. */
- switch (base_type)
- {
- case deffn:
- case deftypefn:
- execute_string ("%cfindex %s\n", COMMAND_PREFIX, defined_name);
- break;
- case defvr:
- case deftypevr:
- case defcv:
- execute_string ("%cvindex %s\n", COMMAND_PREFIX, defined_name);
- break;
- case defop:
- case deftypemethod:
- execute_string ("%cfindex %s on %s\n",
- COMMAND_PREFIX, defined_name, type_name);
- break;
- case deftp:
- execute_string ("%ctindex %s\n", COMMAND_PREFIX, defined_name);
- break;
- }
-
- /* Deallocate the token list. */
- scan_args = defun_args;
- while (1)
- {
- char * arg = (*scan_args++);
- if (arg == NULL)
- break;
- free (arg);
- }
- free (defun_args);
+ char *ret;
+ int save_html = html;
+
+ html = 0;
+ ret = expansion (str, 0);
+ html = save_html;
+
+ return ret;
}
-/* Add an entry for a function, macro, special form, variable, or option.
- If the name of the calling command ends in `x', then this is an extra
- entry included in the body of an insertion of the same type. */
-void
-cm_defun ()
-{
- int x_p;
- enum insertion_type type;
- char *temp = xstrdup (command);
-
- x_p = (command[strlen (command) - 1] == 'x');
-
- if (x_p)
- temp[strlen (temp) - 1] = 0;
-
- type = find_type_from_name (temp);
- free (temp);
-
- /* If we are adding to an already existing insertion, then make sure
- that we are already in an insertion of type TYPE. */
- if (x_p &&
- (!insertion_level || insertion_stack->insertion != type))
- {
- line_error (_("Must be in a `%s' insertion in order to use `%s'x"),
- command, command);
- discard_until ("\n");
- return;
- }
-
- defun_internal (type, x_p);
-}
-/* **************************************************************** */
-/* */
-/* Other Random Commands */
-/* */
-/* **************************************************************** */
-
-/* This says to inhibit the indentation of the next paragraph, but
- not of following paragraphs. */
-void
-cm_noindent ()
-{
- if (!inhibit_paragraph_indentation)
- inhibit_paragraph_indentation = -1;
-}
-
-/* I don't know exactly what to do with this. Should I allow
- someone to switch filenames in the middle of output? Since the
- file could be partially written, this doesn't seem to make sense.
- Another option: ignore it, since they don't *really* want to
- switch files. Finally, complain, or at least warn. */
-void
-cm_setfilename ()
-{
- char *filename;
- get_rest_of_line (&filename);
- /* warning ("`@%s %s' encountered and ignored", command, filename); */
- free (filename);
-}
-
-void
-cm_ignore_line ()
-{
- discard_until ("\n");
-}
-
-/* @br can be immediately followed by `{}', so we have to read those here.
- It should simply close the paragraph. */
-void
-cm_br ()
-{
- if (looking_at ("{}"))
- input_text_offset += 2;
-
- if (curchar () == '\n')
- {
- input_text_offset++;
- line_number++;
- }
-
- close_paragraph ();
-}
-
- /* Insert the number of blank lines passed as argument. */
-void
-cm_sp ()
-{
- int lines;
- char *line;
-
- get_rest_of_line (&line);
-
- if (sscanf (line, "%d", &lines) != 1)
- {
- line_error (_("%csp requires a positive numeric argument"), COMMAND_PREFIX);
- }
- else
- {
- if (lines < 0)
- lines = 0;
-
- while (lines--)
- add_char ('\n');
- }
- free (line);
-}
-
-/* @dircategory LINE outputs INFO-DIR-SECTION LINE,
- but not if --no-headers. */
-
-void
-cm_dircategory ()
-{
- char *line;
-
- get_rest_of_line (&line);;
-
- if (!no_headers)
- {
- insert_string ("INFO-DIR-SECTION ");
- insert_string (line);
- insert ('\n');
- }
-
- free (line);
-}
-
-/* Start a new line with just this text on it.
- Then center the line of text.
- This always ends the current paragraph. */
-void
-cm_center ()
-{
- register int i, start, length;
- int fudge_factor = 1;
- unsigned char *line;
-
- close_paragraph ();
- filling_enabled = indented_fill = 0;
- cm_noindent ();
- start = output_paragraph_offset;
- inhibit_output_flushing ();
- get_rest_of_line ((char **)&line);
- execute_string ("%s", (char *)line);
- free (line);
- uninhibit_output_flushing ();
-
- i = output_paragraph_offset - 1;
- while (i > (start - 1) && output_paragraph[i] == '\n')
- i--;
-
- output_paragraph_offset = ++i;
- length = output_paragraph_offset - start;
-
- if (length < (fill_column - fudge_factor))
- {
- line = (unsigned char *)xmalloc (1 + length);
- memcpy (line, (char *)(output_paragraph + start), length);
-
- i = (fill_column - fudge_factor - length) / 2;
- output_paragraph_offset = start;
-
- while (i--)
- insert (' ');
-
- for (i = 0; i < length; i++)
- insert (line[i]);
-
- free (line);
- }
-
- insert ('\n');
- close_paragraph ();
- filling_enabled = 1;
-}
-
-/* Show what an expression returns. */
-void
-cm_result (arg)
- int arg;
-{
- if (arg == END)
- add_word ("=>");
-}
-
-/* What an expression expands to. */
-void
-cm_expansion (arg)
- int arg;
-{
- if (arg == END)
- add_word ("==>");
-}
-
-/* Indicates two expressions are equivalent. */
-void
-cm_equiv (arg)
- int arg;
-{
- if (arg == END)
- add_word ("==");
-}
-
-/* What an expression may print. */
-void
-cm_print (arg)
- int arg;
-{
- if (arg == END)
- add_word ("-|");
-}
-
-/* An error signaled. */
-void
-cm_error (arg)
- int arg;
-{
- if (arg == END)
- add_word ("error-->");
-}
-
-/* The location of point in an example of a buffer. */
-void
-cm_point (arg)
- int arg;
-{
- if (arg == END)
- add_word ("-!-");
-}
-
-/* Start a new line with just this text on it.
- The text is outdented one level if possible. */
-void
-cm_exdent ()
-{
- char *line;
- int i = current_indent;
-
- if (current_indent)
- current_indent -= default_indentation_increment;
-
- get_rest_of_line (&line);
- close_single_paragraph ();
- execute_string ("%s", line);
- current_indent = i;
- free (line);
- close_single_paragraph ();
-}
-
-
-/* Remember this file, and move onto the next. */
-void
-cm_include ()
-{
- char *filename;
-
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- me_append_before_this_command ();
-#endif /* HAVE_MACROS */
-
- close_paragraph ();
- get_rest_of_line (&filename);
-
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- remember_itext (input_text, input_text_offset);
-#endif /* HAVE_MACROS */
-
- pushfile ();
-
- /* In verbose mode we print info about including another file. */
- if (verbose_mode)
- {
- register int i = 0;
- register FSTACK *stack = filestack;
-
- for (i = 0, stack = filestack; stack; stack = stack->next, i++);
-
- i *= 2;
-
- printf ("%*s", i, "");
- printf ("%c%s %s\n", COMMAND_PREFIX, command, filename);
- fflush (stdout);
- }
-
- if (!find_and_load (filename))
- {
- extern int errno;
-
- popfile ();
- line_number--;
-
- /* Cannot "@include foo", in line 5 of "/wh/bar". */
- line_error ("%c%s %s: %s", COMMAND_PREFIX, command, filename,
- strerror (errno));
-
- free (filename);
- return;
- }
- else
- {
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- remember_itext (input_text, input_text_offset);
-#endif /* HAVE_MACROS */
- reader_loop ();
- }
- free (filename);
- popfile ();
-}
-
-/* The other side of a malformed expression. */
-void
-misplaced_brace ()
-{
- line_error (_("Misplaced %c"), '}');
-}
-
-/* Signals end of processing. Easy to make this happen. */
-void
-cm_bye ()
-{
- input_text_offset = size_of_input_text;
-}
-
/* Set the paragraph indentation variable to the value specified in STRING.
Values can be:
`asis': Don't change existing indentation.
@@ -7654,1929 +3682,12 @@ set_paragraph_indent (string)
else
{
if (sscanf (string, "%d", &paragraph_start_indent) != 1)
- return (-1);
+ return -1;
else
{
if (paragraph_start_indent == 0)
paragraph_start_indent = -1;
}
}
- return (0);
-}
-
-void
-cm_paragraphindent ()
-{
- char *arg;
-
- get_rest_of_line (&arg);
- if (set_paragraph_indent (arg) != 0)
- line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command);
-
- free (arg);
-}
-
-/* **************************************************************** */
-/* */
-/* Indexing Stuff */
-/* */
-/* **************************************************************** */
-
-
-/* An index element... */
-typedef struct index_elt
-{
- struct index_elt *next;
- char *entry; /* The index entry itself. */
- char *node; /* The node from whence it came. */
- int code; /* Nonzero means add `@code{...}' when
- printing this element. */
- int defining_line; /* Line number where this entry was written. */
- char *defining_file; /* Source file for defining_line. */
-} INDEX_ELT;
-
-/* A list of short-names for each index.
-
- There are two indices into the the_indices array.
-
- * read_index is the index that points to the list of index
- entries that we will find if we ask for the list of entries for
- this name.
-
- * write_index is the index that points to the list of index entries
- that we will add new entries to.
-
- Initially, read_index and write index are the same, but the
- @syncodeindex and @synindex commands can change the list we add
- entries to.
-
- For example, after the commands
-
- @cindex foo
- @defindex ii
- @synindex cp ii
- @cindex bar
-
- the cp index will contain the entry `foo', and the new ii
- index will contain the entry `bar'. This is consistent with the
- way texinfo.tex handles the same situation.
-
- In addition, for each index, it is remembered whether that index is
- a code index or not. Code indices have @code{} inserted around the
- first word when they are printed with printindex. */
-typedef struct
-{
- char *name;
- int read_index; /* index entries for `name' */
- int write_index; /* store index entries here, @synindex can change it */
- int code;
-} INDEX_ALIST;
-
-INDEX_ALIST **name_index_alist = (INDEX_ALIST **) NULL;
-
-/* An array of pointers. Each one is for a different index. The
- "synindex" command changes which array slot is pointed to by a
- given "index". */
-INDEX_ELT **the_indices = (INDEX_ELT **) NULL;
-
-/* The number of defined indices. */
-int defined_indices = 0;
-
-void
-init_indices ()
-{
- int i;
-
- /* Create the default data structures. */
-
- /* Initialize data space. */
- if (!the_indices)
- {
- the_indices = (INDEX_ELT **) xmalloc ((1 + defined_indices) *
- sizeof (INDEX_ELT *));
- the_indices[defined_indices] = (INDEX_ELT *) NULL;
-
- name_index_alist = (INDEX_ALIST **) xmalloc ((1 + defined_indices) *
- sizeof (INDEX_ALIST *));
- name_index_alist[defined_indices] = (INDEX_ALIST *) NULL;
- }
-
- /* If there were existing indices, get rid of them now. */
- for (i = 0; i < defined_indices; i++)
- {
- undefindex (name_index_alist[i]->name);
- if (name_index_alist[i])
- { /* Suppose we're called with two input files, and the first
- does a @synindex pg cp. Then, when we get here to start
- the second file, the "pg" element won't get freed by
- undefindex (because it's pointing to "cp"). So free it
- here; otherwise, when we try to define the pg index again
- just below, it will still point to cp. */
- free (name_index_alist[i]->name);
- free (name_index_alist[i]);
- name_index_alist[i] = (INDEX_ALIST *) NULL;
- }
- }
-
- /* Add the default indices. */
- top_defindex ("cp", 0); /* cp is the only non-code index. */
- top_defindex ("fn", 1);
- top_defindex ("ky", 1);
- top_defindex ("pg", 1);
- top_defindex ("tp", 1);
- top_defindex ("vr", 1);
-}
-
-/* Find which element in the known list of indices has this name.
- Returns -1 if NAME isn't found. */
-int
-find_index_offset (name)
- char *name;
-{
- register int i;
- for (i = 0; i < defined_indices; i++)
- if (name_index_alist[i] &&
- strcmp (name, name_index_alist[i]->name) == 0)
- return (i);
- return (-1);
-}
-
-/* Return a pointer to the entry of (name . index) for this name.
- Return NULL if the index doesn't exist. */
-INDEX_ALIST *
-find_index (name)
- char *name;
-{
- int offset = find_index_offset (name);
- if (offset > -1)
- return (name_index_alist[offset]);
- else
- return ((INDEX_ALIST *) NULL);
-}
-
-/* Given an index name, return the offset in the_indices of this index,
- or -1 if there is no such index. */
-int
-translate_index (name)
- char *name;
-{
- INDEX_ALIST *which = find_index (name);
-
- if (which)
- return (which->read_index);
- else
- return (-1);
-}
-
-/* Return the index list which belongs to NAME. */
-INDEX_ELT *
-index_list (name)
- char *name;
-{
- int which = translate_index (name);
- if (which < 0)
- return ((INDEX_ELT *) -1);
- else
- return (the_indices[which]);
-}
-
-/* Please release me, let me go... */
-void
-free_index (index)
- INDEX_ELT *index;
-{
- INDEX_ELT *temp;
-
- while ((temp = index) != (INDEX_ELT *) NULL)
- {
- free (temp->entry);
- /* Do not free the node, because we already freed the tag table,
- which freed all the node names. */
- /* free (temp->node); */
- index = index->next;
- free (temp);
- }
-}
-
-/* Flush an index by name. This will delete the list of entries that
- would be written by a @printindex command for this index. */
-void
-undefindex (name)
- char *name;
-{
- int i;
- int which = find_index_offset (name);
-
- /* The index might have already been freed if this was the target of
- an @synindex. */
- if (which < 0 || !name_index_alist[which])
- return;
-
- i = name_index_alist[which]->read_index;
-
- free_index (the_indices[i]);
- the_indices[i] = (INDEX_ELT *) NULL;
-
- free (name_index_alist[which]->name);
- free (name_index_alist[which]);
- name_index_alist[which] = (INDEX_ALIST *) NULL;
-}
-
-/* Define an index known as NAME. We assign the slot number.
- CODE if Nonzero says to make this a code index. */
-void
-defindex (name, code)
- char *name;
- int code;
-{
- register int i, slot;
-
- /* If it already exists, flush it. */
- undefindex (name);
-
- /* Try to find an empty slot. */
- slot = -1;
- for (i = 0; i < defined_indices; i++)
- if (!name_index_alist[i])
- {
- slot = i;
- break;
- }
-
- if (slot < 0)
- {
- /* No such luck. Make space for another index. */
- slot = defined_indices;
- defined_indices++;
-
- name_index_alist = (INDEX_ALIST **)
- xrealloc ((char *)name_index_alist,
- (1 + defined_indices) * sizeof (INDEX_ALIST *));
- the_indices = (INDEX_ELT **)
- xrealloc ((char *)the_indices,
- (1 + defined_indices) * sizeof (INDEX_ELT *));
- }
-
- /* We have a slot. Start assigning. */
- name_index_alist[slot] = (INDEX_ALIST *) xmalloc (sizeof (INDEX_ALIST));
- name_index_alist[slot]->name = xstrdup (name);
- name_index_alist[slot]->read_index = slot;
- name_index_alist[slot]->write_index = slot;
- name_index_alist[slot]->code = code;
-
- the_indices[slot] = (INDEX_ELT *) NULL;
-}
-
-/* Add the arguments to the current index command to the index NAME. */
-void
-index_add_arg (name)
- char *name;
-{
- int which;
- char *index_entry;
- INDEX_ALIST *tem;
-
- tem = find_index (name);
-
- which = tem ? tem->write_index : -1;
-
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- append_to_expansion_output (input_text_offset + 1);
-#endif /* HAVE_MACROS */
-
- get_rest_of_line (&index_entry);
- ignore_blank_line ();
-
-#if defined (HAVE_MACROS)
- if (macro_expansion_output_stream && !executing_string)
- {
- int op_orig;
-
- remember_itext (input_text, input_text_offset);
- op_orig = output_paragraph_offset;
- me_execute_string (index_entry);
- me_execute_string ("\n");
- output_paragraph_offset = op_orig;
- }
-#endif /* HAVE_MACROS */
-
- if (which < 0)
- {
- line_error (_("Unknown index `%s'"), name);
- free (index_entry);
- }
- else
- {
- INDEX_ELT *new = (INDEX_ELT *) xmalloc (sizeof (INDEX_ELT));
- new->next = the_indices[which];
- new->entry = index_entry;
- new->node = current_node;
- new->code = tem->code;
- new->defining_line = line_number - 1;
- new->defining_file = input_filename;
- the_indices[which] = new;
- }
-}
-
-#define INDEX_COMMAND_SUFFIX "index"
-
-/* The function which user defined index commands call. */
-void
-gen_index ()
-{
- char *name = xstrdup (command);
- if (strlen (name) >= strlen ("index"))
- name[strlen (name) - strlen ("index")] = 0;
- index_add_arg (name);
- free (name);
-}
-
-void
-top_defindex (name, code)
- char *name;
- int code;
-{
- char *temp;
-
- temp = (char *) xmalloc (1 + strlen (name) + strlen ("index"));
- sprintf (temp, "%sindex", name);
- define_user_command (temp, gen_index, 0);
- defindex (name, code);
- free (temp);
-}
-
-/* Define a new index command. Arg is name of index. */
-void
-cm_defindex ()
-{
- gen_defindex (0);
-}
-
-void
-cm_defcodeindex ()
-{
- gen_defindex (1);
-}
-
-void
-gen_defindex (code)
- int code;
-{
- char *name;
- get_rest_of_line (&name);
-
- if (find_index (name))
- {
- line_error (_("Index `%s' already exists"), name);
- free (name);
- return;
- }
- else
- {
- char *temp = (char *) alloca (1 + strlen (name) + strlen ("index"));
- sprintf (temp, "%sindex", name);
- define_user_command (temp, gen_index, 0);
- defindex (name, code);
- free (name);
- }
-}
-
-/* Expects 2 args, on the same line. Both are index abbreviations.
- Make the first one be a synonym for the second one, i.e. make the
- first one have the same index as the second one. */
-void
-cm_synindex ()
-{
- int source, target;
- char *abbrev1, *abbrev2;
-
- skip_whitespace ();
- get_until_in_line (0, " ", &abbrev1);
- target = find_index_offset (abbrev1);
- skip_whitespace ();
- get_until_in_line (0, " ", &abbrev2);
- source = find_index_offset (abbrev2);
- if (source < 0 || target < 0)
- {
- line_error (_("Unknown index `%s' and/or `%s' in @synindex"),
- abbrev1, abbrev2);
- }
- else
- {
- name_index_alist[target]->write_index
- = name_index_alist[source]->write_index;
- }
-
- free (abbrev1);
- free (abbrev2);
-}
-
-void
-cm_pindex () /* Pinhead index. */
-{
- index_add_arg ("pg");
-}
-
-void
-cm_vindex () /* Variable index. */
-{
- index_add_arg ("vr");
-}
-
-void
-cm_kindex () /* Key index. */
-{
- index_add_arg ("ky");
-}
-
-void
-cm_cindex () /* Concept index. */
-{
- index_add_arg ("cp");
-}
-
-void
-cm_findex () /* Function index. */
-{
- index_add_arg ("fn");
-}
-
-void
-cm_tindex () /* Data Type index. */
-{
- index_add_arg ("tp");
-}
-
-/* Sorting the index. */
-int
-index_element_compare (element1, element2)
- INDEX_ELT **element1, **element2;
-{
- return (strcasecmp ((*element1)->entry, (*element2)->entry));
-}
-
-/* Force all index entries to be unique. */
-void
-make_index_entries_unique (array, count)
- INDEX_ELT **array;
- int count;
-{
- register int i, j;
- INDEX_ELT **copy;
- int counter = 1;
-
- copy = (INDEX_ELT **)xmalloc ((1 + count) * sizeof (INDEX_ELT *));
-
- for (i = 0, j = 0; i < count; i++)
- {
- if ((i == (count - 1)) ||
- (array[i]->node != array[i + 1]->node) ||
- (strcmp (array[i]->entry, array[i + 1]->entry) != 0))
- copy[j++] = array[i];
- else
- {
- free (array[i]->entry);
- free (array[i]);
- }
- }
- copy[j] = (INDEX_ELT *)NULL;
-
- /* Now COPY contains only unique entries. Duplicated entries in the
- original array have been freed. Replace the current array with
- the copy, fixing the NEXT pointers. */
- for (i = 0; copy[i] != (INDEX_ELT *)NULL; i++)
- {
-
- copy[i]->next = copy[i + 1];
-
- /* Fix entry names which are the same. They point to different nodes,
- so we make the entry name unique. */
- if ((copy[i + 1] != (INDEX_ELT *)NULL) &&
- (strcmp (copy[i]->entry, copy[i + 1]->entry) == 0))
- {
- char *new_entry_name;
-
- new_entry_name = (char *)xmalloc (10 + strlen (copy[i]->entry));
- sprintf (new_entry_name, "%s <%d>", copy[i]->entry, counter);
- free (copy[i]->entry);
- copy[i]->entry = new_entry_name;
- counter++;
- }
- else
- counter = 1;
-
- array[i] = copy[i];
- }
- array[i] = (INDEX_ELT *)NULL;
-
- /* Free the storage used only by COPY. */
- free (copy);
-}
-
-/* Sort the index passed in INDEX, returning an array of
- pointers to elements. The array is terminated with a NULL
- pointer. We call qsort because it's supposed to be fast.
- I think this looks bad. */
-INDEX_ELT **
-sort_index (index)
- INDEX_ELT *index;
-{
- INDEX_ELT **array;
- INDEX_ELT *temp = index;
- int count = 0;
- int save_line_number = line_number;
- char *save_input_filename = input_filename;
-
- while (temp != (INDEX_ELT *) NULL)
- {
- count++;
- temp = temp->next;
- }
-
- /* We have the length. Make an array. */
-
- array = (INDEX_ELT **) xmalloc ((count + 1) * sizeof (INDEX_ELT *));
- count = 0;
- temp = index;
-
- while (temp != (INDEX_ELT *) NULL)
- {
- array[count++] = temp;
-
- /* Set line number and input filename to the source line for this
- index entry, as this expansion finds any errors. */
- line_number = array[count - 1]->defining_line;
- input_filename = array[count - 1]->defining_file;
-
- /* If this particular entry should be printed as a "code" index,
- then wrap the entry with "@code{...}". */
- array[count - 1]->entry = expansion (temp->entry, index->code);
-
- temp = temp->next;
- }
- array[count] = (INDEX_ELT *) NULL; /* terminate the array. */
- line_number = save_line_number;
- input_filename = save_input_filename;
-
- /* Sort the array. */
- qsort (array, count, sizeof (INDEX_ELT *), index_element_compare);
- make_index_entries_unique (array, count);
- return (array);
-}
-
-/* Nonzero means that we are in the middle of printing an index. */
-int printing_index = 0;
-
-/* Takes one arg, a short name of an index to print.
- Outputs a menu of the sorted elements of the index. */
-void
-cm_printindex ()
-{
- int item;
- INDEX_ELT *index;
- INDEX_ELT **array;
- char *index_name;
- unsigned line_length;
- char *line;
- int saved_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
- int saved_filling_enabled = filling_enabled;
-
- close_paragraph ();
- get_rest_of_line (&index_name);
-
- index = index_list (index_name);
- if (index == (INDEX_ELT *)-1)
- {
- line_error (_("Unknown index `%s' in @printindex"), index_name);
- free (index_name);
- return;
- }
- else
- free (index_name);
-
- /* Do this before sorting, so execute_string in index_element_compare
- will give the same results as when we actually print. */
- printing_index = 1;
- filling_enabled = 0;
- inhibit_paragraph_indentation = 1;
- array = sort_index (index);
-
- close_paragraph ();
- add_word (_("* Menu:\n\n"));
-
-#if defined (HAVE_MACROS)
- me_inhibit_expansion++;
-#endif /* HAVE_MACROS */
-
- /* This will probably be enough. */
- line_length = 100;
- line = xmalloc (line_length);
-
- for (item = 0; (index = array[item]); item++)
- {
- /* A pathological document might have an index entry outside of any
- node. Don't crash. Perhaps should warn. */
- char *index_node = index->node ? index->node : "(none)";
- unsigned new_length = strlen (index->entry);
-
- if (new_length < 37) /* minimum length used below */
- new_length = 37;
- new_length += strlen (index_node) + 7; /* * : .\n\0 */
-
- if (new_length > line_length)
- {
- line_length = new_length;
- line = xrealloc (line, line_length);
- }
-
- /* Print the entry, nicely formatted. We've already expanded any
- commands, including any implicit @code. Thus, can't call
- execute_string, since @@ has turned into @. */
- sprintf (line, "* %-37s %s.\n", index->entry, index_node);
- line[2 + strlen (index->entry)] = ':';
- insert_string (line);
-
- /* Previous `output_paragraph' from growing to the size of the
- whole index. */
- flush_output ();
- }
-
- free (line);
-
-#if defined (HAVE_MACROS)
- me_inhibit_expansion--;
-#endif /* HAVE_MACROS */
-
- printing_index = 0;
- free (array);
- close_single_paragraph ();
- filling_enabled = saved_filling_enabled;
- inhibit_paragraph_indentation = saved_inhibit_paragraph_indentation;
-}
-
-/* User-defined commands, which happens only from user-defined indexes. */
-
-void
-define_user_command (name, proc, needs_braces_p)
- char *name;
- COMMAND_FUNCTION *proc;
- int needs_braces_p;
-{
- int slot = user_command_array_len;
- user_command_array_len++;
-
- if (!user_command_array)
- user_command_array = (COMMAND **) xmalloc (1 * sizeof (COMMAND *));
-
- user_command_array = (COMMAND **) xrealloc (user_command_array,
- (1 + user_command_array_len) *
- sizeof (COMMAND *));
-
- user_command_array[slot] = (COMMAND *) xmalloc (sizeof (COMMAND));
- user_command_array[slot]->name = xstrdup (name);
- user_command_array[slot]->proc = proc;
- user_command_array[slot]->argument_in_braces = needs_braces_p;
-}
-
-/* Some support for footnotes. */
-
-/* Footnotes are a new construct in Info. We don't know the best method
- of implementing them for sure, so we present two possiblities.
-
- SeparateNode:
- Make them look like followed references, with the reference
- destinations in a makeinfo manufactured node or,
-
- EndNode:
- Make them appear at the bottom of the node that they originally
- appeared in. */
-#define SeparateNode 0
-#define EndNode 1
-
-int footnote_style = EndNode;
-int first_footnote_this_node = 1;
-int footnote_count = 0;
-
-/* Set the footnote style based on he style identifier in STRING. */
-int
-set_footnote_style (string)
- char *string;
-{
- if ((strcasecmp (string, "separate") == 0) ||
- (strcasecmp (string, "MN") == 0))
- footnote_style = SeparateNode;
- else if ((strcasecmp (string, "end") == 0) ||
- (strcasecmp (string, "EN") == 0))
- footnote_style = EndNode;
- else
- return (-1);
-
- return (0);
-}
-
-void
-cm_footnotestyle ()
-{
- char *arg;
-
- get_rest_of_line (&arg);
-
- /* If set on command line, do not change the footnote style. */
- if (!footnote_style_preset && set_footnote_style (arg) != 0)
- line_error ("Bad argument to %c%s", COMMAND_PREFIX, command);
-
- free (arg);
-}
-
-typedef struct fn
-{
- struct fn *next;
- char *marker;
- char *note;
-} FN;
-
-FN *pending_notes = (FN *) NULL;
-
-/* A method for remembering footnotes. Note that this list gets output
- at the end of the current node. */
-void
-remember_note (marker, note)
- char *marker, *note;
-{
- FN *temp = (FN *) xmalloc (sizeof (FN));
-
- temp->marker = xstrdup (marker);
- temp->note = xstrdup (note);
- temp->next = pending_notes;
- pending_notes = temp;
- footnote_count++;
-}
-
-/* How to get rid of existing footnotes. */
-void
-free_pending_notes ()
-{
- FN *temp;
-
- while ((temp = pending_notes) != (FN *) NULL)
- {
- free (temp->marker);
- free (temp->note);
- pending_notes = pending_notes->next;
- free (temp);
- }
- first_footnote_this_node = 1;
- footnote_count = 0;
-}
-
-/* What to do when you see a @footnote construct. */
-
- /* Handle a "footnote".
- footnote *{this is a footnote}
- where "*" is the (optional) marker character for this note. */
-void
-cm_footnote ()
-{
- char *marker;
- char *note;
-
- get_until ("{", &marker);
- canon_white (marker);
-
- if (macro_expansion_output_stream && !executing_string)
- append_to_expansion_output (input_text_offset + 1); /* include the { */
-
- /* Read the argument in braces. */
- if (curchar () != '{')
- {
- line_error (_("`%c%s' needs an argument `{...}', not just `%s'"),
- COMMAND_PREFIX, command, marker);
- free (marker);
- return;
- }
- else
- {
- int len;
- int braces = 1;
- int loc = ++input_text_offset;
-
- while (braces)
- {
- if (loc == size_of_input_text)
- {
- line_error (_("No closing brace for footnote `%s'"), marker);
- return;
- }
-
- if (input_text[loc] == '{')
- braces++;
- else if (input_text[loc] == '}')
- braces--;
- else if (input_text[loc] == '\n')
- line_number++;
-
- loc++;
- }
-
- len = (loc - input_text_offset) - 1;
- note = (char *)xmalloc (len + 1);
- strncpy (note, &input_text[input_text_offset], len);
- note[len] = 0;
- input_text_offset = loc;
- }
-
- /* Must write the macro-expanded argument to the macro expansion
- output stream. This is like the case in index_add_arg. */
- if (macro_expansion_output_stream && !executing_string)
- {
- int op_orig;
-
- remember_itext (input_text, input_text_offset);
- op_orig = output_paragraph_offset;
- me_execute_string (note);
- /* Calling me_execute_string on a lone } provokes an error, since
- as far as the reader knows there is no matching {. We wrote
- the { above in the call to append_to_expansion_output. */
- write_region_to_macro_output ("}", 0, 1);
- output_paragraph_offset = op_orig;
- }
-
- if (!current_node || !*current_node)
- {
- line_error (_("Footnote defined without parent node"));
- free (marker);
- free (note);
- return;
- }
-
- if (!*marker)
- {
- free (marker);
-
- if (number_footnotes)
- {
- marker = (char *)xmalloc (10);
- sprintf (marker, "%d", current_footnote_number);
- current_footnote_number++;
- }
- else
- marker = xstrdup ("*");
- }
-
- remember_note (marker, note);
-
- /* Your method should at least insert MARKER. */
- switch (footnote_style)
- {
- case SeparateNode:
- add_word_args ("(%s)", marker);
- if (first_footnote_this_node)
- {
- char *temp_string;
-
- temp_string = (char *)
- xmalloc ((strlen (current_node)) + (strlen (_("-Footnotes"))) + 1);
-
- add_word_args (" (*note %s-Footnotes::)", current_node);
- strcpy (temp_string, current_node);
- strcat (temp_string, "-Footnotes");
- remember_node_reference (temp_string, line_number, followed_reference);
- free (temp_string);
- first_footnote_this_node = 0;
- }
- break;
-
- case EndNode:
- add_word_args ("(%s)", marker);
- break;
-
- default:
- break;
- }
- free (marker);
- free (note);
-}
-
-/* Nonzero means that we are currently in the process of outputting
- footnotes. */
-int already_outputting_pending_notes = 0;
-
-/* Output the footnotes. We are at the end of the current node. */
-void
-output_pending_notes ()
-{
- FN *footnote = pending_notes;
-
- if (!pending_notes)
- return;
-
- switch (footnote_style)
- {
- case SeparateNode:
- {
- char *old_current_node = current_node;
- char *old_command = xstrdup (command);
-
- already_outputting_pending_notes++;
- execute_string ("%cnode %s-Footnotes,,,%s\n",
- COMMAND_PREFIX, current_node, current_node);
- already_outputting_pending_notes--;
- current_node = old_current_node;
- free (command);
- command = old_command;
- }
- break;
-
- case EndNode:
- close_paragraph ();
- in_fixed_width_font++;
- execute_string (_("---------- Footnotes ----------\n\n"));
- in_fixed_width_font--;
- break;
- }
-
- /* Handle the footnotes in reverse order. */
- {
- FN **array = (FN **) xmalloc ((footnote_count + 1) * sizeof (FN *));
-
- array[footnote_count] = (FN *) NULL;
-
- while (--footnote_count > -1)
- {
- array[footnote_count] = footnote;
- footnote = footnote->next;
- }
-
- filling_enabled = 1;
- indented_fill = 1;
-
- while ((footnote = array[++footnote_count]))
- {
- execute_string ("(%s) %s", footnote->marker, footnote->note);
- close_paragraph ();
- }
- close_paragraph ();
- free (array);
- }
-}
-
-/* **************************************************************** */
-/* */
-/* User definable Macros (text substitution) */
-/* */
-/* **************************************************************** */
-
-#if defined (HAVE_MACROS)
-
-/* Array of macros and definitions. */
-MACRO_DEF **macro_list = (MACRO_DEF **)NULL;
-
-int macro_list_len = 0; /* Number of elements. */
-int macro_list_size = 0; /* Number of slots in total. */
-
-/* Return the macro definition of NAME or NULL if NAME is not defined. */
-MACRO_DEF *
-find_macro (name)
- char *name;
-{
- register int i;
- register MACRO_DEF *def;
-
- def = (MACRO_DEF *)NULL;
- for (i = 0; macro_list && (def = macro_list[i]); i++)
- {
- if ((!def->inhibited) && (strcmp (def->name, name) == 0))
- break;
- }
- return (def);
-}
-
-/* Add the macro NAME with ARGLIST and BODY to the list of defined macros.
- SOURCE_FILE is the name of the file where this definition can be found,
- and SOURCE_LINENO is the line number within that file. If a macro already
- exists with NAME, then a warning is produced, and that previous
- definition is overwritten. */
-void
-add_macro (name, arglist, body, source_file, source_lineno, flags)
- char *name;
- char **arglist;
- char *body;
- char *source_file;
- int source_lineno, flags;
-{
- register MACRO_DEF *def;
-
- def = find_macro (name);
-
- if (!def)
- {
- if (macro_list_len + 2 >= macro_list_size)
- macro_list = (MACRO_DEF **)xrealloc
- (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
-
- macro_list[macro_list_len] = (MACRO_DEF *)xmalloc (sizeof (MACRO_DEF));
- macro_list[macro_list_len + 1] = (MACRO_DEF *)NULL;
-
- def = macro_list[macro_list_len];
- macro_list_len += 1;
- def->name = name;
- }
- else
- {
- char *temp_filename = input_filename;
- int temp_line = line_number;
-
- warning (_("macro `%s' previously defined"), name);
-
- input_filename = def->source_file;
- line_number = def->source_lineno;
- warning (_("here is the previous definition of `%s'"), name);
-
- input_filename = temp_filename;
- line_number = temp_line;
-
- if (def->arglist)
- {
- register int i;
-
- for (i = 0; def->arglist[i]; i++)
- free (def->arglist[i]);
-
- free (def->arglist);
- }
- free (def->source_file);
- free (def->body);
- }
-
- def->source_file = xstrdup (source_file);
- def->source_lineno = source_lineno;
- def->body = body;
- def->arglist = arglist;
- def->inhibited = 0;
- def->flags = flags;
-}
-
-/* Delete the macro with name NAME. The macro is deleted from the list,
- but it is also returned. If there was no macro defined, NULL is
- returned. */
-MACRO_DEF *
-delete_macro (name)
- char *name;
-{
- register int i;
- register MACRO_DEF *def;
-
- def = (MACRO_DEF *)NULL;
-
- for (i = 0; macro_list && (def = macro_list[i]); i++)
- if (strcmp (def->name, name) == 0)
- {
- memmove (macro_list + i, macro_list + i + 1,
- ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
- macro_list_len--;
- break;
- }
- return (def);
-}
-
-/* Return the arglist on the current line. This can behave in two different
- ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */
-int braces_required_for_macro_args = 0;
-
-char **
-get_macro_args (def)
- MACRO_DEF *def;
-{
- register int i;
- char *word;
-
- /* Quickly check to see if this macro has been invoked with any arguments.
- If not, then don't skip any of the following whitespace. */
- for (i = input_text_offset; i < size_of_input_text; i++)
- if (!cr_or_whitespace (input_text[i]))
- break;
-
- if (input_text[i] != '{')
- {
- if (braces_required_for_macro_args)
- {
- return ((char **)NULL);
- }
- else
- {
- /* Braces are not required to fill out the macro arguments. If
- this macro takes one argument, it is considered to be the
- remainder of the line, sans whitespace. */
- if (def->arglist && def->arglist[0] && !def->arglist[1])
- {
- char **arglist;
-
- get_rest_of_line (&word);
- if (input_text[input_text_offset - 1] == '\n')
- {
- input_text_offset--;
- line_number--;
- }
- /* canon_white (word); */
- arglist = (char **)xmalloc (2 * sizeof (char *));
- arglist[0] = word;
- arglist[1] = (char *)NULL;
- return (arglist);
- }
- else
- {
- /* The macro either took no arguments, or took more than
- one argument. In that case, it must be invoked with
- arguments surrounded by braces. */
- return ((char **)NULL);
- }
- }
- }
- return (get_brace_args (def->flags & ME_QUOTE_ARG));
-}
-
-/* Substitute actual parameters for named parameters in body.
- The named parameters which appear in BODY must by surrounded
- reverse slashes, as in \foo\. */
-char *
-apply (named, actuals, body)
- char **named, **actuals, *body;
-{
- register int i;
- int new_body_index, new_body_size;
- char *new_body, *text;
- int length_of_actuals;
-
- length_of_actuals = array_len (actuals);
- new_body_size = strlen (body);
- new_body = (char *)xmalloc (1 + new_body_size);
-
- /* Copy chars from BODY into NEW_BODY. */
- i = 0; new_body_index = 0;
-
- while (1)
- {
- if (!body[i])
- break;
-
- if (body[i] != '\\')
- new_body[new_body_index++] = body[i++];
- else
- {
- /* Snarf parameter name, check against named parameters. */
- char *param;
- int param_start, which, len;
-
- param_start = ++i;
- while ((body[i]) && (body[i] != '\\'))
- i++;
-
- len = i - param_start;
- param = (char *)xmalloc (1 + len);
- memcpy (param, body + param_start, len);
- param[len] = 0;
-
- if (body[i]) /* move past \ */
- i++;
-
- /* Now check against named parameters. */
- for (which = 0; named && named[which]; which++)
- if (strcmp (named[which], param) == 0)
- break;
-
- if (named && named[which])
- {
- if (which < length_of_actuals)
- text = actuals[which];
- else
- text = (char *)NULL;
-
- if (!text)
- text = "";
-
- len = strlen (text);
- }
- else
- { /* not a parameter, restore \'s */
- i = body[i] ? (i - 1) : i;
- len++;
- text = xmalloc (1 + len);
- sprintf (text, "\\%s", param);
- }
-
- if ((2 + strlen (param)) < len)
- {
- new_body_size += len + 1;
- new_body = xrealloc (new_body, new_body_size);
- }
-
- free (param);
-
- strcpy (new_body + new_body_index, text);
- new_body_index += len;
-
- if (!named || !named[which])
- free (text);
- }
- }
- new_body[new_body_index] = 0;
- return (new_body);
-}
-
-/* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */
-void
-execute_macro (def)
- MACRO_DEF *def;
-{
- char **arglist;
- int num_args;
- char *execution_string = (char *)NULL;
-
- if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
- me_append_before_this_command ();
-
- /* Find out how many arguments this macro definition takes. */
- num_args = array_len (def->arglist);
-
- /* Gather the arguments present on the line if there are any. */
- arglist = get_macro_args (def);
-
- if (num_args < array_len (arglist))
- {
- free_array (arglist);
- line_error (_("Macro `%s' called with too many args"), def->name);
- return;
- }
-
- if (def->body)
- execution_string = apply (def->arglist, arglist, def->body);
-
- free_array (arglist);
-
- if (def->body)
- {
- if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
- {
- remember_itext (input_text, input_text_offset);
- me_execute_string (execution_string);
- }
- else
- execute_string ("%s", execution_string);
-
- free (execution_string);
- }
-}
-
-/* Read and remember the definition of a macro. */
-void
-cm_macro ()
-{
- register int i;
- char *name, **arglist, *body, *line;
- int body_size, body_index;
- int depth = 1;
- int defining_line = line_number;
- int flags = 0;
-
- arglist = (char **)NULL;
- body = (char *)NULL;
- body_size = 0;
- body_index = 0;
-
- if (macro_expansion_output_stream && !executing_string)
- me_append_before_this_command ();
-
- skip_whitespace ();
-
- /* Get the name of the macro. This is the set of characters which are
- not whitespace and are not `{' immediately following the @macro. */
- {
- int start = input_text_offset;
- int len;
-
- for (i = start;
- (i < size_of_input_text) &&
- (input_text[i] != '{') &&
- (!cr_or_whitespace (input_text[i]));
- i++);
-
- len = i - start;
- name = (char *)xmalloc (1 + len);
- strncpy (name, input_text + start, len);
- name[len] = 0;
- input_text_offset = i;
- }
-
- skip_whitespace ();
-
- /* It is not required that the definition of a macro includes an arglist.
- If not, don't try to get the named parameters, just use a null list. */
- if (curchar () == '{')
- {
- int arglist_index = 0, arglist_size = 0;
- int gathering_words = 1;
- char *word = (char *)NULL;
- int character;
-
- /* Read the words inside of the braces which determine the arglist.
- These words will be replaced within the body of the macro at
- execution time. */
-
- input_text_offset++;
- skip_whitespace_and_newlines ();
-
- while (gathering_words)
- {
- int len;
-
- for (i = input_text_offset;
- (character = input_text[i]);
- i++)
- {
- switch (character)
- {
- case '\n':
- line_number++;
- case ' ':
- case '\t':
- case ',':
- case '}':
- /* Found the end of the current arglist word. Save it. */
- len = i - input_text_offset;
- word = (char *)xmalloc (1 + len);
- strncpy (word, input_text + input_text_offset, len);
- word[len] = 0;
- input_text_offset = i;
-
- /* Advance to the comma or close-brace that signified
- the end of the argument. */
- while ((character = curchar ())
- && character != ','
- && character != '}')
- {
- input_text_offset++;
- if (character == '\n')
- line_number++;
- }
-
- /* Add the word to our list of words. */
- if ((arglist_index + 2) >= arglist_size)
- arglist = (char **)xrealloc
- (arglist, (arglist_size += 10) * sizeof (char *));
-
- arglist[arglist_index++] = word;
- arglist[arglist_index] = (char *)NULL;
- break;
- }
-
- if (character == '}')
- {
- input_text_offset++;
- gathering_words = 0;
- break;
- }
-
- if (character == ',')
- {
- input_text_offset++;
- skip_whitespace_and_newlines ();
- i = input_text_offset - 1;
- }
- }
- }
- }
-
- /* Read the text carefully until we find an "@end macro" which
- matches this one. The text in between is the body of the macro. */
- skip_whitespace_and_newlines ();
-
- while (depth)
- {
- if ((input_text_offset + 9) > size_of_input_text)
- {
- int temp_line = line_number;
- line_number = defining_line;
- line_error (_("%cend macro not found"), COMMAND_PREFIX);
- line_number = temp_line;
- return;
- }
-
- get_rest_of_line (&line);
-
- /* Handle commands only meaningful within a macro. */
- if ((*line == COMMAND_PREFIX) && (depth == 1) &&
- (strncmp (line + 1, "allow-recursion", 15) == 0) &&
- (line[16] == 0 || whitespace (line[16])))
- {
- for (i = 16; whitespace (line[i]); i++);
- strcpy (line, line + i);
- flags |= ME_RECURSE;
- if (!*line)
- {
- free (line);
- continue;
- }
- }
-
- if ((*line == COMMAND_PREFIX) && (depth == 1) &&
- (strncmp (line + 1, "quote-arg", 9) == 0) &&
- (line[10] == 0 || whitespace (line[10])))
- {
- for (i = 10; whitespace (line[i]); i++);
- strcpy (line, line + i);
-
- if (arglist && arglist[0] && !arglist[1])
- {
- flags |= ME_QUOTE_ARG;
- if (!*line)
- {
- free (line);
- continue;
- }
- }
- else
- {
- line_error (_("%cquote-arg only useful when the macro takes a single argument"),
- COMMAND_PREFIX);
- }
- }
-
- if ((*line == COMMAND_PREFIX) &&
- (strncmp (line + 1, "macro ", 6) == 0))
- depth++;
-
- if ((*line == COMMAND_PREFIX) &&
- (strncmp (line + 1, "end macro", 9) == 0))
- depth--;
-
- if (depth)
- {
- if ((body_index + strlen (line) + 3) >= body_size)
- body = (char *)xrealloc
- (body, body_size += 3 + strlen (line));
- strcpy (body + body_index, line);
- body_index += strlen (line);
- body[body_index++] = '\n';
- body[body_index] = 0;
- }
- free (line);
- }
-
- /* If it was an empty macro like
- @macro foo
- @end macro
- create an empty body. (Otherwise, the macro is not expanded.) */
- if (!body)
- {
- body = (char *)malloc(1);
- *body = 0;
- }
-
- /* We now have the name, the arglist, and the body. However, BODY
- includes the final newline which preceded the `@end macro' text.
- Delete it. */
- if (body && strlen (body))
- body[strlen (body) - 1] = 0;
-
- add_macro (name, arglist, body, input_filename, defining_line, flags);
-
- if (macro_expansion_output_stream && !executing_string)
- remember_itext (input_text, input_text_offset);
-}
-
-void
-cm_unmacro ()
-{
- register int i;
- char *line, *name;
- MACRO_DEF *def;
-
- if (macro_expansion_output_stream && !executing_string)
- me_append_before_this_command ();
-
- get_rest_of_line (&line);
-
- for (i = 0; line[i] && !whitespace (line[i]); i++);
- name = (char *)xmalloc (i + 1);
- strncpy (name, line, i);
- name[i] = 0;
-
- def = delete_macro (name);
-
- if (def)
- {
- free (def->source_file);
- free (def->name);
- free (def->body);
-
- if (def->arglist)
- {
- register int i;
-
- for (i = 0; def->arglist[i]; i++)
- free (def->arglist[i]);
-
- free (def->arglist);
- }
-
- free (def);
- }
-
- free (line);
- free (name);
-
- if (macro_expansion_output_stream && !executing_string)
- remember_itext (input_text, input_text_offset);
-}
-
-/* How to output sections of the input file verbatim. */
-
-/* Set the value of POINTER's offset to OFFSET. */
-ITEXT *
-remember_itext (pointer, offset)
- char *pointer;
- int offset;
-{
- register int i;
- ITEXT *itext = (ITEXT *)NULL;
-
- /* If we have no info, initialize a blank list. */
- if (!itext_info)
- {
- itext_info = (ITEXT **)xmalloc ((itext_size = 10) * sizeof (ITEXT *));
- for (i = 0; i < itext_size; i++)
- itext_info[i] = (ITEXT *)NULL;
- }
-
- /* If the pointer is already present in the list, then set the offset. */
- for (i = 0; i < itext_size; i++)
- if ((itext_info[i] != (ITEXT *)NULL) &&
- (itext_info[i]->pointer == pointer))
- {
- itext = itext_info[i];
- itext_info[i]->offset = offset;
- break;
- }
-
- if (i == itext_size)
- {
- /* Find a blank slot (or create a new one), and remember the
- pointer and offset. */
- for (i = 0; i < itext_size; i++)
- if (itext_info[i] == (ITEXT *)NULL)
- break;
-
- /* If not found, then add some slots. */
- if (i == itext_size)
- {
- register int j;
-
- itext_info = (ITEXT **)xrealloc
- (itext_info, (itext_size += 10) * sizeof (ITEXT *));
-
- for (j = i; j < itext_size; j++)
- itext_info[j] = (ITEXT *)NULL;
- }
-
- /* Now add the pointer and the offset. */
- itext_info[i] = (ITEXT *)xmalloc (sizeof (ITEXT));
- itext_info[i]->pointer = pointer;
- itext_info[i]->offset = offset;
- itext = itext_info[i];
- }
- return (itext);
-}
-
-/* Forget the input text associated with POINTER. */
-void
-forget_itext (pointer)
- char *pointer;
-{
- register int i;
-
- for (i = 0; i < itext_size; i++)
- if (itext_info[i] && (itext_info[i]->pointer == pointer))
- {
- free (itext_info[i]);
- itext_info[i] = (ITEXT *)NULL;
- break;
- }
-}
-
-/* Append the text which appeared in input_text from the last offset to
- the character just before the command that we are currently executing. */
-void
-me_append_before_this_command ()
-{
- register int i;
-
- for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--);
- maybe_write_itext (input_text, i);
-}
-
-/* Similar to execute_string (), but only takes a single string argument,
- and remembers the input text location, etc. */
-void
-me_execute_string (execution_string)
- char *execution_string;
-{
- pushfile ();
- input_text_offset = 0;
- input_text = execution_string;
- input_filename = xstrdup (input_filename);
- size_of_input_text = strlen (execution_string);
-
- remember_itext (execution_string, 0);
-
- me_executing_string++;
- reader_loop ();
- popfile ();
- me_executing_string--;
-}
-
-/* Append the text which appears in input_text from the last offset to
- the current OFFSET. */
-void
-append_to_expansion_output (offset)
- int offset;
-{
- register int i;
- ITEXT *itext = (ITEXT *)NULL;
-
- for (i = 0; i < itext_size; i++)
- if (itext_info[i] && itext_info[i]->pointer == input_text)
- {
- itext = itext_info[i];
- break;
- }
-
- if (!itext)
- return;
-
- if (offset > itext->offset)
- {
- write_region_to_macro_output
- (input_text, itext->offset, offset);
- remember_itext (input_text, offset);
- }
-}
-
-/* Only write this input text iff it appears in our itext list. */
-void
-maybe_write_itext (pointer, offset)
- char *pointer;
- int offset;
-{
- register int i;
- ITEXT *itext = (ITEXT *)NULL;
-
- for (i = 0; i < itext_size; i++)
- if (itext_info[i] && (itext_info[i]->pointer == pointer))
- {
- itext = itext_info[i];
- break;
- }
-
- if (itext && (itext->offset < offset))
- {
- write_region_to_macro_output (itext->pointer, itext->offset, offset);
- remember_itext (pointer, offset);
- }
-}
-
-void
-write_region_to_macro_output (string, start, end)
- char *string;
- int start, end;
-{
- if (macro_expansion_output_stream)
- fwrite (string + start, 1, end - start, macro_expansion_output_stream);
-}
-
-#endif /* HAVE_MACROS */
-
-/* Return the length of the array in ARRAY. */
-int
-array_len (array)
- char **array;
-{
- register int i = 0;
-
- if (array)
- for (i = 0; array[i] != (char *)NULL; i++);
-
- return (i);
-}
-
-void
-free_array (array)
- char **array;
-{
- if (array)
- {
- register int i;
-
- for (i = 0; array[i] != (char *)NULL; i++)
- free (array[i]);
-
- free (array);
- }
-}
-
-/* Function is used even when we don't have macros. Although, I have
- to admit, it is unlikely that you would have a use for it if you
- aren't using macros. */
-char **
-get_brace_args (quote_single)
- int quote_single;
-{
- char **arglist, *word;
- int arglist_index, arglist_size;
- int character, escape_seen, start;
- int depth = 1;
-
- /* There is an arglist in braces here, so gather the args inside of it. */
- skip_whitespace_and_newlines ();
- input_text_offset++;
- arglist = (char **)NULL;
- arglist_index = arglist_size = 0;
-
- get_arg:
- skip_whitespace_and_newlines ();
- start = input_text_offset;
- escape_seen = 0;
-
- while ((character = curchar ()))
- {
- if (character == '\\')
- {
- input_text_offset += 2;
- escape_seen = 1;
- }
- else if (character == '{')
- {
- depth++;
- input_text_offset++;
- }
- else if ((character == ',' && !quote_single) ||
- ((character == '}') && depth == 1))
- {
- int len = input_text_offset - start;
-
- if (len || (character != '}'))
- {
- word = (char *)xmalloc (1 + len);
- strncpy (word, input_text + start, len);
- word[len] = 0;
-
- /* Clean up escaped characters. */
- if (escape_seen)
- {
- register int i;
-
- for (i = 0; word[i]; i++)
- if (word[i] == '\\')
- memmove (word + i, word + i + 1,
- 1 + strlen (word + i + 1));
- }
-
- if (arglist_index + 2 >= arglist_size)
- arglist = (char **)xrealloc
- (arglist, (arglist_size += 10) * sizeof (char *));
-
- arglist[arglist_index++] = word;
- arglist[arglist_index] = (char *)NULL;
- }
-
- input_text_offset++;
- if (character == '}')
- break;
- else
- goto get_arg;
- }
- else if (character == '}')
- {
- depth--;
- input_text_offset++;
- }
- else
- {
- input_text_offset++;
- if (character == '\n') line_number++;
- }
- }
- return (arglist);
-}
-
-/* **************************************************************** */
-/* */
-/* Looking For Include Files */
-/* */
-/* **************************************************************** */
-
-/* Given a string containing units of information separated by colons,
- return the next one pointed to by INDEX, or NULL if there are no more.
- Advance INDEX to the character after the colon. */
-char *
-extract_colon_unit (string, index)
- char *string;
- int *index;
-{
- int i, start;
-
- i = *index;
-
- if (!string || (i >= strlen (string)))
- return ((char *)NULL);
-
- /* Each call to this routine leaves the index pointing at a colon if
- there is more to the path. If I is > 0, then increment past the
- `:'. If I is 0, then the path has a leading colon. Trailing colons
- are handled OK by the `else' part of the if statement; an empty
- string is returned in that case. */
- if (i && string[i] == ':')
- i++;
-
- start = i;
-
- while (string[i] && string[i] != ':') i++;
-
- *index = i;
-
- if (i == start)
- {
- if (string[i])
- (*index)++;
-
- /* Return "" in the case of a trailing `:'. */
- return (xstrdup (""));
- }
- else
- {
- char *value;
-
- value = (char *)xmalloc (1 + (i - start));
- strncpy (value, &string[start], (i - start));
- value [i - start] = 0;
-
- return (value);
- }
-}
-
-/* Return the full pathname for FILENAME by searching along PATH.
- When found, return the stat () info for FILENAME in FINFO.
- If PATH is NULL, only the current directory is searched.
- If the file could not be found, return a NULL pointer. */
-char *
-get_file_info_in_path (filename, path, finfo)
- char *filename, *path;
- struct stat *finfo;
-{
- char *dir;
- int result, index = 0;
-
- if (path == (char *)NULL)
- path = ".";
-
- /* Handle absolute pathnames. "./foo", "/foo", "../foo". */
- if (*filename == '/' ||
- (*filename == '.' &&
- (filename[1] == '/' ||
- (filename[1] == '.' && filename[2] == '/')))
-#ifdef WIN32
- /* Handle names that look like "d:/foo/bar" */
- || (isalpha (*filename) && filename [1] == ':'
- && (filename [2] == '/' || filename [2] == '\\'))
-#endif
- )
- {
- if (stat (filename, finfo) == 0)
- return (xstrdup (filename));
- else
- return ((char *)NULL);
- }
-
- while ((dir = extract_colon_unit (path, &index)))
- {
- char *fullpath;
-
- if (!*dir)
- {
- free (dir);
- dir = xstrdup (".");
- }
-
- fullpath = (char *)xmalloc (2 + strlen (dir) + strlen (filename));
- sprintf (fullpath, "%s/%s", dir, filename);
- free (dir);
-
- result = stat (fullpath, finfo);
-
- if (result == 0)
- return (fullpath);
- else
- free (fullpath);
- }
- return NULL;
+ return 0;
}
diff --git a/contrib/texinfo/makeinfo/makeinfo.h b/contrib/texinfo/makeinfo/makeinfo.h
index 205a3bd..caff188 100644
--- a/contrib/texinfo/makeinfo/makeinfo.h
+++ b/contrib/texinfo/makeinfo/makeinfo.h
@@ -1,7 +1,7 @@
-/* makeinfo.h -- Declarations for Makeinfo.
- $Id: makeinfo.h,v 1.3 1997/07/15 18:28:38 karl Exp $
+/* makeinfo.h -- declarations for Makeinfo.
+ $Id: makeinfo.h,v 1.25 1999/09/18 18:09:22 karl Exp $
- Copyright (C) 1996, 97 Free Software Foundation, Inc.
+ Copyright (C) 1996, 97, 98, 99 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,68 +19,44 @@
Written by Brian Fox (bfox@ai.mit.edu). */
-/* Why, oh why, did I ever listen to rms when he said:
- "Don't make lots of small files, just make one big one!" I've
- regretted it ever since with this program, and with readline.
- bfox@ai.mit.edu Thu Jul 11 07:54:32 1996 */
-
-#if !defined (MAKEINFO_H)
+#ifndef MAKEINFO_H
#define MAKEINFO_H
-#if defined (COMPILING_MAKEINFO)
-# define DECLARE(type, var, init) type var = init
+#ifdef COMPILING_MAKEINFO
+# define DECLARE(type,var,init) type var = init
#else
-# define DECLARE(type, var, init) extern type var
+# define DECLARE(type,var,init) extern type var
#endif
-enum insertion_type
-{
- cartouche, defcv, deffn, defivar, defmac, defmethod,
- defop, defopt, defspec, deftp, deftypefn, deftypefun,
- deftypemethod, deftypevar, deftypevr, defun, defvar,
- defvr, detailmenu, direntry, display, enumerate, example,
- flushleft, flushright, format, ftable, group, ifclear,
- ifinfo, ifnothtml, ifnottex, ifset, itemize, lisp, menu,
- multitable, quotation, smallexample, smalllisp, table, vtable,
- bad_type
-};
+/* Hardcoded per GNU standards, not dependent on argv[0]. */
+DECLARE (char *, progname, "makeinfo");
-DECLARE (int, insertion_level, 0);
-
-#if defined (COMPILING_MAKEINFO)
-char *insertion_type_names[] =
+enum reftype
{
- "cartouche", "defcv", "deffn", "defivar", "defmac", "defmethod",
- "defop", "defopt", "defspec", "deftp", "deftypefn", "deftypefun",
- "deftypemethod", "deftypevar", "deftypevr", "defun", "defvar",
- "defvr", "detailmenu", "direntry", "display", "enumerate", "example",
- "flushleft", "flushright", "format", "ftable", "group", "ifclear",
- "ifinfo", "ifnothtml", "ifnottex", "ifset", "itemize", "lisp", "menu",
- "multitable", "quotation", "smallexample", "smalllisp", "table", "vtable",
- "bad_type"
+ menu_reference, followed_reference
};
-#endif
-typedef struct istack_elt
-{
- struct istack_elt *next;
- char *item_function;
- char *filename;
- int line_number;
- int filling_enabled;
- int indented_fill;
- enum insertion_type insertion;
- int inhibited;
- int in_fixed_width_font;
-} INSERTION_ELT;
-
-DECLARE (INSERTION_ELT *, insertion_stack, (INSERTION_ELT *)NULL);
+extern char *get_xref_token ();
+
+/* Nonzero means a string is in execution, as opposed to a file. */
+DECLARE (int, executing_string, 0);
+
+/* Nonzero means to inhibit writing macro expansions to the output
+ stream, because it has already been written. */
+DECLARE (int, me_inhibit_expansion, 0);
+extern char *expansion (), *text_expansion ();
+
/* Current output stream. */
-DECLARE (FILE *, output_stream, (FILE *)NULL);
+DECLARE (FILE *, output_stream, NULL);
+
+DECLARE (char *, pretty_output_filename, NULL);
+
+/* Current output file name. */
+DECLARE (char *, current_output_filename, NULL);
/* Output paragraph buffer. */
-DECLARE (unsigned char *, output_paragraph, (unsigned char *)NULL);
+DECLARE (unsigned char *, output_paragraph, NULL);
/* Offset into OUTPUT_PARAGRAPH. */
DECLARE (int, output_paragraph_offset, 0);
@@ -88,46 +64,132 @@ DECLARE (int, output_paragraph_offset, 0);
/* The output paragraph "cursor" horizontal position. */
DECLARE (int, output_column, 0);
-/* Non-zero means output_paragraph contains text. */
+/* Position in the output file. */
+DECLARE (int, output_position, 0);
+
+/* The offset into OUTPUT_PARAGRAPH where we have a meta character
+ produced by a markup such as @code or @dfn. */
+DECLARE (int, meta_char_pos, -1);
+
+/* Nonzero means output_paragraph contains text. */
DECLARE (int, paragraph_is_open, 0);
+/* Nonzero means that `start_paragraph' MUST be called before we pay
+ any attention to `close_paragraph' calls. */
+DECLARE (int, must_start_paragraph, 0);
+
+/* Nonzero means that we have seen "@top" once already. */
+DECLARE (int, top_node_seen, 0);
+
+/* Nonzero means that we have seen a non-"@top" node already. */
+DECLARE (int, non_top_node_seen, 0);
+
+/* Nonzero indicates that indentation is temporarily turned off. */
+DECLARE (int, no_indent, 1);
+
+/* Nonzero indicates that filling a line also indents the new line. */
+DECLARE (int, indented_fill, 0);
+
+/* Nonzero means forcing output text to be flushright. */
+DECLARE (int, force_flush_right, 0);
+
/* The amount of indentation to apply at the start of each line. */
DECLARE (int, current_indent, 0);
-/* nonzero if we are currently processing a multitable command */
-DECLARE (int, multitable_active, 0);
-
/* The column at which long lines are broken. */
DECLARE (int, fill_column, 72);
+/* Nonzero means that words are not to be split, even in long lines. This
+ gets changed for cm_w (). */
+DECLARE (int, non_splitting_words, 0);
+
+/* Amount by which @example indentation increases/decreases. */
+DECLARE (int, default_indentation_increment, 5);
+
+/* Nonzero means that we are currently hacking the insides of an
+ insertion which would use a fixed width font. */
+DECLARE (int, in_fixed_width_font, 0);
+
+/* Nonzero if we are currently processing a multitable command */
+DECLARE (int, multitable_active, 0);
+
+/* Nonzero means that we're generating HTML. */
+DECLARE (int, html, 0);
+
+/* Nonzero means escape characters in HTML output. */
+DECLARE (int, escape_html, 1);
+extern char *escape_string (); /* do HTML escapes */
+
+/* Nonzero means that the use of paragraph_start_indent is inhibited.
+ @example uses this to line up the left columns of the example text.
+ A negative value for this variable is incremented each time it is used.
+ @noindent uses this to inhibit indentation for a single paragraph. */
+DECLARE (int, inhibit_paragraph_indentation, 0);
+
+/* Nonzero indicates that filling will take place on long lines. */
+DECLARE (int, filling_enabled, 1);
+
+/* The current node's node name. */
+DECLARE (char *, current_node, NULL);
+
+/* Command name in the process of being hacked. */
+DECLARE (char *, command, NULL);
+
+/* Nonzero if the last character inserted has the syntax class of NEWLINE. */
+DECLARE (int, last_char_was_newline, 1);
+
/* The current input file state. */
DECLARE (char *, input_filename, (char *)NULL);
DECLARE (char *, input_text, (char *)NULL);
-DECLARE (int, size_of_input_text, 0);
+DECLARE (int, input_text_length, 0);
DECLARE (int, input_text_offset, 0);
DECLARE (int, line_number, 0);
-
#define curchar() input_text[input_text_offset]
-/* **************************************************************** */
-/* */
-/* Global Defines */
-/* */
-/* **************************************************************** */
-
-/* Error levels */
-#define NO_ERROR 0
-#define SYNTAX 2
-#define FATAL 4
-
+
+/* A colon separated list of directories to search for files included
+ with @include. This can be controlled with the `-I' option to makeinfo. */
+DECLARE (char *, include_files_path, NULL);
+
+/* The filename of the current input file. This is never freed. */
+DECLARE (char *, node_filename, NULL);
+
+/* Nonzero means do not output "Node: Foo" for node separations, that
+ is, generate plain text. (--no-headers) */
+DECLARE (int, no_headers, 0);
+
+/* Nonzero means that we process @html and @rawhtml even when not
+ generating HTML. (--ifhtml) */
+DECLARE (int, process_html, 0);
+
+/* Nonzero means that we process @ifinfo even when generating HTML.
+ (--ifinfo) */
+DECLARE (int, process_info, 1);
+
+/* Nonzero means that we process @tex and @iftex. (--iftex) */
+DECLARE (int, process_tex, 0);
+
+/* Maximum number of references to a single node before complaining.
+ (--reference-limit) */
+DECLARE (int, reference_warning_limit, 1000);
+
+/* Default is to check node references. (--no-validate) */
+DECLARE (int, validating, 1);
+
+/* Nonzero means print information about what is going on. (--verbose) */
+DECLARE (int, verbose_mode, 0);
+
+/* Nonzero means prefix each @chapter, ... with a number like 1. (--number-sections) */
+DECLARE (int, number_sections, 0);
+
+/* Nonzero means expand node names and references while validating.
+ This will avoid errors when the Texinfo document uses features
+ like @@ and @value inconsistently in node names, but will slow
+ the program by about 80%. You HAVE been warned. */
+DECLARE (int, expensive_validation, 0);
+
/* C's standard macros don't check to make sure that the characters being
changed are within range. So I have to check explicitly. */
-/* GNU Library doesn't have toupper(). Until GNU gets this fixed, I will
- have to do it. */
-#ifndef toupper
-#define toupper(c) ((c) - 32)
-#endif
-
#define coerce_to_upper(c) ((islower(c) ? toupper(c) : (c)))
#define coerce_to_lower(c) ((isupper(c) ? tolower(c) : (c)))
@@ -138,9 +200,9 @@ DECLARE (int, line_number, 0);
#define META(c) ((c) | (meta_character_bit))
#define UNMETA(c) ((c) & (~meta_character_bit))
-#define whitespace(c) (((c) == '\t') || ((c) == ' '))
-#define sentence_ender(c) ((c) == '.' || (c) == '?' || (c) == '!')
-#define cr_or_whitespace(c) (((c) == '\t') || ((c) == ' ') || ((c) == '\n'))
+#define whitespace(c) ((c) == '\t' || (c) == ' ')
+#define sentence_ender(c) ((c) == '.' || (c) == '?' || (c) == '!')
+#define cr_or_whitespace(c) (whitespace(c) || (c) == '\r' || (c) == '\n')
#ifndef isletter
#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
@@ -158,33 +220,30 @@ DECLARE (int, line_number, 0);
#define digit_value(c) ((c) - '0')
#endif
-#define member(c, s) (strchr (s, c) != NULL)
+#define HTML_SAFE "$-_.+!*'()"
+#define URL_SAFE_CHAR(ch) (isalnum (ch) || strchr (HTML_SAFE, ch))
#define COMMAND_PREFIX '@'
/* Stuff for splitting large files. */
#define SPLIT_SIZE_THRESHOLD 70000 /* What's good enough for Stallman... */
#define DEFAULT_SPLIT_SIZE 50000 /* Is probably good enough for me. */
-
DECLARE (int, splitting, 1); /* Defaults to true for now. */
-typedef void COMMAND_FUNCTION (); /* So I can say COMMAND_FUNCTION *foo; */
-
-#define command_char(c) ((!whitespace(c)) && \
- ((c) != '\n') && \
- ((c) != '{') && \
- ((c) != '}') && \
- ((c) != '='))
+#define command_char(c) (!cr_or_whitespace(c) \
+ && (c) != '{' \
+ && (c) != '}' \
+ && (c) != '=')
#define skip_whitespace() \
- while ((input_text_offset != size_of_input_text) && \
+ while ((input_text_offset != input_text_length) && \
whitespace (curchar())) \
input_text_offset++
#define skip_whitespace_and_newlines() \
do { \
- while ((input_text_offset != size_of_input_text) && \
- (whitespace (curchar ()) || (curchar () == '\n'))) \
+ while (input_text_offset != input_text_length \
+ && cr_or_whitespace (curchar ())) \
{ \
if (curchar () == '\n') \
line_number++; \
@@ -192,4 +251,10 @@ typedef void COMMAND_FUNCTION (); /* So I can say COMMAND_FUNCTION *foo; */
} \
} while (0)
-#endif /* !MAKEINFO_H */
+/* Return nonzero if STRING is the text at input_text + input_text_offset,
+ else zero. */
+#define looking_at(string) \
+ (strncmp (input_text + input_text_offset, string, strlen (string)) == 0)
+
+
+#endif /* not MAKEINFO_H */
diff --git a/contrib/texinfo/makeinfo/multi.c b/contrib/texinfo/makeinfo/multi.c
index 99c380d..b41bb47 100644
--- a/contrib/texinfo/makeinfo/multi.c
+++ b/contrib/texinfo/makeinfo/multi.c
@@ -1,7 +1,7 @@
/* multi.c -- multitable stuff for makeinfo.
- $Id: multi.c,v 1.9 1997/07/24 22:01:00 karl Exp $
+ $Id: multi.c,v 1.18 1999/08/17 21:06:56 karl Exp $
- Copyright (C) 1996, 97 Free Software Foundation, Inc.
+ Copyright (C) 1996, 97, 98, 99 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "system.h"
+#include "insertion.h"
#include "makeinfo.h"
#define MAXCOLS 100 /* remove this limit later @@ */
@@ -51,6 +52,7 @@ struct env
{
unsigned char *output_paragraph;
int output_paragraph_offset;
+ int meta_char_pos;
int output_column;
int paragraph_is_open;
int current_indent;
@@ -66,20 +68,33 @@ static int last_column;
/* flags indicating whether horizontal and vertical separators need
to be drawn, separating rows and columns in the current multitable. */
static int hsep, vsep;
+
+/* whether this is the first row. */
+static int first_row;
+
+static void output_multitable_row ();
-/* Output a row. Have to keep `output_position' up-to-date for each
- character we output, or the tags table will be off, leading to
- chopped-off output files and undefined nodes (because they're in the
- wrong file, etc.). Perhaps it would be better to accumulate this
- value somewhere and add it once at the end of the table, or return it
- as the value, but this seems simplest. */
+/* Output a row. Calls insert, but also flushes the buffered output
+ when we see a newline, since in multitable every line is a separate
+ paragraph. */
static void
out_char (ch)
int ch;
{
- extern int output_position;
- putc (ch, output_stream);
- output_position++;
+ if (html)
+ add_char (ch);
+ else
+ {
+ int env = select_output_environment (0);
+ insert (ch);
+ if (ch == '\n')
+ {
+ uninhibit_output_flushing ();
+ flush_output ();
+ inhibit_output_flushing ();
+ }
+ select_output_environment (env);
+ }
}
@@ -88,6 +103,12 @@ draw_horizontal_separator ()
{
int i, j, s;
+ if (html)
+ {
+ add_word ("<hr>");
+ return;
+ }
+
for (s = 0; s < envs[0].current_indent; s++)
out_char (' ');
if (vsep)
@@ -101,34 +122,48 @@ draw_horizontal_separator ()
out_char ('\n');
}
+
+/* multitable strategy:
+ for each item {
+ for each column in an item {
+ initialize a new paragraph
+ do ordinary formatting into the new paragraph
+ save the paragraph away
+ repeat if there are more paragraphs in the column
+ }
+ dump out the saved paragraphs and free the storage
+ }
+
+ For HTML we construct a simple HTML 3.2 table with <br>s inserted
+ to help non-tables browsers. `@item' inserts a <tr> and `@tab'
+ inserts <td>; we also try to close <tr>. The only real
+ alternative is to rely on the info formatting engine and present
+ preformatted text. */
+
void
do_multitable ()
{
int ncolumns;
- /*
- * multitable strategy:
- * for each item {
- * for each column in an item {
- * initialize a new paragraph
- * do ordinary formatting into the new paragraph
- * save the paragraph away
- * repeat if there are more paragraphs in the column
- * }
- * dump out the saved paragraphs and free the storage
- * }
- */
-
if (multitable_active)
{
line_error ("Multitables cannot be nested");
return;
}
+ close_single_paragraph ();
+
/* scan the current item function to get the field widths
and number of columns, and set up the output environment list
accordingly. */
ncolumns = setup_multitable_parameters ();
+ first_row = 1;
+
+ /* <p> for non-tables browsers. @multitable implicitly ends the
+ current paragraph, so this is ok. */
+ if (html)
+ add_word ("<p><table>");
+
if (hsep)
draw_horizontal_separator ();
@@ -141,6 +176,53 @@ do_multitable ()
++multitable_active;
}
+/* Called to handle a {...} template on the @multitable line.
+ We're at the { and our first job is to find the matching }; as a side
+ effect, we change *PARAMS to point to after it. Our other job is to
+ expand the template text and return the width of that string. */
+static unsigned
+find_template_width (params)
+ char **params;
+{
+ char *template, *xtemplate;
+ unsigned len;
+ char *start = *params;
+ int brace_level = 0;
+
+ /* The first character should be a {. */
+ if (!params || !*params || **params != '{')
+ {
+ line_error ("find_template width internal error: passed %s",
+ params ? *params : "null");
+ return 0;
+ }
+
+ do
+ {
+ if (**params == '{' && (*params)[-1] != '@')
+ brace_level++;
+ else if (**params == '}' && (*params)[-1] != '@')
+ brace_level--;
+ else if (**params == 0)
+ {
+ line_error (_("Missing } in @multitable template"));
+ return 0;
+ }
+ (*params)++;
+ }
+ while (brace_level > 0);
+
+ template = substring (start + 1, *params - 1); /* omit braces */
+ xtemplate = expansion (template, 0);
+ len = strlen (xtemplate);
+
+ free (template);
+ free (xtemplate);
+
+ return len;
+}
+
+
/* Read the parameters for a multitable from the current command
line, save the parameters away, and return the
number of columns. */
@@ -150,7 +232,7 @@ setup_multitable_parameters ()
char *params = insertion_stack->item_function;
int nchars;
float columnfrac;
- char command[200]; /* naughty, should be no fixed limits */
+ char command[200]; /* xx no fixed limits */
int i = 1;
/* We implement @hsep and @vsep even though TeX doesn't.
@@ -176,12 +258,12 @@ setup_multitable_parameters ()
for ( ; i <= MAXCOLS; i++) {
if (sscanf (params, "%f", &columnfrac) < 1)
goto done;
- /* Unfortunately, can't use %n since some m68k-hp-bsd libc
+ /* Unfortunately, can't use %n since m68k-hp-bsd libc (at least)
doesn't support it. So skip whitespace (preceding the
number) and then non-whitespace (the number). */
while (*params && (*params == ' ' || *params == '\t'))
params++;
- /* Hmm, but what what @columnfractions 3foo. Well, I suppose
+ /* Hmm, but what about @columnfractions 3foo. Well, I suppose
it's invalid input anyway. */
while (*params && *params != ' ' && *params != '\t'
&& *params != '\n' && *params != '@')
@@ -192,15 +274,11 @@ setup_multitable_parameters ()
}
} else if (*params == '{') {
- char *start = params;
- while ((*params != '}' || params[-1] == '@') && *params) {
- params++;
- }
+ unsigned template_width = find_template_width (&params);
+
/* This gives us two spaces between columns. Seems reasonable.
- Really should expand the text, though, so a template of
- `@code{foo}' has a width of five, not ten. Also have to match
- braces, then. How to take into account current_indent here? */
- setup_output_environment (i++, params++ - start);
+ How to take into account current_indent here? */
+ setup_output_environment (i++, template_width + 2);
} else {
warning (_("ignoring stray text `%s' after @multitable"), params);
@@ -252,6 +330,7 @@ select_output_environment (n)
/* stash current env info from global vars into the old environment */
e->output_paragraph = output_paragraph;
e->output_paragraph_offset = output_paragraph_offset;
+ e->meta_char_pos = meta_char_pos;
e->output_column = output_column;
e->paragraph_is_open = paragraph_is_open;
e->current_indent = current_indent;
@@ -262,6 +341,7 @@ select_output_environment (n)
e = &envs[current_env_no];
output_paragraph = e->output_paragraph;
output_paragraph_offset = e->output_paragraph_offset;
+ meta_char_pos = e->meta_char_pos;
output_column = e->output_column;
paragraph_is_open = e->paragraph_is_open;
current_indent = e->current_indent;
@@ -281,8 +361,6 @@ nselect_next_environment ()
}
-static void output_multitable_row ();
-
/* do anything needed at the beginning of processing a
multitable column. */
void
@@ -300,10 +378,20 @@ int
multitable_item ()
{
if (!multitable_active) {
- /* impossible, I think. */
- error (_("multitable item not in active multitable"));
- exit (1);
+ line_error ("multitable_item internal error: no active multitable");
+ xexit (1);
}
+
+ if (html)
+ {
+ if (!first_row)
+ add_word ("<br></tr>"); /* <br> for non-tables browsers. */
+ add_word ("<tr align=\"left\"><td>");
+ first_row = 0;
+ return;
+ }
+ first_row = 0;
+
if (current_env_no > 0) {
output_multitable_row ();
}
@@ -311,7 +399,7 @@ multitable_item ()
select_output_environment (1);
if (!output_paragraph) {
line_error (_("Cannot select column #%d in multitable"), current_env_no);
- exit (FATAL);
+ exit (1);
}
init_column ();
@@ -322,11 +410,11 @@ multitable_item ()
static void
output_multitable_row ()
{
- int i, j, s, remaining;
-
/* offset in the output paragraph of the next char needing
to be output for that column. */
int offset[MAXCOLS];
+ int i, j, s, remaining;
+ int had_newline = 0;
for (i = 0; i <= last_column; i++)
offset[i] = 0;
@@ -340,9 +428,12 @@ output_multitable_row ()
/* remove trailing whitespace from each column */
for (i = 1; i <= last_column; i++) {
- while (cr_or_whitespace (CHAR_AT (envs[i].output_paragraph_offset - 1))) {
- envs[i].output_paragraph_offset--;
- }
+ if (envs[i].output_paragraph_offset)
+ while (cr_or_whitespace (CHAR_AT (envs[i].output_paragraph_offset - 1)))
+ envs[i].output_paragraph_offset--;
+
+ if (i == current_env_no)
+ output_paragraph_offset = envs[i].output_paragraph_offset;
}
/* read the current line from each column, outputting them all
@@ -367,7 +458,7 @@ output_multitable_row ()
out_char ('|');
for (i = 1; i <= last_column; i++) {
- for (s = 0; i < envs[i].current_indent; s++)
+ for (s = 0; s < envs[i].current_indent; s++)
out_char (' ');
for (j = 0; CHAR_ADDR (j) < envs[i].output_paragraph_offset; j++) {
if (CHAR_AT (j) == '\n')
@@ -375,13 +466,22 @@ output_multitable_row ()
out_char (CHAR_AT (j));
}
offset[i] += j + 1; /* skip last text plus skip the newline */
- for (; j <= envs[i].fill_column; j++)
- out_char (' ');
+
+ /* Do not output trailing blanks if we're in the last column and
+ there will be no trailing |. */
+ if (i < last_column && !vsep)
+ for (; j <= envs[i].fill_column; j++)
+ out_char (' ');
if (vsep)
out_char ('|'); /* draw column separator */
}
out_char ('\n'); /* end of line */
+ had_newline = 1;
}
+
+ /* If completely blank item, get blank line despite no other output. */
+ if (!had_newline)
+ out_char ('\n'); /* end of line */
if (hsep)
draw_horizontal_separator ();
@@ -403,7 +503,11 @@ cm_tab ()
if (!multitable_active)
error (_("ignoring @tab outside of multitable"));
- nselect_next_environment ();
+ if (html)
+ add_word ("<td>");
+ else
+ nselect_next_environment ();
+
init_column ();
}
@@ -412,17 +516,19 @@ cm_tab ()
void
end_multitable ()
{
- output_multitable_row ();
+ if (!html)
+ output_multitable_row ();
/* Multitables cannot be nested. Otherwise, we'd have to save the
previous output environment number on a stack somewhere, and then
restore to that environment. */
select_output_environment (0);
- close_paragraph ();
- insert ('\n'); /* we swallow newlines, so insert one of our own */
-
multitable_active = 0;
uninhibit_output_flushing ();
+ close_insertion_paragraph ();
+
+ if (html)
+ add_word ("<br></tr></table>\n");
#if 0
printf (_("** Multicolumn output from last row:\n"));
diff --git a/contrib/texinfo/makeinfo/node.c b/contrib/texinfo/makeinfo/node.c
new file mode 100644
index 0000000..8dbbd42
--- /dev/null
+++ b/contrib/texinfo/makeinfo/node.c
@@ -0,0 +1,1568 @@
+/* node.c -- nodes for Texinfo.
+ $Id: node.c,v 1.23 1999/09/20 12:31:21 karl Exp $
+
+ Copyright (C) 1998, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "cmds.h"
+#include "files.h"
+#include "footnote.h"
+#include "macro.h"
+#include "makeinfo.h"
+#include "node.h"
+#include "sectioning.h"
+#include "insertion.h"
+
+
+/* See comments in node.h. */
+NODE_REF *node_references = NULL;
+NODE_REF *node_node_references = NULL;
+TAG_ENTRY *tag_table = NULL;
+int node_number = -1;
+int current_section = 0;
+int outstanding_node = 0;
+
+/* Adding nodes, and making tags. */
+
+/* Start a new tag table. */
+void
+init_tag_table ()
+{
+ while (tag_table)
+ {
+ TAG_ENTRY *temp = tag_table;
+ free (temp->node);
+ free (temp->prev);
+ free (temp->next);
+ free (temp->up);
+ tag_table = tag_table->next_ent;
+ free (temp);
+ }
+}
+
+/* Write out the contents of the existing tag table.
+ INDIRECT_P says how to format the output (it depends on whether the
+ table is direct or indirect). */
+static void
+write_tag_table_internal (indirect_p)
+ int indirect_p;
+{
+ TAG_ENTRY *node;
+ int old_indent = no_indent;
+
+ no_indent = 1;
+ filling_enabled = 0;
+ must_start_paragraph = 0;
+ close_paragraph ();
+
+ if (!indirect_p)
+ {
+ no_indent = 1;
+ insert ('\n');
+ }
+
+ add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : "");
+
+ /* Do not collapse -- to -, etc., in node names. */
+ in_fixed_width_font++;
+
+ for (node = tag_table; node; node = node->next_ent)
+ {
+ if (node->flags & TAG_FLAG_ANCHOR)
+ { /* This reference is to an anchor. */
+ execute_string ("Ref: %s", node->node);
+ }
+ else
+ { /* This reference is to a node. */
+ execute_string ("Node: %s", node->node);
+ }
+ add_word_args ("\177%d\n", node->position);
+ }
+
+ add_word ("\037\nEnd Tag Table\n");
+
+ /* Do not collapse -- to -, etc., in node names. */
+ in_fixed_width_font--;
+
+ flush_output ();
+ no_indent = old_indent;
+}
+
+void
+write_tag_table ()
+{
+ write_tag_table_internal (0); /* Not indirect. */
+}
+
+void
+write_tag_table_indirect ()
+{
+ write_tag_table_internal (1);
+}
+
+/* Convert "top" and friends into "Top". */
+static void
+normalize_node_name (string)
+ char *string;
+{
+ if (strcasecmp (string, "Top") == 0)
+ strcpy (string, "Top");
+}
+
+char *
+get_node_token (expand)
+ int expand;
+{
+ char *string;
+
+ get_until_in_line (expand, ",", &string);
+
+ if (curchar () == ',')
+ input_text_offset++;
+
+ fix_whitespace (string);
+
+ /* Force all versions of "top" to be "Top". */
+ normalize_node_name (string);
+
+ return string;
+}
+
+/* Expand any macros and other directives in a node name, and
+ return the expanded name as an malloc'ed string. */
+char *
+expand_node_name (node)
+ char *node;
+{
+ char *result = node;
+
+ if (node)
+ {
+ /* Don't expand --, `` etc., in case somebody will want
+ to print the result. */
+ in_fixed_width_font++;
+ result = expansion (node, 0);
+ in_fixed_width_font--;
+ fix_whitespace (result);
+ normalize_node_name (result);
+ }
+ return result;
+}
+
+/* Look up NAME in the tag table, and return the associated
+ tag_entry. If the node is not in the table return NULL. */
+TAG_ENTRY *
+find_node (name)
+ char *name;
+{
+ TAG_ENTRY *tag = tag_table;
+ char *expanded_name;
+ char n1 = name[0];
+
+ while (tag)
+ {
+ if (tag->node[0] == n1 && strcmp (tag->node, name) == 0)
+ return tag;
+ tag = tag->next_ent;
+ }
+
+ if (!expensive_validation)
+ return NULL;
+
+ /* Try harder. Maybe TAG_TABLE has the expanded NAME, or maybe NAME
+ is expanded while TAG_TABLE has its unexpanded form. This may
+ slow down the search, but if they want this feature, let them
+ pay! If they want it fast, they should write every node name
+ consistently (either always expanded or always unexpaned). */
+ expanded_name = expand_node_name (name);
+ for (tag = tag_table; tag; tag = tag->next_ent)
+ {
+ if (STREQ (tag->node, expanded_name))
+ break;
+ /* If the tag name doesn't have the command prefix, there's no
+ chance it could expand into anything but itself. */
+ if (strchr (tag->node, COMMAND_PREFIX))
+ {
+ char *expanded_node = expand_node_name (tag->node);
+
+ if (STREQ (expanded_node, expanded_name))
+ {
+ free (expanded_node);
+ break;
+ }
+ free (expanded_node);
+ }
+ }
+ free (expanded_name);
+ return tag;
+}
+
+/* Similarly for next etc. references in a @node command, where we
+ don't care about most of the entries. */
+static void
+remember_node_node_reference (node)
+ char *node;
+{
+ NODE_REF *temp = xmalloc (sizeof (NODE_REF));
+ int number;
+
+ if (!node) return;
+ temp->next = node_node_references;
+ temp->node = xstrdup (node);
+ temp->type = followed_reference;
+ number = number_of_node (node);
+ if (number)
+ temp->number = number; /* Already assigned. */
+ else
+ {
+ node_number++;
+ temp->number = node_number;
+ }
+ node_node_references = temp;
+}
+
+/* Remember NODE and associates. */
+void
+remember_node (node, prev, next, up, position, line_no, flags)
+ char *node, *prev, *next, *up;
+ int position, line_no, flags;
+{
+ /* Check for existence of this tag already. */
+ if (validating)
+ {
+ TAG_ENTRY *tag = find_node (node);
+ if (tag)
+ {
+ line_error (_("Node `%s' previously defined at line %d"),
+ node, tag->line_no);
+ return;
+ }
+ }
+
+ if (!(flags & TAG_FLAG_ANCHOR))
+ {
+ /* Make this the current node. */
+ current_node = node;
+ }
+
+ /* Add it to the list. */
+ {
+ int number = number_of_node (node);
+
+ TAG_ENTRY *new = xmalloc (sizeof (TAG_ENTRY));
+ new->node = node;
+ new->prev = prev;
+ new->next = next;
+ new->up = up;
+ new->position = position;
+ new->line_no = line_no;
+ new->filename = node_filename;
+ new->touched = 0;
+ new->flags = flags;
+ if (number)
+ new->number = number; /* Already assigned. */
+ else
+ {
+ node_number++;
+ new->number = node_number;
+ }
+ new->next_ent = tag_table;
+ tag_table = new;
+ }
+
+ if (html)
+ { /* Note the references to the next etc. nodes too. */
+ remember_node_node_reference (next);
+ remember_node_node_reference (prev);
+ remember_node_node_reference (up);
+ }
+}
+
+/* Remember this node name for later validation use. This is used to
+ remember menu references while reading the input file. After the
+ output file has been written, if validation is on, then we use the
+ contents of `node_references' as a list of nodes to validate. */
+void
+remember_node_reference (node, line, type)
+ char *node;
+ int line;
+ enum reftype type;
+{
+ NODE_REF *temp = xmalloc (sizeof (NODE_REF));
+ int number = number_of_node (node);
+
+ temp->next = node_references;
+ temp->node = xstrdup (node);
+ temp->line_no = line;
+ temp->section = current_section;
+ temp->type = type;
+ temp->containing_node = xstrdup (current_node ? current_node : "");
+ temp->filename = node_filename;
+ if (number)
+ temp->number = number; /* Already assigned. */
+ else
+ {
+ node_number++;
+ temp->number = node_number;
+ }
+
+ node_references = temp;
+}
+
+static void
+isolate_nodename (nodename)
+ char *nodename;
+{
+ int i, c;
+ int paren_seen, paren;
+
+ if (!nodename)
+ return;
+
+ canon_white (nodename);
+ paren_seen = paren = i = 0;
+
+ if (*nodename == '.' || !*nodename)
+ {
+ *nodename = 0;
+ return;
+ }
+
+ if (*nodename == '(')
+ {
+ paren++;
+ paren_seen++;
+ i++;
+ }
+
+ for (; (c = nodename[i]); i++)
+ {
+ if (paren)
+ {
+ if (c == '(')
+ paren++;
+ else if (c == ')')
+ paren--;
+
+ continue;
+ }
+
+ /* If the character following the close paren is a space, then this
+ node has no more characters associated with it. */
+ if (c == '\t' ||
+ c == '\n' ||
+ c == ',' ||
+ ((paren_seen && nodename[i - 1] == ')') &&
+ (c == ' ' || c == '.')) ||
+ (c == '.' &&
+ ((!nodename[i + 1] ||
+ (cr_or_whitespace (nodename[i + 1])) ||
+ (nodename[i + 1] == ')')))))
+ break;
+ }
+ nodename[i] = 0;
+}
+
+/* This function gets called at the start of every line while inside a
+ menu. It checks to see if the line starts with "* ", and if so and
+ REMEMBER_REF is nonzero, remembers the node reference as type
+ REF_TYPE that this menu refers to. input_text_offset is at the \n
+ just before the menu line. If REMEMBER_REF is zero, REF_TYPE is unused. */
+#define MENU_STARTER "* "
+char *
+glean_node_from_menu (remember_ref, ref_type)
+ int remember_ref;
+ enum reftype ref_type;
+{
+ int i, orig_offset = input_text_offset;
+ char *nodename;
+ char *line, *expanded_line;
+ char *old_input = input_text;
+ size_t old_size = input_text_length;
+
+ if (strncmp (&input_text[input_text_offset + 1],
+ MENU_STARTER,
+ strlen (MENU_STARTER)) != 0)
+ return NULL;
+ else
+ input_text_offset += strlen (MENU_STARTER) + 1;
+
+ /* The menu entry might include macro calls, so we need to expand them. */
+ get_until ("\n", &line);
+ only_macro_expansion++; /* only expand macros in menu entries */
+ expanded_line = expansion (line, 0);
+ only_macro_expansion--;
+ free (line);
+ input_text = expanded_line;
+ input_text_offset = 0;
+ input_text_length = strlen (expanded_line);
+
+ get_until_in_line (0, ":", &nodename);
+ if (curchar () == ':')
+ input_text_offset++;
+
+ if (curchar () != ':')
+ {
+ free (nodename);
+ get_until_in_line (0, "\n", &nodename);
+ isolate_nodename (nodename);
+ }
+
+ input_text = old_input;
+ input_text_offset = orig_offset;
+ input_text_length = old_size;
+ free (expanded_line);
+ fix_whitespace (nodename);
+ normalize_node_name (nodename);
+ i = strlen (nodename);
+ if (i && nodename[i - 1] == ':')
+ nodename[i - 1] = 0;
+
+ if (remember_ref)
+ remember_node_reference (nodename, line_number, ref_type);
+
+ return nodename;
+}
+
+/* Set the name of the current output file. */
+void
+set_current_output_filename (fname)
+ const char *fname;
+{
+ if (current_output_filename)
+ free (current_output_filename);
+ current_output_filename = xstrdup (fname);
+}
+
+/* The order is: nodename, nextnode, prevnode, upnode.
+ If all of the NEXT, PREV, and UP fields are empty, they are defaulted.
+ You must follow a node command which has those fields defaulted
+ with a sectioning command (e.g. @chapter) giving the "level" of that node.
+ It is an error not to do so.
+ The defaults come from the menu in this node's parent. */
+void
+cm_node ()
+{
+ char *node, *prev, *next, *up;
+ int new_node_pos, defaulting, this_section;
+ int no_warn = 0;
+
+ if (strcmp (command, "nwnode") == 0)
+ no_warn = TAG_FLAG_NO_WARN;
+
+ /* Get rid of unmatched brace arguments from previous commands. */
+ discard_braces ();
+
+ /* There also might be insertions left lying around that haven't been
+ ended yet. Do that also. */
+ discard_insertions (1);
+
+ if (!html && !already_outputting_pending_notes)
+ {
+ close_paragraph ();
+ output_pending_notes ();
+ }
+
+ if (html && splitting && top_node_seen)
+ {
+ /* End the current split output file. */
+ close_paragraph ();
+ output_pending_notes ();
+ start_paragraph ();
+ /* Fixme: html: need a navigation bar here. */
+ add_word ("</body></html>\n");
+ close_paragraph ();
+ fclose (output_stream);
+ output_stream = NULL;
+ }
+
+ filling_enabled = indented_fill = 0;
+ new_node_pos = output_position;
+ if (!html || (html && splitting))
+ current_footnote_number = 1;
+
+ if (macro_expansion_output_stream && !executing_string)
+ append_to_expansion_output (input_text_offset + 1);
+
+ /* Do not collapse -- to -, etc., in node names. */
+ in_fixed_width_font++;
+
+ /* While expanding the @node line, leave any non-macros
+ intact, so that the macro-expanded output includes them. */
+ only_macro_expansion++;
+ node = get_node_token (1);
+ only_macro_expansion--;
+ next = get_node_token (0);
+ prev = get_node_token (0);
+ up = get_node_token (0);
+
+ if (verbose_mode)
+ printf (_("Formatting node %s...\n"), node);
+
+ if (macro_expansion_output_stream && !executing_string)
+ remember_itext (input_text, input_text_offset);
+
+ no_indent = 1;
+ if (!no_headers && !html)
+ {
+ add_word_args ("\037\nFile: %s, Node: ", pretty_output_filename);
+
+ if (macro_expansion_output_stream && !executing_string)
+ me_execute_string (node);
+ else
+ execute_string ("%s", node);
+ filling_enabled = indented_fill = 0;
+ }
+
+ /* Check for defaulting of this node's next, prev, and up fields. */
+ defaulting = (*next == 0 && *prev == 0 && *up == 0);
+
+ this_section = what_section (input_text + input_text_offset);
+
+ /* If we are defaulting, then look at the immediately following
+ sectioning command (error if none) to determine the node's
+ level. Find the node that contains the menu mentioning this node
+ that is one level up (error if not found). That node is the "Up"
+ of this node. Default the "Next" and "Prev" from the menu. */
+ if (defaulting)
+ {
+ NODE_REF *last_ref = NULL;
+ NODE_REF *ref = node_references;
+
+ if (this_section < 0 && !STREQ (node, "Top"))
+ {
+ char *polite_section_name = "top";
+ int i;
+
+ for (i = 0; section_alist[i].name; i++)
+ if (section_alist[i].level == current_section + 1)
+ {
+ polite_section_name = section_alist[i].name;
+ break;
+ }
+
+ line_error
+ (_("Node `%s' requires a sectioning command (e.g. %c%s)"),
+ node, COMMAND_PREFIX, polite_section_name);
+ }
+ else
+ {
+ if (strcmp (node, "Top") == 0)
+ {
+ /* Default the NEXT pointer to be the first menu item in
+ this node, if there is a menu in this node. We have to
+ try very hard to find the menu, as it may be obscured
+ by execution_strings which are on the filestack. For
+ every member of the filestack which has a FILENAME
+ member which is identical to the current INPUT_FILENAME,
+ search forward from that offset. */
+ int saved_input_text_offset = input_text_offset;
+ int saved_input_text_length = input_text_length;
+ char *saved_input_text = input_text;
+ FSTACK *next_file = filestack;
+
+ int orig_offset, orig_size;
+
+ /* No matter what, make this file point back at `(dir)'. */
+ free (up);
+ up = xstrdup ("(dir)"); /* html fixxme */
+
+ while (1)
+ {
+ orig_offset = input_text_offset;
+ orig_size =
+ search_forward (node_search_string, orig_offset);
+
+ if (orig_size < 0)
+ orig_size = input_text_length;
+
+ input_text_offset = search_forward ("\n@menu", orig_offset);
+ if (input_text_offset > -1
+ && cr_or_whitespace (input_text[input_text_offset + 6]))
+ {
+ char *nodename_from_menu = NULL;
+
+ input_text_offset =
+ search_forward ("\n* ", input_text_offset);
+
+ if (input_text_offset != -1)
+ nodename_from_menu = glean_node_from_menu (0, 0);
+
+ if (nodename_from_menu)
+ {
+ free (next);
+ next = nodename_from_menu;
+ break;
+ }
+ }
+
+ /* We got here, so it hasn't been found yet. Try
+ the next file on the filestack if there is one. */
+ if (next_file
+ && FILENAME_CMP (next_file->filename, input_filename)
+ == 0)
+ {
+ input_text = next_file->text;
+ input_text_offset = next_file->offset;
+ input_text_length = next_file->size;
+ next_file = next_file->next;
+ }
+ else
+ { /* No more input files to check. */
+ break;
+ }
+ }
+
+ input_text = saved_input_text;
+ input_text_offset = saved_input_text_offset;
+ input_text_length = saved_input_text_length;
+ }
+ }
+
+ /* Fix the level of the menu references in the Top node, iff it
+ was declared with @top, and no subsequent reference was found. */
+ if (top_node_seen && !non_top_node_seen)
+ {
+ /* Then this is the first non-@top node seen. */
+ int level;
+
+ level = set_top_section_level (this_section - 1);
+ non_top_node_seen = 1;
+
+ while (ref)
+ {
+ if (ref->section == level)
+ ref->section = this_section - 1;
+ ref = ref->next;
+ }
+
+ ref = node_references;
+ }
+
+ while (ref)
+ {
+ if (ref->section == (this_section - 1)
+ && ref->type == menu_reference
+ && strcmp (ref->node, node) == 0)
+ {
+ char *containing_node = ref->containing_node;
+
+ free (up);
+ up = xstrdup (containing_node);
+
+ if (last_ref
+ && last_ref->type == menu_reference
+ && strcmp (last_ref->containing_node, containing_node) == 0)
+ {
+ free (next);
+ next = xstrdup (last_ref->node);
+ }
+
+ while (ref->section == this_section - 1
+ && ref->next
+ && ref->next->type != menu_reference)
+ ref = ref->next;
+
+ if (ref->next && ref->type == menu_reference
+ && strcmp (ref->next->containing_node, containing_node) == 0)
+ {
+ free (prev);
+ prev = xstrdup (ref->next->node);
+ }
+ else if (!ref->next
+ && strcasecmp (ref->containing_node, "Top") == 0)
+ {
+ free (prev);
+ prev = xstrdup (ref->containing_node);
+ }
+ break;
+ }
+ last_ref = ref;
+ ref = ref->next;
+ }
+ }
+
+ /* Insert the correct args if we are expanding macros, and the node's
+ pointers weren't defaulted. */
+ if (macro_expansion_output_stream && !executing_string && !defaulting)
+ {
+ char *temp;
+ int op_orig = output_paragraph_offset;
+ int meta_pos_orig = meta_char_pos;
+ int extra = html ? strlen (node) : 0;
+
+ temp = xmalloc (7 + extra + strlen (next) + strlen (prev) + strlen (up));
+ sprintf (temp, "%s, %s, %s, %s", html ? node : "", next, prev, up);
+ me_execute_string (temp);
+ free (temp);
+
+ output_paragraph_offset = op_orig;
+ meta_char_pos = meta_pos_orig;
+ }
+
+ if (!*node)
+ {
+ line_error (_("No node name specified for `%c%s' command"),
+ COMMAND_PREFIX, command);
+ free (node);
+ free (next); next = NULL;
+ free (prev); prev= NULL;
+ free (up); up = NULL;
+ node_number++; /* else it doesn't get bumped */
+ }
+ else
+ {
+ if (!*next) { free (next); next = NULL; }
+ if (!*prev) { free (prev); prev = NULL; }
+ if (!*up) { free (up); up = NULL; }
+ remember_node (node, prev, next, up, new_node_pos, line_number, no_warn);
+ outstanding_node = 1;
+ }
+
+ if (html)
+ {
+ char *tem;
+
+ if (splitting)
+ { /* this code not operational, we do not currently split html */
+ char filename[20];
+
+ sprintf (filename, "node%d.html", number_of_node (node));
+ output_stream = fopen (filename, "w");
+ if (output_stream == NULL)
+ {
+ fs_error (filename);
+ xexit (1);
+ }
+ set_current_output_filename (filename);
+ /* FIXME: when this code is operational, we will need to
+ expand node, next, prev, and up before output. */
+ add_word_args ("<html><head><title>%s</title>", node);
+ if (next) add_link (next, "rel=next");
+ if (prev) add_link (prev, "rel=previous");
+ if (up) add_link (up, "rel=up");
+ add_word ("</head>\n<body>\n");
+ }
+
+ if (!splitting && no_headers)
+ { /* cross refs need a name="#anchor" even if we're not writing headers*/
+ add_word ("<a name=\"");
+ tem = expand_node_name (node);
+ add_anchor_name (tem, 0);
+ add_word ("\"></a>");
+ free (tem);
+ }
+
+ if (splitting || !no_headers)
+ { /* Navigation bar. The <p> avoids the links area running
+ on with old Lynxen. */
+ add_word_args ("<p>%s\n", splitting ? "" : "<hr>");
+ add_word_args ("%s<a name=\"", _("Node:"));
+ tem = expand_node_name (node);
+ add_anchor_name (tem, 0);
+ add_word_args ("\">%s</a>", tem);
+ free (tem);
+
+ if (next)
+ {
+ add_word (",\n");
+ add_word (_("Next:"));
+ add_word ("<a rel=next href=\"");
+ tem = expansion (next, 0);
+ add_anchor_name (tem, 1);
+ add_word_args ("\">%s</a>", tem);
+ free (tem);
+ }
+ if (prev)
+ {
+ add_word (",\n");
+ add_word (_("Previous:"));
+ add_word ("<a rel=previous href=\"");
+ tem = expansion (prev, 0);
+ add_anchor_name (tem, 1);
+ add_word_args ("\">%s</a>", tem);
+ free (tem);
+ }
+ if (up)
+ {
+ add_word (",\n");
+ add_word (_("Up:"));
+ add_word ("<a rel=up href=\"");
+ tem = expansion (up, 0);
+ add_anchor_name (tem, 1);
+ add_word_args ("\">%s</a>", tem);
+ free (tem);
+ }
+ /* html fixxme: we want a `top' or `contents' link here. */
+
+ add_word_args ("\n%s<br>\n", splitting ? "<hr>" : "");
+ }
+ }
+
+ else if (!no_headers)
+ {
+ if (macro_expansion_output_stream)
+ me_inhibit_expansion++;
+
+ /* These strings are not translatable. */
+ if (next)
+ {
+ execute_string (", Next: %s", next);
+ filling_enabled = indented_fill = 0;
+ }
+ if (prev)
+ {
+ execute_string (", Prev: %s", prev);
+ filling_enabled = indented_fill = 0;
+ }
+ if (up)
+ {
+ execute_string (", Up: %s", up);
+ filling_enabled = indented_fill = 0;
+ }
+ if (macro_expansion_output_stream)
+ me_inhibit_expansion--;
+ }
+
+ close_paragraph ();
+ no_indent = 0;
+
+ /* Change the section only if there was a sectioning command. */
+ if (this_section >= 0)
+ current_section = this_section;
+
+ if (current_node && STREQ (current_node, "Top"))
+ top_node_seen = 1;
+
+ filling_enabled = 1;
+ in_fixed_width_font--;
+}
+
+/* Cross-reference target at an arbitrary spot. */
+void
+cm_anchor (arg)
+ int arg;
+{
+ char *anchor;
+
+ if (arg == END)
+ return;
+
+ /* Parse the anchor text. */
+ anchor = get_xref_token (1);
+
+ /* In HTML mode, need to actually produce some output. */
+ if (html)
+ {
+ /* If this anchor is at the beginning of a new paragraph, make
+ sure a new paragraph is indeed started. */
+ if (!paragraph_is_open)
+ {
+ start_paragraph ();
+ if (!in_fixed_width_font || in_menu || in_detailmenu)
+ {
+ insert_string ("<p>");
+ in_paragraph = 1;
+ }
+ }
+ add_word ("<a name=\"");
+ add_anchor_name (anchor, 0);
+ add_word ("\"></a>");
+ }
+
+ /* Save it in the tag table. */
+ remember_node (anchor, NULL, NULL, NULL, output_position + output_column,
+ line_number, TAG_FLAG_ANCHOR);
+}
+
+/* Find NODE in REF_LIST. */
+static NODE_REF *
+find_node_reference (node, ref_list)
+ char *node;
+ NODE_REF *ref_list;
+{
+ NODE_REF *orig_ref_list = ref_list;
+ char *expanded_node;
+
+ while (ref_list)
+ {
+ if (strcmp (node, ref_list->node) == 0)
+ break;
+ ref_list = ref_list->next;
+ }
+
+ if (ref_list || !expensive_validation)
+ return ref_list;
+
+ /* Maybe NODE is not expanded yet. This may be SLOW. */
+ expanded_node = expand_node_name (node);
+ for (ref_list = orig_ref_list; ref_list; ref_list = ref_list->next)
+ {
+ if (STREQ (expanded_node, ref_list->node))
+ break;
+ if (strchr (ref_list->node, COMMAND_PREFIX))
+ {
+ char *expanded_ref = expand_node_name (ref_list->node);
+
+ if (STREQ (expanded_node, expanded_ref))
+ {
+ free (expanded_ref);
+ break;
+ }
+ free (expanded_ref);
+ }
+ }
+ free (expanded_node);
+ return ref_list;
+}
+
+void
+free_node_references ()
+{
+ NODE_REF *list, *temp;
+
+ list = node_references;
+
+ while (list)
+ {
+ temp = list;
+ free (list->node);
+ free (list->containing_node);
+ list = list->next;
+ free (temp);
+ }
+ node_references = NULL;
+}
+
+void
+free_node_node_references ()
+{
+ NODE_REF *list, *temp;
+
+ list = node_references;
+
+ while (list)
+ {
+ temp = list;
+ free (list->node);
+ list = list->next;
+ free (temp);
+ }
+ node_node_references = NULL;
+}
+
+/* Return the number assigned to a named node in either the tag_table
+ or node_references list or zero if no number has been assigned. */
+int
+number_of_node (node)
+ char *node;
+{
+ NODE_REF *temp_ref;
+ TAG_ENTRY *temp_node = find_node (node);
+
+ if (temp_node)
+ return temp_node->number;
+ else if ((temp_ref = find_node_reference (node, node_references)))
+ return temp_ref->number;
+ else if ((temp_ref = find_node_reference (node, node_node_references)))
+ return temp_ref->number;
+ else
+ return 0;
+}
+
+/* validation */
+
+/* Return 1 if TAG (at LINE) correctly validated, or 0 if not.
+ LABEL is the (translated) description of the type of reference --
+ Menu, Cross, Next, etc. */
+
+static int
+validate (tag, line, label)
+ char *tag;
+ int line;
+ char *label;
+{
+ TAG_ENTRY *result;
+
+ /* If there isn't a tag to verify, or if the tag is in another file,
+ then it must be okay. */
+ if (!tag || !*tag || *tag == '(')
+ return 1;
+
+ /* Otherwise, the tag must exist. */
+ result = find_node (tag);
+
+ if (!result)
+ {
+ line_number = line;
+ line_error (_("%s reference to nonexistent node `%s'"), label, tag);
+ return 0;
+ }
+ result->touched++;
+ return 1;
+}
+
+/* The strings here are followed in the message by `reference to...' in
+ the `validate' routine. They are only used in messages, thus are
+ translated. */
+static char *
+reftype_type_string (type)
+ enum reftype type;
+{
+ switch (type)
+ {
+ case menu_reference:
+ return _("Menu");
+ case followed_reference:
+ return _("Cross");
+ default:
+ return "Internal-bad-reference-type";
+ }
+}
+
+static void
+validate_other_references (ref_list)
+ NODE_REF *ref_list;
+{
+ char *old_input_filename = input_filename;
+
+ while (ref_list)
+ {
+ input_filename = ref_list->filename;
+ validate (ref_list->node, ref_list->line_no,
+ reftype_type_string (ref_list->type));
+ ref_list = ref_list->next;
+ }
+ input_filename = old_input_filename;
+}
+
+/* Validation of an info file.
+ Scan through the list of tag entries touching the Prev, Next, and Up
+ elements of each. It is an error not to be able to touch one of them,
+ except in the case of external node references, such as "(DIR)".
+
+ If the Prev is different from the Up,
+ then the Prev node must have a Next pointing at this node.
+
+ Every node except Top must have an Up.
+ The Up node must contain some sort of reference, other than a Next,
+ to this node.
+
+ If the Next is different from the Next of the Up,
+ then the Next node must have a Prev pointing at this node. */
+void
+validate_file (tag_table)
+ TAG_ENTRY *tag_table;
+{
+ char *old_input_filename = input_filename;
+ TAG_ENTRY *tags = tag_table;
+
+ while (tags)
+ {
+ TAG_ENTRY *temp_tag;
+ char *tem1, *tem2;
+
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+
+ /* If this is a "no warn" node, don't validate it in any way. */
+ if (tags->flags & TAG_FLAG_NO_WARN)
+ {
+ tags = tags->next_ent;
+ continue;
+ }
+
+ /* If this node has a Next, then make sure that the Next exists. */
+ if (tags->next)
+ {
+ validate (tags->next, tags->line_no, _("Next"));
+
+ /* If the Next node exists, and there is no Up, then make sure
+ that the Prev of the Next points back. But do nothing if
+ we aren't supposed to issue warnings about this node. */
+ temp_tag = find_node (tags->next);
+ if (temp_tag && !(temp_tag->flags & TAG_FLAG_NO_WARN))
+ {
+ char *prev = temp_tag->prev;
+ int you_lose = !prev || !STREQ (prev, tags->node);
+
+ if (you_lose && expensive_validation)
+ {
+ tem1 = expand_node_name (prev);
+ tem2 = expand_node_name (tags->node);
+
+ if (STREQ (tem1, tem2))
+ you_lose = 0;
+ free (tem1);
+ free (tem2);
+ }
+ if (you_lose)
+ {
+ line_error (_("Next field of node `%s' not pointed to"),
+ tags->node);
+ line_number = temp_tag->line_no;
+ input_filename = temp_tag->filename;
+ line_error (_("This node (%s) has the bad Prev"),
+ temp_tag->node);
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+ temp_tag->flags |= TAG_FLAG_PREV_ERROR;
+ }
+ }
+ }
+
+ /* Validate the Prev field if there is one, and we haven't already
+ complained about it in some way. You don't have to have a Prev
+ field at this stage. */
+ if (!(tags->flags & TAG_FLAG_PREV_ERROR) && tags->prev)
+ {
+ int valid_p = validate (tags->prev, tags->line_no, _("Prev"));
+
+ if (!valid_p)
+ tags->flags |= TAG_FLAG_PREV_ERROR;
+ else
+ { /* If the Prev field is not the same as the Up field,
+ then the node pointed to by the Prev field must have
+ a Next field which points to this node. */
+ int prev_equals_up = !tags->up || STREQ (tags->prev, tags->up);
+
+ if (!prev_equals_up && expensive_validation)
+ {
+ tem1 = expand_node_name (tags->prev);
+ tem2 = expand_node_name (tags->up);
+ prev_equals_up = STREQ (tem1, tem2);
+ free (tem1);
+ free (tem2);
+ }
+ if (!prev_equals_up)
+ {
+ temp_tag = find_node (tags->prev);
+
+ /* If we aren't supposed to issue warnings about the
+ target node, do nothing. */
+ if (!temp_tag || (temp_tag->flags & TAG_FLAG_NO_WARN))
+ /* Do nothing. */ ;
+ else
+ {
+ int you_lose = !temp_tag->next
+ || !STREQ (temp_tag->next, tags->node);
+
+ if (temp_tag->next && you_lose && expensive_validation)
+ {
+ tem1 = expand_node_name (temp_tag->next);
+ tem2 = expand_node_name (tags->node);
+ if (STREQ (tem1, tem2))
+ you_lose = 0;
+ free (tem1);
+ free (tem2);
+ }
+ if (you_lose)
+ {
+ line_error
+ (_("Prev field of node `%s' not pointed to"),
+ tags->node);
+ line_number = temp_tag->line_no;
+ input_filename = temp_tag->filename;
+ line_error (_("This node (%s) has the bad Next"),
+ temp_tag->node);
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+ temp_tag->flags |= TAG_FLAG_NEXT_ERROR;
+ }
+ }
+ }
+ }
+ }
+
+ if (!tags->up
+ && !(tags->flags & TAG_FLAG_ANCHOR)
+ && strcasecmp (tags->node, "Top") != 0)
+ line_error (_("`%s' has no Up field"), tags->node);
+ else if (tags->up)
+ {
+ int valid_p = validate (tags->up, tags->line_no, _("Up"));
+
+ /* If node X has Up: Y, then warn if Y fails to have a menu item
+ or note pointing at X, if Y isn't of the form "(Y)". */
+ if (valid_p && *tags->up != '(')
+ {
+ NODE_REF *nref;
+ NODE_REF *tref = NULL;
+ NODE_REF *list = node_references;
+
+ for (;;)
+ {
+ nref = find_node_reference (tags->node, list);
+ if (!nref)
+ break;
+
+ if (strcmp (nref->containing_node, tags->up) == 0)
+ {
+ if (nref->type != menu_reference)
+ {
+ tref = nref;
+ list = nref->next;
+ }
+ else
+ break;
+ }
+ list = nref->next;
+ }
+
+ if (!nref)
+ {
+ if (!tref && expensive_validation)
+ {
+ /* Sigh... This might be AWFULLY slow, but if
+ they want this feature, they'll have to pay!
+ We do all the loop again expanding each
+ containing_node reference as we go. */
+ char *tags_up = expand_node_name (tags->up);
+ char *tem;
+
+ list = node_references;
+
+ for (;;)
+ {
+ nref = find_node_reference (tags->node, list);
+ if (!nref)
+ break;
+ tem = expand_node_name (nref->containing_node);
+ if (STREQ (tem, tags_up))
+ {
+ if (nref->type != menu_reference)
+ tref = nref;
+ else
+ {
+ free (tem);
+ break;
+ }
+ }
+ free (tem);
+ list = nref->next;
+ }
+ }
+ if (!nref && !tref)
+ {
+ temp_tag = find_node (tags->up);
+ line_number = temp_tag->line_no;
+ input_filename = temp_tag->filename;
+ line_error (
+ _("Node `%s' lacks menu item for `%s' despite being its Up target"),
+ tags->up, tags->node);
+ line_number = tags->line_no;
+ input_filename = tags->filename;
+ }
+ }
+ }
+ }
+ tags = tags->next_ent;
+ }
+
+ validate_other_references (node_references);
+ /* We have told the user about the references which didn't exist.
+ Now tell him about the nodes which aren't referenced. */
+
+ for (tags = tag_table; tags; tags = tags->next_ent)
+ {
+ /* If this node is a "no warn" node, do nothing. */
+ if (tags->flags & TAG_FLAG_NO_WARN)
+ {
+ tags = tags->next_ent;
+ continue;
+ }
+
+ /* Special hack. If the node in question appears to have
+ been referenced more than REFERENCE_WARNING_LIMIT times,
+ give a warning. */
+ if (tags->touched > reference_warning_limit)
+ {
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+ warning (_("node `%s' has been referenced %d times"),
+ tags->node, tags->touched);
+ }
+
+ if (tags->touched == 0)
+ {
+ input_filename = tags->filename;
+ line_number = tags->line_no;
+
+ /* Notice that the node "Top" is special, and doesn't have to
+ be referenced. Anchors don't have to be referenced
+ either, you might define them for another document. */
+ if (strcasecmp (tags->node, "Top") != 0
+ && !(tags->flags & TAG_FLAG_ANCHOR))
+ warning (_("unreferenced node `%s'"), tags->node);
+ }
+ }
+ input_filename = old_input_filename;
+}
+
+
+/* Splitting */
+
+/* Return true if the tag entry pointed to by TAGS is the last node.
+ This means only anchors follow. */
+
+static int
+last_node_p (tags)
+ TAG_ENTRY *tags;
+{
+ int last = 1;
+ while (tags->next_ent) {
+ tags = tags->next_ent;
+ if (tags->flags & TAG_FLAG_ANCHOR)
+ ;
+ else
+ {
+ last = 0;
+ break;
+ }
+ }
+
+ return last;
+}
+
+
+/* Split large output files into a series of smaller files. Each file
+ is pointed to in the tag table, which then gets written out as the
+ original file. The new files have the same name as the original file
+ with a "-num" attached. SIZE is the largest number of bytes to allow
+ in any single split file. */
+void
+split_file (filename, size)
+ char *filename;
+ int size;
+{
+ char *root_filename, *root_pathname;
+ char *the_file, *filename_part ();
+ struct stat fileinfo;
+ long file_size;
+ char *the_header;
+ int header_size;
+ int dos_file_names = 0; /* if nonzero, don't exceed 8+3 limits */
+
+ /* Can only do this to files with tag tables. */
+ if (!tag_table)
+ return;
+
+ if (size == 0)
+ size = DEFAULT_SPLIT_SIZE;
+
+ if ((stat (filename, &fileinfo) != 0) ||
+ (((long) fileinfo.st_size) < SPLIT_SIZE_THRESHOLD))
+ return;
+ file_size = (long) fileinfo.st_size;
+
+ the_file = find_and_load (filename);
+ if (!the_file)
+ return;
+
+ root_filename = filename_part (filename);
+ root_pathname = pathname_part (filename);
+
+ /* Do we need to generate names of subfiles which don't exceed 8+3 limits? */
+ dos_file_names = !HAVE_LONG_FILENAMES (root_pathname ? root_pathname : ".");
+
+ if (!root_pathname)
+ root_pathname = xstrdup ("");
+
+ /* Start splitting the file. Walk along the tag table
+ outputting sections of the file. When we have written
+ all of the nodes in the tag table, make the top-level
+ pointer file, which contains indirect pointers and
+ tags for the nodes. */
+ {
+ int which_file = 1;
+ TAG_ENTRY *tags = tag_table;
+ char *indirect_info = NULL;
+
+ /* Remember the `header' of this file. The first tag in the file is
+ the bottom of the header; the top of the file is the start. */
+ the_header = xmalloc (1 + (header_size = tags->position));
+ memcpy (the_header, the_file, header_size);
+
+ while (tags)
+ {
+ int file_top, file_bot, limit;
+
+ /* Have to include the Control-_. */
+ file_top = file_bot = tags->position;
+ limit = file_top + size;
+
+ /* If the rest of this file is only one node, then
+ that is the entire subfile. */
+ if (last_node_p (tags))
+ {
+ int i = tags->position + 1;
+ char last_char = the_file[i];
+
+ while (i < file_size)
+ {
+ if ((the_file[i] == '\037') &&
+ ((last_char == '\n') ||
+ (last_char == '\014')))
+ break;
+ else
+ last_char = the_file[i];
+ i++;
+ }
+ file_bot = i;
+ tags = tags->next_ent;
+ goto write_region;
+ }
+
+ /* Otherwise, find the largest number of nodes that can fit in
+ this subfile. */
+ for (; tags; tags = tags->next_ent)
+ {
+ if (last_node_p (tags))
+ {
+ /* This entry is the last node. Search forward for the end
+ of this node, and that is the end of this file. */
+ int i = tags->position + 1;
+ char last_char = the_file[i];
+
+ while (i < file_size)
+ {
+ if ((the_file[i] == '\037') &&
+ ((last_char == '\n') ||
+ (last_char == '\014')))
+ break;
+ else
+ last_char = the_file[i];
+ i++;
+ }
+ file_bot = i;
+
+ if (file_bot < limit)
+ {
+ tags = tags->next_ent;
+ goto write_region;
+ }
+ else
+ {
+ /* Here we want to write out everything before the last
+ node, and then write the last node out in a file
+ by itself. */
+ file_bot = tags->position;
+ goto write_region;
+ }
+ }
+
+ /* Write region only if this was a node, not an anchor. */
+ if (tags->next_ent->position > limit
+ && !(tags->flags & TAG_FLAG_ANCHOR))
+ {
+ if (tags->position == file_top)
+ tags = tags->next_ent;
+
+ file_bot = tags->position;
+
+ write_region:
+ {
+ int fd;
+ char *split_filename, *split_basename;
+ unsigned root_len = strlen (root_filename);
+
+ split_filename = xmalloc (10 + strlen (root_pathname)
+ + root_len);
+ split_basename = xmalloc (10 + root_len);
+ sprintf (split_basename, "%s-%d", root_filename, which_file);
+ if (dos_file_names)
+ {
+ char *dot = strchr (split_basename, '.');
+ unsigned base_len = strlen (split_basename);
+
+ if (dot)
+ { /* Make foobar.i1, .., foobar.i99, foobar.100, ... */
+ dot[1] = 'i';
+ memmove (which_file <= 99 ? dot + 2 : dot + 1,
+ split_basename + root_len + 1,
+ strlen (split_basename + root_len + 1) + 1);
+ }
+ else if (base_len > 8)
+ {
+ /* Make foobar-1, .., fooba-10, .., foob-100, ... */
+ unsigned numlen = base_len - root_len;
+
+ memmove (split_basename + 8 - numlen,
+ split_basename + root_len, numlen + 1);
+ }
+ }
+ sprintf (split_filename, "%s%s", root_pathname,
+ split_basename);
+
+ fd = open (split_filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
+ if (fd < 0
+ || write (fd, the_header, header_size) != header_size
+ || write (fd, the_file + file_top, file_bot - file_top)
+ != (file_bot - file_top)
+ || (close (fd)) < 0)
+ {
+ perror (split_filename);
+ if (fd != -1)
+ close (fd);
+ xexit (1);
+ }
+
+ if (!indirect_info)
+ {
+ indirect_info = the_file + file_top;
+ sprintf (indirect_info, "\037\nIndirect:\n");
+ indirect_info += strlen (indirect_info);
+ }
+
+ sprintf (indirect_info, "%s: %d\n",
+ split_basename, file_top);
+
+ free (split_basename);
+ free (split_filename);
+ indirect_info += strlen (indirect_info);
+ which_file++;
+ break;
+ }
+ }
+ }
+ }
+
+ /* We have sucessfully created the subfiles. Now write out the
+ original again. We must use `output_stream', or
+ write_tag_table_indirect () won't know where to place the output. */
+ output_stream = fopen (filename, "w");
+ if (!output_stream)
+ {
+ perror (filename);
+ xexit (1);
+ }
+
+ {
+ int distance = indirect_info - the_file;
+ fwrite (the_file, 1, distance, output_stream);
+
+ /* Inhibit newlines. */
+ paragraph_is_open = 0;
+
+ write_tag_table_indirect ();
+ fclose (output_stream);
+ free (the_header);
+ free (the_file);
+ return;
+ }
+ }
+}
diff --git a/contrib/texinfo/makeinfo/node.h b/contrib/texinfo/makeinfo/node.h
new file mode 100644
index 0000000..e2fc883
--- /dev/null
+++ b/contrib/texinfo/makeinfo/node.h
@@ -0,0 +1,111 @@
+/* node.h -- declarations for Node.
+ $Id: node.h,v 1.5 1999/07/11 16:50:19 karl Exp $
+
+ Copyright (C) 1996, 97, 98, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#ifndef NODE_H
+#define NODE_H
+
+/* The various references that we know about. */
+/* What we remember for each node. */
+typedef struct tentry
+{
+ struct tentry *next_ent;
+ char *node; /* Name of this node. */
+ char *prev; /* Name of "Prev:" for this node. */
+ char *next; /* Name of "Next:" for this node. */
+ char *up; /* Name of "Up:" for this node. */
+ int position; /* Output file position of this node. */
+ int line_no; /* Defining line in source file. */
+ char *filename; /* The file that this node was found in. */
+ int touched; /* Nonzero means this node has been referenced. */
+ int flags;
+ int number; /* Number for this node, relevant for HTML
+ splitting -- from use+define order, not just
+ define. */
+} TAG_ENTRY;
+
+/* If node-a has a "Next" for node-b, but node-b has no "Prev" for node-a,
+ we turn on this flag bit in node-b's tag entry. This means that when
+ it is time to validate node-b, we don't report an additional error
+ if there was no "Prev" field. */
+#define TAG_FLAG_PREV_ERROR 1
+#define TAG_FLAG_NEXT_ERROR 2
+#define TAG_FLAG_UP_ERROR 4
+#define TAG_FLAG_NO_WARN 8
+#define TAG_FLAG_IS_TOP 16
+#define TAG_FLAG_ANCHOR 32
+
+/* Menu reference, *note reference, and validation hacking. */
+
+/* A structure to remember references with. A reference to a node is
+ either an entry in a menu, or a cross-reference made with [px]ref. */
+typedef struct node_ref
+{
+ struct node_ref *next;
+ char *node; /* Name of node referred to. */
+ char *containing_node; /* Name of node containing this reference. */
+ int line_no; /* Line number where the reference occurs. */
+ int section; /* Section level where the reference occurs. */
+ char *filename; /* Name of file where the reference occurs. */
+ enum reftype type; /* Type of reference, either menu or note. */
+ int number; /* Number for this node, relevant for
+ HTML splitting -- from use+define
+ order, not just define. */
+} NODE_REF;
+
+/* The linked list of such structures. */
+extern NODE_REF *node_references;
+
+/* A similar list for references occuring in @node next
+ and similar references, needed for HTML. */
+extern NODE_REF *node_node_references;
+
+/* List of all nodes. */
+extern TAG_ENTRY *tag_table;
+
+/* Counter for setting node_ref.number; zero is Top. */
+extern int node_number;
+
+/* The current node's section level. */
+extern int current_section;
+
+/* Nonzero when the next sectioning command should generate an anchor
+ corresponding to the current node in HTML mode. */
+extern int outstanding_node;
+
+extern TAG_ENTRY *find_node ();
+
+/* A search string which is used to find a line defining a node. */
+DECLARE (char *, node_search_string, "\n@node ");
+
+/* Extract node name from a menu item. */
+extern char *glean_node_from_menu ();
+
+/* Remember a node for later validation. */
+extern void remember_node_reference ();
+
+/* Remember the name of the current output file. */
+extern void set_current_output_filename ();
+
+/* Expand macros and commands in the node name and canonicalize
+ whitespace in the resulting expansion. */
+extern char *expand_node_name ();
+
+#endif /* NODE_H */
diff --git a/contrib/texinfo/makeinfo/sectioning.c b/contrib/texinfo/makeinfo/sectioning.c
new file mode 100644
index 0000000..b06785b
--- /dev/null
+++ b/contrib/texinfo/makeinfo/sectioning.c
@@ -0,0 +1,691 @@
+/* sectioning.c -- all related stuff @chapter, @section... @contents
+ $Id: sectioning.c,v 1.12 1999/08/17 21:06:50 karl Exp $
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written by Karl Heinz Marbaise <kama@hippo.fido.de>. */
+
+#include "system.h"
+#include "cmds.h"
+#include "macro.h"
+#include "makeinfo.h"
+#include "node.h"
+#include "toc.h"
+#include "sectioning.h"
+
+/* See comment in sectioning.h. */
+section_alist_type section_alist[] = {
+ { "unnumberedsubsubsec", 5, ENUM_SECT_NO, TOC_YES },
+ { "unnumberedsubsec", 4, ENUM_SECT_NO, TOC_YES },
+ { "unnumberedsec", 3, ENUM_SECT_NO, TOC_YES },
+ { "unnumbered", 2, ENUM_SECT_NO, TOC_YES },
+
+ { "appendixsubsubsec", 5, ENUM_SECT_APP, TOC_YES }, /* numbered like A.X.X.X */
+ { "appendixsubsec", 4, ENUM_SECT_APP, TOC_YES },
+ { "appendixsec", 3, ENUM_SECT_APP, TOC_YES },
+ { "appendixsection", 3, ENUM_SECT_APP, TOC_YES },
+ { "appendix", 2, ENUM_SECT_APP, TOC_YES },
+
+ { "subsubsec", 5, ENUM_SECT_YES, TOC_YES },
+ { "subsubsection", 5, ENUM_SECT_YES, TOC_YES },
+ { "subsection", 4, ENUM_SECT_YES, TOC_YES },
+ { "section", 3, ENUM_SECT_YES, TOC_YES },
+ { "chapter", 2, ENUM_SECT_YES, TOC_YES },
+
+ { "subsubheading", 5, ENUM_SECT_NO, TOC_NO },
+ { "subheading", 4, ENUM_SECT_NO, TOC_NO },
+ { "heading", 3, ENUM_SECT_NO, TOC_NO },
+ { "chapheading", 2, ENUM_SECT_NO, TOC_NO },
+ { "majorheading", 2, ENUM_SECT_NO, TOC_NO },
+
+ { "top", 1, ENUM_SECT_NO, TOC_YES },
+ { NULL, 0, 0, 0 }
+};
+
+/* The argument of @settitle, used for HTML. */
+char *title = NULL;
+
+
+#define APPENDIX_MAGIC 1024
+#define UNNUMBERED_MAGIC 2048
+
+/* Number memory for every level @chapter, @section,
+ @subsection, @subsubsection. */
+static int numbers [] = { 0, 0, 0, 0 };
+
+/* enum_marker == APPENDIX_MAGIC then we are counting appendencies
+ enum_marker == UNNUMBERED_MAGIC then we are within unnumbered area.
+ Handling situations like this:
+ @unnumbered ..
+ @section ... */
+static int enum_marker = 0;
+
+/* Organized by level commands. That is, "*" == chapter, "=" == section. */
+static char *scoring_characters = "*=-.";
+
+/* Amount to offset the name of sectioning commands to levels by. */
+static int section_alist_offset = 0;
+
+
+/* num == ENUM_SECT_NO means unnumbered (should never call this)
+ num == ENUM_SECT_YES means numbered
+ num == ENUM_SECT_APP means numbered like A.1 and so on */
+char *
+get_sectioning_number (level, num)
+ int level;
+ int num;
+{
+ static char s[100]; /* should ever be enough for 99.99.99.99
+ Appendix A.1 */
+
+ char *p;
+ int i;
+
+ s[0] = 0;
+
+ /* create enumeration in front of chapter, section, subsection and so on. */
+ for (i = 0; i < level; i++)
+ {
+ p = s + strlen (s);
+ if ((i == 0) && (enum_marker == APPENDIX_MAGIC))
+ sprintf (p, "%c.", numbers[i] + 64); /* Should be changed to
+ be more portable */
+ else
+ sprintf (p, "%d.", numbers[i]);
+ }
+
+ /* the last number is never followed by a dot */
+ p = s + strlen (s);
+ if ((num == ENUM_SECT_APP)
+ && (i == 0)
+ && (enum_marker == APPENDIX_MAGIC))
+ sprintf (p, _("Appendix %c "), numbers[i] + 64);
+ else
+ sprintf (p, "%d ", numbers[i]);
+
+ return s;
+}
+
+
+/* Set the level of @top to LEVEL. Return the old level of @top. */
+int
+set_top_section_level (level)
+ int level;
+{
+ int i, result = -1;
+
+ for (i = 0; section_alist[i].name; i++)
+ if (strcmp (section_alist[i].name, "top") == 0)
+ {
+ result = section_alist[i].level;
+ section_alist[i].level = level;
+ break;
+ }
+ return result;
+}
+
+
+/* return the index of the given sectioning command in section_alist */
+int
+search_sectioning (text)
+ char *text;
+{
+ int i;
+ char *t;
+
+ /* ignore the optional command prefix */
+ if (text[0] == COMMAND_PREFIX)
+ text++;
+
+ for (i = 0; (t = section_alist[i].name); i++)
+ {
+ if (strcmp (t, text) == 0)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/* Return an integer which identifies the type section present in TEXT. */
+int
+what_section (text)
+ char *text;
+{
+ int index, j;
+ char *temp;
+ int return_val;
+
+ find_section_command:
+ for (j = 0; text[j] && cr_or_whitespace (text[j]); j++);
+ if (text[j] != COMMAND_PREFIX)
+ return -1;
+
+ text = text + j + 1;
+
+ /* We skip @c, @comment, and @?index commands. */
+ if ((strncmp (text, "comment", strlen ("comment")) == 0) ||
+ (text[0] == 'c' && cr_or_whitespace (text[1])) ||
+ (strcmp (text + 1, "index") == 0))
+ {
+ while (*text++ != '\n');
+ goto find_section_command;
+ }
+
+ /* Handle italicized sectioning commands. */
+ if (*text == 'i')
+ text++;
+
+ for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++);
+
+ temp = xmalloc (1 + j);
+ strncpy (temp, text, j);
+ temp[j] = 0;
+
+ index = search_sectioning (temp);
+ free (temp);
+ if (index >= 0)
+ {
+ return_val = section_alist[index].level + section_alist_offset;
+ if (return_val < 0)
+ return_val = 0;
+ else if (return_val > 5)
+ return_val = 5;
+ return return_val;
+ }
+ return -1;
+}
+
+
+void
+sectioning_underscore (cmd)
+ char *cmd;
+{
+ char character;
+ char *temp;
+ int level;
+
+ temp = xmalloc (2 + strlen (cmd));
+ temp[0] = COMMAND_PREFIX;
+ strcpy (&temp[1], cmd);
+ level = what_section (temp);
+ free (temp);
+ level -= 2;
+
+ if (level < 0)
+ level = 0;
+
+ if (html)
+ sectioning_html (level, cmd);
+ else
+ {
+ character = scoring_characters[level];
+ insert_and_underscore (level, character, cmd);
+ }
+}
+
+/* insert_and_underscore and sectioning_html are the
+ only functions which call this.
+ I have created this, because it was exactly the same
+ code in both functions. */
+static char *
+handle_enum_increment (level, index)
+ int level;
+ int index;
+{
+ /* special for unnumbered */
+ if (number_sections && section_alist[index].num == ENUM_SECT_NO)
+ {
+ if (level == 0
+ && enum_marker != UNNUMBERED_MAGIC)
+ enum_marker = UNNUMBERED_MAGIC;
+ }
+ /* enumerate only things which are allowed */
+ if (number_sections && section_alist[index].num)
+ {
+ /* reset the marker if we get into enumerated areas */
+ if (section_alist[index].num == ENUM_SECT_YES
+ && level == 0
+ && enum_marker == UNNUMBERED_MAGIC)
+ enum_marker = 0;
+ /* This is special for appendix; if we got the first
+ time an appendix command then we are entering appendix.
+ Thats the point we have to start countint with A, B and so on. */
+ if (section_alist[index].num == ENUM_SECT_APP
+ && level == 0
+ && enum_marker != APPENDIX_MAGIC)
+ {
+ enum_marker = APPENDIX_MAGIC;
+ numbers [0] = 0; /* this means we start with Appendix A */
+ }
+
+ /* only increment counters if we are not in unnumbered
+ area. This handles situations like this:
+ @unnumbered .... This sets enum_marker to UNNUMBERED_MAGIC
+ @section .... */
+ if (enum_marker != UNNUMBERED_MAGIC)
+ {
+ int i;
+
+ /* reset all counters which are one level deeper */
+ for (i = level; i < 3; i++)
+ numbers [i + 1] = 0;
+
+ numbers[level]++;
+ return xstrdup
+ (get_sectioning_number (level, section_alist[index].num));
+ }
+ } /* if (number_sections)... */
+
+ return xstrdup ("");
+}
+
+
+/* Insert the text following input_text_offset up to the end of the line
+ in a new, separate paragraph. Directly underneath it, insert a
+ line of WITH_CHAR, the same length of the inserted text. */
+void
+insert_and_underscore (level, with_char, cmd)
+ int level;
+ int with_char;
+ char *cmd;
+{
+ int i, len;
+ int index;
+ int old_no_indent;
+ unsigned char *starting_pos, *ending_pos;
+ char *temp;
+
+ close_paragraph ();
+ filling_enabled = indented_fill = 0;
+ old_no_indent = no_indent;
+ no_indent = 1;
+
+ if (macro_expansion_output_stream && !executing_string)
+ append_to_expansion_output (input_text_offset + 1);
+
+ get_rest_of_line (0, &temp);
+ starting_pos = output_paragraph + output_paragraph_offset;
+
+ index = search_sectioning (cmd);
+ if (index < 0)
+ {
+ /* should never happen, but a poor guy, named Murphy ... */
+ warning (_("Internal error (search_sectioning) \"%s\"!"), cmd);
+ return;
+ }
+
+ /* This is a bit tricky: we must produce "X.Y SECTION-NAME" in the
+ Info output and in TOC, but only SECTION-NAME in the macro-expanded
+ output. */
+
+ /* Step 1: produce "X.Y" and add it to Info output. */
+ add_word (handle_enum_increment (level, index));
+
+ /* Step 2: add "SECTION-NAME" to both Info and macro-expanded output. */
+ if (macro_expansion_output_stream && !executing_string)
+ {
+ char *temp1 = xmalloc (2 + strlen (temp));
+ sprintf (temp1, "%s\n", temp);
+ remember_itext (input_text, input_text_offset);
+ me_execute_string (temp1);
+ free (temp1);
+ }
+ else
+ execute_string ("%s\n", temp);
+
+ /* Step 3: pluck "X.Y SECTION-NAME" from the output buffer and
+ insert it into the TOC. */
+ ending_pos = output_paragraph + output_paragraph_offset;
+ if (section_alist[index].toc == TOC_YES)
+ toc_add_entry (substring (starting_pos, ending_pos - 1),
+ level, current_node, NULL);
+
+ free (temp);
+
+ len = (ending_pos - starting_pos) - 1;
+ for (i = 0; i < len; i++)
+ add_char (with_char);
+ insert ('\n');
+ close_paragraph ();
+ filling_enabled = 1;
+ no_indent = old_no_indent;
+}
+
+/* Insert the text following input_text_offset up to the end of the
+ line as an HTML heading element of the appropriate `level' and
+ tagged as an anchor for the current node.. */
+void
+sectioning_html (level, cmd)
+ int level;
+ char *cmd;
+{
+ static int toc_ref_count = 0;
+ int index;
+ int old_no_indent;
+ unsigned char *starting_pos, *ending_pos;
+ char *temp, *toc_anchor = NULL;
+
+ close_paragraph ();
+ filling_enabled = indented_fill = 0;
+ old_no_indent = no_indent;
+ no_indent = 1;
+
+ add_word_args ("<h%d>", level + 1); /* level 0 is <h1> */
+
+ /* If we are outside of any node, produce an anchor that
+ the TOC could refer to. */
+ if (!current_node || !*current_node)
+ {
+ starting_pos = output_paragraph + output_paragraph_offset;
+ add_word_args ("<a name=\"TOC%d\">", toc_ref_count++);
+ toc_anchor = substring (starting_pos + 9,
+ output_paragraph + output_paragraph_offset);
+ }
+ starting_pos = output_paragraph + output_paragraph_offset;
+
+ if (macro_expansion_output_stream && !executing_string)
+ append_to_expansion_output (input_text_offset + 1);
+
+ get_rest_of_line (0, &temp);
+
+ index = search_sectioning (cmd);
+ if (index < 0)
+ {
+ /* should never happen, but a poor guy, named Murphy ... */
+ warning (_("Internal error (search_sectioning) \"%s\"!"), cmd);
+ return;
+ }
+
+ /* Produce "X.Y" and add it to HTML output. */
+ add_word (handle_enum_increment (level, index));
+
+ /* add the section name to both HTML and macro-expanded output. */
+ if (macro_expansion_output_stream && !executing_string)
+ {
+ remember_itext (input_text, input_text_offset);
+ me_execute_string (temp);
+ write_region_to_macro_output ("\n", 0, 1);
+ }
+ else
+ execute_string ("%s", temp);
+
+ ending_pos = output_paragraph + output_paragraph_offset;
+
+ /* Pluck ``X.Y SECTION-NAME'' from the output buffer and insert it
+ into the TOC. */
+ if (section_alist[index].toc == TOC_YES)
+ toc_add_entry (substring (starting_pos, ending_pos),
+ level, current_node, toc_anchor);
+
+ free (temp);
+
+ if (outstanding_node)
+ outstanding_node = 0;
+
+ add_word_args ("</h%d>", level+1);
+ close_paragraph();
+ filling_enabled = 1;
+ no_indent = old_no_indent;
+}
+
+
+/* Shift the meaning of @section to @chapter. */
+void
+cm_raisesections ()
+{
+ discard_until ("\n");
+ section_alist_offset--;
+}
+
+/* Shift the meaning of @chapter to @section. */
+void
+cm_lowersections ()
+{
+ discard_until ("\n");
+ section_alist_offset++;
+}
+
+/* The command still works, but prints a warning message in addition. */
+void
+cm_ideprecated (arg, start, end)
+ int arg, start, end;
+{
+ warning (_("%c%s is obsolete; use %c%s instead"),
+ COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1);
+ sectioning_underscore (command + 1);
+}
+
+
+/* Treat this just like @unnumbered. The only difference is
+ in node defaulting. */
+void
+cm_top ()
+{
+ /* It is an error to have more than one @top. */
+ if (top_node_seen && strcmp (current_node, "Top") != 0)
+ {
+ TAG_ENTRY *tag = tag_table;
+
+ line_error (_("Node with %ctop as a section already exists"),
+ COMMAND_PREFIX);
+
+ while (tag)
+ {
+ if (tag->flags & TAG_FLAG_IS_TOP)
+ {
+ int old_line_number = line_number;
+ char *old_input_filename = input_filename;
+
+ line_number = tag->line_no;
+ input_filename = tag->filename;
+ line_error (_("Here is the %ctop node"), COMMAND_PREFIX);
+ input_filename = old_input_filename;
+ line_number = old_line_number;
+ return;
+ }
+ tag = tag->next_ent;
+ }
+ }
+ else
+ {
+ TAG_ENTRY *top_node = find_node ("Top");
+ top_node_seen = 1;
+
+ /* It is an error to use @top before you have used @node. */
+ if (!tag_table)
+ {
+ char *top_name;
+
+ get_rest_of_line (0, &top_name);
+ line_error (_("%ctop used before %cnode, defaulting to %s"),
+ COMMAND_PREFIX, COMMAND_PREFIX, top_name);
+ execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name);
+ free (top_name);
+ return;
+ }
+ else if (html && splitting)
+ {
+ char *next = top_node ? top_node->next : NULL;
+
+ add_word ("<p>");
+ if (next)
+ {
+ add_word (_("Next:"));
+ add_word ("<a rel=next href=\"");
+ add_anchor_name (next, 1);
+ add_word ("\">");
+ execute_string (next);
+ add_word ("</a>\n");
+ }
+ }
+
+ cm_unnumbered ();
+
+ /* The most recently defined node is the top node. */
+ tag_table->flags |= TAG_FLAG_IS_TOP;
+
+ /* Now set the logical hierarchical level of the Top node. */
+ {
+ int orig_offset = input_text_offset;
+
+ input_text_offset = search_forward (node_search_string, orig_offset);
+
+ if (input_text_offset > 0)
+ {
+ int this_section;
+
+ /* We have encountered a non-top node, so mark that one exists. */
+ non_top_node_seen = 1;
+
+ /* Move to the end of this line, and find out what the
+ sectioning command is here. */
+ while (input_text[input_text_offset] != '\n')
+ input_text_offset++;
+
+ if (input_text_offset < input_text_length)
+ input_text_offset++;
+
+ this_section = what_section (input_text + input_text_offset);
+
+ /* If we found a sectioning command, then give the top section
+ a level of this section - 1. */
+ if (this_section != -1)
+ set_top_section_level (this_section - 1);
+ }
+ input_text_offset = orig_offset;
+ }
+ }
+}
+
+/* The remainder of the text on this line is a chapter heading. */
+void
+cm_chapter ()
+{
+ sectioning_underscore ("chapter");
+}
+
+/* The remainder of the text on this line is a section heading. */
+void
+cm_section ()
+{
+ sectioning_underscore ("section");
+}
+
+/* The remainder of the text on this line is a subsection heading. */
+void
+cm_subsection ()
+{
+ sectioning_underscore ("subsection");
+}
+
+/* The remainder of the text on this line is a subsubsection heading. */
+void
+cm_subsubsection ()
+{
+ sectioning_underscore ("subsubsection");
+}
+
+/* The remainder of the text on this line is an unnumbered heading. */
+void
+cm_unnumbered ()
+{
+ sectioning_underscore ("unnumbered");
+}
+
+/* The remainder of the text on this line is an unnumbered section heading. */
+void
+cm_unnumberedsec ()
+{
+ sectioning_underscore ("unnumberedsec");
+}
+
+/* The remainder of the text on this line is an unnumbered
+ subsection heading. */
+void
+cm_unnumberedsubsec ()
+{
+ sectioning_underscore ("unnumberedsubsec");
+}
+
+/* The remainder of the text on this line is an unnumbered
+ subsubsection heading. */
+void
+cm_unnumberedsubsubsec ()
+{
+ sectioning_underscore ("unnumberedsubsubsec");
+}
+
+/* The remainder of the text on this line is an appendix heading. */
+void
+cm_appendix ()
+{
+ sectioning_underscore ("appendix");
+}
+
+/* The remainder of the text on this line is an appendix section heading. */
+void
+cm_appendixsec ()
+{
+ sectioning_underscore ("appendixsec");
+}
+
+/* The remainder of the text on this line is an appendix subsection heading. */
+void
+cm_appendixsubsec ()
+{
+ sectioning_underscore ("appendixsubsec");
+}
+
+/* The remainder of the text on this line is an appendix
+ subsubsection heading. */
+void
+cm_appendixsubsubsec ()
+{
+ sectioning_underscore ("appendixsubsubsec");
+}
+
+/* Compatibility functions substitute for chapter, section, etc. */
+void
+cm_majorheading ()
+{
+ sectioning_underscore ("majorheading");
+}
+
+void
+cm_chapheading ()
+{
+ sectioning_underscore ("chapheading");
+}
+
+void
+cm_heading ()
+{
+ sectioning_underscore ("heading");
+}
+
+void
+cm_subheading ()
+{
+ sectioning_underscore ("subheading");
+}
+
+void
+cm_subsubheading ()
+{
+ sectioning_underscore ("subsubheading");
+}
diff --git a/contrib/texinfo/makeinfo/sectioning.h b/contrib/texinfo/makeinfo/sectioning.h
new file mode 100644
index 0000000..75243f0
--- /dev/null
+++ b/contrib/texinfo/makeinfo/sectioning.h
@@ -0,0 +1,80 @@
+/* sectioning.h -- all related stuff @chapter, @section... @contents
+ $Id: sectioning.h,v 1.2 1999/03/09 22:48:15 karl Exp $
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written by Karl Heinz Marbaise <kama@hippo.fido.de>. */
+
+#ifndef SECTIONING_H
+#define SECTIONING_H
+
+/* Sectioning. */
+extern void
+ cm_chapter (), cm_unnumbered (), cm_appendix (), cm_top (),
+ cm_section (), cm_unnumberedsec (), cm_appendixsec (),
+ cm_subsection (), cm_unnumberedsubsec (), cm_appendixsubsec (),
+ cm_subsubsection (), cm_unnumberedsubsubsec (), cm_appendixsubsubsec (),
+ cm_heading (), cm_chapheading (), cm_subheading (), cm_subsubheading (),
+ cm_majorheading (), cm_raisesections (), cm_lowersections (),
+
+ cm_ideprecated ();
+
+extern void
+ sectioning_underscore (), insert_and_underscore ();
+
+extern int what_section ();
+
+
+
+/* is needed in node.c */
+extern int set_top_section_level ();
+
+extern void sectioning_html ();
+extern int what_section ();
+
+/* The argument of @settitle, used for HTML. */
+extern char *title;
+
+
+/* Here is a structure which associates sectioning commands with
+ an integer that reflects the depth of the current section. */
+typedef struct
+{
+ char *name;
+ int level; /* I can't replace the levels with defines
+ because it is changed during run */
+ int num; /* ENUM_SECT_NO means no enumeration...
+ ENUM_SECT_YES means enumerated version
+ ENUM_SECT_APP appendix (Character enumerated
+ at first position */
+ int toc; /* TOC_NO means do not enter in toc;
+ TOC_YES means enter it in toc */
+} section_alist_type;
+
+extern section_alist_type section_alist[];
+
+/* enumerate sections */
+#define ENUM_SECT_NO 0
+#define ENUM_SECT_YES 1
+#define ENUM_SECT_APP 2
+
+/* make entries into toc no/yes */
+#define TOC_NO 0
+#define TOC_YES 1
+
+
+#endif /* not SECTIONING_H */
diff --git a/contrib/texinfo/makeinfo/toc.c b/contrib/texinfo/makeinfo/toc.c
new file mode 100644
index 0000000..41c5ffb
--- /dev/null
+++ b/contrib/texinfo/makeinfo/toc.c
@@ -0,0 +1,476 @@
+/* toc.c -- table of contents handling.
+ $Id: toc.c,v 1.14 1999/08/09 20:28:18 karl Exp $
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written by Karl Heinz Marbaise <kama@hippo.fido.de>. */
+
+#include "system.h"
+#include "makeinfo.h"
+#include "cmds.h"
+#include "files.h"
+#include "macro.h"
+#include "node.h"
+#include "lang.h"
+#include "makeinfo.h"
+#include "sectioning.h"
+#include "toc.h"
+
+
+
+
+/* array of toc entries */
+static TOC_ENTRY_ELT **toc_entry_alist = NULL;
+
+/* toc_counter start from 0 ... n for every @chapter, @section ... */
+static int toc_counter = 0;
+
+/* the file where we found the @contents directive */
+char *contents_filename;
+
+/* the file where we found the @shortcontents directive */
+char *shortcontents_filename;
+
+static const char contents_placebo[] = "\n...Table of Contents...\n";
+static const char shortcontents_placebo[] = "\n...Short Contents...\n";
+static const char lots_of_stars[] =
+"***************************************************************************";
+
+
+/* Routine to add an entry to the table of contents */
+int
+toc_add_entry (tocname, level, node_name, anchor)
+ char *tocname;
+ int level;
+ char *node_name;
+ char *anchor;
+{
+ char *tocname_and_node, *expanded_node, *s, *d;
+
+ if (!node_name)
+ node_name = "";
+
+ /* I assume that xrealloc behaves like xmalloc if toc_entry_alist is
+ NULL */
+ toc_entry_alist = xrealloc (toc_entry_alist,
+ (toc_counter + 1) * sizeof (TOC_ENTRY_ELT *));
+
+ toc_entry_alist[toc_counter] = xmalloc (sizeof (TOC_ENTRY_ELT));
+
+ if (html)
+ {
+ /* We need to insert the expanded node name into the TOC, so
+ that when we eventually output the TOC, its <A REF= link will
+ point to the <A NAME= tag created by cm_node in the navigation
+ bar. We cannot expand the containing_node member, for the
+ reasons explained in the WARNING below. We also cannot wait
+ with the node name expansion until the TOC is actually output,
+ since by that time the macro definitions may have been changed.
+ So instead we store in the tocname member the expanded node
+ name and the TOC name concatenated together (with the necessary
+ HTML markup), since that's how they are output. */
+ if (!anchor)
+ s = expanded_node = expand_node_name (node_name);
+ else
+ expanded_node = anchor;
+ /* Sigh... Need to HTML-escape the expanded node name like
+ add_anchor_name does, except that we are not writing this to
+ the output, so can't use add_anchor_name... */
+ /* The factor 5 in the next allocation is because the maximum
+ expansion of HTML-escaping is for the & character, which is
+ output as "&amp;". 2 is for "> that separates node from tocname. */
+ d = tocname_and_node = (char *)xmalloc (2 + 5 * strlen (expanded_node)
+ + strlen (tocname) + 1);
+ if (!anchor)
+ {
+ for (; *s; s++)
+ {
+ if (*s == '&')
+ {
+ strcpy (d, "&amp;");
+ d += 5;
+ }
+ else if (! URL_SAFE_CHAR (*s))
+ {
+ sprintf (d, "%%%x", (unsigned char) *s);
+ /* do this manually since sprintf returns char * on
+ SunOS 4 and other old systems. */
+ while (*d)
+ d++;
+ }
+ else
+ *d++ = *s;
+ }
+ strcpy (d, "\">");
+ }
+ else
+ /* Section outside any node, they provided explicit anchor. */
+ strcpy (d, anchor);
+ strcat (d, tocname);
+ free (tocname); /* it was malloc'ed by substring() */
+ free (expanded_node);
+ toc_entry_alist[toc_counter]->name = tocname_and_node;
+ }
+ else
+ toc_entry_alist[toc_counter]->name = tocname;
+ /* WARNING! The node name saved in containing_node member must
+ be the node name with _only_ macros expanded (the macros in
+ the node name are expanded by cm_node when it grabs the name
+ from the @node directive). Non-macros, like @value, @@ and
+ other @-commands must NOT be expanded in containing_node,
+ because toc_find_section_of_node looks up the node name where
+ they are also unexpanded. You *have* been warned! */
+ toc_entry_alist[toc_counter]->containing_node = xstrdup (node_name);
+ toc_entry_alist[toc_counter]->level = level;
+ toc_entry_alist[toc_counter]->number = toc_counter;
+
+ /* have to be done at least */
+ return toc_counter++;
+}
+
+/* Return the name of a chapter/section/subsection etc. that
+ corresponds to the node NODE. If the node isn't found,
+ return NULL.
+
+ WARNING! This function relies on NODE being unexpanded
+ except for macros (i.e., @value, @@, and other non-macros
+ should NOT be expanded), because the containing_node member
+ stores unexpanded node names.
+
+ Note that this function returns the first section whose
+ containing node is NODE. Thus, they will lose if they use
+ more than a single chapter structioning command in a node,
+ or if they have a node without any structuring commands. */
+char *
+toc_find_section_of_node (node)
+ char *node;
+{
+ int i;
+
+ if (!node)
+ node = "";
+ for (i = 0; i < toc_counter; i++)
+ if (STREQ (node, toc_entry_alist[i]->containing_node))
+ return toc_entry_alist[i]->name;
+
+ return NULL;
+}
+
+/* free up memory used by toc entries */
+void
+toc_free ()
+{
+ int i;
+
+ if (toc_counter)
+ {
+ for (i = 0; i < toc_counter; i++)
+ {
+ free (toc_entry_alist[i]->name);
+ free (toc_entry_alist[i]->containing_node);
+ free (toc_entry_alist[i]);
+ }
+
+ free (toc_entry_alist);
+ toc_entry_alist = NULL; /* to be sure ;-) */
+ toc_counter = 0; /* to be absolutley sure ;-) */
+ }
+}
+
+
+/* print table of contents in HTML, may be we can produce a standalone
+ HTML file? */
+static void
+contents_update_html (fp)
+ FILE *fp;
+{
+ int i;
+ int k;
+ int last_level;
+
+ /* does exist any toc? */
+ if (!toc_counter)
+ /* no, so return to sender ;-) */
+ return;
+
+ flush_output (); /* in case we are writing stdout */
+
+ fprintf (fp, "\n<h1>%s</h1>\n<ul>\n", _("Table of Contents"));
+
+ last_level = toc_entry_alist[0]->level;
+
+ for (i = 0; i < toc_counter; i++)
+ {
+ if (toc_entry_alist[i]->level > last_level)
+ {
+ /* unusual, but it is possible
+ @chapter ...
+ @subsubsection ... ? */
+ for (k = 0; k < (toc_entry_alist[i]->level-last_level); k++)
+ fputs ("<ul>\n", fp);
+ }
+ else if (toc_entry_alist[i]->level < last_level)
+ {
+ /* @subsubsection ...
+ @chapter ... this IS usual.*/
+ for (k = 0; k < (last_level-toc_entry_alist[i]->level); k++)
+ fputs ("</ul>\n", fp);
+ }
+
+ fprintf (fp, "<li><a href=\"#%s</a>\n", toc_entry_alist[i]->name);
+
+ last_level = toc_entry_alist[i]->level;
+ }
+
+ /* Go back to start level. */
+ if (toc_entry_alist[0]->level < last_level)
+ for (k = 0; k < (last_level-toc_entry_alist[0]->level); k++)
+ fputs ("</ul>\n", fp);
+
+ fputs ("</ul>\n\n", fp);
+}
+
+/* print table of contents in ASCII (--no-headers)
+ May be we should create a new command line switch --ascii ? */
+static void
+contents_update_info (fp)
+ FILE *fp;
+{
+ int i;
+ int k;
+
+ if (!toc_counter)
+ return;
+
+ flush_output (); /* in case we are writing stdout */
+
+ fprintf (fp, "%s\n%.*s\n\n", _("Table of Contents"),
+ (int) strlen (_("Table of Contents")), lots_of_stars);
+
+ for (i = 0; i < toc_counter; i++)
+ {
+ if (toc_entry_alist[i]->level == 0)
+ fputs ("\n", fp);
+
+ /* indention with two spaces per level, should this
+ changed? */
+ for (k = 0; k < toc_entry_alist[i]->level; k++)
+ fputs (" ", fp);
+
+ fprintf (fp, "%s\n", toc_entry_alist[i]->name);
+ }
+ fputs ("\n\n", fp);
+}
+
+/* shortcontents in HTML; Should this produce a standalone file? */
+static void
+shortcontents_update_html (fp)
+ FILE *fp;
+{
+ int i;
+
+ /* does exist any toc? */
+ if (!toc_counter)
+ return;
+
+ flush_output (); /* in case we are writing stdout */
+
+ fprintf (fp, "\n<h1>%s</h1>\n<ul>\n", _("Short Contents"));
+
+ for (i = 0; i < toc_counter; i++)
+ {
+ if ((toc_entry_alist[i])->level == 0)
+ {
+ fputs ("<li>", fp);
+ fprintf (fp, "<a href=\"#%s\n", toc_entry_alist[i]->name);
+ }
+ }
+
+ fputs ("</ul>\n\n", fp);
+}
+
+/* short contents in ASCII (--no-headers).
+ May be we should create a new command line switch --ascii ? */
+static void
+shortcontents_update_info (fp)
+ FILE *fp;
+{
+ int i;
+
+ if (!toc_counter)
+ return;
+
+ flush_output (); /* in case we are writing stdout */
+
+ fprintf (fp, "%s\n%.*s\n\n", _("Short Contents"),
+ (int) strlen (_("Short Contents")), lots_of_stars);
+
+ for (i = 0; i < toc_counter; i++)
+ {
+ if ((toc_entry_alist[i])->level == 0)
+ fprintf (fp, "%s\n", toc_entry_alist[i]->name);
+ }
+ fputs ("\n\n", fp);
+}
+
+
+static FILE *toc_fp;
+static char *toc_buf;
+
+static int
+rewrite_top (fname, placebo)
+ const char *fname, *placebo;
+{
+ int idx;
+
+ toc_buf = find_and_load (fname);
+
+ if (!toc_buf)
+ {
+ /* Can't rewrite standard output. No point in complaining. */
+ if (!STREQ (fname, "-"))
+ fs_error (fname);
+ return -1;
+ }
+
+ idx = search_forward (placebo, 0);
+
+ if (idx < 0)
+ {
+ error (_("%s: TOC should be here, but it was not found"), fname);
+ return -1;
+ }
+
+ toc_fp = fopen (fname, "w");
+ if (!toc_fp)
+ {
+ fs_error (fname);
+ return -1;
+ }
+
+ if (fwrite (toc_buf, 1, idx, toc_fp) != idx)
+ {
+ fs_error (fname);
+ return -1;
+ }
+
+ return idx + strlen (placebo);
+}
+
+static void
+contents_update ()
+{
+ int cont_idx = rewrite_top (contents_filename, contents_placebo);
+
+ if (cont_idx < 0)
+ return;
+
+ if (html)
+ contents_update_html (toc_fp);
+ else
+ contents_update_info (toc_fp);
+
+ if (fwrite (toc_buf + cont_idx, 1, input_text_length - cont_idx, toc_fp)
+ != input_text_length - cont_idx
+ || fclose (toc_fp) != 0)
+ fs_error (contents_filename);
+}
+
+static void
+shortcontents_update ()
+{
+ int cont_idx = rewrite_top (shortcontents_filename, shortcontents_placebo);
+
+ if (cont_idx < 0)
+ return;
+
+ if (html)
+ shortcontents_update_html (toc_fp);
+ else
+ shortcontents_update_info (toc_fp);
+
+ if (fwrite (toc_buf + cont_idx, 1, input_text_length - cont_idx - 1, toc_fp)
+ != input_text_length - cont_idx - 1
+ || fclose (toc_fp) != 0)
+ fs_error (shortcontents_filename);
+}
+
+void
+toc_update ()
+{
+ if (!html && !no_headers)
+ return;
+
+ if (contents_filename)
+ contents_update ();
+ if (shortcontents_filename)
+ shortcontents_update ();
+}
+
+void
+cm_contents (arg)
+ int arg;
+{
+ if ((html || no_headers) && arg == START)
+ {
+ if (contents_filename)
+ {
+ free (contents_filename);
+ contents_filename = NULL;
+ }
+
+ if (contents_filename && STREQ (contents_filename, "-"))
+ {
+ if (html)
+ contents_update_html (stdout);
+ else
+ contents_update_info (stdout);
+ }
+ else
+ {
+ contents_filename = xstrdup (current_output_filename);
+ insert_string (contents_placebo); /* just mark it, for now */
+ }
+ }
+}
+
+void
+cm_shortcontents (arg)
+ int arg;
+{
+ if ((html || no_headers) && arg == START)
+ {
+ if (shortcontents_filename)
+ {
+ free (shortcontents_filename);
+ shortcontents_filename = NULL;
+ }
+
+ if (shortcontents_filename && STREQ (shortcontents_filename, "-"))
+ {
+ if (html)
+ shortcontents_update_html (stdout);
+ else
+ shortcontents_update_info (stdout);
+ }
+ else
+ {
+ shortcontents_filename = xstrdup (current_output_filename);
+ insert_string (shortcontents_placebo); /* just mark it, for now */
+ }
+ }
+}
diff --git a/contrib/texinfo/makeinfo/toc.h b/contrib/texinfo/makeinfo/toc.h
new file mode 100644
index 0000000..a37faf7
--- /dev/null
+++ b/contrib/texinfo/makeinfo/toc.h
@@ -0,0 +1,49 @@
+/* toc.h -- table of contents handling.
+ $Id: toc.h,v 1.4 1999/04/25 19:49:22 karl Exp $
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written by Karl Heinz Marbaise <kama@hippo.fido.de>. */
+
+#ifndef TOC_H
+#define TOC_H
+
+/* the file where we found the @contents directive */
+extern char *contents_filename;
+
+/* the file where we found the @shortcontents directive */
+extern char *shortcontents_filename;
+
+/* Structure to hold one entry for the toc. */
+typedef struct toc_entry_elt {
+ char *name;
+ char *containing_node; /* Name of node containing this section. */
+ int number; /* counting number from 0...n independent from
+ chapter/section can be used for anchors or
+ references to it. */
+ int level; /* level: chapter, section, subsection... */
+} TOC_ENTRY_ELT;
+
+/* all routines which have relationship with TOC should start with
+ toc_ (this is a kind of name-space) */
+extern int toc_add_entry (); /* return the number for the toc-entry */
+extern void toc_free ();
+extern char *toc_find_section_of_node ();
+
+extern void cm_contents (), cm_shortcontents ();
+
+#endif /* not TOC_H */
OpenPOWER on IntegriCloud