diff options
Diffstat (limited to 'Build/source/utils/texinfo/makeinfo')
87 files changed, 26025 insertions, 0 deletions
diff --git a/Build/source/utils/texinfo/makeinfo/Makefile.am b/Build/source/utils/texinfo/makeinfo/Makefile.am new file mode 100644 index 00000000000..5f9f82dfd43 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/Makefile.am @@ -0,0 +1,28 @@ +# $Id: Makefile.am,v 1.5 2004/04/11 17:56:46 karl Exp $ +# Makefile.am for texinfo/makeinfo. +# Run automake in .. to produce Makefile.in from this. +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +bin_PROGRAMS = makeinfo + +localedir = $(datadir)/locale +INCLUDES = -I$(top_srcdir)/lib -I../intl -DLOCALEDIR=\"$(localedir)\" +LDADD = ../lib/libtxi.a $(LIBINTL) + +makeinfo_SOURCES = \ + cmds.c cmds.h defun.c defun.h \ + files.c files.h float.c float.h footnote.c footnote.h \ + html.c html.h index.c index.h insertion.c insertion.h lang.c lang.h \ + macro.c macro.h makeinfo.c makeinfo.h multi.c multi.h node.c node.h \ + sectioning.c sectioning.h toc.c toc.h xml.c xml.h xref.c xref.h + +EXTRA_DIST = README + +SUBDIRS = tests diff --git a/Build/source/utils/texinfo/makeinfo/Makefile.in b/Build/source/utils/texinfo/makeinfo/Makefile.in new file mode 100644 index 00000000000..fe059dd4fb6 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/Makefile.in @@ -0,0 +1,600 @@ +# Makefile.in generated by automake 1.9.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# $Id: Makefile.am,v 1.5 2004/04/11 17:56:46 karl Exp $ +# Makefile.am for texinfo/makeinfo. +# Run automake in .. to produce Makefile.in from this. +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +SOURCES = $(makeinfo_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = makeinfo$(EXEEXT) +subdir = makeinfo +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/codeset.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc21.m4 \ + $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intdiv0.m4 \ + $(top_srcdir)/m4/intmax.m4 $(top_srcdir)/m4/inttypes-pri.m4 \ + $(top_srcdir)/m4/inttypes.m4 $(top_srcdir)/m4/inttypes_h.m4 \ + $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \ + $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/onceonly_2_57.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/signed.m4 $(top_srcdir)/m4/size_max.m4 \ + $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ + $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ + $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_makeinfo_OBJECTS = cmds.$(OBJEXT) defun.$(OBJEXT) files.$(OBJEXT) \ + float.$(OBJEXT) footnote.$(OBJEXT) html.$(OBJEXT) \ + index.$(OBJEXT) insertion.$(OBJEXT) lang.$(OBJEXT) \ + macro.$(OBJEXT) makeinfo.$(OBJEXT) multi.$(OBJEXT) \ + node.$(OBJEXT) sectioning.$(OBJEXT) toc.$(OBJEXT) \ + xml.$(OBJEXT) xref.$(OBJEXT) +makeinfo_OBJECTS = $(am_makeinfo_OBJECTS) +makeinfo_LDADD = $(LDADD) +am__DEPENDENCIES_1 = +makeinfo_DEPENDENCIES = ../lib/libtxi.a $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(makeinfo_SOURCES) +DIST_SOURCES = $(makeinfo_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GENCAT = @GENCAT@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +HAVE_ASPRINTF = @HAVE_ASPRINTF@ +HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@ +HAVE_SNPRINTF = @HAVE_SNPRINTF@ +HAVE_WPRINTF = @HAVE_WPRINTF@ +HELP2MAN = @HELP2MAN@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTALL_WARNINGS_FALSE = @INSTALL_WARNINGS_FALSE@ +INSTALL_WARNINGS_TRUE = @INSTALL_WARNINGS_TRUE@ +INSTOBJEXT = @INSTOBJEXT@ +INTLBISON = @INTLBISON@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TERMLIBS = @TERMLIBS@ +TOOLS_ONLY_FALSE = @TOOLS_ONLY_FALSE@ +TOOLS_ONLY_TRUE = @TOOLS_ONLY_TRUE@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +native_tools = @native_tools@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +localedir = $(datadir)/locale +INCLUDES = -I$(top_srcdir)/lib -I../intl -DLOCALEDIR=\"$(localedir)\" +LDADD = ../lib/libtxi.a $(LIBINTL) +makeinfo_SOURCES = \ + cmds.c cmds.h defun.c defun.h \ + files.c files.h float.c float.h footnote.c footnote.h \ + html.c html.h index.c index.h insertion.c insertion.h lang.c lang.h \ + macro.c macro.h makeinfo.c makeinfo.h multi.c multi.h node.c node.h \ + sectioning.c sectioning.h toc.c toc.h xml.c xml.h xref.c xref.h + +EXTRA_DIST = README +SUBDIRS = tests +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu makeinfo/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu makeinfo/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +makeinfo$(EXEEXT): $(makeinfo_OBJECTS) $(makeinfo_DEPENDENCIES) + @rm -f makeinfo$(EXEEXT) + $(LINK) $(makeinfo_LDFLAGS) $(makeinfo_OBJECTS) $(makeinfo_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmds.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defun.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/files.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/float.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/footnote.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/html.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/index.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/insertion.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lang.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/macro.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/makeinfo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/multi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sectioning.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/toc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xref.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(mkdir_p) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-binPROGRAMS clean-generic clean-recursive ctags \ + ctags-recursive distclean distclean-compile distclean-generic \ + distclean-recursive distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-recursive pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/Build/source/utils/texinfo/makeinfo/README b/Build/source/utils/texinfo/makeinfo/README new file mode 100644 index 00000000000..17c437170b6 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/README @@ -0,0 +1,17 @@ +$Id: README,v 1.3 2004/04/11 17:56:46 karl Exp $ +texinfo/makeinfo/README + + Copyright (C) 2002 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. + +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 other formats: plain ASCII (with --no-headers) +or HTML (with --html) or XML (with --xml). + +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/Build/source/utils/texinfo/makeinfo/cmds.c b/Build/source/utils/texinfo/makeinfo/cmds.c new file mode 100644 index 00000000000..87ac7bb80de --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/cmds.c @@ -0,0 +1,1883 @@ +/* cmds.c -- Texinfo commands. + $Id: cmds.c,v 1.55 2004/12/14 00:15:36 karl Exp $ + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 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 "html.h" +#include "insertion.h" +#include "lang.h" +#include "macro.h" +#include "makeinfo.h" +#include "node.h" +#include "sectioning.h" +#include "toc.h" +#include "xml.h" + +#ifdef TM_IN_SYS_TIME +#include <sys/time.h> +#else +#include <time.h> +#endif + +/* Options. */ +static void cm_exampleindent (void), + cm_firstparagraphindent (void), + cm_paragraphindent (void), + cm_novalidate (void); + +/* Internals. */ +static void cm_obsolete (int arg, int start, int end), + not_fixed_width (int arg); + +/* The dispatch table. */ +COMMAND command_table[] = { + { "\t", insert_space, NO_BRACE_ARGS }, + { "\n", insert_space, NO_BRACE_ARGS }, + { " ", insert_space, NO_BRACE_ARGS }, + { "!", cm_punct, 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 }, + { ".", cm_punct, NO_BRACE_ARGS }, + { "/", cm_no_op, NO_BRACE_ARGS }, + { ":", cm_colon, NO_BRACE_ARGS }, + { "=", cm_accent, MAYBE_BRACE_ARGS }, + { "?", cm_punct, NO_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 }, + { "LaTeX", cm_LaTeX, 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 }, + { "abbr", cm_abbr, BRACE_ARGS }, + { "acronym", cm_acronym, BRACE_ARGS }, + { "ae", cm_special_char, BRACE_ARGS }, + { "afivepaper", cm_ignore_line, NO_BRACE_ARGS }, + { "afourlatex", cm_ignore_line, NO_BRACE_ARGS }, + { "afourpaper", cm_ignore_line, NO_BRACE_ARGS }, + { "afourwide", 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 }, + { "author", cm_author, NO_BRACE_ARGS }, + { "b", cm_b, BRACE_ARGS }, + { "bullet", cm_bullet, BRACE_ARGS }, + { "bye", cm_bye, NO_BRACE_ARGS }, + { "c", cm_comment, NO_BRACE_ARGS }, + { "caption", cm_caption, 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 }, + { "comma", cm_comma, BRACE_ARGS }, + { "command", cm_code, BRACE_ARGS }, + { "comment", cm_comment, NO_BRACE_ARGS }, + { "contents", cm_contents, NO_BRACE_ARGS }, + { "copying", cm_copying, 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 }, + { "deftypecv", cm_defun, NO_BRACE_ARGS }, + { "deftypecvx", 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_dmn, BRACE_ARGS }, + { "docbook", cm_docbook, NO_BRACE_ARGS }, + { "documentdescription", cm_documentdescription, NO_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 }, + { "euro", cm_special_char, BRACE_ARGS }, + { "evenfooting", cm_ignore_line, NO_BRACE_ARGS }, + { "evenheading", cm_ignore_line, NO_BRACE_ARGS }, + { "everyfooting", cm_ignore_line, NO_BRACE_ARGS }, + { "everyheading", cm_ignore_line, NO_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 }, + { "firstparagraphindent", cm_firstparagraphindent, NO_BRACE_ARGS }, + { "float", cm_float, 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 }, + { "headitem", cm_headitem, 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 }, + { "ifdocbook", cm_ifdocbook, NO_BRACE_ARGS }, + { "ifhtml", cm_ifhtml, NO_BRACE_ARGS }, + { "ifinfo", cm_ifinfo, NO_BRACE_ARGS }, + { "ifnotdocbook", cm_ifnotdocbook, NO_BRACE_ARGS }, + { "ifnothtml", cm_ifnothtml, NO_BRACE_ARGS }, + { "ifnotinfo", cm_ifnotinfo, NO_BRACE_ARGS }, + { "ifnotplaintext", cm_ifnotplaintext, NO_BRACE_ARGS }, + { "ifnottex", cm_ifnottex, NO_BRACE_ARGS }, + { "ifnotxml", cm_ifnotxml, NO_BRACE_ARGS }, + { "ifplaintext", cm_ifplaintext, NO_BRACE_ARGS }, + { "ifset", cm_ifset, NO_BRACE_ARGS }, + { "iftex", cm_iftex, NO_BRACE_ARGS }, + { "ifxml", cm_ifxml, NO_BRACE_ARGS }, + { "ignore", command_name_condition, NO_BRACE_ARGS }, + { "image", cm_image, BRACE_ARGS }, + { "include", cm_include, NO_BRACE_ARGS }, + { "indent", cm_indent, NO_BRACE_ARGS }, + { "indicateurl", cm_indicate_url, BRACE_ARGS }, + { "inforef", cm_inforef, BRACE_ARGS }, + { "insertcopying", cm_insert_copying, NO_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 }, + { "listoffloats", cm_listoffloats, NO_BRACE_ARGS }, + { "lowersections", cm_lowersections, NO_BRACE_ARGS }, + { "macro", cm_macro, NO_BRACE_ARGS }, + { "majorheading", cm_majorheading, NO_BRACE_ARGS }, + { "math", cm_math, 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_cmd, NO_BRACE_ARGS }, + { "novalidate", cm_novalidate, NO_BRACE_ARGS }, + { "nwnode", cm_node, NO_BRACE_ARGS }, + { "o", cm_special_char, BRACE_ARGS }, + { "oddfooting", cm_ignore_line, NO_BRACE_ARGS }, + { "oddheading", cm_ignore_line, NO_BRACE_ARGS }, + { "oe", cm_special_char, BRACE_ARGS }, + { "option", cm_code, BRACE_ARGS }, + { "ordf", cm_special_char, BRACE_ARGS }, + { "ordm", cm_special_char, 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 }, + { "registeredsymbol", cm_registeredsymbol, BRACE_ARGS }, + { "result", cm_result, BRACE_ARGS }, + { "ringaccent", cm_accent, MAYBE_BRACE_ARGS }, + { "rmacro", cm_rmacro, NO_BRACE_ARGS }, + { "samp", cm_code, BRACE_ARGS }, + { "sansserif", cm_sansserif, 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 }, + { "shortcaption", cm_caption, BRACE_ARGS }, + { "shortcontents", cm_contents, NO_BRACE_ARGS }, + { "shorttitlepage", cm_ignore_line, NO_BRACE_ARGS }, + { "slanted", cm_slanted, 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 }, + { "subtitle", cm_titlepage_cmds, NO_BRACE_ARGS }, + { "summarycontents", cm_contents, 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 }, + { "tie", cm_tie, BRACE_ARGS }, + { "tieaccent", cm_accent, MAYBE_BRACE_ARGS }, + { "tindex", cm_tindex, NO_BRACE_ARGS }, + { "title", cm_titlepage_cmds, NO_BRACE_ARGS }, + { "titlefont", cm_titlefont, BRACE_ARGS }, + { "titlepage", cm_titlepage, 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_uref, BRACE_ARGS }, + { "v", cm_accent, MAYBE_BRACE_ARGS }, + { "value", cm_value, BRACE_ARGS }, + { "var", cm_var, BRACE_ARGS }, + { "verb", cm_verb, NO_BRACE_ARGS }, + { "verbatim", cm_verbatim, NO_BRACE_ARGS }, + { "verbatiminclude", cm_verbatiminclude, NO_BRACE_ARGS }, + { "vindex", cm_vindex, NO_BRACE_ARGS }, + { "vtable", cm_vtable, NO_BRACE_ARGS }, + { "vskip", cm_ignore_line, NO_BRACE_ARGS }, + { "w", cm_w, BRACE_ARGS }, + { "xml", cm_xml, NO_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 (int arg) +{ + if (arg == START) + add_word (command); +} + +void +insert_space (int arg) +{ + if (arg == START) + { + if (xml && !docbook) + xml_insert_entity ("space"); + else + add_char (' '); + } +} + +/* Insert a comma. Useful when a literal , would break our parsing of + multiple arguments. */ +void +cm_comma (int arg) +{ + if (arg == START) + add_char (','); +} + + +/* Force a line break in the output. */ +void +cm_asterisk (void) +{ + if (html) + add_word ("<br>"); + else if (xml && !docbook) + xml_insert_entity ("linebreak"); + else if (docbook) + xml_asterisk (); + else + { + close_single_paragraph (); + cm_noindent (); + } +} + +/* Insert ellipsis. */ +void +cm_dots (int arg) +{ + if (arg == START) + { + if (xml && !docbook) + xml_insert_entity ("dots"); + else if (docbook) + xml_insert_entity ("hellip"); + else + if (html && !in_fixed_width_font) + insert_string ("<small class=\"dots\">...</small>"); + else + add_word ("..."); + } +} + +/* Insert ellipsis for sentence end. */ +void +cm_enddots (int arg) +{ + if (arg == START) + { + if (xml && !docbook) + xml_insert_entity ("enddots"); + else if (docbook) + { + xml_insert_entity ("hellip"); + add_char ('.'); + } + else + if (html && !in_fixed_width_font) + insert_string ("<small class=\"enddots\">....</small>"); + else + add_word ("...."); + } +} + +void +cm_bullet (int arg) +{ + if (arg == START) + { + if (html) + add_word ("•"); + else if (xml && !docbook) + xml_insert_entity ("bullet"); + else if (docbook) + xml_insert_entity ("bull"); + else + add_char ('*'); + } +} + +void +cm_minus (int arg) +{ + if (arg == START) + { + if (xml) + xml_insert_entity ("minus"); + else if (html) + add_word ("−"); + else + add_char ('-'); + } +} + +/* Formatting a dimension unit. */ +void +cm_dmn (int arg) +{ + if (html) + insert_html_tag_with_attribute (arg, "span", "class=\"dmn\""); + else if (docbook) + /* No units in docbook yet. */ + ; + else if (xml) + xml_insert_element (DIMENSION, arg); +} + +/* Insert "TeX". */ +void +cm_TeX (int arg) +{ + static int last_position; + + if (arg == START) + { + if (xml) + xml_insert_entity ("tex"); + else + add_word ("TeX"); + + last_position = output_paragraph_offset; + } + else if (last_position != output_paragraph_offset) + { + warning (_("arguments to @%s ignored"), command); + output_paragraph_offset = last_position; + } +} + +/* Insert "LaTeX". */ +void +cm_LaTeX (int arg) +{ + static int last_position; + + if (arg == START) + { + if (xml) + xml_insert_entity ("latex"); + else + add_word ("LaTeX"); + + last_position = output_paragraph_offset; + } + else if (last_position != output_paragraph_offset) + { + warning (_("arguments to @%s ignored"), command); + output_paragraph_offset = last_position; + } +} + +/* Copyright symbol. */ +void +cm_copyright (int arg) +{ + if (arg == START) + { + if (html) + add_word ("©"); + else if (xml && !docbook) + xml_insert_entity ("copyright"); + else if (docbook) + xml_insert_entity ("copy"); + else + add_word ("(C)"); + } +} + +/* Registered symbol. */ +void +cm_registeredsymbol (int arg) +{ + if (arg == START) + { + if (html) + add_word ("®"); + else if (docbook) + xml_insert_entity ("reg"); + else if (xml && !docbook) + xml_insert_entity ("registered"); + else + add_word ("(R)"); + } +} + +void +cm_today (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_comment (void) +{ + /* For HTML, do not output comments before HTML header is written, + otherwise comments before @settitle cause an empty <title> in the + header. */ + if ((html && html_output_head_p) || xml) + { + char *line; + get_rest_of_line (0, &line); + + if (strlen (line) > 0) + { + int save_inhibit_indentation = inhibit_paragraph_indentation; + int save_paragraph_is_open = paragraph_is_open; + int save_escape_html = escape_html; + int save_xml_no_para = xml_no_para; + int i; + + inhibit_paragraph_indentation = 1; + escape_html = 0; + xml_no_para = 1; + + /* @c and @comment can appear between @item and @itemx, + @deffn and @deffnx. */ + xml_dont_touch_items_defs++; + + /* Use insert for HTML, and XML when indentation is enabled. + For Docbook, use add_char. */ + if (xml && xml_indentation_increment > 0 + && output_paragraph[output_paragraph_offset-1] != '\n') + insert ('\n'); + + /* Crunch double hyphens in comments. */ + add_html_block_elt ("<!-- "); + for (i = 0; i < strlen (line); i++) + if (line[i] != '-' || (i && line[i-1] != '-')) + add_char (line[i]); + add_word (" -->"); + + if (html) + add_char ('\n'); + + inhibit_paragraph_indentation = save_inhibit_indentation; + paragraph_is_open = save_paragraph_is_open; + escape_html = save_escape_html; + xml_no_para = save_xml_no_para; + xml_dont_touch_items_defs--; + } + + free (line); + } + else + cm_ignore_line (); +} + + + +/* We keep acronyms with two arguments around, to be able to refer to them + later with only one argument. */ +static ACRONYM_DESC *acronyms_stack = NULL; + +static void +cm_acronym_or_abbr (int arg, int is_abbr) +{ + char *aa, *description; + unsigned len; + + /* We do everything at START. */ + if (arg == END) + return; + + get_until_in_braces (",", &aa); + if (input_text[input_text_offset] == ',') + input_text_offset++; + get_until_in_braces ("}", &description); + + canon_white (aa); + canon_white (description); + + /* If not enclosed in braces, strip after comma to be compatible + with texinfo.tex. */ + if (description[0] != '{' && strchr (description, ',') != NULL) + { + int i = 0; + while (description[i] != ',') + i++; + /* For now, just terminate the string at comma. */ + description[i] = 0; + } + + /* Get description out of braces. */ + if (description[0] == '{') + description++; + + len = strlen (description); + if (len && description[len-1] == '}') + description[len-1] = 0; + + /* Save new description. */ + if (strlen (description) > 0) + { + ACRONYM_DESC *new = xmalloc (sizeof (ACRONYM_DESC)); + + new->acronym = xstrdup (aa); + new->description = xstrdup (description); + new->next = acronyms_stack; + acronyms_stack = new; + } + + if (html) + { + add_word (is_abbr ? "<abbr" : "<acronym"); + + if (strlen (description) > 0) + add_word_args (" title=\"%s\"", text_expansion (description)); + else if (acronyms_stack) + { + /* No second argument, get from previous. Search order is from + last to first defined, so we get the most recent version of + the description. */ + ACRONYM_DESC *temp = acronyms_stack; + + while (temp) + { + if (STREQ (aa, temp->acronym) + && strlen (temp->description) > 0) + { + add_word_args (" title=\"%s\"", + text_expansion (temp->description)); + break; + } + temp = temp->next; + } + } + + add_char ('>'); + execute_string ("%s", aa); + add_word (is_abbr ? "</abbr>" : "</acronym>"); + } + else if (docbook) + { + xml_insert_element (is_abbr ? ABBREV : ACRONYM, START); + execute_string ("%s", aa); + xml_insert_element (is_abbr ? ABBREV : ACRONYM, END); + } + else if (xml) + { + xml_insert_element (is_abbr ? ABBREV : ACRONYM, START); + + xml_insert_element (is_abbr ? ABBREVWORD : ACRONYMWORD, START); + execute_string ("%s", aa); + xml_insert_element (is_abbr ? ABBREVWORD : ACRONYMWORD, END); + + if (strlen (description) > 0) + { + xml_insert_element (is_abbr ? ABBREVDESC : ACRONYMDESC, START); + execute_string ("%s", description); + xml_insert_element (is_abbr ? ABBREVDESC : ACRONYMDESC, END); + } + + xml_insert_element (is_abbr ? ABBREV : ACRONYM, END); + } + else + execute_string ("%s", aa); + + /* Put description into parenthesis after the acronym for all outputs + except XML. */ + if (strlen (description) > 0 && (!xml || docbook)) + add_word_args (" (%s)", description); +} + +void +cm_acronym (int arg) +{ + cm_acronym_or_abbr (arg, 0); +} + +void +cm_abbr (int arg) +{ + cm_acronym_or_abbr (arg, 1); +} + +void +cm_tt (int arg) +{ + /* @t{} is a no-op in Info. */ + if (html) + insert_html_tag (arg, "tt"); + else if (xml) + xml_insert_element (TT, arg); +} + +void +cm_code (int arg) +{ + if (arg == START) + in_fixed_width_font++; + + if (xml) + { + if (STREQ (command, "command")) + xml_insert_element (COMMAND_TAG, arg); + else if (STREQ (command, "env")) + xml_insert_element (ENV, arg); + else if (STREQ (command, "file")) + xml_insert_element (FILE_TAG, arg); + else if (STREQ (command, "option")) + xml_insert_element (OPTION, arg); + else if (STREQ (command, "samp")) + { + if (docbook && arg == START) + { + /* Even though @samp is in_fixed_width_font, it + should always start a paragraph. Unfortunately, + in_fixed_width_font inhibits that. */ + xml_start_para (); + xml_insert_entity ("lsquo"); + } + xml_insert_element (SAMP, arg); + if (docbook && arg == END) + xml_insert_entity ("rsquo"); + } + else + xml_insert_element (CODE, arg); + } + else if (html) + { + if (STREQ (command, "code")) + insert_html_tag (arg, "code"); + else + { /* Use <samp> tag in general to get typewriter. */ + if (arg == START) + { /* If @samp specifically, add quotes a la TeX output. */ + if (STREQ (command, "samp")) add_char ('`'); + add_word ("<samp>"); + } + insert_html_tag_with_attribute (arg, "span", "class=\"%s\"",command); + if (arg == END) + { + add_word ("</samp>"); + if (STREQ (command, "samp")) add_char ('\''); + } + } + } + else + { + extern int printing_index; + + if (!printing_index) + { + if (arg == START) + add_char ('`'); + else + add_meta_char ('\''); + } + } +} + +void +cm_kbd (int arg) +{ + if (xml) + xml_insert_element (KBD, arg); + else 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); + } +} + +/* Just show a url (http://example.org/..., for example), don't link to it. */ +void +cm_indicate_url (int arg, int start, int end) +{ + if (xml) + xml_insert_element (URL, arg); + else if (html) + { + if (arg == START) + add_word ("<"); + insert_html_tag (arg, "code"); + if (arg != START) + add_word (">"); + } + else + if (arg == START) + add_word ("<"); + else + add_word (">"); +} + +void +cm_key (int arg) +{ + if (xml) + xml_insert_element (KEY, arg); + else if (html) + add_word (arg == START ? "<" : ">"); + else + add_char (arg == START ? '<' : '>'); +} + +/* Handle a command that switches to a non-fixed-width font. */ +void +not_fixed_width (int arg) +{ + if (arg == START) + in_fixed_width_font = 0; +} + +/* @var in makeinfo just uppercases the text. */ +void +cm_var (int arg, int start_pos, int end_pos) +{ + if (xml) + xml_insert_element (VAR, arg); + else + { + 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 (int arg, int start_pos, int end_pos) +{ + if (xml) + xml_insert_element (SC, arg); + else + { + not_fixed_width (arg); + + if (arg == START) + { + if (html) + insert_html_tag_with_attribute (arg, "span", "class=\"sc\""); + } + else + { + int all_upper; + + if (html) + start_pos += sizeof ("<span class=\"sc\">") - 1; /* skip <span> */ + + /* Avoid the warning below if there's no text inside @sc{}, or + when processing menus under --no-headers. */ + all_upper = start_pos < end_pos; + + while (start_pos < end_pos) + { + unsigned char c = output_paragraph[start_pos]; + if (!isupper (c)) + all_upper = 0; + if (!html) + 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, "span"); + } + } +} + +void +cm_dfn (int arg, int position) +{ + if (xml) + xml_insert_element (DFN, arg); + else + { + if (html) + insert_html_tag (arg, "dfn"); + else if (arg == START) + add_char ('"'); + else + add_meta_char ('"'); + } +} + +void +cm_emph (int arg) +{ + if (xml) + xml_insert_element (EMPH, arg); + else if (html) + insert_html_tag (arg, "em"); + else + add_char ('_'); +} + +void +cm_verb (int arg) +{ + int character; + int delimiter = 0; /* avoid warning */ + int seen_end = 0; + + in_fixed_width_font++; + /* are these necessary ? */ + last_char_was_newline = 0; + + if (html) + add_word ("<tt>"); + + if (input_text_offset < input_text_length) + { + character = curchar (); + if (character == '{') + input_text_offset++; + else + line_error (_("`{' expected, but saw `%c'"), character); + } + + if (input_text_offset < input_text_length) + { + delimiter = curchar (); + input_text_offset++; + } + + while (input_text_offset < input_text_length) + { + character = curchar (); + + if (character == '\n') + { + line_number++; + if (html) + add_word ("<br>\n"); + } + + else if (html && character == '<') + add_word ("<"); + + else if (html && character == '&') + add_word ("&"); + + else if (character == delimiter && input_text[input_text_offset+1] == '}') + { /* Assume no newlines in END_VERBATIM. */ + seen_end = 1; + input_text_offset++; + break; + } + + else + add_char (character); + + input_text_offset++; + } + + if (!seen_end) + warning (_("end of file inside verb block")); + + if (input_text_offset < input_text_length) + { + character = curchar (); + if (character == '}') + input_text_offset++; + else + line_error (_("`}' expected, but saw `%c'"), character); + } + + if (html) + add_word ("</tt>"); + + in_fixed_width_font--; +} + + +void +cm_strong (int arg, int start_pos, int end_pos) +{ + if (docbook && arg == START) + xml_insert_element_with_attribute (B, arg, "role=\"bold\""); + else if (xml) + xml_insert_element (STRONG, arg); + else if (html) + insert_html_tag (arg, "strong"); + else + add_char ('*'); + + if (!xml && !html && !docbook && !no_headers + && arg == END + && end_pos - start_pos >= 6 + && (STRNCASEEQ ((char *) output_paragraph + start_pos, "*Note:", 6) + || STRNCASEEQ ((char *) output_paragraph + start_pos, "*Note ", 6))) + { + /* Translators: "Note:" is literal here and should not be + translated. @strong{Nota}, say, does not cause the problem. */ + warning (_("@strong{Note...} produces a spurious cross-reference in Info; reword to avoid that")); + /* Adjust the output to avoid writing the bad xref. */ + output_paragraph[start_pos + 5] = '_'; + } +} + +void +cm_cite (int arg, int position) +{ + if (xml) + xml_insert_element (CITE, arg); + else 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 (int arg, int start, int end) +{ + if (xml) + xml_insert_element (NOTFIXEDWIDTH, arg); + not_fixed_width (arg); +} + +void +cm_i (int arg) +{ + /* Make use of <lineannotation> of Docbook, if we are + inside an @example or similar. */ + extern int printing_index; + if (docbook && !filling_enabled && !printing_index) + xml_insert_element (LINEANNOTATION, arg); + else if (xml) + xml_insert_element (I, arg); + else if (html) + insert_html_tag (arg, "i"); + else + not_fixed_width (arg); +} + +void +cm_slanted (int arg) +{ + /* Make use of <lineannotation> of Docbook, if we are + inside an @example or similar. */ + extern int printing_index; + if (docbook && !filling_enabled && !printing_index) + xml_insert_element (LINEANNOTATION, arg); + else if (xml) + xml_insert_element (SLANTED, arg); + else if (html) + insert_html_tag (arg, "i"); + else + not_fixed_width (arg); +} + +void +cm_b (int arg) +{ + /* See cm_i comments. */ + extern int printing_index; + if (docbook && !filling_enabled && !printing_index) + xml_insert_element (LINEANNOTATION, arg); + else if (docbook && arg == START) + xml_insert_element_with_attribute (B, arg, "role=\"bold\""); + else if (xml) + xml_insert_element (B, arg); + else if (html) + insert_html_tag (arg, "b"); + else + not_fixed_width (arg); +} + +void +cm_r (int arg) +{ + /* See cm_i comments. */ + extern int printing_index; + if (docbook && !filling_enabled && !printing_index) + xml_insert_element (LINEANNOTATION, arg); + else if (xml) + xml_insert_element (R, arg); + else if (html) + insert_html_tag_with_attribute (arg, "span", "class=\"roman\""); + else + not_fixed_width (arg); +} + +void +cm_sansserif (int arg) +{ + /* See cm_i comments. */ + extern int printing_index; + if (docbook && !filling_enabled && !printing_index) + xml_insert_element (LINEANNOTATION, arg); + else if (xml) + xml_insert_element (SANSSERIF, arg); + else if (html) + insert_html_tag_with_attribute (arg, "span", "class=\"sansserif\""); + else + not_fixed_width (arg); +} + +void +cm_titlefont (int arg) +{ + if (xml) + xml_insert_element (TITLEFONT, arg); + else + { + not_fixed_width (arg); + if (html) + { + html_title_written = 1; /* suppress title from @settitle */ + if (arg == START) + add_word ("<h1 class=\"titlefont\">"); + else + add_word ("</h1>\n"); + } + } +} + + +/* Unfortunately, we cannot interpret @math{} contents like TeX does. We just + pass them through. */ +void +cm_math (int arg) +{ + if (xml && !docbook) + xml_insert_element (MATH, arg); +} + +/* Various commands are no-op's. */ +void +cm_no_op (void) +{ +} + + +/* For proofing single chapters, etc. */ +void +cm_novalidate (void) +{ + validating = 0; +} + + +/* Prevent the argument from being split across two lines. */ +void +cm_w (int arg) +{ + if (arg == START) + non_splitting_words++; + else + { + if (docbook || html || xml) + /* This is so @w{$}Log$ doesn't end up as <dollar>Log<dollar> + in the output. */ + insert_string ("<!-- /@w -->"); + + non_splitting_words--; + } +} + + +/* An unbreakable word space. Same as @w{ } for makeinfo, but different + for TeX (the space stretches and stretches, and does not inhibit + hyphenation). */ +void +cm_tie (int arg) +{ + if (arg == START) + { + cm_w (START); + add_char (' '); + } + else + cm_w (END); +} + +/* Explain that this command is obsolete, thus the user shouldn't + do anything with it. */ +static void +cm_obsolete (int arg, int start, int end) +{ + if (arg == START) + warning (_("%c%s is obsolete"), COMMAND_PREFIX, command); +} + + +/* Inhibit the indentation of the next paragraph, but not of following + paragraphs. */ +void +cm_noindent (void) +{ + if (!inhibit_paragraph_indentation) + inhibit_paragraph_indentation = -1; +} + +void +cm_noindent_cmd (void) +{ + cm_noindent (); + xml_no_indent = 1; + skip_whitespace_and_newlines(); + + if (xml) + xml_start_para (); + else if (html && !paragraph_is_open) + add_html_block_elt ("<p class=\"noindent\">"); + else + { + paragraph_is_open = 0; + start_paragraph (); + } +} + +/* Force indentation of the next paragraph. */ +void +cm_indent (void) +{ + inhibit_paragraph_indentation = 0; + xml_no_indent = 0; + skip_whitespace_and_newlines(); + + if (xml) + xml_start_para (); + else if (html && !paragraph_is_open) + add_html_block_elt ("<p class=\"indent\">"); + else + start_paragraph (); +} + +/* 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 (void) +{ + char *filename; + get_rest_of_line (1, &filename); + /* warning ("`@%s %s' encountered and ignored", command, filename); */ + if (xml) + add_word_args ("<setfilename>%s</setfilename>", filename); + free (filename); +} + +void +cm_settitle (void) +{ + if (xml) + { + xml_begin_document (current_output_filename); + xml_insert_element (SETTITLE, START); + xml_in_book_title = 1; + get_rest_of_line (0, &title); + execute_string ("%s", title); + xml_in_book_title = 0; + xml_insert_element (SETTITLE, END); + } + else + get_rest_of_line (0, &title); +} + + +/* Ignore argument in braces. */ +void +cm_ignore_arg (int arg, int start_pos, int end_pos) +{ + if (arg == END) + output_paragraph_offset = start_pos; +} + +/* Ignore argument on rest of line. */ +void +cm_ignore_line (void) +{ + discard_until ("\n"); +} + +/* Insert the number of blank lines passed as argument. */ +void +cm_sp (void) +{ + int lines; + char *line; + + /* Due to tricky stuff in execute_string(), @value{} can't be expanded. + So there is really no reason to enable expansion for @sp parameters. */ + get_rest_of_line (0, &line); + + if (sscanf (line, "%d", &lines) != 1 || lines <= 0) + line_error (_("@sp requires a positive numeric argument, not `%s'"), line); + else + { + if (xml) + { + /* @sp can appear between @item and @itemx, @deffn and @deffnx. */ + xml_dont_touch_items_defs++; + xml_insert_element_with_attribute (SP, START, "lines=\"%s\"", line); + /* insert_string (line);*/ + xml_insert_element (SP, END); + xml_dont_touch_items_defs--; + } + 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 generates an extra blank line. */ + close_single_paragraph (); + + if (lines && html && !executing_string) + html_output_head (); + + if (html) + add_html_block_elt ("<pre class=\"sp\">\n"); + + while (lines--) + add_char ('\n'); + + if (html) + add_html_block_elt ("</pre>\n"); + + filling_enabled = save_filling_enabled; + } + } + free (line); +} + +/* @dircategory LINE outputs INFO-DIR-SECTION LINE, unless --no-headers. */ +void +cm_dircategory (void) +{ + char *line; + + if (html || docbook) + cm_ignore_line (); + else if (xml) + { + xml_insert_element (DIRCATEGORY, START); + get_rest_of_line (1, &line); + insert_string (line); + free (line); + xml_insert_element (DIRCATEGORY, END); + } + 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. + */ +void +cm_center (void) +{ + if (xml) + { + char *line; + xml_insert_element (CENTER, START); + get_rest_of_line (0, &line); + execute_string ("%s", line); + free (line); + xml_insert_element (CENTER, END); + } + else + { + int i, start, length; + char *line; + int save_indented_fill = indented_fill; + int save_filling_enabled = filling_enabled; + int fudge_factor = 1; + + filling_enabled = indented_fill = 0; + cm_noindent (); + start = output_paragraph_offset; + + if (html) + add_html_block_elt ("<div align=\"center\">"); + + inhibit_output_flushing (); + get_rest_of_line (0, &line); + execute_string ("%s", line); + free (line); + uninhibit_output_flushing (); + if (html) + add_html_block_elt ("</div>"); + + 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'); + filling_enabled = save_filling_enabled; + indented_fill = save_indented_fill; + close_single_paragraph (); + if (looking_at("\n")) + insert ('\n'); + } +} + +/* Show what an expression returns. */ +void +cm_result (int arg) +{ + if (arg == END) + add_word (html ? "=>" : "=>"); +} + +/* What an expression expands to. */ +void +cm_expansion (int arg) +{ + if (arg == END) + add_word (html ? "==>" : "==>"); +} + +/* Indicates two expressions are equivalent. */ +void +cm_equiv (int arg) +{ + if (arg == END) + add_word ("=="); +} + +/* What an expression may print. */ +void +cm_print (int arg) +{ + if (arg == END) + add_word ("-|"); +} + +/* An error signaled. */ +void +cm_error (int arg) +{ + if (arg == END) + add_word (html ? "error-->" : "error-->"); +} + +/* The location of point in an example of a buffer. */ +void +cm_point (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 (void) +{ + 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>"); + else if (docbook) + xml_insert_element (LINEANNOTATION, START); + else if (xml) + xml_insert_element (EXDENT, START); + + /* Can't close_single_paragraph, then we lose preceding blank lines. */ + flush_output (); + execute_string ("%s", line); + free (line); + + if (html) + add_word ("<br>"); + else if (xml) + { + xml_insert_element (docbook ? LINEANNOTATION : EXDENT, END); + insert ('\n'); + } + + close_single_paragraph (); + + current_indent = save_indent; + in_fixed_width_font = save_in_fixed_width_font; + if (!xml) + start_paragraph (); +} + +/* + Read include-filename, process the include-file: + verbatim_include == 0: process through reader_loop + verbatim_include != 0: process through handle_verbatim_environment + */ +static void +handle_include (int verbatim_include) +{ + char *arg, *filename; + + if (macro_expansion_output_stream && !executing_string) + me_append_before_this_command (); + + if (!insertion_stack) + close_paragraph (); /* No blank lines etc. if not at outer level. */ + + get_rest_of_line (0, &arg); + /* We really only want to expand @value, but it's easier to just do + everything. TeX will only work with @value. */ + filename = text_expansion (arg); + free (arg); + + 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, 1)) + { + popfile (); + line_number--; + + /* /wh/bar:5: @include/@verbatiminclude `foo': No such file or dir */ + 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); + + if (!verbatim_include) + reader_loop (); + else + handle_verbatim_environment (0); + } + free (filename); + popfile (); +} + + +/* Include file as if put in @verbatim environment */ +void +cm_verbatiminclude (void) +{ + handle_include (1); +} + + +/* Remember this file, and move onto the next. */ +void +cm_include (void) +{ + handle_include (0); +} + + +/* @bye: Signals end of processing. Easy to make this happen. */ + +void +cm_bye (void) +{ + discard_braces (); /* should not have any unclosed braces left */ + input_text_offset = input_text_length; +} + +/* @paragraphindent */ + +static void +cm_paragraphindent (void) +{ + 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_example_indentation_increment (char *string) +{ + if (strcmp (string, "asis") == 0 || strcmp (string, _("asis")) == 0) + ; + else if (strcmp (string, "none") == 0 || strcmp (string, _("none")) == 0) + example_indentation_increment = 0; + else if (sscanf (string, "%d", &example_indentation_increment) != 1) + return -1; + return 0; +} + +static void +cm_exampleindent (void) +{ + char *arg; + + get_rest_of_line (1, &arg); + if (set_example_indentation_increment (arg) != 0) + line_error (_("Bad argument to @%s"), command); + + if (input_text[input_text_offset] == '\n') + close_single_paragraph (); + + free (arg); +} + + +/* @firstparagraphindent: suppress indentation in first paragraphs after + headings. */ +static int +set_firstparagraphindent (char *string) +{ + if (STREQ (string, "insert") || STREQ (string, _("insert"))) + do_first_par_indent = 1; + else if (STREQ (string, "none") || STREQ (string, _("none"))) + do_first_par_indent = 0; + else + return -1; + return 0; +} + +static void +cm_firstparagraphindent (void) +{ + char *arg; + + get_rest_of_line (1, &arg); + if (set_firstparagraphindent (arg) != 0) + line_error (_("Bad argument to %c%s"), COMMAND_PREFIX, command); + + free (arg); +} + +/* For DocBook and XML, produce . for `.@:'. This gives the processing + software a fighting chance to treat it specially by not adding extra space. + + Do this also for ?, !, and :. */ +void +cm_colon (void) +{ + if (xml) + { + if (strchr (".?!:", input_text[input_text_offset-3]) != NULL) + { + /* Erase literal character that's there, except `>', which is + part of the XML tag. */ + if (output_paragraph[output_paragraph_offset-1] != '>') + output_paragraph_offset--; + + switch (input_text[input_text_offset-3]) + { + case '.': + xml_insert_entity ("period"); + break; + case '?': + xml_insert_entity ("quest"); + break; + case '!': + xml_insert_entity ("excl"); + break; + case ':': + xml_insert_entity ("colon"); + break; + } + } + } +} + +/* Ending sentences explicitly. Currently, only outputs entities for XML + output, for other formats it calls insert_self. */ +void +cm_punct (int arg) +{ + if (xml && !docbook) + { + switch (input_text[input_text_offset-1]) + { + case '.': + xml_insert_entity ("eosperiod"); + break; + case '?': + xml_insert_entity ("eosquest"); + break; + case '!': + xml_insert_entity ("eosexcl"); + break; + } + } + else + { + insert_self (arg); + } +} diff --git a/Build/source/utils/texinfo/makeinfo/cmds.h b/Build/source/utils/texinfo/makeinfo/cmds.h new file mode 100644 index 00000000000..68245505b51 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/cmds.h @@ -0,0 +1,213 @@ +/* cmds.h -- declarations for cmds.c. + $Id: cmds.h,v 1.9 2004/11/26 00:48:35 karl Exp $ + + Copyright (C) 1998, 1999, 2002, 2003, 2004 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[]; + +typedef struct acronym_desc +{ + struct acronym_desc *next; + char *acronym; + char *description; +} ACRONYM_DESC; + +/* Texinfo commands. */ +extern void insert_self (int arg), + insert_space (int arg), + cm_ignore_line (void), + cm_ignore_arg (int arg, int start_pos, int end_pos), + cm_comment (void), + cm_no_op (void); + +/* Document structure and meta information. */ +extern void cm_setfilename (void), + cm_settitle (void), + cm_documentdescription (void), + cm_node (void), + cm_menu (void), + cm_detailmenu (void), + cm_dircategory (void), + cm_direntry (void), + cm_bye (void); + +/* File inclusion. */ +extern void cm_include (void), + cm_verbatiminclude (void); + +/* Cross referencing commands. */ +extern void cm_anchor (int arg), + cm_xref (int arg), + cm_pxref (int arg), + cm_ref (int arg), + cm_inforef (int arg), + cm_uref (int arg); + +/* Special insertions. */ +extern void cm_LaTeX (int arg), + cm_TeX (int arg), + cm_bullet (int arg), + cm_colon (void), + cm_comma (int arg), + cm_copyright (int arg), + cm_dots (int arg), + cm_enddots (int arg), + cm_equiv (int arg), + cm_error (int arg), + cm_expansion (int arg), + cm_image (int arg), + cm_insert_copying (void), + cm_minus (int arg), + cm_point (int arg), + cm_print (int arg), + cm_punct (int arg), + cm_registeredsymbol (int arg), + cm_result (int arg); + +/* Emphasis and markup. */ +extern void cm_acronym (int arg), + cm_abbr (int arg), + cm_b (int arg), + cm_cite (int arg, int position), + cm_code (int arg), + cm_dfn (int arg, int position), + cm_dmn (int arg), + cm_email (int arg), + cm_emph (int arg), + cm_i (int arg), + cm_kbd (int arg), + cm_key (int arg), + cm_math (int arg), + cm_not_fixed_width (int arg, int start, int end), + cm_r (int arg), + cm_sansserif (int arg), + cm_sc (int arg, int start_pos, int end_pos), + cm_slanted (int arg), + cm_strong (int arg, int start_pos, int end_pos), + cm_tt (int arg), + cm_indicate_url (int arg, int start, int end), + cm_var (int arg, int start_pos, int end_pos), + cm_verb (int arg); + +/* Block environments. */ +extern void cm_cartouche (void), + cm_group (void), + cm_display (void), + cm_smalldisplay (void), + cm_example (void), + cm_smallexample (void), + cm_smalllisp (void), + cm_lisp (void), + cm_format (void), + cm_smallformat (void), + cm_quotation (void), + cm_copying (void), + cm_flushleft (void), + cm_flushright (void), + cm_verbatim (void), + cm_end (void); + +/* Tables, lists, enumerations. */ +extern void cm_table (void), + cm_ftable (void), + cm_vtable (void), + cm_itemize (void), + cm_enumerate (void), + cm_multitable (void), + cm_headitem (void), + cm_item (void), + cm_itemx (void), + cm_tab (void); + +extern void cm_center (void), + cm_exdent (void), + cm_indent (void), + cm_noindent (void), + cm_noindent_cmd (void); + +/* Line and page breaks. */ +extern void cm_asterisk (void), + cm_sp (void), + cm_page (void); + +/* Non breaking words. */ +extern void cm_tie (int arg), + cm_w (int arg); + +/* Title page creation. */ +extern void cm_titlepage (void), + cm_author (void), + cm_titlepage_cmds (void), + cm_titlefont (int arg), + cm_today (int arg); + +/* Floats. */ +extern void cm_float (void), + cm_caption (int arg), + cm_shortcaption (void), + cm_listoffloats (void); + +/* Indices. */ +extern void cm_kindex (void), + cm_cindex (void), + cm_findex (void), + cm_pindex (void), + cm_vindex (void), + cm_tindex (void), + cm_defindex (void), + cm_defcodeindex (void), + cm_synindex (void), + cm_printindex (void); + +/* Conditionals. */ +extern void cm_set (void), + cm_clear (void), + cm_ifset (void), + cm_ifclear (void), + cm_ifeq (void), + cm_value (int arg, int start_pos, int end_pos); + +#endif /* !CMDS_H */ diff --git a/Build/source/utils/texinfo/makeinfo/defun.c b/Build/source/utils/texinfo/makeinfo/defun.c new file mode 100644 index 00000000000..0323353edf5 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/defun.c @@ -0,0 +1,720 @@ +/* defun.c -- @defun and friends. + $Id: defun.c,v 1.11 2004/04/11 17:56:46 karl Exp $ + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 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 "xml.h" +#include "insertion.h" +#include "makeinfo.h" +#include "cmds.h" +#include "html.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 (struct token_accumulator *accumulator) +{ + accumulator->length = 0; + accumulator->index = 0; + accumulator->tokens = NULL; +} + +static void +accumulate_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 (char **string_pointer) +{ + char *scan_string = (*string_pointer) + 1; + unsigned int level = 1; + int started_command = 0; + + 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--; + line_error (_("Missing `}' in @def arg")); + line_number++; + *string_pointer = scan_string - 1; + return 0; + } + + if (c == '{' && !started_command) + level++; + if (c == '}' && !started_command) + level--; + + /* remember if at @. */ + started_command = (c == '@' && !started_command); + } +} + +/* 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 (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; + } + + /* Make commas separate tokens so to differentiate them from + parameter types in XML output. */ + else if (*scan_string == ',') + { + token_start = scan_string; + scan_string += 1; + token_end = 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; + } + + /* End token if we are looking at a comma, as commas are + delimiters too. */ + if (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 (char **defun_args, int auto_var_p) +{ + int pending_space = 0; + + if (xml) + { + xml_process_defun_args (defun_args, auto_var_p); + return; + } + + 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])) + { + /* Within @deffn and friends, texinfo.tex makes parentheses + sans serif and brackets bold. We use roman instead. */ + if (html) + insert_html_tag (START, ""); + + add_char (defun_arg[0]); + + if (html) + insert_html_tag (END, ""); + } + /* else if (defun_arg[0] == '&' || defun_arg[0] == COMMAND_PREFIX) */ + /* execute_string ("%s", defun_arg); */ + /* else if (auto_var_p) */ + /* execute_string ("%s", defun_arg); */ + else + execute_string ("%s", defun_arg); + } +} + +static char * +next_nonwhite_defun_arg (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 (int type) +{ + int 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 deftypecv: base_type = deftypecv; 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 (int type, int x_p) +{ + int base_type; + char **defun_args, **scan_args; + const char *category; + char *defined_name; + char *type_name = NULL; + char *type_name2 = NULL; + + { + 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); + + /* Basic line continuation. If a line ends with \s*@\s* concatanate + the next line. */ + { + char *next_line, *new_line; + int i; + + line_continuation: + i = strlen (line) - 1; + + if (line[i] == '@' && line[i-1] != '@') + { + get_rest_of_line (0, &next_line); + new_line = (char *) xmalloc (i + strlen (next_line) + 2); + strncpy (new_line, line, i); + new_line[i] = '\0'; + free (line); + strcat (new_line, " "); + strcat (new_line, next_line); + line = xstrdup (new_line); + free (next_line); + free (new_line); + + goto line_continuation; + } + } + + 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 == deftypecv) + || (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 == deftypecv) + || (base_type == deftypeivar) + || (base_type == deftypemethod) + || (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; + } + + /* It's easy to write @defun foo(arg1 arg2), but a following ( is + misparsed by texinfo.tex and this is next to impossible to fix. + Warn about it. */ + if (*scan_args && **scan_args && **scan_args == '(') + warning ("`%c' follows defined name `%s' instead of whitespace", + **scan_args, defined_name); + + 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 && !xml) + 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 deftypecv: + 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; + } + else 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) + insert_string ("<div class=\"defun\">\n"); + else + rollback_empty_tag ("blockquote"); + + /* 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: + execute_string ("--- %s: ", category); + break; + + case defcv: + case deftypecv: + case deftypeivar: + execute_string ("--- %s %s %s: ", category, _("of"), type_name); + break; + + case defop: + case deftypemethod: + case deftypeop: + execute_string ("--- %s %s %s: ", category, _("on"), type_name); + break; + } /* switch (base_type)... */ + + switch (base_type) + { + case deffn: + case defvr: + case deftp: + /* <var> is for the following function arguments. */ + insert_html_tag (START, "b"); + execute_string ("%s", defined_name); + insert_html_tag (END, "b"); + insert_html_tag (START, "var"); + break; + case deftypefn: + case deftypevr: + execute_string ("%s ", type_name); + insert_html_tag (START, "b"); + execute_string ("%s", defined_name); + insert_html_tag (END, "b"); + insert_html_tag (START, "var"); + break; + case defcv: + case defop: + insert_html_tag (START, "b"); + execute_string ("%s", defined_name); + insert_html_tag (END, "b"); + insert_html_tag (START, "var"); + break; + case deftypecv: + case deftypeivar: + case deftypemethod: + case deftypeop: + execute_string ("%s ", type_name2); + insert_html_tag (START, "b"); + execute_string ("%s", defined_name); + insert_html_tag (END, "b"); + insert_html_tag (START, "var"); + break; + } + } + else if (xml) + xml_begin_def_term (base_type, category, defined_name, type_name, + type_name2); + + 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; + if (!html) + close_single_paragraph (); + + /* Make an entry in the appropriate index. (XML and + Docbook already got their entries, so skip them.) */ + if (!xml) + switch (base_type) + { + case deffn: + case deftypefn: + execute_string ("@findex %s\n", defined_name); + break; + case defcv: + case deftypecv: + case deftypevr: + case defvr: + 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; + } + + if (xml) + xml_end_def_term (); + else if (html) + { + inhibit_paragraph_indentation = 1; + no_indent = 1; + insert_html_tag (END, "var"); + insert_string ("<br>\n"); + /* Indent the definition a bit. */ + add_html_block_elt ("<blockquote>"); + no_indent = 0; + inhibit_paragraph_indentation = 0; + paragraph_is_open = 0; + } + + /* 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 (void) +{ + int type; + char *base_command = xstrdup (command); /* command with any `x' removed */ + int x_p = (command[strlen (command) - 1] == 'x'); + + if (x_p) + base_command[strlen (base_command) - 1] = 0; + + type = find_type_from_name (base_command); + + /* 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_ELT *i = insertion_stack; + /* Skip over ifclear and ifset conditionals. */ + while (i && (i->insertion == ifset || i->insertion == ifclear)) + i = i->next; + + if (!i || i->insertion != type) + { + line_error (_("Must be in `@%s' environment to use `@%s'"), + base_command, command); + discard_until ("\n"); + return; + } + } + + defun_internal (type, x_p); + free (base_command); +} diff --git a/Build/source/utils/texinfo/makeinfo/defun.h b/Build/source/utils/texinfo/makeinfo/defun.h new file mode 100644 index 00000000000..9af73ec4a57 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/defun.h @@ -0,0 +1,31 @@ +/* defun.h -- declaration for defuns. + $Id: defun.h,v 1.2 2004/04/11 17:56:47 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 (int type); +extern void cm_defun (void); + +#endif /* !DEFUN_H */ + diff --git a/Build/source/utils/texinfo/makeinfo/depend.mak b/Build/source/utils/texinfo/makeinfo/depend.mak new file mode 100644 index 00000000000..6e69c6a2a85 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/depend.mak @@ -0,0 +1,203 @@ +$(objdir)/macro.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + macro.h \ + makeinfo.h \ + insertion.h \ + files.h \ + cmds.h + +$(objdir)/toc.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + makeinfo.h \ + insertion.h \ + cmds.h \ + files.h \ + macro.h \ + node.h \ + html.h \ + lang.h \ + sectioning.h \ + toc.h + +$(objdir)/files.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + files.h \ + macro.h \ + makeinfo.h + +$(objdir)/lang.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + cmds.h \ + lang.h \ + makeinfo.h \ + sectioning.h \ + insertion.h \ + xml.h + +$(objdir)/insertion.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + cmds.h \ + defun.h \ + insertion.h \ + macro.h \ + makeinfo.h \ + multi.h \ + xml.h + +$(objdir)/index.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + index.h \ + makeinfo.h \ + insertion.h \ + cmds.h \ + lang.h \ + macro.h \ + toc.h \ + html.h \ + xml.h + +$(objdir)/node.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + cmds.h \ + files.h \ + footnote.h \ + macro.h \ + makeinfo.h \ + node.h \ + html.h \ + sectioning.h \ + insertion.h \ + xml.h + +$(objdir)/makeinfo.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + $(kpathseadir)/getopt.h \ + makeinfo.h \ + cmds.h \ + files.h \ + footnote.h \ + html.h \ + index.h \ + insertion.h \ + macro.h \ + node.h \ + toc.h \ + xml.h + +$(objdir)/sectioning.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + macro.h \ + makeinfo.h \ + node.h \ + toc.h \ + sectioning.h \ + insertion.h \ + cmds.h \ + html.h \ + xml.h + +$(objdir)/cmds.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + cmds.h \ + defun.h \ + insertion.h \ + files.h \ + footnote.h \ + index.h \ + makeinfo.h \ + lang.h \ + macro.h \ + node.h \ + sectioning.h \ + toc.h \ + multi.h \ + html.h \ + xml.h + +$(objdir)/xml.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + makeinfo.h \ + insertion.h \ + macro.h \ + cmds.h \ + lang.h \ + xml.h + +$(objdir)/defun.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + defun.h \ + insertion.h \ + xml.h \ + makeinfo.h \ + cmds.h \ + html.h + +$(objdir)/multi.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + multi.h \ + insertion.h \ + makeinfo.h \ + cmds.h \ + xml.h + +$(objdir)/html.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + cmds.h \ + html.h \ + lang.h \ + makeinfo.h \ + sectioning.h + +$(objdir)/footnote.obj: \ + ../lib/system.h \ + ../config.h \ + $(gnuw32dir)/win32lib.h \ + ../lib/gettext.h \ + footnote.h \ + macro.h \ + makeinfo.h \ + node.h \ + xml.h + diff --git a/Build/source/utils/texinfo/makeinfo/files.c b/Build/source/utils/texinfo/makeinfo/files.c new file mode 100644 index 00000000000..db112262ee2 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/files.c @@ -0,0 +1,784 @@ +/* files.c -- file-related functions for makeinfo. + $Id: files.c,v 1.5 2004/07/27 00:06:31 karl Exp $ + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 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 "html.h" +#include "index.h" +#include "macro.h" +#include "makeinfo.h" +#include "node.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 (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. */ +char * +get_file_info_in_path (char *filename, char *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; +} + +/* Prepend and append new paths to include_files_path. */ +void +prepend_to_include_path (char *path) +{ + if (!include_files_path) + { + include_files_path = xstrdup (path); + include_files_path = xrealloc (include_files_path, + strlen (include_files_path) + 3); /* 3 for ":.\0" */ + strcat (strcat (include_files_path, PATH_SEP), "."); + } + else + { + char *tmp = xstrdup (include_files_path); + include_files_path = xrealloc (include_files_path, + strlen (include_files_path) + strlen (path) + 2); /* 2 for ":\0" */ + strcpy (include_files_path, path); + strcat (include_files_path, PATH_SEP); + strcat (include_files_path, tmp); + free (tmp); + } +} + +void +append_to_include_path (char *path) +{ + if (!include_files_path) + include_files_path = xstrdup ("."); + + include_files_path = (char *) xrealloc (include_files_path, + 2 + strlen (include_files_path) + strlen (path)); + strcat (include_files_path, PATH_SEP); + strcat (include_files_path, path); +} + +/* Remove the first path from the include_files_path. */ +void +pop_path_from_include_path (void) +{ + int i = 0; + char *tmp; + + if (include_files_path) + for (i = 0; i < strlen (include_files_path) + && include_files_path[i] != ':'; i++); + + /* Advance include_files_path to the next char from ':' */ + tmp = (char *) xmalloc (strlen (include_files_path) - i); + strcpy (tmp, (char *) include_files_path + i + 1); + + free (include_files_path); + include_files_path = tmp; +} + +/* Find and load the file named FILENAME. Return a pointer to + the loaded file, or NULL if it can't be loaded. If USE_PATH is zero, + just look for the given file (this is used in handle_delayed_writes), + else search along include_files_path. */ + +char * +find_and_load (char *filename, int use_path) +{ + struct stat fileinfo; + long file_size; + int file = -1, count = 0; + char *fullpath, *result; + int n, bytes_to_read; + + result = fullpath = NULL; + + fullpath + = get_file_info_in_path (filename, use_path ? include_files_path : NULL, + &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. It's also needed on Cygwin. And so + we might as well use it everywhere. */ + bytes_to_read = file_size; + while ((n = read (file, result + count, bytes_to_read)) > 0) + { + count += n; + bytes_to_read -= n; + } + if (0 < count && count < file_size) + result = xrealloc (result, count + 2); /* why waste the slack? */ + else if (n == -1) +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. */ +static void +push_node_filename (void) +{ + 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++; +} + +static void +pop_node_filename (void) +{ + node_filename = node_filename_stack[--node_filename_stack_index]; +} + +/* Save the state of the current input file. */ +void +pushfile (void) +{ + 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 (void) +{ + 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 (void) +{ + 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 (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; +} + +static char * +filename_non_directory (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 (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 = 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 (char *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 full path to FILENAME. */ +static char * +full_pathname (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; +} + +/* Return the expansion of FILENAME. */ +char * +expand_filename (char *filename, char *input_name) +{ + int i; + + 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; +} + +char * +output_name_from_input_name (char *name) +{ + return expand_filename (NULL, name); +} + + +/* Modify the file name FNAME so that it fits the limitations of the + underlying filesystem. In particular, truncate the file name as it + would be truncated by the filesystem. We assume the result can + never be longer than the original, otherwise we couldn't be sure we + have enough space in the original string to modify it in place. */ +char * +normalize_filename (char *fname) +{ + int maxlen; + char orig[PATH_MAX + 1]; + int i; + char *lastdot, *p; + +#ifdef _PC_NAME_MAX + maxlen = pathconf (fname, _PC_NAME_MAX); + if (maxlen < 1) +#endif + maxlen = PATH_MAX; + + i = skip_directory_part (fname); + if (fname[i] == '\0') + return fname; /* only a directory name -- don't modify */ + strcpy (orig, fname + i); + + switch (maxlen) + { + case 12: /* MS-DOS 8+3 filesystem */ + if (orig[0] == '.') /* leading dots are not allowed */ + orig[0] = '_'; + lastdot = strrchr (orig, '.'); + if (!lastdot) + lastdot = orig + strlen (orig); + strncpy (fname + i, orig, lastdot - orig); + for (p = fname + i; + p < fname + i + (lastdot - orig) && p < fname + i + 8; + p++) + if (*p == '.') + *p = '_'; + *p = '\0'; + if (*lastdot == '.') + strncat (fname + i, lastdot, 4); + break; + case 14: /* old Unix systems with 14-char limitation */ + strcpy (fname + i, orig); + if (strlen (fname + i) > 14) + fname[i + 14] = '\0'; + break; + default: + strcpy (fname + i, orig); + if (strlen (fname) > maxlen - 1) + fname[maxlen - 1] = '\0'; + break; + } + + return fname; +} + +/* Delayed writing functions. A few of the commands + needs to be handled at the end, namely @contents, + @shortcontents, @printindex and @listoffloats. + These functions take care of that. */ +static DELAYED_WRITE *delayed_writes = NULL; +int handling_delayed_writes = 0; + +void +register_delayed_write (char *delayed_command) +{ + DELAYED_WRITE *new; + + if (!current_output_filename || !*current_output_filename) + { + /* Cannot register if we don't know what the output file is. */ + warning (_("`%s' omitted before output filename"), delayed_command); + return; + } + + if (STREQ (current_output_filename, "-")) + { + /* Do not register a new write if the output file is not seekable. + Let the user know about it first, though. */ + warning (_("`%s' omitted since writing to stdout"), delayed_command); + return; + } + + /* Don't complain if the user is writing /dev/null, since surely they + don't care, but don't register the delayed write, either. */ + if (FILENAME_CMP (current_output_filename, NULL_DEVICE) == 0 + || FILENAME_CMP (current_output_filename, ALSO_NULL_DEVICE) == 0) + return; + + /* We need the HTML header in the output, + to get a proper output_position. */ + if (!executing_string && html) + html_output_head (); + /* Get output_position updated. */ + flush_output (); + + new = xmalloc (sizeof (DELAYED_WRITE)); + new->command = xstrdup (delayed_command); + new->filename = xstrdup (current_output_filename); + new->input_filename = xstrdup (input_filename); + new->position = output_position; + new->calling_line = line_number; + new->node = current_node ? xstrdup (current_node): ""; + + new->node_order = node_order; + new->index_order = index_counter; + + new->next = delayed_writes; + delayed_writes = new; +} + +void +handle_delayed_writes (void) +{ + DELAYED_WRITE *temp = (DELAYED_WRITE *) reverse_list + ((GENERIC_LIST *) delayed_writes); + int position_shift_amount, line_number_shift_amount; + char *delayed_buf; + + handling_delayed_writes = 1; + + while (temp) + { + delayed_buf = find_and_load (temp->filename, 0); + + if (output_paragraph_offset > 0) + { + error (_("Output buffer not empty.")); + return; + } + + if (!delayed_buf) + { + fs_error (temp->filename); + return; + } + + output_stream = fopen (temp->filename, "w"); + if (!output_stream) + { + fs_error (temp->filename); + return; + } + + if (fwrite (delayed_buf, 1, temp->position, output_stream) != temp->position) + { + fs_error (temp->filename); + return; + } + + { + int output_position_at_start = output_position; + int line_number_at_start = output_line_number; + + /* In order to make warnings and errors + refer to the correct line number. */ + input_filename = temp->input_filename; + line_number = temp->calling_line; + + execute_string ("%s", temp->command); + flush_output (); + + /* Since the output file is modified, following delayed writes + need to be updated by this amount. */ + position_shift_amount = output_position - output_position_at_start; + line_number_shift_amount = output_line_number - line_number_at_start; + } + + if (fwrite (delayed_buf + temp->position, 1, + input_text_length - temp->position, output_stream) + != input_text_length - temp->position + || fclose (output_stream) != 0) + fs_error (temp->filename); + + /* Done with the buffer. */ + free (delayed_buf); + + /* Update positions in tag table for nodes that are defined after + the line this delayed write is registered. */ + if (!html && !xml) + { + TAG_ENTRY *node; + for (node = tag_table; node; node = node->next_ent) + if (node->order > temp->node_order) + node->position += position_shift_amount; + } + + /* Something similar for the line numbers in all of the defined + indices. */ + { + int i; + for (i = 0; i < defined_indices; i++) + if (name_index_alist[i]) + { + char *name = ((INDEX_ALIST *) name_index_alist[i])->name; + INDEX_ELT *index; + for (index = index_list (name); index; index = index->next) + if ((no_headers || STREQ (index->node, temp->node)) + && index->entry_number > temp->index_order) + index->output_line += line_number_shift_amount; + } + } + + /* Shift remaining delayed positions + by the length of this write. */ + { + DELAYED_WRITE *future_write = temp->next; + while (future_write) + { + if (STREQ (temp->filename, future_write->filename)) + future_write->position += position_shift_amount; + future_write = future_write->next; + } + } + + temp = temp->next; + } +} diff --git a/Build/source/utils/texinfo/makeinfo/files.h b/Build/source/utils/texinfo/makeinfo/files.h new file mode 100644 index 00000000000..0943663467f --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/files.h @@ -0,0 +1,70 @@ +/* files.h -- declarations for files.c. + $Id: files.h,v 1.4 2004/07/27 00:06:31 karl Exp $ + + Copyright (C) 1998, 2002, 2004 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 (void); +extern void popfile (void); +extern void flush_file_stack (void); +extern char *get_file_info_in_path (char *filename, char *path, + struct stat *finfo); +extern char *find_and_load (char *filename, int use_path); +extern char *output_name_from_input_name (char *name); +extern char *expand_filename (char *filename, char *input_name); +extern char *filename_part (char *filename); +extern char *pathname_part (char *filename); +extern char *normalize_filename (char *fname); +extern void append_to_include_path (char *path); +extern void prepend_to_include_path (char *path); +extern void pop_path_from_include_path (void); +extern void register_delayed_write (char *delayed_command); +extern void handle_delayed_writes (void); + +typedef struct delayed_write +{ + struct delayed_write *next; + char *command; + char *filename; + char *input_filename; + char *node; + int position; + int calling_line; + + int node_order; + int index_order; +} DELAYED_WRITE; + +extern int handling_delayed_writes; + +#endif /* !FILES_H */ diff --git a/Build/source/utils/texinfo/makeinfo/float.c b/Build/source/utils/texinfo/makeinfo/float.c new file mode 100644 index 00000000000..b2c9a3367c1 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/float.c @@ -0,0 +1,430 @@ +/* float.c -- float environment functions. + $Id: float.c,v 1.8 2004/07/05 22:23:22 karl Exp $ + + Copyright (C) 2003, 2004 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. + + Originally written by Alper Ersoy <dirt@gtk.org>. */ + +#include "system.h" +#include "makeinfo.h" +#include "cmds.h" +#include "files.h" +#include "float.h" +#include "html.h" +#include "sectioning.h" +#include "xml.h" + +static FLOAT_ELT *float_stack = NULL; + +void +add_new_float (char *id, char *title, char *shorttitle, + char *type, char *position) +{ + FLOAT_ELT *new = xmalloc (sizeof (FLOAT_ELT)); + unsigned long num_len; + + new->id = id; + new->type = type; + new->title = title; + new->shorttitle = shorttitle; + new->position = position; + new->title_used = 0; + new->defining_line = line_number - 1; + + new->number = current_chapter_number (); + /* Append dot if not @unnumbered. */ + num_len = strlen (new->number); + if (num_len > 0) + { + new->number = xrealloc (new->number, num_len + 1 + 1); + new->number[num_len] = '.'; + new->number[num_len+1] = '\0'; + } + + { /* Append the current float number. */ + unsigned len = strlen (new->number) + 21; /* that's 64 bits */ + char *s = xmalloc (len + 1); + + sprintf (s, "%s%d", new->number, + count_floats_of_type_in_chapter (text_expansion (type), + new->number) + 1); + free (new->number); + new->number = xstrdup (s); + } + + /* Plain text output needs sectioning number and its title, + when listing floats. */ + if (!html && !xml && no_headers) + { + new->section = current_sectioning_number (); + if (strlen (new->section) == 0) + new->section_name = current_sectioning_name (); + else + new->section_name = ""; + } + + new->next = float_stack; + float_stack = new; +} + +int +count_floats_of_type_in_chapter (char *type, char *chapter) +{ + int i = 0; + int l = strlen (chapter); + FLOAT_ELT *temp = float_stack; + + while (temp && strncmp (temp->number, chapter, l) == 0) + { + if (strlen (temp->id) > 0 && STREQ (text_expansion (temp->type), type)) + i++; + temp = temp->next; + } + + return i; +} + +char * +current_float_title (void) +{ + return float_stack->title; +} + +char * +current_float_shorttitle (void) +{ + return float_stack->shorttitle; +} + +char * +current_float_type (void) +{ + return float_stack->type; +} + +char * +current_float_position (void) +{ + return float_stack->position; +} + +char * +current_float_number (void) +{ + return float_stack->number; +} + +char * +current_float_id (void) +{ + return float_stack->id; +} + +char * +get_float_ref (char *id) +{ + FLOAT_ELT *temp = float_stack; + + while (temp) + { + if (STREQ (id, temp->id)) + { + char *s = xmalloc (strlen (temp->type) + strlen (temp->number) + 2); + sprintf (s, "%s %s", temp->type, temp->number); + return s; + } + temp = temp->next; + } + + return NULL; +} + +static int +float_type_exists (char *check_type) +{ + /* Check if the requested float_type exists in the floats stack. */ + FLOAT_ELT *temp; + + for (temp = float_stack; temp; temp = temp->next) + if (STREQ (temp->type, check_type) && temp->id && *temp->id) + return 1; + + return 0; +} + +void +cm_listoffloats (void) +{ + char *float_type; + get_rest_of_line (1, &float_type); + + /* get_rest_of_line increments the line number by one, + so to make warnings/errors point to the correct line, + we decrement the line_number again. */ + if (!handling_delayed_writes) + line_number--; + + if (handling_delayed_writes && !float_type_exists (float_type)) + warning (_("Requested float type `%s' not previously used"), float_type); + + if (xml) + { + xml_insert_element_with_attribute (LISTOFFLOATS, START, + "type=\"%s\"", text_expansion (float_type)); + xml_insert_element (LISTOFFLOATS, END); + } + else if (!handling_delayed_writes) + { + int command_len = sizeof ("@ ") + strlen (command) + strlen (float_type); + char *list_command = xmalloc (command_len + 1); + + /* These are for the text following @listoffloats command. + Handling them with delayed writes is too late. */ + close_paragraph (); + cm_noindent (); + + sprintf (list_command, "@%s %s", command, float_type); + register_delayed_write (list_command); + free (list_command); + } + else if (float_type_exists (float_type)) + { + FLOAT_ELT *temp = (FLOAT_ELT *) reverse_list + ((GENERIC_LIST *) float_stack); + FLOAT_ELT *new_start = temp; + + if (html) + insert_string ("<ul class=\"listoffloats\">\n"); + else + { + if (!no_headers) + insert_string ("* Menu:\n\n"); + } + + while (temp) + { + if (strlen (temp->id) > 0 && STREQ (float_type, temp->type)) + { + if (html) + { + /* A bit of space for HTML reabality. */ + insert_string (" "); + add_html_block_elt ("<li>"); + + /* Simply relying on @ref command doesn't work here, because + commas in the caption may confuse the argument parsing. */ + add_word ("<a href=\""); + add_anchor_name (temp->id, 1); + add_word ("\">"); + + if (strlen (float_type) > 0) + execute_string ("%s", float_type); + + if (strlen (temp->id) > 0) + { + if (strlen (float_type) > 0) + add_char (' '); + + add_word (temp->number); + } + + if (strlen (temp->title) > 0) + { + if (strlen (float_type) > 0 + || strlen (temp->id) > 0) + insert_string (": "); + + execute_string ("%s", temp->title); + } + + add_word ("</a>"); + + add_html_block_elt ("</li>\n"); + } + else + { + char *entry; + char *raw_entry; + char *title = expansion (temp->title, 0); + + int len; + int aux_chars_len; /* these are asterisk, colon, etc. */ + int column_width; /* width of the first column in menus. */ + int number_len; /* length of Figure X.Y: etc. */ + int i = 0; + + /* Chosen widths are to match what @printindex produces. */ + if (no_headers) + { + column_width = 43; + /* We have only one auxiliary character, NULL. */ + aux_chars_len = sizeof (""); + } + else + { + column_width = 37; + /* We'll be adding an asterisk, followed by a space + and then a colon after the title, to construct a + proper menu item. */ + aux_chars_len = sizeof ("* :"); + } + + /* Allocate enough space for possible expansion later. */ + raw_entry = (char *) xmalloc (strlen (float_type) + + strlen (temp->number) + strlen (title) + + sizeof (": ")); + + sprintf (raw_entry, "%s %s", float_type, temp->number); + + if (strlen (title) > 0) + strcat (raw_entry, ": "); + + number_len = strlen (raw_entry); + + len = strlen (title) + strlen (raw_entry); + + /* If we have a @shortcaption, try it if @caption is + too long to fit on a line. */ + if (len + aux_chars_len > column_width + && strlen (temp->shorttitle) > 0) + title = expansion (temp->shorttitle, 0); + + strcat (raw_entry, title); + len = strlen (raw_entry); + + if (len + aux_chars_len > column_width) + { /* Shorten long titles by looking for a space before + column_width - strlen (" ..."). */ + /* -1 is for NULL, which is already in aux_chars_len. */ + aux_chars_len += sizeof ("...") - 1; + len = column_width - aux_chars_len; + while (raw_entry[len] != ' ' && len >= 0) + len--; + + /* Advance to the whitespace. */ + len++; + + /* If we are at the end of, say, Figure X.Y:, but + we have a title, then this means title does not + contain any whitespaces. Or it may be that we + went as far as the beginning. Just print as much + as possible of the title. */ + if (len == 0 + || (len == number_len && strlen (title) > 0)) + len = column_width - sizeof ("..."); + + /* Break here. */ + raw_entry[len] = 0; + + entry = xmalloc (len + aux_chars_len); + + if (!no_headers) + strcpy (entry, "* "); + else + entry[0] = 0; + + strcat (entry, raw_entry); + strcat (entry, "..."); + + if (!no_headers) + strcat (entry, ":"); + } + else + { + entry = xmalloc (len + aux_chars_len); + + if (!no_headers) + strcpy (entry, "* "); + else + entry[0] = 0; + + strcat (entry, raw_entry); + + if (!no_headers) + strcat (entry, ":"); + } + + insert_string (entry); + + i = strlen (entry); + /* We insert space chars until ``column_width + four spaces'' + is reached, to make the layout the same with what we produce + for @printindex. This is of course not obligatory, though + easier on the eye. -1 is for NULL. */ + while (i < column_width + sizeof (" ") - 1) + { + insert (' '); + i++; + } + + if (no_headers) + { + if (strlen (temp->section) > 0) + { /* We got your number. */ + insert_string ((char *) _("See ")); + insert_string (temp->section); + } + else + { /* Sigh, @float in an @unnumbered. :-\ */ + insert_string ("\n "); + insert_string ((char *) _("See ")); + insert_string ("``"); + insert_string (expansion (temp->section_name, 0)); + insert_string ("''"); + } + } + else + insert_string (temp->id); + + insert_string (".\n"); + + free (entry); + free (title); + } + } + temp = temp->next; + } + + if (html) + { + inhibit_paragraph_indentation = 1; + insert_string ("</ul>\n\n"); + } + else + insert ('\n'); + + /* Retain the original order of float stack. */ + temp = new_start; + float_stack = (FLOAT_ELT *) reverse_list ((GENERIC_LIST *) temp); + } + + free (float_type); + /* Re-increment the line number, because get_rest_of_line + left us looking at the next line after the command. */ + line_number++; +} + +int +current_float_used_title (void) +{ + return float_stack->title_used; +} + +void current_float_set_title_used (void) +{ + float_stack->title_used = 1; +} diff --git a/Build/source/utils/texinfo/makeinfo/float.h b/Build/source/utils/texinfo/makeinfo/float.h new file mode 100644 index 00000000000..be9deb58096 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/float.h @@ -0,0 +1,56 @@ +/* float.h -- declarations for the float environment. + $Id: float.h,v 1.5 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 2003, 2004 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 Alper Ersoy <dirt@gtk.org>. */ + +#ifndef FLOAT_H +#define FLOAT_H + +typedef struct float_elt +{ + struct float_elt *next; + char *id; + char *type; + char *title; + char *shorttitle; + char *position; + char *number; + char *section; + char *section_name; + short title_used; + int defining_line; +} FLOAT_ELT; + +extern void add_new_float (char *id, char *title, char *shorttitle, + char *type, char *position); +extern void current_float_set_title_used (void); + +/* Information retrieval about the current float env. */ +extern char *current_float_id (void); +extern char *current_float_title (void); +extern char *current_float_shorttitle (void); +extern char *current_float_type (void); +extern char *current_float_position (void); +extern char *current_float_number (void); +extern char *get_float_ref (char *id); + +extern int count_floats_of_type_in_chapter (char *type, char *chapter); +extern int current_float_used_title (void); + +#endif /* not FLOAT_H */ diff --git a/Build/source/utils/texinfo/makeinfo/footnote.c b/Build/source/utils/texinfo/makeinfo/footnote.c new file mode 100644 index 00000000000..e5a7f4c08f5 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/footnote.c @@ -0,0 +1,391 @@ +/* footnote.c -- footnotes for Texinfo. + $Id: footnote.c,v 1.7 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1998, 1999, 2002 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" +#include "node.h" +#include "xml.h" +#include "xref.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 (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 (void) +{ + 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. */ +static void +remember_note (char *marker, char *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 (void) +{ + 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 (void) +{ + 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; + } + + /* output_pending_notes is non-reentrant (it uses a global data + structure pending_notes, which it frees before it returns), and + TeX doesn't grok footnotes inside footnotes anyway. Disallow + that. */ + if (already_outputting_pending_notes) + { + line_error (_("Footnotes inside footnotes are not allowed")); + free (marker); + free (note); + return; + } + + if (!*marker) + { + free (marker); + + if (number_footnotes) + { + marker = xmalloc (10); + sprintf (marker, "%d", current_footnote_number); + } + else + marker = xstrdup ("*"); + } + + if (xml) + xml_insert_footnote (note); + else + { + 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) + { + /* Hyperlink also serves as an anchor (mnemonic: fnd is footnote + definition.) */ + add_html_elt ("<a rel=\"footnote\" href="); + add_word_args ("\"#fn-%d\" name=\"fnd-%d\"><sup>%s</sup></a>", + current_footnote_number, 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 (void) +{ + FN *footnote = pending_notes; + + if (!pending_notes) + return; + + if (html) + { + add_html_block_elt ("<div class=\"footnote\">\n<hr>\n"); + /* We add an anchor here so @printindex can refer to this point + (as the node name) for entries defined in footnotes. */ + if (!splitting) + add_word ("<a name=\"texinfo-footnotes-in-document\"></a>"); + add_word_args ("<h4>%s</h4>", (char *) _("Footnotes")); + } + 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. */ + { + int save_in_fixed_width_font = in_fixed_width_font; + 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; + in_fixed_width_font = 0; + + while ((footnote = array[++footnote_count])) + { + if (html) + { + /* Make the text of every footnote begin a separate paragraph. */ + add_html_block_elt ("<p class=\"footnote\"><small>"); + /* Make footnote number a link to its definition. */ + add_word_args ("[<a name=\"fn-%d\" href=\"#fnd-%d\">%d</a>]", + footnote->number, footnote->number, footnote->number); + add_word ("</small> "); + already_outputting_pending_notes++; + execute_string ("%s", footnote->note); + already_outputting_pending_notes--; + 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 ("<hr></div>"); + close_paragraph (); + free (array); + + in_fixed_width_font = save_in_fixed_width_font; + } + + free_pending_notes (); +} diff --git a/Build/source/utils/texinfo/makeinfo/footnote.h b/Build/source/utils/texinfo/makeinfo/footnote.h new file mode 100644 index 00000000000..e4f95102c5f --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/footnote.h @@ -0,0 +1,38 @@ +/* footnote.h -- declarations for footnote.c. + $Id: footnote.h,v 1.2 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 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 (void); +extern void cm_footnotestyle (void); + +extern int set_footnote_style (char *string); /* called for -s option */ + +extern void output_pending_notes (void); /* called for output */ + +#endif /* !FOOTNOTE_H */ diff --git a/Build/source/utils/texinfo/makeinfo/html.c b/Build/source/utils/texinfo/makeinfo/html.c new file mode 100644 index 00000000000..be2c136d41f --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/html.c @@ -0,0 +1,822 @@ +/* html.c -- html-related utilities. + $Id: html.c,v 1.28 2004/12/06 01:13:06 karl Exp $ + + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 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 "html.h" +#include "lang.h" +#include "makeinfo.h" +#include "node.h" +#include "sectioning.h" + + +/* Append CHAR to BUFFER, (re)allocating as necessary. We don't handle + null characters. */ + +typedef struct +{ + unsigned size; /* allocated */ + unsigned length; /* used */ + char *buffer; +} buffer_type; + +static buffer_type * +init_buffer (void) +{ + buffer_type *buf = xmalloc (sizeof (buffer_type)); + buf->length = 0; + buf->size = 0; + buf->buffer = NULL; + + return buf; +} + +static void +append_char (buffer_type *buf, int c) +{ + buf->length++; + if (buf->length >= buf->size) + { + buf->size += 100; + buf->buffer = xrealloc (buf->buffer, buf->size); + } + buf->buffer[buf->length - 1] = c; + buf->buffer[buf->length] = 0; +} + +/* Read the cascading style-sheet file FILENAME. Write out any @import + commands, which must come first, by the definition of css. If the + file contains any actual css code following the @imports, return it; + else return NULL. */ +static char * +process_css_file (char *filename) +{ + int c; + int lastchar = 0; + FILE *f; + buffer_type *import_text = init_buffer (); + buffer_type *inline_text = init_buffer (); + unsigned lineno = 1; + enum { null_state, comment_state, import_state, inline_state } state + = null_state, prev_state; + + prev_state = null_state; + + /* read from stdin if `-' is the filename. */ + f = STREQ (filename, "-") ? stdin : fopen (filename, "r"); + if (!f) + { + error (_("%s: could not open --css-file: %s"), progname, filename); + return NULL; + } + + /* Read the file. The @import statements must come at the beginning, + with only whitespace and comments allowed before any inline css code. */ + while ((c = getc (f)) >= 0) + { + if (c == '\n') + lineno++; + + switch (state) + { + case null_state: /* between things */ + if (c == '@') + { /* Only @import and @charset should switch into + import_state, other @-commands, such as @media, should + put us into inline_state. I don't think any other css + @-commands start with `i' or `c', although of course + this will break when such a command is defined. */ + int nextchar = getc (f); + if (nextchar == 'i' || nextchar == 'c') + { + append_char (import_text, c); + state = import_state; + } + else + { + ungetc (nextchar, f); /* wasn't an @import */ + state = inline_state; + } + } + else if (c == '/') + { /* possible start of a comment */ + int nextchar = getc (f); + if (nextchar == '*') + state = comment_state; + else + { + ungetc (nextchar, f); /* wasn't a comment */ + state = inline_state; + } + } + else if (isspace (c)) + ; /* skip whitespace; maybe should use c_isspace? */ + + else + /* not an @import, not a comment, not whitespace: we must + have started the inline text. */ + state = inline_state; + + if (state == inline_state) + append_char (inline_text, c); + + if (state != null_state) + prev_state = null_state; + break; + + case comment_state: + if (c == '/' && lastchar == '*') + state = prev_state; /* end of comment */ + break; /* else ignore this comment char */ + + case import_state: + append_char (import_text, c); /* include this import char */ + if (c == ';') + { /* done with @import */ + append_char (import_text, '\n'); /* make the output nice */ + state = null_state; + prev_state = import_state; + } + break; + + case inline_state: + /* No harm in writing out comments, so don't bother parsing + them out, just append everything. */ + append_char (inline_text, c); + break; + } + + lastchar = c; + } + + /* Reached the end of the file. We should not be still in a comment. */ + if (state == comment_state) + warning (_("%s:%d: --css-file ended in comment"), filename, lineno); + + /* Write the @import text, if any. */ + if (import_text->buffer) + { + add_word (import_text->buffer); + free (import_text->buffer); + free (import_text); + } + + /* We're wasting the buffer struct memory, but so what. */ + return inline_text->buffer; +} + +HSTACK *htmlstack = NULL; + +/* See html.h. */ +int html_output_head_p = 0; +int html_title_written = 0; + +void +html_output_head (void) +{ + static const char *html_title = NULL; + char *encoding; + + if (html_output_head_p) + return; + html_output_head_p = 1; + + encoding = current_document_encoding (); + + /* The <title> should not have markup, so use text_expansion. */ + if (!html_title) + html_title = escape_string (title ? + text_expansion (title) : (char *) _("Untitled")); + + /* Make sure this is the very first string of the output document. */ + output_paragraph_offset = 0; + + add_html_block_elt_args ("<html lang=\"%s\">\n<head>\n", + language_table[language_code].abbrev); + + /* When splitting, add current node's name to title if it's available and not + Top. */ + if (splitting && current_node && !STREQ (current_node, "Top")) + add_word_args ("<title>%s - %s</title>\n", + escape_string (xstrdup (current_node)), html_title); + else + add_word_args ("<title>%s</title>\n", html_title); + + add_word ("<meta http-equiv=\"Content-Type\" content=\"text/html"); + if (encoding && *encoding) + add_word_args ("; charset=%s", encoding); + + add_word ("\">\n"); + + if (!document_description) + document_description = html_title; + + add_word_args ("<meta name=\"description\" content=\"%s\">\n", + document_description); + add_word_args ("<meta name=\"generator\" content=\"makeinfo %s\">\n", + VERSION); + + /* Navigation bar links. */ + if (!splitting) + add_word ("<link title=\"Top\" rel=\"top\" href=\"#Top\">\n"); + else if (tag_table) + { + /* Always put a top link. */ + add_word ("<link title=\"Top\" rel=\"start\" href=\"index.html#Top\">\n"); + + /* We already have a top link, avoid duplication. */ + if (tag_table->up && !STREQ (tag_table->up, "Top")) + add_link (tag_table->up, "rel=\"up\""); + + if (tag_table->prev) + add_link (tag_table->prev, "rel=\"prev\""); + + if (tag_table->next) + add_link (tag_table->next, "rel=\"next\""); + + /* fixxme: Look for a way to put links to various indices in the + document. Also possible candidates to be added here are First and + Last links. */ + } + else + { + /* We are splitting, but we neither have a tag_table. So this must be + index.html. So put a link to Top. */ + add_word ("<link title=\"Top\" rel=\"start\" href=\"#Top\">\n"); + } + + add_word ("<link href=\"http://www.gnu.org/software/texinfo/\" \ +rel=\"generator-home\" title=\"Texinfo Homepage\">\n"); + + if (copying_text) + { /* It is not ideal that we include the html markup here within + <head>, so we use text_expansion. */ + insert_string ("<!--\n"); + insert_string (text_expansion (copying_text)); + insert_string ("-->\n"); + } + + /* Put the style definitions in a comment for the sake of browsers + that don't support <style>. */ + add_word ("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n"); + add_word ("<style type=\"text/css\"><!--\n"); + + { + char *css_inline = NULL; + + if (css_include) + /* This writes out any @import commands from the --css-file, + and returns any actual css code following the imports. */ + css_inline = process_css_file (css_include); + + /* This seems cleaner than adding <br>'s at the end of each line for + these "roman" displays. It's hardly the end of the world if the + browser doesn't do <style>s, in any case; they'll just come out in + typewriter. */ +#define CSS_FONT_INHERIT "font-family:inherit" + add_word_args (" pre.display { %s }\n", CSS_FONT_INHERIT); + add_word_args (" pre.format { %s }\n", CSS_FONT_INHERIT); + + /* Alternatively, we could do <font size=-1> in insertion.c, but this + way makes it easier to override. */ +#define CSS_FONT_SMALLER "font-size:smaller" + add_word_args (" pre.smalldisplay { %s; %s }\n", CSS_FONT_INHERIT, + CSS_FONT_SMALLER); + add_word_args (" pre.smallformat { %s; %s }\n", CSS_FONT_INHERIT, + CSS_FONT_SMALLER); + add_word_args (" pre.smallexample { %s }\n", CSS_FONT_SMALLER); + add_word_args (" pre.smalllisp { %s }\n", CSS_FONT_SMALLER); + + /* Since HTML doesn't have a sc element, we use span with a bit of + CSS spice instead. */ +#define CSS_FONT_SMALL_CAPS "font-variant:small-caps" + add_word_args (" span.sc { %s }\n", CSS_FONT_SMALL_CAPS); + + /* Roman (default) font class, closest we can come. */ +#define CSS_FONT_ROMAN "font-family:serif; font-weight:normal;" + add_word_args (" span.roman { %s } \n", CSS_FONT_ROMAN); + + /* Sans serif font class. */ +#define CSS_FONT_SANSSERIF "font-family:sans-serif; font-weight:normal;" + add_word_args (" span.sansserif { %s } \n", CSS_FONT_SANSSERIF); + + /* Write out any css code from the user's --css-file. */ + if (css_inline) + insert_string (css_inline); + + add_word ("--></style>\n"); + } + + add_word ("</head>\n<body>\n"); + + if (title && !html_title_written && titlepage_cmd_present) + { + add_word_args ("<h1 class=\"settitle\">%s</h1>\n", html_title); + html_title_written = 1; + } + + free (encoding); +} + +/* Escape HTML special characters in the string if necessary, + returning a pointer to a possibly newly-allocated one. */ +char * +escape_string (char *string) +{ + char *newstring; + int i = 0, newlen = 0; + + do + { + /* Find how much to allocate. */ + switch (string[i]) + { + case '"': + newlen += 6; /* `"' */ + break; + case '&': + newlen += 5; /* `&' */ + break; + case '<': + case '>': + newlen += 4; /* `<', `>' */ + break; + default: + newlen++; + } + } + while (string[i++]); + + if (newlen == i) return string; /* Already OK. */ + + newstring = xmalloc (newlen); + i = 0; + do + { + switch (string[i]) + { + case '"': + strcpy (newstring, """); + newstring += 6; + break; + case '&': + strcpy (newstring, "&"); + newstring += 5; + break; + case '<': + strcpy (newstring, "<"); + newstring += 4; + break; + case '>': + strcpy (newstring, ">"); + newstring += 4; + break; + default: + newstring[0] = string[i]; + newstring++; + } + } + while (string[i++]); + free (string); + return newstring - newlen; +} + +/* Save current tag. */ +static void +push_tag (char *tag, char *attribs) +{ + HSTACK *newstack = xmalloc (sizeof (HSTACK)); + + newstack->tag = tag; + newstack->attribs = xstrdup (attribs); + newstack->next = htmlstack; + htmlstack = newstack; +} + +/* Get last tag. */ +static void +pop_tag (void) +{ + HSTACK *tos = htmlstack; + + if (!tos) + { + line_error (_("[unexpected] no html tag to pop")); + return; + } + + free (htmlstack->attribs); + + htmlstack = htmlstack->next; + free (tos); +} + +/* Check if tag is an empty or a whitespace only element. + If so, remove it, keeping whitespace intact. */ +int +rollback_empty_tag (char *tag) +{ + int check_position = output_paragraph_offset; + int taglen = strlen (tag); + int rollback_happened = 0; + char *contents = ""; + char *contents_canon_white = ""; + + /* If output_paragraph is empty, we cannot rollback :-\ */ + if (output_paragraph_offset <= 0) + return 0; + + /* Find the end of the previous tag. */ + while (output_paragraph[check_position-1] != '>' && check_position > 0) + check_position--; + + /* Save stuff between tag's end to output_paragraph's end. */ + if (check_position != output_paragraph_offset) + { + contents = xmalloc (output_paragraph_offset - check_position + 1); + memcpy (contents, output_paragraph + check_position, + output_paragraph_offset - check_position); + + contents[output_paragraph_offset - check_position] = '\0'; + + contents_canon_white = xstrdup (contents); + canon_white (contents_canon_white); + } + + /* Find the start of the previous tag. */ + while (output_paragraph[check_position-1] != '<' && check_position > 0) + check_position--; + + /* Check to see if this is the tag. */ + if (strncmp ((char *) output_paragraph + check_position, tag, taglen) == 0 + && (whitespace (output_paragraph[check_position + taglen]) + || output_paragraph[check_position + taglen] == '>')) + { + if (!contents_canon_white || !*contents_canon_white) + { + /* Empty content after whitespace removal, so roll it back. */ + output_paragraph_offset = check_position - 1; + rollback_happened = 1; + + /* Original contents may not be empty (whitespace.) */ + if (contents && *contents) + { + insert_string (contents); + free (contents); + } + } + } + + return rollback_happened; +} + +/* Open or close TAG according to START_OR_END. */ +void +#if defined (VA_FPRINTF) && __STDC__ +insert_html_tag_with_attribute (int start_or_end, char *tag, char *format, ...) +#else +insert_html_tag_with_attribute (start_or_end, tag, format, va_alist) + int start_or_end; + char *tag; + char *format; + va_dcl +#endif +{ + char *old_tag = NULL; + char *old_attribs = NULL; + char formatted_attribs[2000]; /* xx no fixed limits */ + int do_return = 0; + extern int in_html_elt; + + if (start_or_end != START) + pop_tag (); + + if (htmlstack) + { + old_tag = htmlstack->tag; + old_attribs = htmlstack->attribs; + } + + if (format) + { +#ifdef VA_SPRINTF + va_list ap; +#endif + + VA_START (ap, format); +#ifdef VA_SPRINTF + VA_SPRINTF (formatted_attribs, format, ap); +#else + sprintf (formatted_attribs, format, a1, a2, a3, a4, a5, a6, a7, a8); +#endif + va_end (ap); + } + else + formatted_attribs[0] = '\0'; + + /* Exception: can nest multiple spans. */ + if (htmlstack + && STREQ (htmlstack->tag, tag) + && !(STREQ (tag, "span") && STREQ (old_attribs, formatted_attribs))) + do_return = 1; + + if (start_or_end == START) + push_tag (tag, formatted_attribs); + + if (do_return) + return; + + in_html_elt++; + + /* texinfo.tex doesn't support more than one font attribute + at the same time. */ + if ((start_or_end == START) && old_tag && *old_tag + && !rollback_empty_tag (old_tag)) + add_word_args ("</%s>", old_tag); + + if (*tag) + { + if (start_or_end == START) + add_word_args (format ? "<%s %s>" : "<%s>", tag, formatted_attribs); + else if (!rollback_empty_tag (tag)) + /* Insert close tag only if we didn't rollback, + in which case the opening tag is removed. */ + add_word_args ("</%s>", tag); + } + + if ((start_or_end != START) && old_tag && *old_tag) + add_word_args (strlen (old_attribs) > 0 ? "<%s %s>" : "<%s>", + old_tag, old_attribs); + + in_html_elt--; +} + +void +insert_html_tag (int start_or_end, char *tag) +{ + insert_html_tag_with_attribute (start_or_end, tag, NULL); +} + +/* Output an HTML <link> to the filename for NODE, including the + other string as extra attributes. */ +void +add_link (char *nodename, char *attributes) +{ + if (nodename) + { + add_html_elt ("<link "); + add_word_args ("%s", attributes); + add_word_args (" href=\""); + add_anchor_name (nodename, 1); + add_word_args ("\" title=\"%s\">\n", nodename); + } +} + +/* Output NAME with characters escaped as appropriate for an anchor + name, i.e., escape URL special characters with our _00hh convention + if OLD is zero. (See the manual for details on the new scheme.) + + If OLD is nonzero, generate the node name with the 4.6-and-earlier + convention of %hh (and more special characters output as-is, notably + - and *). This is only so that external references to old names can + still work with HTML generated by the new makeinfo; the gcc folks + needed this. Our own HTML does not refer to these names. */ + +void +add_escaped_anchor_name (char *name, int old) +{ + canon_white (name); + + if (!old && !strchr ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + *name)) + { /* XHTML does not allow anything but an ASCII letter to start an + identifier. Therefore kludge in this constant string if we + have a nonletter. */ + add_word ("g_t"); + } + + for (; *name; name++) + { + if (cr_or_whitespace (*name)) + add_char ('-'); + + else if (!old && !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 ("_00%x", (unsigned char) *name); + + else if (old && !URL_SAFE_CHAR (*name) && !OLD_URL_SAFE_CHAR (*name)) + /* Different output convention, but still cast as above. */ + 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 zero, generate text for name= in the new node name + conversion convention. + If HREF is negative, generate text for name= in the old convention. + If HREF is positive, generate the name for an href= attribute, i.e., + including the `#' if it's an internal reference. */ +void +add_anchor_name (char *nodename, int href) +{ + if (href > 0) + { + if (splitting) + add_url_name (nodename, href); + add_char ('#'); + } + /* Always add NODENAME, so that the reference would pinpoint the + exact node on its file. This is so several nodes could share the + same file, in case of file-name clashes, but also for more + accurate browser positioning. */ + if (strcasecmp (nodename, "(dir)") == 0) + /* Strip the parens, but keep the original letter-case. */ + add_word_args ("%.3s", nodename + 1); + else if (strcasecmp (nodename, "top") == 0) + add_word ("Top"); + else + add_escaped_anchor_name (nodename, href < 0); +} + +/* Insert the text for the name of a reference in an HTML url, aprropriate + for NODENAME */ +void +add_url_name (char *nodename, int href) +{ + add_nodename_to_filename (nodename, href); +} + +/* Convert non [A-Za-z0-9] to _00xx, where xx means the hexadecimal + representation of the ASCII character. Also convert spaces and + newlines to dashes. */ +static void +fix_filename (char *filename) +{ + int i; + int len = strlen (filename); + char *oldname = xstrdup (filename); + + *filename = '\0'; + + for (i = 0; i < len; i++) + { + if (cr_or_whitespace (oldname[i])) + strcat (filename, "-"); + else if (URL_SAFE_CHAR (oldname[i])) + strncat (filename, (char *) oldname + i, 1); + else + { + char *hexchar = xmalloc (6 * sizeof (char)); + sprintf (hexchar, "_00%x", (unsigned char) oldname[i]); + strcat (filename, hexchar); + free (hexchar); + } + + /* Check if we are nearing boundaries. */ + if (strlen (filename) >= PATH_MAX - 20) + break; + } + + free (oldname); +} + +/* As we can't look-up a (forward-referenced) nodes' html filename + from the tentry, we take the easy way out. We assume that + nodenames are unique, and generate the html filename from the + nodename, that's always known. */ +static char * +nodename_to_filename_1 (char *nodename, int href) +{ + char *p; + char *filename; + char dirname[PATH_MAX]; + + if (strcasecmp (nodename, "Top") == 0) + { + /* We want to convert references to the Top node into + "index.html#Top". */ + if (href) + filename = xstrdup ("index.html"); /* "#Top" is added by our callers */ + else + filename = xstrdup ("Top"); + } + else if (strcasecmp (nodename, "(dir)") == 0) + /* We want to convert references to the (dir) node into + "../index.html". */ + filename = xstrdup ("../index.html"); + else + { + filename = xmalloc (PATH_MAX); + dirname[0] = '\0'; + *filename = '\0'; + + /* Check for external reference: ``(info-document)node-name'' + Assume this node lives at: ``../info-document/node-name.html'' + + We need to handle the special case (sigh): ``(info-document)'', + ie, an external top-node, which should translate to: + ``../info-document/info-document.html'' */ + + p = nodename; + if (*nodename == '(') + { + int length; + + p = strchr (nodename, ')'); + if (p == NULL) + { + line_error (_("[unexpected] invalid node name: `%s'"), nodename); + xexit (1); + } + + length = p - nodename - 1; + if (length > 5 && + FILENAME_CMPN (p - 5, ".info", 5) == 0) + length -= 5; + /* This is for DOS, and also for Windows and GNU/Linux + systems that might have Info files copied from a DOS 8+3 + filesystem. */ + if (length > 4 && + FILENAME_CMPN (p - 4, ".inf", 4) == 0) + length -= 4; + strcpy (filename, "../"); + strncpy (dirname, nodename + 1, length); + *(dirname + length) = '\0'; + fix_filename (dirname); + strcat (filename, dirname); + strcat (filename, "/"); + p++; + } + + /* In the case of just (info-document), there will be nothing + remaining, and we will refer to ../info-document/, which will + work fine. */ + strcat (filename, p); + if (*p) + { + /* Hmm */ + fix_filename (filename + strlen (filename) - strlen (p)); + strcat (filename, ".html"); + } + } + + /* Produce a file name suitable for the underlying filesystem. */ + normalize_filename (filename); + +#if 0 + /* We add ``#Nodified-filename'' anchor to external references to be + prepared for non-split HTML support. Maybe drop this. */ + if (href && *dirname) + { + strcat (filename, "#"); + strcat (filename, p); + /* Hmm, again */ + fix_filename (filename + strlen (filename) - strlen (p)); + } +#endif + + return filename; +} + +/* If necessary, ie, if current filename != filename of node, output + the node name. */ +void +add_nodename_to_filename (char *nodename, int href) +{ + /* for now, don't check: always output filename */ + char *filename = nodename_to_filename_1 (nodename, href); + add_word (filename); + free (filename); +} + +char * +nodename_to_filename (char *nodename) +{ + /* The callers of nodename_to_filename use the result to produce + <a href=, so call nodename_to_filename_1 with last arg non-zero. */ + return nodename_to_filename_1 (nodename, 1); +} diff --git a/Build/source/utils/texinfo/makeinfo/html.h b/Build/source/utils/texinfo/makeinfo/html.h new file mode 100644 index 00000000000..d2b5411282f --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/html.h @@ -0,0 +1,65 @@ +/* html.h -- declarations for html-related utilities. + $Id: html.h,v 1.6 2004/11/30 02:03:23 karl Exp $ + + Copyright (C) 1999, 2000, 2002, 2004 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 + +/* A stack of font tags. */ +typedef struct hstack +{ + struct hstack *next; + char *tag; + char *attribs; +} HSTACK; + +/* Nonzero if we have output the <head>. */ +extern int html_output_head_p; + +/* Nonzero if we have output a title, from @titlefont or @settitle. */ +extern int html_title_written; + +/* Perform the <head> output. */ +extern void html_output_head (void); + +/* 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 *nodename, char *attributes); + +/* Escape URL-special characters. */ +extern void add_escaped_anchor_name (char *name, int old); + +/* See html.c. */ +extern void add_anchor_name (char *nodename, int href); +extern void add_url_name (char *nodename, int href); +extern void add_nodename_to_filename (char *nodename, int href); +extern char *nodename_to_filename (char *nodename); +extern int rollback_empty_tag (char *tag); + +#if defined (VA_FPRINTF) && __STDC__ +extern void insert_html_tag_with_attribute (int start_or_end, char *tag, char *format, ...); +#else +extern void insert_html_tag_with_attribute (); +#endif + +#endif /* !HTML_H */ diff --git a/Build/source/utils/texinfo/makeinfo/index.c b/Build/source/utils/texinfo/makeinfo/index.c new file mode 100644 index 00000000000..710e8b6855b --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/index.c @@ -0,0 +1,964 @@ +/* index.c -- indexing for Texinfo. + $Id: index.c,v 1.17 2004/11/30 02:03:23 karl Exp $ + + Copyright (C) 1998, 1999, 2002, 2003, 2004 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 "footnote.h" +#include "html.h" +#include "index.h" +#include "lang.h" +#include "macro.h" +#include "sectioning.h" +#include "toc.h" +#include "xml.h" + +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; + +/* This is the order of the index. */ +int index_counter = 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) (const char *a, const char *b) = strcasecmp; + +/* Function to compare index entries for sorting. (Calls + `index_compare_fn' above.) */ +int index_element_compare (const void *element1, const void *element2); + +/* Find which element in the known list of indices has this name. + Returns -1 if NAME isn't found. */ +static int +find_index_offset (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. */ +static INDEX_ALIST * +find_index (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. */ +static void +define_user_command (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_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 (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. */ +static void +index_add_arg (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)); + + index_counter++; + + /* Get output line number updated before doing anything. */ + if (!html && !xml) + flush_output (); + + new->next = the_indices[which]; + new->entry = NULL; + new->entry_text = index_entry; + /* Since footnotes are handled at the very end of the document, + node name in the non-split HTML outputs always show the last + node. We artificially make it ``Footnotes''. */ + if (html && !splitting && already_outputting_pending_notes) + new->node = xstrdup (_("Footnotes")); + else + new->node = current_node ? current_node : xstrdup (""); + if (!html && !xml && no_headers) + { + new->section = current_sectioning_number (); + if (strlen (new->section) == 0) + new->section_name = current_sectioning_name (); + else + new->section_name = ""; + } + else + { + new->section = NULL; + new->section_name = NULL; + } + new->code = tem->code; + new->defining_line = line_number - 1; + new->output_line = no_headers ? output_line_number : node_line_number; + /* 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); + + if (html && splitting) + { + if (current_output_filename && *current_output_filename) + new->output_file = filename_part (current_output_filename); + else + new->output_file = xstrdup (""); + } + else + new->output_file = NULL; + + new->entry_number = index_counter; + the_indices[which] = new; + +#if 0 + /* The index breaks if there are colons in the entry. + -- This is true, but it's too painful to force changing index + entries to use `colon', and too confusing for users. The real + fix is to change Info support to support arbitrary characters + in node names, and we're not ready to do that. --karl, + 19mar02. */ + if (strchr (new->entry_text, ':')) + warning (_("Info cannot handle `:' in index entry `%s'"), + new->entry_text); +#endif + + if (html) + { + /* Anchor. */ + int removed_empty_elt = 0; + + /* We must put the anchor outside the <dl> and <ul> blocks. */ + if (rollback_empty_tag ("dl")) + removed_empty_elt = 1; + else if (rollback_empty_tag ("ul")) + removed_empty_elt = 2; + + add_word ("<a name=\"index-"); + add_escaped_anchor_name (index_entry, 0); + add_word_args ("-%d\"></a>", index_counter); + + if (removed_empty_elt == 1) + add_html_block_elt_args ("\n<dl>"); + else if (removed_empty_elt == 2) + add_html_block_elt_args ("\n<ul>"); + } + } + + if (xml) + xml_insert_indexterm (index_entry, name); +} + +/* The function which user defined index commands call. */ +static void +gen_index (void) +{ + 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 (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 (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 (void) +{ + 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++) + { + 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. */ + undefindex (name_index_alist[i]->name); + + /* undefindex sets all this to null in some cases. */ + if (name_index_alist[i]) + { + 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. */ +static int +translate_index (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 (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 (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 (void) +{ + gen_defindex (0); +} + +void +cm_defcodeindex (void) +{ + 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 (void) +{ + 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 + { + if (xml && !docbook) + xml_synindex (abbrev1, abbrev2); + else + name_index_alist[target]->write_index + = name_index_alist[source]->write_index; + } + + free (abbrev1); + free (abbrev2); +} + +void +cm_pindex (void) /* Pinhead index. */ +{ + index_add_arg ("pg"); +} + +void +cm_vindex (void) /* Variable index. */ +{ + index_add_arg ("vr"); +} + +void +cm_kindex (void) /* Key index. */ +{ + index_add_arg ("ky"); +} + +void +cm_cindex (void) /* Concept index. */ +{ + index_add_arg ("cp"); +} + +void +cm_findex (void) /* Function index. */ +{ + index_add_arg ("fn"); +} + +void +cm_tindex (void) /* Data Type index. */ +{ + index_add_arg ("tp"); +} + +int +index_element_compare (const void *element1, const void *element2) +{ + INDEX_ELT **elt1 = (INDEX_ELT **) element1; + INDEX_ELT **elt2 = (INDEX_ELT **) element2; + + return index_compare_fn ((*elt1)->entry, (*elt2)->entry); +} + +/* Force all index entries to be unique. */ +static void +make_index_entries_unique (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. */ + +static INDEX_ELT ** +sort_index (INDEX_ELT *index) +{ + INDEX_ELT **array; + INDEX_ELT *temp; + 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; + + for (temp = index, count = 0; temp; temp = temp->next, count++) + ; + /* We have the length, now we can allocate an array. */ + array = xmalloc ((count + 1) * sizeof (INDEX_ELT *)); + + for (temp = index, count = 0; temp; temp = temp->next, count++) + { + /* Allocate new memory for the return array, since parts of the + original INDEX get freed. Otherwise, if the document calls + @printindex twice on the same index, with duplicate entries, + we'll have garbage the second time. There are cleaner ways to + deal, but this will suffice for now. */ + array[count] = xmalloc (sizeof (INDEX_ELT)); + *(array[count]) = *(temp); /* struct assignment, hope it's ok */ + + /* Adjust next pointers to use the new memory. */ + if (count > 0) + array[count-1]->next = array[count]; + + /* Set line number and input filename to the source line for this + index entry, as this expansion finds any errors. */ + line_number = array[count]->defining_line; + input_filename = array[count]->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]->entry = expansion (temp->entry_text, array[count]->code); + } + 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); + + /* Remove duplicate entries. */ + make_index_entries_unique (array, count); + + /* Replace the original index with the sorted one, in case the + document wants to print it again. If the index wasn't empty. */ + if (index) + *index = **array; + + return array; +} + +static void +insert_index_output_line_no (int line_number, int output_line_number_len) +{ + int last_column; + int str_size = output_line_number_len + strlen (_("(line )")) + + sizeof (NULL); + char *out_line_no_str = (char *) xmalloc (str_size + 1); + + /* Do not translate ``(line NNN)'' below for !no_headers case (Info output), + because it's something like the ``* Menu'' strings. For plaintext output + it should be translated though. */ + sprintf (out_line_no_str, + no_headers ? _("(line %*d)") : "(line %*d)", + output_line_number_len, line_number); + + { + int i = output_paragraph_offset; + while (0 < i && output_paragraph[i-1] != '\n') + i--; + last_column = output_paragraph_offset - i; + } + + if (last_column + strlen (out_line_no_str) > fill_column) + { + insert ('\n'); + last_column = 0; + } + + while (last_column + strlen (out_line_no_str) < fill_column) + { + insert (' '); + last_column++; + } + + insert_string (out_line_no_str); + insert ('\n'); + + free (out_line_no_str); +} + +/* 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 (void) +{ + char *index_name; + get_rest_of_line (0, &index_name); + + /* get_rest_of_line increments the line number by one, + so to make warnings/errors point to the correct line, + we decrement the line_number again. */ + if (!handling_delayed_writes) + line_number--; + + if (xml && !docbook) + { + xml_insert_element (PRINTINDEX, START); + insert_string (index_name); + xml_insert_element (PRINTINDEX, END); + } + else if (!handling_delayed_writes) + { + int command_len = sizeof ("@ ") + strlen (command) + strlen (index_name); + char *index_command = xmalloc (command_len + 1); + + close_paragraph (); + if (docbook) + xml_begin_index (); + + sprintf (index_command, "@%s %s", command, index_name); + register_delayed_write (index_command); + free (index_command); + } + else + { + int item; + INDEX_ELT *index; + INDEX_ELT *last_index = 0; + INDEX_ELT **array; + 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; + unsigned output_line_number_len; + + 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 is in the good environment */ + if (xml && docbook) + xml_begin_index (); + + /* 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; + xml_sort_index = 1; + array = sort_index (index); + xml_sort_index = 0; + close_paragraph (); + if (html) + add_html_block_elt_args ("<ul class=\"index-%s\" compact>", + index_name); + else if (!no_headers && !docbook) + { /* Info. Add magic cookie for info readers (to treat this + menu differently), and the usual start-of-menu. */ + add_char ('\0'); + add_word ("\010[index"); + add_char ('\0'); + add_word ("\010]\n"); + add_word ("* Menu:\n\n"); + } + + me_inhibit_expansion++; + + /* This will probably be enough. */ + line_length = 100; + line = xmalloc (line_length); + + { + char *max_output_line_number = (char *) xmalloc (25 * sizeof (char)); + + if (no_headers) + sprintf (max_output_line_number, "%d", output_line_number); + else + { + INDEX_ELT *tmp_entry = index; + unsigned tmp = 0; + for (tmp_entry = index; tmp_entry; tmp_entry = tmp_entry->next) + tmp = tmp_entry->output_line > tmp ? tmp_entry->output_line : tmp; + sprintf (max_output_line_number, "%d", tmp); + } + + output_line_number_len = strlen (max_output_line_number); + free (max_output_line_number); + } + + 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 = (char *) _("(outside of any node)"); + } + + if (html) + { + /* For HTML, we need to expand and HTML-escape the + original entry text, at the same time. Consider + @cindex J@"urgen. We want Jüurgen. We can't + expand and then escape since we'll end up with + J&uuml;rgen. We can't escape and then expand + because then `expansion' will see J@"urgen, and + @"urgen is not a command. */ + char *html_entry = + maybe_escaped_expansion (index->entry_text, index->code, 1); + + add_html_block_elt_args ("\n<li><a href=\"%s#index-", + (splitting && index->output_file) ? index->output_file : ""); + add_escaped_anchor_name (index->entry_text, 0); + add_word_args ("-%d\">%s</a>: ", index->entry_number, + html_entry); + free (html_entry); + + add_word ("<a href=\""); + if (index->node && *index->node) + { + /* Ensure any non-macros in the node name are expanded. */ + char *expanded_index; + + in_fixed_width_font++; + expanded_index = expansion (index_node, 0); + in_fixed_width_font--; + add_anchor_name (expanded_index, 1); + expanded_index = escape_string (expanded_index); + add_word_args ("\">%s</a>", expanded_index); + free (expanded_index); + } + 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); + + add_html_block_elt ("</li>"); + } + else if (xml && docbook) + { + /* In the DocBook case, the expanded index entry is not + good for us, since it was expanded for non-DocBook mode + inside sort_index. So we send the original entry text + to be used with execute_string. */ + xml_insert_indexentry (index->entry_text, 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. ", index_node); + insert_index_output_line_no (index->output_line, + output_line_number_len); + 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. */ + sprintf (line, "%-*s ", number_sections ? 46 : 1, index->entry); + line[strlen (index->entry)] = ':'; + insert_string (line); + + if (strlen (index->section) > 0) + { /* We got your number. */ + insert_string ((char *) _("See ")); + insert_string (index->section); + } + else + { /* Sigh, index in an @unnumbered. :-\ */ + insert_string ("\n "); + insert_string ((char *) _("See ")); + insert_string ("``"); + insert_string (expansion (index->section_name, 0)); + insert_string ("''"); + } + + insert_string (". "); + insert_index_output_line_no (index->output_line, + output_line_number_len); + } + } + + /* Prevent `output_paragraph' from growing to the size of the + whole index. */ + flush_output (); + last_index = index; + } + + free (line); + + me_inhibit_expansion--; + printing_index = 0; + + 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_html_block_elt ("</ul>"); + else if (xml && docbook) + xml_end_index (); + } + + free (index_name); + /* Re-increment the line number, because get_rest_of_line + left us looking at the next line after the command. */ + line_number++; +} diff --git a/Build/source/utils/texinfo/makeinfo/index.h b/Build/source/utils/texinfo/makeinfo/index.h new file mode 100644 index 00000000000..3ff723daa18 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/index.h @@ -0,0 +1,93 @@ +/* index.h -- declarations for index.c. + $Id: index.h,v 1.2 2004/04/11 17:56:47 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; + +/* 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. */ + char *section; /* Current section number we are in, */ + char *section_name; /* ... and its title. */ + int code; /* Nonzero means add `@code{...}' when + printing this element. */ + int defining_line; /* Line number where this entry was written. */ + int output_line; /* And line number where it is in the output. */ + char *defining_file; /* Source file for defining_line. */ + char *output_file; /* Output file for output_line. */ + int entry_number; /* Entry number. */ +} 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; + +extern INDEX_ALIST **name_index_alist; + +/* Initialize all indices. */ +extern void init_indices (void); + +extern int defined_indices; +extern int printing_index; +extern int index_counter; + +INDEX_ELT *index_list (char *name); + +#endif /* !INDEX_H */ diff --git a/Build/source/utils/texinfo/makeinfo/insertion.c b/Build/source/utils/texinfo/makeinfo/insertion.c new file mode 100644 index 00000000000..05a20440eba --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/insertion.c @@ -0,0 +1,2376 @@ +/* insertion.c -- insertions for Texinfo. + $Id: insertion.c,v 1.55 2004/11/11 18:34:28 karl Exp $ + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 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 "float.h" +#include "html.h" +#include "insertion.h" +#include "macro.h" +#include "makeinfo.h" +#include "multi.h" +#include "xml.h" + +/* Must match list in insertion.h. */ +static char *insertion_type_names[] = +{ + "cartouche", "copying", "defcv", "deffn", "defivar", "defmac", + "defmethod", "defop", "defopt", "defspec", "deftp", "deftypecv", + "deftypefn", "deftypefun", "deftypeivar", "deftypemethod", + "deftypeop", "deftypevar", "deftypevr", "defun", "defvar", "defvr", + "detailmenu", "direntry", "display", "documentdescription", + "enumerate", "example", "float", "flushleft", "flushright", "format", + "ftable", "group", "ifclear", "ifdocbook", "ifhtml", "ifinfo", + "ifnotdocbook", "ifnothtml", "ifnotinfo", "ifnotplaintext", "ifnottex", + "ifnotxml", "ifplaintext", "ifset", "iftex", "ifxml", "itemize", "lisp", + "menu", "multitable", "quotation", "rawdocbook", "rawhtml", "rawtex", + "rawxml", "smalldisplay", "smallexample", "smallformat", "smalllisp", + "verbatim", "table", "tex", "vtable", "titlepage", "bad_type" +}; + +/* All nested environments. */ +INSERTION_ELT *insertion_stack = NULL; + +/* How deeply we're nested. */ +int insertion_level = 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; + +/* How to examine menu lines. */ +int in_detailmenu = 0; + +/* Whether to examine menu lines. */ +int in_menu = 0; + +/* Set to 1 if <p> is written in normal context. + Used for menu and itemize. */ +int in_paragraph = 0; + +/* Since an insertion is already in the stack before we reach the switch + statement, we cannot use is_in_insertion_of_type (always returns true.) Also + making it return the level found, and comparing it with the current level is + no use, due to the order of stack. */ +static int float_active = 0; + +/* Unsetting escape_html blindly causes text inside @html/etc. to be escaped if + used within a rmacro. */ +static int raw_output_block = 0; + +/* Non-zero if a <dl> element has a <dt> element in it. We use this when + deciding whether to insert a <br> or not. */ +static int html_deflist_has_term = 0; + +void +init_insertion_stack (void) +{ + insertion_stack = NULL; +} + +/* Return the type of the current insertion. */ +static enum insertion_type +current_insertion_type (void) +{ + 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 (void) +{ + 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 ifnotplaintext: + case ifnottex: + case ifnotxml: + case ifplaintext: + case ifset: + case iftex: + case ifxml: + case rawdocbook: + case rawhtml: + case rawxml: + 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. */ +static char * +get_item_function (void) +{ + char *item_function; + char *item_loc; + + get_rest_of_line (0, &item_function); + + /* If the document erroneously says + @itemize @bullet @item foobar + it's nicer to give an error up front than repeat `@bullet expected + braces' until we get a segmentation fault. */ + item_loc = strstr (item_function, "@item"); + if (item_loc) + { + line_error (_("@item not allowed in argument to @itemize")); + *item_loc = 0; + } + + /* 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. */ +static void +push_insertion (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 (void) +{ + 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. */ +static const char * +insertion_type_pname (enum insertion_type type) +{ + if ((int) type < (int) bad_type) + { + if (type == rawdocbook) + return "docbook"; + else if (type == rawhtml) + return "html"; + else if (type == rawxml) + return "xml"; + else if (type == rawtex) + return "tex"; + else + 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 (char *name) +{ + int index = 0; + while (index < (int) bad_type) + { + if (STREQ (name, insertion_type_names[index])) + return (enum insertion_type) index; + if (index == rawdocbook && STREQ (name, "docbook")) + return rawdocbook; + if (index == rawhtml && STREQ (name, "html")) + return rawhtml; + if (index == rawxml && STREQ (name, "xml")) + return rawxml; + if (index == rawtex && STREQ (name, "tex")) + return rawtex; + index++; + } + return bad_type; +} + +/* Simple function to query insertion_stack to see if we are inside a given + insertion type. */ +int +is_in_insertion_of_type (int type) +{ + INSERTION_ELT *temp = insertion_stack; + + if (!insertion_level) + return 0; + + while (temp) + { + if (temp->insertion == type) + return 1; + temp = temp->next; + } + + return 0; +} + + +static int +defun_insertion (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 == deftypecv) + || (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; + +static void +start_enumerating (int at, int 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; +} + +static void +stop_enumerating (void) +{ + --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. */ +static void +enumerate_item (void) +{ + 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 (void) +{ + 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_html_block_elt_args ("<ol type=%c start=%d>\n", type, start); +} + +/* Conditionally parse based on the current command name. */ +void +command_name_condition (void) +{ + 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 (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 && !xml) + add_word ("* Menu:\n"); + + if (xml) + xml_insert_element (MENU, START); + else + in_fixed_width_font++; + + next_menu_item_number = 1; + 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++; + } + + if (xml) + { + xml_insert_element (DETAILMENU, START); + skip_whitespace_and_newlines(); + } + else + in_fixed_width_font++; + + 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; + + case documentdescription: + { + char *desc; + int start_of_end; + int save_fixed_width; + + discard_until ("\n"); /* ignore the @documentdescription line */ + start_of_end = get_until ("\n@end documentdescription", &desc); + save_fixed_width = in_fixed_width_font; + + in_fixed_width_font = 0; + document_description = expansion (desc, 0); + free (desc); + + in_fixed_width_font = save_fixed_width; + input_text_offset = start_of_end; /* go back to the @end to match */ + } + break; + + case copying: + /* Save the copying text away for @insertcopying, + typically used on the back of the @titlepage (for TeX) and + the Top node (for info/html). */ + if (input_text[input_text_offset] != '\n') + discard_until ("\n"); /* ignore remainder of @copying line */ + + input_text_offset = get_until ("\n@end copying", ©ing_text); + canon_white (copying_text); + + /* For info, output the copying text right away, so it will end up + in the header of the Info file, before the first node, and thus + get copied automatically to all the split files. For xml, also + output it right away since xml output is never split. + For html, we output it specifically in html_output_head. + For plain text, there's no way to hide it, so the author must + use @insertcopying in the desired location. */ + if (docbook) + { + if (!xml_in_bookinfo) + { + xml_insert_element (BOOKINFO, START); + xml_in_bookinfo = 1; + } + xml_insert_element (LEGALNOTICE, START); + } + + if (!html && !no_headers) + cm_insert_copying (); + + if (docbook) + xml_insert_element (LEGALNOTICE, END); + + break; + + case quotation: + /* @quotation does filling (@display doesn't). */ + if (html) + add_html_block_elt ("<blockquote>\n"); + else + { + /* with close_single_paragraph, we get no blank line above + within @copying. */ + close_paragraph (); + last_char_was_newline = no_indent = 0; + indented_fill = filling_enabled = 1; + inhibit_paragraph_indentation = 1; + } + current_indent += default_indentation_increment; + if (xml) + xml_insert_quotation (insertion_stack->item_function, START); + else if (strlen(insertion_stack->item_function)) + execute_string ("@b{%s:} ", insertion_stack->item_function); + break; + + case example: + case smallexample: + case lisp: + case smalllisp: + in_fixed_width_font++; + /* fall through */ + + /* Like @example but no fixed width font. */ + case display: + case smalldisplay: + /* Like @display but without indentation. */ + case smallformat: + case format: + close_single_paragraph (); + inhibit_paragraph_indentation = 1; + filling_enabled = 0; + last_char_was_newline = 0; + + if (html) + /* Kludge alert: if <pre> is followed by a newline, IE3, + mozilla, maybe others render an extra blank line before the + pre-formatted block. So don't output a newline. */ + add_html_block_elt_args ("<pre class=\"%s\">", command); + + if (type != format && type != smallformat) + { + current_indent += example_indentation_increment; + if (html) + { + /* Since we didn't put \n after <pre>, we need to insert + the indentation by hand. */ + int i; + for (i = current_indent; i > 0; i--) + add_char (' '); + } + } + 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_html_block_elt ("<ul>\n"); + in_paragraph = 0; + } + else + { /* We are just starting, so this <dl> + has no <dt> children yet. */ + html_deflist_has_term = 0; + add_html_block_elt ("<dl>\n"); + } + } + if (xml) + xml_begin_table (type, insertion_stack->item_function); + + while (input_text[input_text_offset] == '\n' + && input_text[input_text_offset+1] == '\n') + { + line_number++; + input_text_offset++; + } + + 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 (); + in_paragraph = 0; + } + + if (xml) + xml_begin_enumerate (enumeration_arg); + + if (isdigit (*enumeration_arg)) + start_enumerating (atoi (enumeration_arg), ENUM_DIGITS); + else + start_enumerating (*enumeration_arg, ENUM_ALPHA); + break; + + /* @group produces no output in info. */ + case group: + /* Only close the paragraph if we are not inside of an + @example-like environment. */ + if (xml) + xml_insert_element (GROUP, START); + else 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; + + case cartouche: + if (html) + add_html_block_elt ("<p><table class=\"cartouche\" summary=\"cartouche\" border=\"1\"><tr><td>\n"); + if (in_menu) + no_discard++; + break; + + case floatenv: + /* Cannot nest floats, so complain. */ + if (float_active) + { + line_error (_("%cfloat environments cannot be nested"), COMMAND_PREFIX); + pop_insertion (); + break; + } + + float_active++; + + { /* Collect data about this float. */ + /* Example: @float [FLOATTYPE][,XREFLABEL][,POSITION] */ + char floattype[200] = ""; + char xreflabel[200] = ""; + char position[200] = ""; + char *text; + char *caption; + char *shortcaption; + int start_of_end; + int save_line_number = line_number; + int save_input_text_offset = input_text_offset; + int i; + + if (strlen (insertion_stack->item_function) > 0) + { + int i = 0, t = 0, c = 0; + while (insertion_stack->item_function[i]) + { + if (insertion_stack->item_function[i] == ',') + { + switch (t) + { + case 0: + floattype[c] = '\0'; + break; + case 1: + xreflabel[c] = '\0'; + break; + case 2: + position[c] = '\0'; + break; + } + c = 0; + t++; + i++; + continue; + } + + switch (t) + { + case 0: + floattype[c] = insertion_stack->item_function[i]; + break; + case 1: + xreflabel[c] = insertion_stack->item_function[i]; + break; + case 2: + position[c] = insertion_stack->item_function[i]; + break; + } + c++; + i++; + } + } + + skip_whitespace_and_newlines (); + + start_of_end = get_until ("\n@end float", &text); + + /* Get also the @caption. */ + i = search_forward_until_pos ("\n@caption{", + save_input_text_offset, start_of_end); + if (i > -1) + { + input_text_offset = i + sizeof ("\n@caption{") - 1; + get_until_in_braces ("\n@end float", &caption); + input_text_offset = save_input_text_offset; + } + else + caption = ""; + + /* ... and the @shortcaption. */ + i = search_forward_until_pos ("\n@shortcaption{", + save_input_text_offset, start_of_end); + if (i > -1) + { + input_text_offset = i + sizeof ("\n@shortcaption{") - 1; + get_until_in_braces ("\n@end float", &shortcaption); + input_text_offset = save_input_text_offset; + } + else + shortcaption = ""; + + canon_white (xreflabel); + canon_white (floattype); + canon_white (position); + canon_white (caption); + canon_white (shortcaption); + + add_new_float (xstrdup (xreflabel), + xstrdup (caption), xstrdup (shortcaption), + xstrdup (floattype), xstrdup (position)); + + /* Move to the start of the @float so the contents get processed as + usual. */ + input_text_offset = save_input_text_offset; + line_number = save_line_number; + } + + if (html) + add_html_block_elt ("<div class=\"float\">\n"); + else if (docbook) + xml_insert_element (FLOAT, START); + else if (xml) + { + xml_insert_element_with_attribute (FLOAT, START, + "name=\"%s\"", current_float_id ()); + + xml_insert_element (FLOATTYPE, START); + execute_string ("%s", current_float_type ()); + xml_insert_element (FLOATTYPE, END); + + xml_insert_element (FLOATPOS, START); + execute_string ("%s", current_float_position ()); + xml_insert_element (FLOATPOS, END); + } + else + { /* Info */ + close_single_paragraph (); + inhibit_paragraph_indentation = 1; + } + + /* Anchor now. Note that XML documents get their + anchors with <float name="anchor"> tag. */ + if ((!xml || docbook) && strlen (current_float_id ()) > 0) + execute_string ("@anchor{%s}", current_float_id ()); + + break; + + /* Insertions that are no-ops in info, but do something in TeX. */ + case ifclear: + case ifdocbook: + case ifhtml: + case ifinfo: + case ifnotdocbook: + case ifnothtml: + case ifnotinfo: + case ifnotplaintext: + case ifnottex: + case ifnotxml: + case ifplaintext: + case ifset: + case iftex: + case ifxml: + case rawtex: + if (in_menu) + no_discard++; + break; + + case rawdocbook: + case rawhtml: + case rawxml: + raw_output_block++; + + if (raw_output_block > 0) + { + xml_no_para = 1; + escape_html = 0; + xml_keep_space++; + } + + { + /* Some deuglification for improved readability. */ + extern int xml_in_para; + if (xml && !xml_in_para && xml_indentation_increment > 0) + add_char ('\n'); + } + + break; + + case defcv: + case deffn: + case defivar: + case defmac: + case defmethod: + case defop: + case defopt: + case defspec: + case deftp: + case deftypecv: + 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; + if (xml) + xml_begin_definition (); + break; + + case flushleft: + close_single_paragraph (); + inhibit_paragraph_indentation = 1; + filling_enabled = indented_fill = no_indent = 0; + if (html) + add_html_block_elt ("<div align=\"left\">"); + break; + + case flushright: + close_single_paragraph (); + filling_enabled = indented_fill = no_indent = 0; + inhibit_paragraph_indentation = 1; + force_flush_right++; + if (html) + add_html_block_elt ("<div align=\"right\">"); + break; + + case titlepage: + xml_insert_element (TITLEPAGE, START); + 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. */ +static void +end_insertion (int type) +{ + int 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 (); + + if (xml) + { + switch (type) + { + case ifinfo: + case documentdescription: + break; + case quotation: + xml_insert_quotation ("", END); + break; + case example: + xml_insert_element (EXAMPLE, END); + if (docbook && current_insertion_type () == floatenv) + xml_insert_element (FLOATEXAMPLE, END); + break; + case smallexample: + xml_insert_element (SMALLEXAMPLE, END); + if (docbook && current_insertion_type () == floatenv) + xml_insert_element (FLOATEXAMPLE, END); + break; + case lisp: + xml_insert_element (LISP, END); + if (docbook && current_insertion_type () == floatenv) + xml_insert_element (FLOATEXAMPLE, END); + break; + case smalllisp: + xml_insert_element (SMALLLISP, END); + if (docbook && current_insertion_type () == floatenv) + xml_insert_element (FLOATEXAMPLE, END); + break; + case cartouche: + xml_insert_element (CARTOUCHE, END); + break; + case format: + if (docbook && xml_in_bookinfo && xml_in_abstract) + { + xml_insert_element (ABSTRACT, END); + xml_in_abstract = 0; + } + else + xml_insert_element (FORMAT, END); + break; + case smallformat: + xml_insert_element (SMALLFORMAT, END); + break; + case display: + xml_insert_element (DISPLAY, END); + break; + case smalldisplay: + xml_insert_element (SMALLDISPLAY, END); + break; + case table: + case ftable: + case vtable: + case itemize: + xml_end_table (type); + break; + case enumerate: + xml_end_enumerate (); + break; + case group: + xml_insert_element (GROUP, END); + break; + case titlepage: + xml_insert_element (TITLEPAGE, END); + break; + } + } + switch (type) + { + /* Insertions which have no effect on paragraph formatting. */ + case copying: + line_number--; + break; + + case ifclear: + case ifdocbook: + case ifinfo: + case ifhtml: + case ifnotdocbook: + case ifnothtml: + case ifnotinfo: + case ifnotplaintext: + case ifnottex: + case ifnotxml: + case ifplaintext: + case ifset: + case iftex: + case ifxml: + case rawtex: + case titlepage: + break; + + case rawdocbook: + case rawhtml: + case rawxml: + raw_output_block--; + + if (raw_output_block <= 0) + { + xml_no_para = 0; + escape_html = 1; + xml_keep_space--; + } + + if ((xml || html) && output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + break; + + case detailmenu: + if (xml) + xml_insert_element (DETAILMENU, END); + + in_detailmenu--; /* No longer hacking menus. */ + if (!in_menu) + { + if (!no_headers) + close_insertion_paragraph (); + } + break; + + case direntry: /* Eaten if html. */ + insert_string ("END-INFO-DIR-ENTRY\n\n"); + close_insertion_paragraph (); + break; + + case documentdescription: + if (xml) + insert_string (document_description); + xml_insert_element (DOCUMENTDESCRIPTION, END); + break; + + case menu: + in_menu--; /* No longer hacking menus. */ + if (html && !no_headers) + add_html_block_elt ("</ul>\n"); + else if (!no_headers && !xml) + close_insertion_paragraph (); + break; + + case multitable: + end_multitable (); + break; + + case enumerate: + stop_enumerating (); + close_insertion_paragraph (); + current_indent -= default_indentation_increment; + if (html) + add_html_block_elt ("</ol>\n"); + break; + + case flushleft: + if (html) + add_html_block_elt ("</div>\n"); + close_insertion_paragraph (); + break; + + case cartouche: + if (html) + add_html_block_elt ("</td></tr></table>\n"); + close_insertion_paragraph (); + break; + + case group: + if (!xml || docbook) + close_insertion_paragraph (); + break; + + case floatenv: + if (xml) + xml_insert_element (FLOAT, END); + else + { + if (html) + add_html_block_elt ("<p><strong class=\"float-caption\">"); + else + close_paragraph (); + + no_indent = 1; + + /* Legend: + 1) @float Foo,lbl & no caption: Foo 1.1 + 2) @float Foo & no caption: Foo + 3) @float ,lbl & no caption: 1.1 + 4) @float & no caption: */ + + if (!xml && !html) + indent (current_indent); + + if (strlen (current_float_type ())) + execute_string ("%s", current_float_type ()); + + if (strlen (current_float_id ()) > 0) + { + if (strlen (current_float_type ()) > 0) + add_char (' '); + + add_word (current_float_number ()); + } + + if (strlen (current_float_title ()) > 0) + { + if (strlen (current_float_type ()) > 0 + || strlen (current_float_id ()) > 0) + insert_string (": "); + + execute_string ("%s", current_float_title ()); + } + + /* Indent the following paragraph. */ + inhibit_paragraph_indentation = 0; + + if (html) + add_word ("</strong></p></div>\n"); + else + close_paragraph (); + } + float_active--; + 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 && type != quotation) + current_indent -= example_indentation_increment; + else if (type == quotation) + current_indent -= default_indentation_increment; + + if (html) + { /* The complex code in close_paragraph that kills whitespace + does not function here, since we've inserted non-whitespace + (the </whatever>) before it. The indentation already got + inserted at the end of the last example line, so we have to + delete it, or browsers wind up showing an extra blank line. */ + kill_self_indent (default_indentation_increment); + add_html_block_elt (type == quotation + ? "</blockquote>\n" : "</pre>\n"); + } + + /* The ending of one of these insertions always marks the + start of a new paragraph, except for the XML output. */ + if (!xml || docbook) + close_insertion_paragraph (); + + /* </pre> closes paragraph without messing with </p>. */ + if (html && type != quotation) + paragraph_is_open = 0; + break; + + case table: + case ftable: + case vtable: + current_indent -= default_indentation_increment; + if (html) + add_html_block_elt ("</dl>\n"); + close_insertion_paragraph (); + break; + + case itemize: + current_indent -= default_indentation_increment; + if (html) + add_html_block_elt ("</ul>\n"); + close_insertion_paragraph (); + break; + + case flushright: + force_flush_right--; + if (html) + add_html_block_elt ("</div>\n"); + close_insertion_paragraph (); + break; + + /* Handle the @defun insertions with this default clause. */ + default: + { + int 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 deftypecv: + case deftypefn: + case deftypevr: + case defcv: + case defop: + case deftypemethod: + case deftypeop: + case deftypeivar: + if (html) + { + if (paragraph_is_open) + add_html_block_elt ("</p>"); + /* close the div and blockquote which has been opened in defun.c */ + if (!rollback_empty_tag ("blockquote")) + add_html_block_elt ("</blockquote>"); + add_html_block_elt ("</div>\n"); + } + if (xml) + xml_end_definition (); + 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 (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 == rawdocbook + || insertion_stack->insertion == rawhtml + || insertion_stack->insertion == rawxml + || insertion_stack->insertion == rawtex)) + break; + else + { + const char *offender = insertion_type_pname (insertion_stack->insertion); + + file_line_error (insertion_stack->filename, + insertion_stack->line_number, + _("No matching `%cend %s'"), COMMAND_PREFIX, + offender); + pop_insertion (); + } + } + line_number = real_line_number; +} + +/* Insertion (environment) commands. */ + +void +cm_quotation (void) +{ + /* We start the blockquote element in the insertion. */ + begin_insertion (quotation); +} + +void +cm_example (void) +{ + if (docbook && current_insertion_type () == floatenv) + xml_begin_docbook_float (FLOATEXAMPLE); + + if (xml) + { + /* Rollback previous newlines. These occur between + </para> and <example>. */ + if (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + + xml_insert_element (EXAMPLE, START); + + /* Make sure example text is starting on a new line + for improved readability. */ + if (docbook) + add_char ('\n'); + } + + begin_insertion (example); +} + +void +cm_smallexample (void) +{ + if (docbook && current_insertion_type () == floatenv) + xml_begin_docbook_float (FLOATEXAMPLE); + + if (xml) + { + /* See cm_example comments about newlines. */ + if (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + xml_insert_element (SMALLEXAMPLE, START); + if (docbook) + add_char ('\n'); + } + + begin_insertion (smallexample); +} + +void +cm_lisp (void) +{ + if (docbook && current_insertion_type () == floatenv) + xml_begin_docbook_float (FLOATEXAMPLE); + + if (xml) + { + /* See cm_example comments about newlines. */ + if (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + xml_insert_element (LISP, START); + if (docbook) + add_char ('\n'); + } + + begin_insertion (lisp); +} + +void +cm_smalllisp (void) +{ + if (docbook && current_insertion_type () == floatenv) + xml_begin_docbook_float (FLOATEXAMPLE); + + if (xml) + { + /* See cm_example comments about newlines. */ + if (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + xml_insert_element (SMALLLISP, START); + if (docbook) + add_char ('\n'); + } + + begin_insertion (smalllisp); +} + +void +cm_cartouche (void) +{ + if (docbook && current_insertion_type () == floatenv) + xml_begin_docbook_float (CARTOUCHE); + + if (xml) + xml_insert_element (CARTOUCHE, START); + begin_insertion (cartouche); +} + +void +cm_copying (void) +{ + begin_insertion (copying); +} + +/* Not an insertion, despite the name, but it goes with cm_copying. */ +void +cm_insert_copying (void) +{ + if (!copying_text) + { + warning ("@copying not used before %s", command); + return; + } + + execute_string ("%s", copying_text); + + if (!xml && !html) + { + add_word ("\n\n"); + /* Update output_position so that the node positions in the tag + tables will take account of the copying text. */ + flush_output (); + } +} + +void +cm_format (void) +{ + if (xml) + { + if (docbook && xml_in_bookinfo) + { + xml_insert_element (ABSTRACT, START); + xml_in_abstract = 1; + } + else + { + /* See cm_example comments about newlines. */ + if (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + xml_insert_element (FORMAT, START); + if (docbook) + add_char ('\n'); + } + } + begin_insertion (format); +} + +void +cm_smallformat (void) +{ + if (xml) + { + /* See cm_example comments about newlines. */ + if (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + xml_insert_element (SMALLFORMAT, START); + if (docbook) + add_char ('\n'); + } + + begin_insertion (smallformat); +} + +void +cm_display (void) +{ + if (xml) + { + /* See cm_example comments about newlines. */ + if (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + xml_insert_element (DISPLAY, START); + if (docbook) + add_char ('\n'); + } + + begin_insertion (display); +} + +void +cm_smalldisplay (void) +{ + if (xml) + { + /* See cm_example comments about newlines. */ + if (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + xml_insert_element (SMALLDISPLAY, START); + if (docbook) + add_char ('\n'); + } + + begin_insertion (smalldisplay); +} + +void +cm_direntry (void) +{ + if (html || xml || no_headers) + command_name_condition (); + else + begin_insertion (direntry); +} + +void +cm_documentdescription (void) +{ + if (html) + begin_insertion (documentdescription); + + else if (xml) + { + xml_insert_element (DOCUMENTDESCRIPTION, START); + begin_insertion (documentdescription); + } + + else + command_name_condition (); +} + + +void +cm_itemize (void) +{ + 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 (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 (void) +{ + do_enumeration (enumerate, "1"); +} + +/* Handle verbatim environment: + find_end_verbatim == 0: process until end of file + find_end_verbatim != 0: process until 'COMMAND_PREFIXend verbatim' + or end of file + + We cannot simply copy input stream onto output stream; as the + verbatim environment may be encapsulated in an @example environment, + for example. */ +void +handle_verbatim_environment (int find_end_verbatim) +{ + int character; + int seen_end = 0; + int save_filling_enabled = filling_enabled; + int save_inhibit_paragraph_indentation = inhibit_paragraph_indentation; + int save_escape_html = escape_html; + + if (!insertion_stack) + close_single_paragraph (); /* no blank lines if not at outer level */ + inhibit_paragraph_indentation = 1; + filling_enabled = 0; + in_fixed_width_font++; + last_char_was_newline = 0; + + /* No indentation: this is verbatim after all + If you want indent, enclose @verbatim in @example + current_indent += default_indentation_increment; + */ + + if (html) + { /* If inside @example, we'll be preceded by the indentation + already. Browsers will ignore those spaces because we're about + to start another <pre> (don't ask me). So, wipe them out for + cleanliness, and re-insert. */ + int i; + kill_self_indent (default_indentation_increment); + add_html_block_elt ("<pre class=\"verbatim\">"); + for (i = current_indent; i > 0; i--) + add_char (' '); + } + else if (xml) + { + xml_insert_element (VERBATIM, START); + escape_html = 0; + add_word ("<![CDATA["); + } + + while (input_text_offset < input_text_length) + { + character = curchar (); + + if (character == '\n') + line_number++; + + /* Assume no newlines in END_VERBATIM. */ + else if (find_end_verbatim && (character == COMMAND_PREFIX) /* @ */ + && (input_text_length - input_text_offset > sizeof (END_VERBATIM)) + && !strncmp (&input_text[input_text_offset+1], END_VERBATIM, + sizeof (END_VERBATIM)-1)) + { + input_text_offset += sizeof (END_VERBATIM); + seen_end = 1; + break; + } + + if (html && character == '&' && escape_html) + add_word ("&"); + else if (html && character == '<' && escape_html) + add_word ("<"); + else + add_char (character); + + input_text_offset++; + } + + if (find_end_verbatim && !seen_end) + warning (_("end of file inside verbatim block")); + + if (html) + { /* See comments in example case above. */ + kill_self_indent (default_indentation_increment); + add_word ("</pre>"); + } + else if (xml) + { + add_word ("]]>"); + xml_insert_element (VERBATIM, END); + escape_html = save_escape_html; + } + + in_fixed_width_font--; + filling_enabled = save_filling_enabled; + inhibit_paragraph_indentation = save_inhibit_paragraph_indentation; +} + +void +cm_verbatim (void) +{ + handle_verbatim_environment (1); +} + +void +cm_table (void) +{ + begin_insertion (table); +} + +void +cm_multitable (void) +{ + begin_insertion (multitable); /* @@ */ +} + +void +cm_ftable (void) +{ + begin_insertion (ftable); +} + +void +cm_vtable (void) +{ + begin_insertion (vtable); +} + +void +cm_group (void) +{ + begin_insertion (group); +} + +/* Insert raw HTML (no escaping of `<' etc.). */ +void +cm_html (int arg) +{ + if (process_html) + begin_insertion (rawhtml); + else + command_name_condition (); +} + +void +cm_xml (int arg) +{ + if (process_xml) + begin_insertion (rawxml); + else + command_name_condition (); +} + +void +cm_docbook (int arg) +{ + if (process_docbook) + begin_insertion (rawdocbook); + else + command_name_condition (); +} + +void +cm_ifdocbook (void) +{ + if (process_docbook) + begin_insertion (ifdocbook); + else + command_name_condition (); +} + +void +cm_ifnotdocbook (void) +{ + if (!process_docbook) + begin_insertion (ifnotdocbook); + else + command_name_condition (); +} + +void +cm_ifhtml (void) +{ + if (process_html) + begin_insertion (ifhtml); + else + command_name_condition (); +} + +void +cm_ifnothtml (void) +{ + if (!process_html) + begin_insertion (ifnothtml); + else + command_name_condition (); +} + + +void +cm_ifinfo (void) +{ + if (process_info) + begin_insertion (ifinfo); + else + command_name_condition (); +} + +void +cm_ifnotinfo (void) +{ + if (!process_info) + begin_insertion (ifnotinfo); + else + command_name_condition (); +} + + +void +cm_ifplaintext (void) +{ + if (process_plaintext) + begin_insertion (ifplaintext); + else + command_name_condition (); +} + +void +cm_ifnotplaintext (void) +{ + if (!process_plaintext) + begin_insertion (ifnotplaintext); + else + command_name_condition (); +} + + +void +cm_tex (void) +{ + if (process_tex) + begin_insertion (rawtex); + else + command_name_condition (); +} + +void +cm_iftex (void) +{ + if (process_tex) + begin_insertion (iftex); + else + command_name_condition (); +} + +void +cm_ifnottex (void) +{ + if (!process_tex) + begin_insertion (ifnottex); + else + command_name_condition (); +} + +void +cm_ifxml (void) +{ + if (process_xml) + begin_insertion (ifxml); + else + command_name_condition (); +} + +void +cm_ifnotxml (void) +{ + if (!process_xml) + begin_insertion (ifnotxml); + else + command_name_condition (); +} + + +/* Generic xrefable block with a caption. */ +void +cm_float (void) +{ + begin_insertion (floatenv); +} + +void +cm_caption (int arg) +{ + char *temp; + + /* This is a no_op command for most formats, as we handle it during @float + insertion. For XML though, we handle it here to keep document structure + as close as possible, to the Texinfo source. */ + + /* Everything is already handled at START. */ + if (arg == END) + return; + + /* Check if it's mislocated. */ + if (current_insertion_type () != floatenv) + line_error (_("@%s not meaningful outside `@float' environment"), command); + + get_until_in_braces ("\n@end float", &temp); + + if (xml) + { + int elt = STREQ (command, "shortcaption") ? SHORTCAPTION : CAPTION; + xml_insert_element (elt, START); + if (!docbook) + execute_string ("%s", temp); + xml_insert_element (elt, END); + } + + free (temp); +} + +/* Begin an insertion where the lines are not filled or indented. */ +void +cm_flushleft (void) +{ + 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 (void) +{ + begin_insertion (flushright); +} + +void +cm_menu (void) +{ + if (current_node == NULL && !macro_expansion_output_stream) + { + 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 (void) +{ + if (current_node == NULL && !macro_expansion_output_stream) + { /* 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); +} + +/* Title page commands. */ + +void +cm_titlepage (void) +{ + titlepage_cmd_present = 1; + if (xml && !docbook) + begin_insertion (titlepage); + else + command_name_condition (); +} + +void +cm_author (void) +{ + char *rest; + get_rest_of_line (1, &rest); + + if (is_in_insertion_of_type (quotation)) + { + if (html) + add_word_args ("— %s", rest); + else if (docbook) + { + /* FIXME Ideally, we should use an attribution element, + but they are supposed to be at the start of quotation + blocks. So to avoid looking ahead mess, let's just + use mdash like HTML for now. */ + xml_insert_entity ("mdash"); + add_word (rest); + } + else if (xml) + { + xml_insert_element (AUTHOR, START); + add_word (rest); + xml_insert_element (AUTHOR, END); + } + else + add_word_args ("-- %s", rest); + } + else if (is_in_insertion_of_type (titlepage)) + { + if (xml && !docbook) + { + xml_insert_element (AUTHOR, START); + add_word (rest); + xml_insert_element (AUTHOR, END); + } + } + else + line_error (_("@%s not meaningful outside `@titlepage' and `@quotation' environments"), + command); + + free (rest); +} + +void +cm_titlepage_cmds (void) +{ + char *rest; + + get_rest_of_line (1, &rest); + + if (!is_in_insertion_of_type (titlepage)) + line_error (_("@%s not meaningful outside `@titlepage' environment"), + command); + + if (xml && !docbook) + { + int elt = 0; + + if (STREQ (command, "title")) + elt = BOOKTITLE; + else if (STREQ (command, "subtitle")) + elt = BOOKSUBTITLE; + + xml_insert_element (elt, START); + add_word (rest); + xml_insert_element (elt, END); + } + + free (rest); +} + +/* End existing insertion block. */ +void +cm_end (void) +{ + char *temp; + int type; + + get_rest_of_line (0, &temp); + + if (!insertion_level) + { + line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command); + return; + } + + 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 `%s' to `@%s', using `%s'"), + temp, command, insertion_type_pname (current_insertion_type ())); + } + if (xml && type == menu) /* fixme */ + { + xml_end_menu (); + } + end_insertion (type); + free (temp); +} + +/* @itemx, @item. */ + +static int itemx_flag = 0; + +/* Return whether CMD takes a brace-delimited {arg}. */ +int +command_needs_braces (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 (void) +{ + 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 ifnotplaintext: + case ifnottex: + case ifnotxml: + case ifplaintext: + case ifset: + case iftex: + case ifxml: + case rawdocbook: + case rawhtml: + case rawxml: + 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) + add_html_block_elt ("<li>"); + else if (xml) + xml_begin_item (); + 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) + { /* 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. */ + rollback_empty_tag ("dd"); + + /* Force the browser to render one blank line before + each new @item in a table. But don't do that if + 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 && html_deflist_has_term) + add_html_block_elt ("<br>"); + + /* We are about to insert a <dt>, so this <dl> has a term. + Feel free to insert a <br> next time. :) */ + html_deflist_has_term = 1; + + add_html_block_elt ("<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); + + add_html_block_elt ("<dd>"); + } + else if (xml) /* && docbook)*/ /* 05-08 */ + { + xml_begin_table_item (); + + if (!docbook && current_insertion_type () == ftable) + execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line); + + if (!docbook && current_insertion_type () == vtable) + execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line); + + if (item_func && *item_func) + execute_string ("%s{%s}", item_func, rest_of_line); + else + execute_string ("%s", rest_of_line); + xml_continue_table_item (); + } + 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 (void) +{ + itemx_flag++; + cm_item (); + itemx_flag--; +} + +int headitem_flag = 0; + +void +cm_headitem (void) +{ + headitem_flag = 1; + cm_item (); +} diff --git a/Build/source/utils/texinfo/makeinfo/insertion.h b/Build/source/utils/texinfo/makeinfo/insertion.h new file mode 100644 index 00000000000..ace55716f2a --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/insertion.h @@ -0,0 +1,78 @@ +/* insertion.h -- declarations for insertion.c. + $Id: insertion.h,v 1.10 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1998, 1999, 2001, 2002, 2003 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, copying, defcv, deffn, defivar, defmac, defmethod, defop, + defopt, defspec, deftp, deftypecv, deftypefn, deftypefun, deftypeivar, + deftypemethod, deftypeop, deftypevar, deftypevr, defun, defvar, defvr, + detailmenu, direntry, display, documentdescription, enumerate, + example, floatenv, flushleft, flushright, format, ftable, group, + ifclear, ifdocbook, ifhtml, ifinfo, ifnotdocbook, ifnothtml, ifnotinfo, + ifnotplaintext, ifnottex, ifnotxml, ifplaintext, ifset, iftex, ifxml, + itemize, lisp, menu, multitable, quotation, rawdocbook, rawhtml, rawtex, + rawxml, smalldisplay, smallexample, smallformat, smalllisp, verbatim, + table, tex, vtable, titlepage, bad_type +}; + +typedef struct istack_elt +{ + struct istack_elt *next; + char *item_function; + char *filename; + int line_number; + int filling_enabled; + int indented_fill; + int 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 int headitem_flag; +extern int after_headitem; + +extern void init_insertion_stack (void); +extern void command_name_condition (void); +extern void cm_ifdocbook (void), cm_ifnotdocbook(void), cm_docbook (int arg); +extern void cm_ifhtml (void), cm_ifnothtml(void), cm_html (int arg); +extern void cm_ifinfo (void), cm_ifnotinfo (void); +extern void cm_ifplaintext (void), cm_ifnotplaintext(void); +extern void cm_iftex (void), cm_ifnottex (void), cm_tex (void); +extern void cm_ifxml (void), cm_ifnotxml (void), cm_xml (int arg); +extern void handle_verbatim_environment (int find_end_verbatim); +extern void begin_insertion (enum insertion_type type); +extern void pop_insertion (void); +extern void discard_insertions (int specials_ok); + +extern int is_in_insertion_of_type (int type); +extern int command_needs_braces (char *cmd); + +extern enum insertion_type find_type_from_name (char *name); +#endif /* !INSERTION_H */ diff --git a/Build/source/utils/texinfo/makeinfo/lang.c b/Build/source/utils/texinfo/makeinfo/lang.c new file mode 100644 index 00000000000..c72e8dbc631 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/lang.c @@ -0,0 +1,1020 @@ +/* lang.c -- language-dependent support. + $Id: lang.c,v 1.14 2004/11/22 23:57:33 karl Exp $ + + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 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. + + Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>. */ + +#include "system.h" +#include "cmds.h" +#include "files.h" +#include "lang.h" +#include "makeinfo.h" +#include "xml.h" + +/* Current document encoding. */ +encoding_code_type document_encoding_code = no_encoding; + +/* Current language code; default is English. */ +language_code_type language_code = en; + +/* By default, unsupported encoding is an empty string. */ +char *unknown_encoding = NULL; + +static iso_map_type us_ascii_map [] = {{NULL, 0, 0}}; /* ASCII map is trivial */ + +/* Translation table between HTML and ISO Codes. The last item is + hopefully the Unicode. It might be possible that those Unicodes are + not correct, cause I didn't check them. kama */ +static iso_map_type iso8859_1_map [] = { + { "nbsp", 0xA0, 0x00A0 }, + { "iexcl", 0xA1, 0x00A1 }, + { "cent", 0xA2, 0x00A2 }, + { "pound", 0xA3, 0x00A3 }, + { "curren", 0xA4, 0x00A4 }, + { "yen", 0xA5, 0x00A5 }, + { "brkbar", 0xA6, 0x00A6 }, + { "sect", 0xA7, 0x00A7 }, + { "uml", 0xA8, 0x00A8 }, + { "copy", 0xA9, 0x00A9 }, + { "ordf", 0xAA, 0x00AA }, + { "laquo", 0xAB, 0x00AB }, + { "not", 0xAC, 0x00AC }, + { "shy", 0xAD, 0x00AD }, + { "reg", 0xAE, 0x00AE }, + { "hibar", 0xAF, 0x00AF }, + { "deg", 0xB0, 0x00B0 }, + { "plusmn", 0xB1, 0x00B1 }, + { "sup2", 0xB2, 0x00B2 }, + { "sup3", 0xB3, 0x00B3 }, + { "acute", 0xB4, 0x00B4 }, + { "micro", 0xB5, 0x00B5 }, + { "para", 0xB6, 0x00B6 }, + { "middot", 0xB7, 0x00B7 }, + { "cedil", 0xB8, 0x00B8 }, + { "sup1", 0xB9, 0x00B9 }, + { "ordm", 0xBA, 0x00BA }, + { "raquo", 0xBB, 0x00BB }, + { "frac14", 0xBC, 0x00BC }, + { "frac12", 0xBD, 0x00BD }, + { "frac34", 0xBE, 0x00BE }, + { "iquest", 0xBF, 0x00BF }, + { "Agrave", 0xC0, 0x00C0 }, + { "Aacute", 0xC1, 0x00C1 }, + { "Acirc", 0xC2, 0x00C2 }, + { "Atilde", 0xC3, 0x00C3 }, + { "Auml", 0xC4, 0x00C4 }, + { "Aring", 0xC5, 0x00C5 }, + { "AElig", 0xC6, 0x00C6 }, + { "Ccedil", 0xC7, 0x00C7 }, + { "Ccedil", 0xC7, 0x00C7 }, + { "Egrave", 0xC8, 0x00C8 }, + { "Eacute", 0xC9, 0x00C9 }, + { "Ecirc", 0xCA, 0x00CA }, + { "Euml", 0xCB, 0x00CB }, + { "Igrave", 0xCC, 0x00CC }, + { "Iacute", 0xCD, 0x00CD }, + { "Icirc", 0xCE, 0x00CE }, + { "Iuml", 0xCF, 0x00CF }, + { "ETH", 0xD0, 0x00D0 }, + { "Ntilde", 0xD1, 0x00D1 }, + { "Ograve", 0xD2, 0x00D2 }, + { "Oacute", 0xD3, 0x00D3 }, + { "Ocirc", 0xD4, 0x00D4 }, + { "Otilde", 0xD5, 0x00D5 }, + { "Ouml", 0xD6, 0x00D6 }, + { "times", 0xD7, 0x00D7 }, + { "Oslash", 0xD8, 0x00D8 }, + { "Ugrave", 0xD9, 0x00D9 }, + { "Uacute", 0xDA, 0x00DA }, + { "Ucirc", 0xDB, 0x00DB }, + { "Uuml", 0xDC, 0x00DC }, + { "Yacute", 0xDD, 0x00DD }, + { "THORN", 0xDE, 0x00DE }, + { "szlig", 0xDF, 0x00DF }, + { "agrave", 0xE0, 0x00E0 }, + { "aacute", 0xE1, 0x00E1 }, + { "acirc", 0xE2, 0x00E2 }, + { "atilde", 0xE3, 0x00E3 }, + { "auml", 0xE4, 0x00E4 }, + { "aring", 0xE5, 0x00E5 }, + { "aelig", 0xE6, 0x00E6 }, + { "ccedil", 0xE7, 0x00E7 }, + { "egrave", 0xE8, 0x00E8 }, + { "eacute", 0xE9, 0x00E9 }, + { "ecirc", 0xEA, 0x00EA }, + { "euml", 0xEB, 0x00EB }, + { "igrave", 0xEC, 0x00EC }, + { "iacute", 0xED, 0x00ED }, + { "icirc", 0xEE, 0x00EE }, + { "iuml", 0xEF, 0x00EF }, + { "eth", 0xF0, 0x00F0 }, + { "ntilde", 0xF1, 0x00F1 }, + { "ograve", 0xF2, 0x00F2 }, + { "oacute", 0xF3, 0x00F3 }, + { "ocirc", 0xF4, 0x00F4 }, + { "otilde", 0xF5, 0x00F5 }, + { "ouml", 0xF6, 0x00F6 }, + { "divide", 0xF7, 0x00F7 }, + { "oslash", 0xF8, 0x00F8 }, + { "ugrave", 0xF9, 0x00F9 }, + { "uacute", 0xFA, 0x00FA }, + { "ucirc", 0xFB, 0x00FB }, + { "uuml", 0xFC, 0x00FC }, + { "yacute", 0xFD, 0x00FD }, + { "thorn", 0xFE, 0x00FE }, + { "yuml", 0xFF, 0x00FF }, + { NULL, 0, 0 } +}; + + +/* ISO 8859-15, also known as Latin 9, differs from Latin 1 in only a + few positions. http://www.cs.tut.fi/~jkorpela/latin9.html has a good + explanation and listing, summarized here. The names are abbreviated + from the official Unicode names, to fit in a decent line length. + + code position + dec oct hex latin1 latin1 name latin9 latin9 name + + 164 0244 0xA4 U+00A4 currency symbol U+20AC euro sign + 166 0246 0xA6 U+00A6 broken bar U+0160 S with caron + 168 0250 0xA8 U+00A8 diaeresis U+0161 s with caron + 180 0264 0xB4 U+00B4 acute accent U+017D Z with caron + 184 0270 0xB8 U+00B8 cedilla U+017E z with caron + 188 0274 0xBC U+00BC fraction 1/4 U+0152 ligature OE + 189 0275 0xBD U+00BD fraction 1/2 U+0153 ligature oe + 190 0276 0xBE U+00BE fraction 3/4 U+0178 Y with diaeresis +*/ + +static iso_map_type iso8859_15_map [] = { + { "nbsp", 0xA0, 0x00A0 }, + { "iexcl", 0xA1, 0x00A1 }, + { "cent", 0xA2, 0x00A2 }, + { "pound", 0xA3, 0x00A3 }, + { "euro", 0xA4, 0x20AC }, + { "yen", 0xA5, 0x00A5 }, + { "Scaron", 0xA6, 0x0160 }, + { "sect", 0xA7, 0x00A7 }, + { "scaron", 0xA8, 0x0161 }, + { "copy", 0xA9, 0x00A9 }, + { "ordf", 0xAA, 0x00AA }, + { "laquo", 0xAB, 0x00AB }, + { "not", 0xAC, 0x00AC }, + { "shy", 0xAD, 0x00AD }, + { "reg", 0xAE, 0x00AE }, + { "hibar", 0xAF, 0x00AF }, + { "deg", 0xB0, 0x00B0 }, + { "plusmn", 0xB1, 0x00B1 }, + { "sup2", 0xB2, 0x00B2 }, + { "sup3", 0xB3, 0x00B3 }, + { "Zcaron", 0xB4, 0x017D }, + { "micro", 0xB5, 0x00B5 }, + { "para", 0xB6, 0x00B6 }, + { "middot", 0xB7, 0x00B7 }, + { "zcaron", 0xB8, 0x017E }, + { "sup1", 0xB9, 0x00B9 }, + { "ordm", 0xBA, 0x00BA }, + { "raquo", 0xBB, 0x00BB }, + { "OElig", 0xBC, 0x0152 }, + { "oelig", 0xBD, 0x0153 }, + { "Yuml", 0xBE, 0x0178 }, + { "iquest", 0xBF, 0x00BF }, + { "Agrave", 0xC0, 0x00C0 }, + { "Aacute", 0xC1, 0x00C1 }, + { "Acirc", 0xC2, 0x00C2 }, + { "Atilde", 0xC3, 0x00C3 }, + { "Auml", 0xC4, 0x00C4 }, + { "Aring", 0xC5, 0x00C5 }, + { "AElig", 0xC6, 0x00C6 }, + { "Ccedil", 0xC7, 0x00C7 }, + { "Ccedil", 0xC7, 0x00C7 }, + { "Egrave", 0xC8, 0x00C8 }, + { "Eacute", 0xC9, 0x00C9 }, + { "Ecirc", 0xCA, 0x00CA }, + { "Euml", 0xCB, 0x00CB }, + { "Igrave", 0xCC, 0x00CC }, + { "Iacute", 0xCD, 0x00CD }, + { "Icirc", 0xCE, 0x00CE }, + { "Iuml", 0xCF, 0x00CF }, + { "ETH", 0xD0, 0x00D0 }, + { "Ntilde", 0xD1, 0x00D1 }, + { "Ograve", 0xD2, 0x00D2 }, + { "Oacute", 0xD3, 0x00D3 }, + { "Ocirc", 0xD4, 0x00D4 }, + { "Otilde", 0xD5, 0x00D5 }, + { "Ouml", 0xD6, 0x00D6 }, + { "times", 0xD7, 0x00D7 }, + { "Oslash", 0xD8, 0x00D8 }, + { "Ugrave", 0xD9, 0x00D9 }, + { "Uacute", 0xDA, 0x00DA }, + { "Ucirc", 0xDB, 0x00DB }, + { "Uuml", 0xDC, 0x00DC }, + { "Yacute", 0xDD, 0x00DD }, + { "THORN", 0xDE, 0x00DE }, + { "szlig", 0xDF, 0x00DF }, + { "agrave", 0xE0, 0x00E0 }, + { "aacute", 0xE1, 0x00E1 }, + { "acirc", 0xE2, 0x00E2 }, + { "atilde", 0xE3, 0x00E3 }, + { "auml", 0xE4, 0x00E4 }, + { "aring", 0xE5, 0x00E5 }, + { "aelig", 0xE6, 0x00E6 }, + { "ccedil", 0xE7, 0x00E7 }, + { "egrave", 0xE8, 0x00E8 }, + { "eacute", 0xE9, 0x00E9 }, + { "ecirc", 0xEA, 0x00EA }, + { "euml", 0xEB, 0x00EB }, + { "igrave", 0xEC, 0x00EC }, + { "iacute", 0xED, 0x00ED }, + { "icirc", 0xEE, 0x00EE }, + { "iuml", 0xEF, 0x00EF }, + { "eth", 0xF0, 0x00F0 }, + { "ntilde", 0xF1, 0x00F1 }, + { "ograve", 0xF2, 0x00F2 }, + { "oacute", 0xF3, 0x00F3 }, + { "ocirc", 0xF4, 0x00F4 }, + { "otilde", 0xF5, 0x00F5 }, + { "ouml", 0xF6, 0x00F6 }, + { "divide", 0xF7, 0x00F7 }, + { "oslash", 0xF8, 0x00F8 }, + { "ugrave", 0xF9, 0x00F9 }, + { "uacute", 0xFA, 0x00FA }, + { "ucirc", 0xFB, 0x00FB }, + { "uuml", 0xFC, 0x00FC }, + { "yacute", 0xFD, 0x00FD }, + { "thorn", 0xFE, 0x00FE }, + { "yuml", 0xFF, 0x00FF }, + { NULL, 0, 0 } +}; + + + +/* Date: Mon, 31 Mar 2003 00:19:28 +0200 + From: Wojciech Polak <polak@gnu.org> +... + * Primary Polish site for ogonki is http://www.agh.edu.pl/ogonki/, + but it's only in Polish language (it has some interesting links). + + * A general site about ISO 8859-2 at http://nl.ijs.si/gnusl/cee/iso8859-2.html + + * ISO 8859-2 Character Set at http://nl.ijs.si/gnusl/cee/charset.html + This site provides almost all information about iso-8859-2, + including the character table!!! (must see!) + + * ISO 8859-2 and even HTML entities !!! (must see!) + http://people.ssh.fi/mtr/genscript/88592.txt + + * (minor) http://www.agh.edu.pl/ogonki/plchars.html + One more table, this time it includes even information about Polish + characters in Unicode. +*/ + +static iso_map_type iso8859_2_map [] = { + { "nbsp", 0xA0, 0x00A0 }, /* NO-BREAK SPACE */ + { "", 0xA1, 0x0104 }, /* LATIN CAPITAL LETTER A WITH OGONEK */ + { "", 0xA2, 0x02D8 }, /* BREVE */ + { "", 0xA3, 0x0141 }, /* LATIN CAPITAL LETTER L WITH STROKE */ + { "curren", 0xA4, 0x00A4 }, /* CURRENCY SIGN */ + { "", 0xA5, 0x013D }, /* LATIN CAPITAL LETTER L WITH CARON */ + { "", 0xA6, 0x015A }, /* LATIN CAPITAL LETTER S WITH ACUTE */ + { "sect", 0xA7, 0x00A7 }, /* SECTION SIGN */ + { "uml", 0xA8, 0x00A8 }, /* DIAERESIS */ + { "", 0xA9, 0x0160 }, /* LATIN CAPITAL LETTER S WITH CARON */ + { "", 0xAA, 0x015E }, /* LATIN CAPITAL LETTER S WITH CEDILLA */ + { "", 0xAB, 0x0164 }, /* LATIN CAPITAL LETTER T WITH CARON */ + { "", 0xAC, 0x0179 }, /* LATIN CAPITAL LETTER Z WITH ACUTE */ + { "shy", 0xAD, 0x00AD }, /* SOFT HYPHEN */ + { "", 0xAE, 0x017D }, /* LATIN CAPITAL LETTER Z WITH CARON */ + { "", 0xAF, 0x017B }, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + { "deg", 0xB0, 0x00B0 }, /* DEGREE SIGN */ + { "", 0xB1, 0x0105 }, /* LATIN SMALL LETTER A WITH OGONEK */ + { "", 0xB2, 0x02DB }, /* OGONEK */ + { "", 0xB3, 0x0142 }, /* LATIN SMALL LETTER L WITH STROKE */ + { "acute", 0xB4, 0x00B4 }, /* ACUTE ACCENT */ + { "", 0xB5, 0x013E }, /* LATIN SMALL LETTER L WITH CARON */ + { "", 0xB6, 0x015B }, /* LATIN SMALL LETTER S WITH ACUTE */ + { "", 0xB7, 0x02C7 }, /* CARON (Mandarin Chinese third tone) */ + { "cedil", 0xB8, 0x00B8 }, /* CEDILLA */ + { "", 0xB9, 0x0161 }, /* LATIN SMALL LETTER S WITH CARON */ + { "", 0xBA, 0x015F }, /* LATIN SMALL LETTER S WITH CEDILLA */ + { "", 0xBB, 0x0165 }, /* LATIN SMALL LETTER T WITH CARON */ + { "", 0xBC, 0x017A }, /* LATIN SMALL LETTER Z WITH ACUTE */ + { "", 0xBD, 0x02DD }, /* DOUBLE ACUTE ACCENT */ + { "", 0xBE, 0x017E }, /* LATIN SMALL LETTER Z WITH CARON */ + { "", 0xBF, 0x017C }, /* LATIN SMALL LETTER Z WITH DOT ABOVE */ + { "", 0xC0, 0x0154 }, /* LATIN CAPITAL LETTER R WITH ACUTE */ + { "", 0xC1, 0x00C1 }, /* LATIN CAPITAL LETTER A WITH ACUTE */ + { "", 0xC2, 0x00C2 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ + { "", 0xC3, 0x0102 }, /* LATIN CAPITAL LETTER A WITH BREVE */ + { "", 0xC4, 0x00C4 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ + { "", 0xC5, 0x0139 }, /* LATIN CAPITAL LETTER L WITH ACUTE */ + { "", 0xC6, 0x0106 }, /* LATIN CAPITAL LETTER C WITH ACUTE */ + { "", 0xC7, 0x00C7 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */ + { "", 0xC8, 0x010C }, /* LATIN CAPITAL LETTER C WITH CARON */ + { "", 0xC9, 0x00C9 }, /* LATIN CAPITAL LETTER E WITH ACUTE */ + { "", 0xCA, 0x0118 }, /* LATIN CAPITAL LETTER E WITH OGONEK */ + { "", 0xCB, 0x00CB }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ + { "", 0xCC, 0x011A }, /* LATIN CAPITAL LETTER E WITH CARON */ + { "", 0xCD, 0x00CD }, /* LATIN CAPITAL LETTER I WITH ACUTE */ + { "", 0xCE, 0x00CE }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ + { "", 0xCF, 0x010E }, /* LATIN CAPITAL LETTER D WITH CARON */ + { "", 0xD0, 0x0110 }, /* LATIN CAPITAL LETTER D WITH STROKE */ + { "", 0xD1, 0x0143 }, /* LATIN CAPITAL LETTER N WITH ACUTE */ + { "", 0xD2, 0x0147 }, /* LATIN CAPITAL LETTER N WITH CARON */ + { "", 0xD3, 0x00D3 }, /* LATIN CAPITAL LETTER O WITH ACUTE */ + { "", 0xD4, 0x00D4 }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ + { "", 0xD5, 0x0150 }, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + { "", 0xD6, 0x00D6 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */ + { "times", 0xD7, 0x00D7 }, /* MULTIPLICATION SIGN */ + { "", 0xD8, 0x0158 }, /* LATIN CAPITAL LETTER R WITH CARON */ + { "", 0xD9, 0x016E }, /* LATIN CAPITAL LETTER U WITH RING ABOVE */ + { "", 0xDA, 0x00DA }, /* LATIN CAPITAL LETTER U WITH ACUTE */ + { "", 0xDB, 0x0170 }, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + { "", 0xDC, 0x00DC }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */ + { "", 0xDD, 0x00DD }, /* LATIN CAPITAL LETTER Y WITH ACUTE */ + { "", 0xDE, 0x0162 }, /* LATIN CAPITAL LETTER T WITH CEDILLA */ + { "", 0xDF, 0x00DF }, /* LATIN SMALL LETTER SHARP S (German) */ + { "", 0xE0, 0x0155 }, /* LATIN SMALL LETTER R WITH ACUTE */ + { "", 0xE1, 0x00E1 }, /* LATIN SMALL LETTER A WITH ACUTE */ + { "", 0xE2, 0x00E2 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */ + { "", 0xE3, 0x0103 }, /* LATIN SMALL LETTER A WITH BREVE */ + { "", 0xE4, 0x00E4 }, /* LATIN SMALL LETTER A WITH DIAERESIS */ + { "", 0xE5, 0x013A }, /* LATIN SMALL LETTER L WITH ACUTE */ + { "", 0xE6, 0x0107 }, /* LATIN SMALL LETTER C WITH ACUTE */ + { "", 0xE7, 0x00E7 }, /* LATIN SMALL LETTER C WITH CEDILLA */ + { "", 0xE8, 0x010D }, /* LATIN SMALL LETTER C WITH CARON */ + { "", 0xE9, 0x00E9 }, /* LATIN SMALL LETTER E WITH ACUTE */ + { "", 0xEA, 0x0119 }, /* LATIN SMALL LETTER E WITH OGONEK */ + { "", 0xEB, 0x00EB }, /* LATIN SMALL LETTER E WITH DIAERESIS */ + { "", 0xEC, 0x011B }, /* LATIN SMALL LETTER E WITH CARON */ + { "", 0xED, 0x00ED }, /* LATIN SMALL LETTER I WITH ACUTE */ + { "", 0xEE, 0x00EE }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */ + { "", 0xEF, 0x010F }, /* LATIN SMALL LETTER D WITH CARON */ + { "", 0xF0, 0x0111 }, /* LATIN SMALL LETTER D WITH STROKE */ + { "", 0xF1, 0x0144 }, /* LATIN SMALL LETTER N WITH ACUTE */ + { "", 0xF2, 0x0148 }, /* LATIN SMALL LETTER N WITH CARON */ + { "", 0xF3, 0x00F3 }, /* LATIN SMALL LETTER O WITH ACUTE */ + { "", 0xF4, 0x00F4 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */ + { "", 0xF5, 0x0151 }, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + { "", 0xF6, 0x00F6 }, /* LATIN SMALL LETTER O WITH DIAERESIS */ + { "divide", 0xF7, 0x00F7 }, /* DIVISION SIGN */ + { "", 0xF8, 0x0159 }, /* LATIN SMALL LETTER R WITH CARON */ + { "", 0xF9, 0x016F }, /* LATIN SMALL LETTER U WITH RING ABOVE */ + { "", 0xFA, 0x00FA }, /* LATIN SMALL LETTER U WITH ACUTE */ + { "", 0xFB, 0x0171 }, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + { "", 0xFC, 0x00FC }, /* LATIN SMALL LETTER U WITH DIAERESIS */ + { "", 0xFD, 0x00FD }, /* LATIN SMALL LETTER Y WITH ACUTE */ + { "", 0xFE, 0x0163 }, /* LATIN SMALL LETTER T WITH CEDILLA */ + { "", 0xFF, 0x02D9 }, /* DOT ABOVE (Mandarin Chinese light tone) */ + { NULL, 0, 0 } +}; + +encoding_type encoding_table[] = { + { no_encoding, "(no encoding)", NULL }, + { US_ASCII, "US-ASCII", us_ascii_map }, + { ISO_8859_1, "iso-8859-1", (iso_map_type *) iso8859_1_map }, + { ISO_8859_2, "iso-8859-2", (iso_map_type *) iso8859_2_map }, + { ISO_8859_3, "iso-8859-3", NULL }, + { ISO_8859_4, "iso-8859-4", NULL }, + { ISO_8859_5, "iso-8859-5", NULL }, + { ISO_8859_6, "iso-8859-6", NULL }, + { ISO_8859_7, "iso-8859-7", NULL }, + { ISO_8859_8, "iso-8859-8", NULL }, + { ISO_8859_9, "iso-8859-9", NULL }, + { ISO_8859_10, "iso-8859-10", NULL }, + { ISO_8859_11, "iso-8859-11", NULL }, + { ISO_8859_12, "iso-8859-12", NULL }, + { ISO_8859_13, "iso-8859-13", NULL }, + { ISO_8859_14, "iso-8859-14", NULL }, + { ISO_8859_15, "iso-8859-15", (iso_map_type *) iso8859_15_map }, + { last_encoding_code, NULL, NULL } +}; + + +language_type 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. */ + +/* XML documents can make use of this data. Unfortunately, it clashes with + the structure currently used. So instead of enclosing content into + a language block, we just output an empty element. Anyways, a stream based + parser can make good use of it. */ +void +cm_documentlanguage (void) +{ + language_code_type c; + char *lang_arg; + + /* Read the line with the language code on it. */ + get_rest_of_line (0, &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); + + if (xml && !docbook) + { + xml_insert_element_with_attribute (DOCUMENTLANGUAGE, START, "xml:lang=\"%s\"", lang_arg); + xml_insert_element (DOCUMENTLANGUAGE, END); + } + + free (lang_arg); +} + + + +/* Search through the encoding table for the given character, returning + its equivalent. */ + +static int +cm_search_iso_map (char *html) +{ + int i; + iso_map_type *iso = encoding_table[document_encoding_code].isotab; + + /* If no conversion table for this encoding, quit. */ + if (!iso) + return -1; + + for (i = 0; iso[i].html; i++) + { + if (strcmp (html, iso[i].html) == 0) + return i; + } + + return -1; +} + + +/* @documentencoding. Set the translation table. */ + +void +cm_documentencoding (void) +{ + if (!handling_delayed_writes) + { + encoding_code_type enc; + char *enc_arg; + + /* This is ugly and probably needs to apply to other commands' + argument parsing as well. When we're doing @documentencoding, + we're generally in the frontmatter of the document, and so the. + expansion in html/xml/docbook would generally be the empty string. + (Because those modes wait until the first normal text of the + document to start outputting.) The result would thus be a warning + "unrecognized encoding name `'". Sigh. */ + int save_html = html; + int save_xml = xml; + + html = 0; + xml = 0; + get_rest_of_line (1, &enc_arg); + html = save_html; + xml = save_xml; + + /* See if we have this encoding. */ + for (enc = no_encoding+1; enc != last_encoding_code; enc++) + { + if (strcasecmp (enc_arg, encoding_table[enc].encname) == 0) + { + document_encoding_code = enc; + break; + } + } + + /* If we didn't find this code, complain. */ + if (enc == last_encoding_code) + { + warning (_("unrecognized encoding name `%s'"), enc_arg); + /* Let the previous one go. */ + if (unknown_encoding && *unknown_encoding) + free (unknown_encoding); + unknown_encoding = xstrdup (enc_arg); + } + + else if (encoding_table[document_encoding_code].isotab == NULL) + warning (_("sorry, encoding `%s' not supported"), enc_arg); + + free (enc_arg); + } + else if (xml) + { + char *encoding = current_document_encoding (); + + if (encoding && *encoding) + { + insert_string (" encoding=\""); + insert_string (encoding); + insert_string ("\""); + } + + free (encoding); + } +} + +char * +current_document_encoding (void) +{ + if (document_encoding_code != no_encoding) + return xstrdup (encoding_table[document_encoding_code].encname); + else if (unknown_encoding && *unknown_encoding) + return xstrdup (unknown_encoding); + else + return xstrdup (""); +} + + +/* If html or xml output, add &HTML_STR; to the output. If not html and + the user requested encoded output, add the real 8-bit character + corresponding to HTML_STR from the translation tables. Otherwise, + add INFO_STR. */ + +static void +add_encoded_char (char *html_str, char *info_str) +{ + if (html) + add_word_args ("&%s;", html_str); + else if (xml) + xml_insert_entity (html_str); + else if (enable_encoding) + { + /* Look for HTML_STR in the current translation table. */ + int rc = cm_search_iso_map (html_str); + if (rc >= 0) + /* We found it, add the real character. */ + add_char (encoding_table[document_encoding_code].isotab[rc].bytecode); + else + { /* We didn't find it, that seems bad. */ + warning (_("invalid encoded character `%s'"), html_str); + add_word (info_str); + } + } + else + add_word (info_str); +} + + + +/* Output an accent for HTML or XML. */ + +static void +cm_accent_generic_html (int arg, int start, int end, char *html_supported, + int single, int html_solo_standalone, char *html_solo) +{ + static int valid_html_accent; /* yikes */ + + 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). */ + int saved_escape_html = escape_html; + escape_html = 0; + valid_html_accent = 1; + add_char ('&'); + escape_html = saved_escape_html; + } + else + { /* @dotless{i} is not listed in html_supported but HTML entities + starting with `i' can be used, such as î. */ + int save_input_text_offset = input_text_offset; + char *accent_contents; + + get_until_in_braces ("\n", &accent_contents); + canon_white (accent_contents); + + if (strstr (accent_contents, "@dotless{i")) + { + add_word_args ("&%c", accent_contents[9]); + valid_html_accent = 1; + } + else + { + /* Search for @dotless{} wasn't successful, so rewind. */ + input_text_offset = save_input_text_offset; + valid_html_accent = 0; + if (html_solo_standalone) + { /* No special HTML support, so produce standalone char. */ + if (xml) + xml_insert_entity (html_solo); + else + add_word_args ("&%s;", html_solo); + } + else + /* If the html_solo does not exist as standalone character + (namely ˆ ` ˜), then we use + the single character version instead. */ + add_char (single); + } + + free (accent_contents); + } + } + 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 (';'); + } + } +} + + +static void +cm_accent_generic_no_headers (int arg, int start, int end, int single, + char *html_solo) +{ + if (arg == END) + { + if (no_encoding) + add_char (single); + else + { + int rc; + char *buffer = xmalloc (1 + strlen (html_solo) + 1); + buffer[0] = output_paragraph[end - 1]; + buffer[1] = 0; + strcat (buffer, html_solo); + + rc = cm_search_iso_map (buffer); + if (rc >= 0) + /* A little bit tricky ;-) + Here we replace the character which has + been inserted in read_command with + the value we have found in converting table + Does there exist a better way to do this? kama. */ + output_paragraph[end - 1] + = encoding_table[document_encoding_code].isotab[rc].bytecode; + else + { /* If we didn't find a translation for this character, + put the single instead. E.g., &Xuml; does not exist so X¨ + should be produced. */ + /* When the below warning is issued, an author has nothing + wrong in their document, let alone anything ``fixable'' + on their side. So it is commented out for now. */ + /* warning (_("%s is an invalid ISO code, using %c"), + buffer, single); */ + add_char (single); + } + + free (buffer); + } + } +} + + + +/* Accent commands that take explicit arguments and don't have any + special HTML support. */ + +void +cm_accent (int arg) +{ + int old_escape_html = escape_html; + escape_html = 0; + 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 || xml) ? "¯" : "="); + 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 || xml) ? "<" : "<"); + } + escape_html = old_escape_html; +} + +/* 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, Ä 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. 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 nonzero the given HTML_SOLO + exists as valid standalone character in HTML, e.g., ¨. */ + +static void +cm_accent_generic (int arg, int start, int end, char *html_supported, + int single, int html_solo_standalone, char *html_solo) +{ + /* Accentuating space characters makes no sense, so issue a warning. */ + if (arg == START && isspace (input_text[input_text_offset])) + warning ("Accent command `@%s' must not be followed by whitespace", + command); + + if (html || xml) + cm_accent_generic_html (arg, start, end, html_supported, + single, html_solo_standalone, html_solo); + else if (no_headers) + cm_accent_generic_no_headers (arg, start, end, single, html_solo); + else if (arg == END) + { + if (enable_encoding) + /* use 8-bit if available */ + cm_accent_generic_no_headers (arg, start, end, single, html_solo); + else + /* use regular character */ + add_char (single); + } +} + +void +cm_accent_umlaut (int arg, int start, int end) +{ + cm_accent_generic (arg, start, end, "aouAOUEeIiy", '"', 1, "uml"); +} + +void +cm_accent_acute (int arg, int start, int end) +{ + cm_accent_generic (arg, start, end, "AEIOUYaeiouy", '\'', 1, "acute"); +} + +void +cm_accent_cedilla (int arg, int start, int end) +{ + cm_accent_generic (arg, start, end, "Cc", ',', 1, "cedil"); +} + +void +cm_accent_hat (int arg, int start, int end) +{ + cm_accent_generic (arg, start, end, "AEIOUaeiou", '^', 0, "circ"); +} + +void +cm_accent_grave (int arg, int start, int end) +{ + cm_accent_generic (arg, start, end, "AEIOUaeiou", '`', 0, "grave"); +} + +void +cm_accent_tilde (int arg, int start, int end) +{ + cm_accent_generic (arg, start, end, "ANOano", '~', 0, "tilde"); +} + + + +/* Non-English letters/characters that don't insert themselves. */ +void +cm_special_char (int arg) +{ + int old_escape_html = escape_html; + escape_html = 0; + + 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 (command[0] == 'O') + add_encoded_char ("Oslash", "/O"); + else if (command[0] == 'o') + add_encoded_char ("oslash", "/o"); + else + add_word_args ("/%c", command[0]); + } + else if (strcmp (command, "exclamdown") == 0) + add_encoded_char ("iexcl", "!"); + else if (strcmp (command, "questiondown") == 0) + add_encoded_char ("iquest", "?"); + else if (strcmp (command, "euro") == 0) + /* http://www.cs.tut.fi/~jkorpela/html/euro.html suggests that + € degrades best in old browsers. */ + add_encoded_char ("euro", "Euro "); + else if (strcmp (command, "pounds") == 0) + add_encoded_char ("pound" , "#"); + else if (strcmp (command, "ordf") == 0) + add_encoded_char ("ordf" , "a"); + else if (strcmp (command, "ordm") == 0) + add_encoded_char ("ordm" , "o"); + else if (strcmp (command, "AE") == 0) + add_encoded_char ("AElig", command); + else if (strcmp (command, "ae") == 0) + add_encoded_char ("aelig", command); + else if (strcmp (command, "OE") == 0) + add_encoded_char ("OElig", command); + else if (strcmp (command, "oe") == 0) + add_encoded_char ("oelig", command); + else if (strcmp (command, "AA") == 0) + add_encoded_char ("Aring", command); + else if (strcmp (command, "aa") == 0) + add_encoded_char ("aring", command); + else if (strcmp (command, "ss") == 0) + add_encoded_char ("szlig", command); + else + line_error ("cm_special_char internal error: command=@%s", command); + } + escape_html = old_escape_html; +} + +/* Dotless i or j. */ +void +cm_dotless (int arg, int start, int end) +{ + if (arg == END) + { + xml_no_para --; + 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. */ + } + else + xml_no_para ++; +} diff --git a/Build/source/utils/texinfo/makeinfo/lang.h b/Build/source/utils/texinfo/makeinfo/lang.h new file mode 100644 index 00000000000..b231455a6e9 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/lang.h @@ -0,0 +1,148 @@ +/* lang.h -- declarations for language codes etc. + $Id: lang.h,v 1.6 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1999, 2001, 2002, 2003 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. + + Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>. */ + +#ifndef LANG_H +#define LANG_H + +/* The language code which can be changed through @documentlanguage + * Actually we don't currently support this (may be in the future) ;-) + * These code are the 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 for each language. */ +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_type; + +extern language_type language_table[]; + + + +/* The document encoding. This is useful to produce true 8-bit + characters according to the @documentencoding. */ + +typedef enum { + no_encoding, + US_ASCII, + ISO_8859_1, + ISO_8859_2, + ISO_8859_3, /* this and none of the rest are supported. */ + ISO_8859_4, + ISO_8859_5, + ISO_8859_6, + ISO_8859_7, + ISO_8859_8, + ISO_8859_9, + ISO_8859_10, + ISO_8859_11, + ISO_8859_12, + ISO_8859_13, + ISO_8859_14, + ISO_8859_15, + last_encoding_code +} encoding_code_type; + +/* The current document encoding, or null if not set. */ +extern encoding_code_type document_encoding_code; + +/* If an encoding is not supported, just keep it as a string. */ +extern char *unknown_encoding; + +/* Maps an HTML abbreviation to ISO and Unicode codes for a given code. */ + +typedef unsigned short int unicode_t; /* should be 16 bits */ +typedef unsigned char byte_t; + +typedef struct +{ + char *html; /* HTML equivalent like umlaut auml => ä */ + byte_t bytecode; /* 8-Bit Code (ISO 8859-1,...) */ + unicode_t unicode; /* Unicode in U+ convention */ +} iso_map_type; + +/* Information about the document encoding. */ +typedef struct +{ + encoding_code_type ec; /* document encoding type (see above enum) */ + char *encname; /* encoding name like "iso-8859-1", valid in + HTML and Emacs */ + iso_map_type *isotab; /* address of ISO translation table */ +} encoding_type; + +/* Table with all the encoding codes that we recognize. */ +extern encoding_type encoding_table[]; + + +/* The commands. */ +extern void cm_documentlanguage (void), + cm_documentencoding (void); + +/* Accents, other non-English characters. */ +void cm_accent (int arg), cm_special_char (int arg), + cm_dotless (int arg, int start, int end); + +extern void cm_accent_umlaut (int arg, int start, int end), + cm_accent_acute (int arg, int start, int end), + cm_accent_cedilla (int arg, int start, int end), + cm_accent_hat (int arg, int start, int end), + cm_accent_grave (int arg, int start, int end), + cm_accent_tilde (int arg, int start, int end); + +extern char *current_document_encoding (void); + +#endif /* not LANG_H */ diff --git a/Build/source/utils/texinfo/makeinfo/macro.c b/Build/source/utils/texinfo/makeinfo/macro.c new file mode 100644 index 00000000000..65ac0dac8f8 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/macro.c @@ -0,0 +1,1108 @@ +/* macro.c -- user-defined macros for Texinfo. + $Id: macro.c,v 1.6 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1998, 1999, 2002, 2003 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 "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 (char **array) +{ + int i = 0; + + if (array) + for (i = 0; array[i]; i++); + + return i; +} + +void +free_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 (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. */ +static void +add_macro (char *name, char **arglist, char *body, char *source_file, + int source_lineno, int 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 (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; +} + +static char ** +get_macro_args (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\. */ +static char * +apply (char **named, char **actuals, char *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, 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++; + + if (len == 0) + { /* \\ always means \, even if macro has no args. */ + len++; + text = xmalloc (1 + len); + sprintf (text, "\\%s", param); + } + else + { + int which; + + /* 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); + text = xstrdup (text); /* so we can free it */ + } + else + { /* not a parameter, so it's an error. */ + warning (_("\\ in macro expansion followed by `%s' instead of 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; + + 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 (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 (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 (char *mactype, int recursive) +{ + int i, start; + char *name, *line; + char *last_end = NULL; + char *body = NULL; + char **arglist = NULL; + int body_size = 0, body_index = 0; + int depth = 1; + int flags = 0; + int defining_line = line_number; + + 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. */ + 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) + { + file_line_error (input_filename, defining_line, + _("%cend macro not found"), COMMAND_PREFIX); + 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", 10) == 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 text for future expansions. */ + remember_itext (input_text, input_text_offset); + + /* Bizarrely, output the @macro itself. This is so texinfo.tex + will have a chance to read it when texi2dvi calls makeinfo -E. + The problem is that we don't really expand macros in all + contexts; a @table's @item is one. And a fix is not obvious to + me, since it appears virtually identical to any other internal + expansion. Just setting a variable in cm_item caused other + strange expansion problems. */ + write_region_to_macro_output ("@", 0, 1); + write_region_to_macro_output (mactype, 0, strlen (mactype)); + write_region_to_macro_output (" ", 0, 1); + write_region_to_macro_output (input_text, start, input_text_offset); + } +} + +void +cm_macro (void) +{ + define_macro ("macro", 0); +} + +void +cm_rmacro (void) +{ + 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 (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 (void) +{ + 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 (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 (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 (void) +{ + 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 (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 (char *execution_string, char *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 (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 (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 (char *string, int start, int 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 aname = cmdname */ + +void +cm_alias (void) +{ + alias_type *a = xmalloc (sizeof (alias_type)); + + skip_whitespace (); + get_until_in_line (0, "=", &(a->alias)); + canon_white (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 (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 (void) +{ + 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 (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 (int arg, int start, int 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/Build/source/utils/texinfo/makeinfo/macro.h b/Build/source/utils/texinfo/makeinfo/macro.h new file mode 100644 index 00000000000..fbc0e59e651 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/macro.h @@ -0,0 +1,77 @@ +/* macro.h -- declarations for macro.c. + $Id: macro.h,v 1.2 2004/04/11 17:56:47 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 (MACRO_DEF *def); +extern MACRO_DEF *find_macro (char *name); +extern char *expand_macro (MACRO_DEF *def); + +extern ITEXT *remember_itext (char *pointer, int offset); +extern void forget_itext (char *pointer); +extern void maybe_write_itext (char *pointer, int offset); +extern void write_region_to_macro_output (char *string, int start, int end); +extern void append_to_expansion_output (int offset); +extern void me_append_before_this_command (void); +extern void me_execute_string (char *execution_string); +extern void me_execute_string_keep_state (char *execution_string, + char *append_string); + +extern char *alias_expand (char *tok); +extern int enclosure_command (char *tok); +extern void enclosure_expand (int arg, int start, int end); + +/* The @commands. */ +extern void cm_macro (void), cm_rmacro (void), cm_unmacro (void); +extern void cm_alias (void), cm_definfoenclose (void); + +extern int array_len (char **array); +extern void free_array (char **array); +extern char **get_brace_args (int quote_single); + +#endif /* not MACRO_H */ diff --git a/Build/source/utils/texinfo/makeinfo/makeinfo.c b/Build/source/utils/texinfo/makeinfo/makeinfo.c new file mode 100644 index 00000000000..22ed4c4fd99 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/makeinfo.c @@ -0,0 +1,4157 @@ +/* makeinfo -- convert Texinfo source into other formats. + $Id: makeinfo.c,v 1.74 2004/12/19 17:15:42 karl Exp $ + + Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004 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. + + Original author of makeinfo: Brian Fox (bfox@ai.mit.edu). */ + +#include "system.h" +#include "getopt.h" + +#define COMPILING_MAKEINFO +#include "makeinfo.h" +#include "cmds.h" +#include "files.h" +#include "float.h" +#include "footnote.h" +#include "html.h" +#include "index.h" +#include "insertion.h" +#include "lang.h" +#include "macro.h" +#include "node.h" +#include "sectioning.h" +#include "toc.h" +#include "xml.h" + +/* You can change some of the behavior of Makeinfo by changing the + following defines: */ + +/* Define INDENT_PARAGRAPHS_IN_TABLE if you want the paragraphs which + appear within an @table, @ftable, or @itemize environment to have + standard paragraph indentation. Without this, such paragraphs have + no starting indentation. */ +/* #define INDENT_PARAGRAPHS_IN_TABLE */ + +/* 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 + line, with the --paragraph-indent option, or within the texinfo file, + with the @paragraphindent command. */ +#define PARAGRAPH_START_INDENT 3 + +/* Define DEFAULT_PARAGRAPH_SPACING as the number of blank lines that you + wish to appear between paragraphs. A value of 1 creates a single blank + 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 + +/* Global variables. */ + +/* The output file name. */ +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 = NULL; +static char *save_command_output_filename = NULL; + +#define INITIAL_PARAGRAPH_SPACE 5000 +int paragraph_buffer_len = INITIAL_PARAGRAPH_SPACE; + +/* 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. + < 0 means indent to column zero by removing indentation if necessary. + + This is normally zero, but some people prefer paragraph starts to be + somewhat more indented than paragraph bodies. A pretty value for + this is 3. */ +int paragraph_start_indent = PARAGRAPH_START_INDENT; + +/* 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 index in our internal command table of the currently + executing command. */ +int command_index; + +/* 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 }; + +/* Values for calling handle_variable_internal (). */ +#define SET 1 +#define CLEAR 2 +#define IFSET 3 +#define IFCLEAR 4 + +/* Flags controlling the operation of the program. */ + +/* Default is to remove output if there were errors. */ +int force = 0; + +/* Default is to notify users of bad choices. */ +int print_warnings = 1; + +/* Number of errors that we tolerate on a given fileset. */ +int max_error_level = 100; + +/* 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; + +/* Nonzero means don't replace whitespace with in HTML mode. */ +int in_html_elt = 0; + +/* Nonzero means we are inserting a block level HTML element that must not be + enclosed in a <p>, such as <ul>, <ol> and <h?>. */ +int in_html_block_level_elt = 0; + +/* True when expanding a macro definition. */ +static int executing_macro = 0; + +/* True when we are inside a <li> block of a menu. */ +static int in_menu_item = 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 = NULL; + +static void convert_from_file (char *name); +static void convert_from_loaded_file (char *name); +static void convert_from_stream (FILE *stream, char *name); +static void do_flush_right_indentation (void); +static void handle_variable (int action); +static void handle_variable_internal (int action, char *name); +static void init_brace_stack (void); +static void init_internals (void); +static void pop_and_call_brace (void); +static void remember_brace (COMMAND_FUNCTION (*proc)); +static int end_of_sentence_p (void); + +void maybe_update_execution_strings (char **text, unsigned int new_len); + +/* Error handling. */ + +/* Number of errors encountered. */ +int errors_printed = 0; + +/* Remember that an error has been printed. If more than + max_error_level have been printed, then exit the program. */ +static void +remember_error (void) +{ + errors_printed++; + if (max_error_level && (errors_printed > max_error_level)) + { + fprintf (stderr, _("Too many errors! Gave up.\n")); + flush_file_stack (); + if (errors_printed - max_error_level < 2) + cm_bye (); + xexit (1); + } +} + +/* Print the last error gotten from the file system. */ +int +fs_error (char *filename) +{ + remember_error (); + perror (filename); + return 0; +} + +/* Print an error message, and return false. */ +void +#if defined (VA_FPRINTF) && __STDC__ +error (const char *format, ...) +#else +error (format, va_alist) + const char *format; + va_dcl +#endif +{ +#ifdef VA_FPRINTF + va_list ap; +#endif + + remember_error (); + + VA_START (ap, format); +#ifdef VA_FPRINTF + VA_FPRINTF (stderr, format, ap); +#else + fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8); +#endif /* not VA_FPRINTF */ + va_end (ap); + + putc ('\n', stderr); +} + +/* Just like error (), but print the input file and line number as well. */ +void +#if defined (VA_FPRINTF) && __STDC__ +file_line_error (char *infile, int lno, const char *format, ...) +#else +file_line_error (infile, lno, format, va_alist) + char *infile; + int lno; + const char *format; + va_dcl +#endif +{ +#ifdef VA_FPRINTF + va_list ap; +#endif + + remember_error (); + fprintf (stderr, "%s:%d: ", infile, lno); + + VA_START (ap, format); +#ifdef VA_FPRINTF + VA_FPRINTF (stderr, format, ap); +#else + fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8); +#endif /* not VA_FPRINTF */ + va_end (ap); + + fprintf (stderr, ".\n"); +} + +/* Just like file_line_error (), but take the input file and the line + number from global variables. */ +void +#if defined (VA_FPRINTF) && __STDC__ +line_error (const char *format, ...) +#else +line_error (format, va_alist) + const char *format; + va_dcl +#endif +{ +#ifdef VA_FPRINTF + va_list ap; +#endif + + remember_error (); + fprintf (stderr, "%s:%d: ", input_filename, line_number); + + VA_START (ap, format); +#ifdef VA_FPRINTF + VA_FPRINTF (stderr, format, ap); +#else + fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8); +#endif /* not VA_FPRINTF */ + va_end (ap); + + fprintf (stderr, ".\n"); +} + +void +#if defined (VA_FPRINTF) && __STDC__ +warning (const char *format, ...) +#else +warning (format, va_alist) + const char *format; + va_dcl +#endif +{ +#ifdef VA_FPRINTF + va_list ap; +#endif + + if (print_warnings) + { + fprintf (stderr, _("%s:%d: warning: "), input_filename, line_number); + + VA_START (ap, format); +#ifdef VA_FPRINTF + VA_FPRINTF (stderr, format, ap); +#else + fprintf (stderr, format, a1, a2, a3, a4, a5, a6, a7, a8); +#endif /* not VA_FPRINTF */ + va_end (ap); + + fprintf (stderr, ".\n"); + } +} + + +/* The other side of a malformed expression. */ +static void +misplaced_brace (void) +{ + line_error (_("Misplaced %c"), '}'); +} + +/* Main. */ + +/* Display the version info of this invocation of Makeinfo. */ +static void +print_version_info (void) +{ + 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 (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"), progname); + puts (""); + + puts (_("\ +Translate Texinfo source documentation to various other formats, by default\n\ +Info files suitable for reading online with Emacs or standalone GNU Info.\n")); + + printf (_("\ +General options:\n\ + --error-limit=NUM quit after NUM errors (default %d).\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\ + --reference-limit=NUM warn about at most NUM references (default %d).\n\ + -v, --verbose explain what is being done.\n\ + --version display version information and exit.\n"), + max_error_level, reference_warning_limit); + puts (""); + + /* xgettext: no-wrap */ + puts (_("\ +Output format selection (default is to produce Info):\n\ + --docbook output Docbook XML rather than Info.\n\ + --html output HTML rather than Info.\n\ + --xml output Texinfo XML rather than Info.\n\ + --plaintext output plain text rather than Info.\n\ +")); + + puts (_("\ +General output options:\n\ + -E, --macro-expand FILE output macro-expanded source to FILE.\n\ + ignoring any @setfilename.\n\ + --no-headers suppress node separators, Node: lines, and menus\n\ + from Info output (thus producing plain text)\n\ + or from HTML (thus producing shorter output);\n\ + also, write to standard output by default.\n\ + --no-split suppress splitting of Info or HTML output,\n\ + generate only one output file.\n\ + --number-sections output chapter and sectioning numbers.\n\ + -o, --output=FILE output to FILE (directory if split HTML),\n\ +")); + + printf (_("\ +Options for Info and plain text:\n\ + --enable-encoding output accented and special characters in\n\ + Info output based on @documentencoding.\n\ + --fill-column=NUM break Info lines at NUM characters (default %d).\n\ + --footnote-style=STYLE output footnotes in Info according to STYLE:\n\ + `separate' to put them in their own node;\n\ + `end' to put them at the end of the node\n\ + in which they are defined (default).\n\ + --paragraph-indent=VAL indent Info paragraphs by VAL spaces (default %d).\n\ + If VAL is `none', do not indent; if VAL is\n\ + `asis', preserve existing indentation.\n\ + --split-size=NUM split Info files at size NUM (default %d).\n"), + fill_column, paragraph_start_indent, + DEFAULT_SPLIT_SIZE); + puts (""); + + puts (_("\ +Options for HTML:\n\ + --css-include=FILE include FILE in HTML <style> output;\n\ + read stdin if FILE is -.\n\ +")); + + printf (_("\ +Options for XML and Docbook:\n\ + --output-indent=VAL indent XML elements by VAL spaces (default %d).\n\ + If VAL is 0, ignorable whitespace is dropped.\n\ +"), xml_indentation_increment); + puts (""); + + puts (_("\ +Input file options:\n\ + --commands-in-node-names allow @ commands in node names.\n\ + -D VAR define the variable VAR, as with @set.\n\ + -I DIR append DIR to the @include search path.\n\ + -P DIR prepend DIR to the @include search path.\n\ + -U VAR undefine the variable VAR, as with @clear.\n\ +")); + + puts (_("\ +Conditional processing in input:\n\ + --ifdocbook process @ifdocbook and @docbook even if\n\ + not generating Docbook.\n\ + --ifhtml process @ifhtml and @html even if not generating HTML.\n\ + --ifinfo process @ifinfo even if not generating Info.\n\ + --ifplaintext process @ifplaintext even if not generating plain text.\n\ + --iftex process @iftex and @tex; implies --no-split.\n\ + --ifxml process @ifxml and @xml.\n\ + --no-ifdocbook do not process @ifdocbook and @docbook text.\n\ + --no-ifhtml do not process @ifhtml and @html text.\n\ + --no-ifinfo do not process @ifinfo text.\n\ + --no-ifplaintext do not process @ifplaintext text.\n\ + --no-iftex do not process @iftex and @tex text.\n\ + --no-ifxml do not process @ifxml and @xml text.\n\ +\n\ + Also, for the --no-ifFORMAT options, do process @ifnotFORMAT text.\n\ +")); + + puts (_("\ + 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, --ifinfo is on and the others are off;\n\ + if generating plain text, --ifplaintext is on and the others are off;\n\ + if generating XML, --ifxml is on and the others are off.\n\ +")); + + fputs (_("\ +Examples:\n\ + makeinfo foo.texi write Info to foo's @setfilename\n\ + makeinfo --html foo.texi write HTML to @setfilename\n\ + makeinfo --xml foo.texi write Texinfo XML to @setfilename\n\ + makeinfo --docbook foo.texi write DocBook XML to @setfilename\n\ + makeinfo --no-headers foo.texi write plain text to standard output\n\ +\n\ + makeinfo --html --no-headers foo.texi write html without node lines, menus\n\ + makeinfo --number-sections foo.texi write Info with numbered sections\n\ + makeinfo --no-split foo.texi write one Info file however big\n\ +"), stdout); + + puts (_("\n\ +Email bug reports to bug-texinfo@gnu.org,\n\ +general questions and discussion to help-texinfo@gnu.org.\n\ +Texinfo home page: http://www.gnu.org/software/texinfo/")); + + } /* end of full help */ + + xexit (exit_value); +} + +struct option long_options[] = +{ + { "commands-in-node-names", 0, &expensive_validation, 1 }, + { "css-include", 1, 0, 'C' }, + { "docbook", 0, 0, 'd' }, + { "enable-encoding", 0, &enable_encoding, 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' }, + { "ifdocbook", 0, &process_docbook, 1 }, + { "ifhtml", 0, &process_html, 1 }, + { "ifinfo", 0, &process_info, 1 }, + { "ifplaintext", 0, &process_plaintext, 1 }, + { "iftex", 0, &process_tex, 1 }, + { "ifxml", 0, &process_xml, 1 }, + { "macro-expand", 1, 0, 'E' }, + { "no-headers", 0, &no_headers, 1 }, + { "no-ifdocbook", 0, &process_docbook, 0 }, + { "no-ifhtml", 0, &process_html, 0 }, + { "no-ifinfo", 0, &process_info, 0 }, + { "no-ifplaintext", 0, &process_plaintext, 0 }, + { "no-iftex", 0, &process_tex, 0 }, + { "no-ifxml", 0, &process_xml, 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' }, + { "output-indent", 1, 0, 'i' }, + { "paragraph-indent", 1, 0, 'p' }, + { "plaintext", 0, 0, 't' }, + { "reference-limit", 1, 0, 'r' }, + { "split-size", 1, 0, 'S'}, + { "verbose", 0, &verbose_mode, 1 }, + { "version", 0, 0, 'V' }, + { "xml", 0, 0, 'x' }, + {NULL, 0, NULL, 0} +}; + +/* We use handle_variable_internal for -D and -U, and it depends on + execute_string, which depends on input_filename, which is not defined + while we are handling options. :-\ So we save these defines in this + struct, and handle them later. */ +typedef struct command_line_define +{ + struct command_line_define *next; + int action; + char *define; +} COMMAND_LINE_DEFINE; + +static COMMAND_LINE_DEFINE *command_line_defines = NULL; + +/* For each file mentioned in the command line, process it, turning + Texinfo commands into wonderfully formatted output text. */ +int +main (int argc, char **argv) +{ + int c, ind; + int reading_from_stdin = 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, ""); +#ifdef LC_MESSAGES /* ultrix */ + setlocale (LC_MESSAGES, ""); +#endif + setlocale (LC_CTYPE, ""); + setlocale (LC_COLLATE, ""); +#endif + +#ifdef ENABLE_NLS + /* Set the text message domain. */ + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); +#endif + + /* If TEXINFO_OUTPUT_FORMAT envvar is set, use it to set default output. + Can be overridden with one of the output options. */ + if (getenv ("TEXINFO_OUTPUT_FORMAT") != NULL) + { + if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "docbook")) + { + splitting = 0; + html = 0; + docbook = 1; + xml = 1; + process_docbook = 1; + } + else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "html")) + { + html = 1; + docbook = 0; + xml = 0; + process_html = 1; + } + else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "info")) + { + html = 0; + docbook = 0; + xml = 0; + } + else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "plaintext")) + { + splitting = 0; + no_headers = 1; + html = 0; + docbook = 0; + xml = 0; + process_plaintext = 1; + } + else if (STREQ (getenv ("TEXINFO_OUTPUT_FORMAT"), "xml")) + { + splitting = 0; + html = 0; + docbook = 0; + xml = 1; + process_xml = 1; + } + else + fprintf (stderr, + _("%s: Ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'.\n"), + progname, getenv ("TEXINFO_OUTPUT_FORMAT")); + } + + /* Parse argument flags from the input line. */ + while ((c = getopt_long (argc, argv, "D:de:E:f:hI:i:o:p:P:r:s:t:U:vV:wx", + long_options, &ind)) != EOF) + { + if (c == 0 && long_options[ind].flag == 0) + c = long_options[ind].val; + + switch (c) + { + case 'C': /* --css-include */ + css_include = xstrdup (optarg); + break; + + case 'D': + case 'U': + /* User specified variable to set or clear. */ + if (xml && !docbook) + { + COMMAND_LINE_DEFINE *new = xmalloc (sizeof (COMMAND_LINE_DEFINE)); + new->action = (c == 'D') ? SET : CLEAR; + new->define = xstrdup (optarg); + new->next = command_line_defines; + command_line_defines = new; + } + else + handle_variable_internal ((c == 'D' ? SET : CLEAR), optarg); + break; + + case 'd': /* --docbook */ + splitting = 0; + xml = 1; + docbook = 1; + html = 0; + process_docbook = 1; + break; + + case 'e': /* --error-limit */ + if (sscanf (optarg, "%d", &max_error_level) != 1) + { + fprintf (stderr, + _("%s: %s arg must be numeric, not `%s'.\n"), + progname, "--error-limit", optarg); + usage (1); + } + break; + + case 'E': /* --macro-expand */ + if (!macro_expansion_output_stream) + { + macro_expansion_filename = optarg; + macro_expansion_output_stream + = strcmp (optarg, "-") == 0 ? stdout : fopen (optarg, "w"); + if (!macro_expansion_output_stream) + error (_("%s: could not open macro expansion output `%s'"), + progname, optarg); + } + else + fprintf (stderr, + _("%s: ignoring second macro expansion output `%s'.\n"), + progname, optarg); + break; + + case 'f': /* --fill-column */ + if (sscanf (optarg, "%d", &fill_column) != 1) + { + fprintf (stderr, + _("%s: %s arg must be numeric, not `%s'.\n"), + progname, "--fill-column", optarg); + usage (1); + } + break; + + case 'h': /* --help */ + usage (0); + break; + + case 'I': + /* Append user-specified dir to include file path. */ + append_to_include_path (optarg); + break; + + case 'i': + if (sscanf (optarg, "%d", &xml_indentation_increment) != 1) + { + fprintf (stderr, + _("%s: %s arg must be numeric, not `%s'.\n"), + progname, "--output-indent", optarg); + usage (1); + } + break; + + case 'o': /* --output */ + command_output_filename = xstrdup (optarg); + save_command_output_filename = command_output_filename; + break; + + case 'p': /* --paragraph-indent */ + if (set_paragraph_indent (optarg) < 0) + { + fprintf (stderr, + _("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"), + progname, optarg); + usage (1); + } + break; + + case 'P': + /* Prepend user-specified include dir to include path. */ + prepend_to_include_path (optarg); + break; + + case 'r': /* --reference-limit */ + if (sscanf (optarg, "%d", &reference_warning_limit) != 1) + { + fprintf (stderr, + _("%s: %s arg must be numeric, not `%s'.\n"), + progname, "--reference-limit", optarg); + usage (1); + } + break; + + case 's': /* --footnote-style */ + if (set_footnote_style (optarg) < 0) + { + fprintf (stderr, + _("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"), + progname, optarg); + usage (1); + } + footnote_style_preset = 1; + break; + + case 'S': /* --split-size */ + if (sscanf (optarg, "%d", &split_size) != 1) + { + fprintf (stderr, + _("%s: %s arg must be numeric, not `%s'.\n"), + progname, "--split-size", optarg); + usage (1); + } + break; + + case 't': /* --plaintext */ + splitting = 0; + no_headers = 1; + html = 0; + docbook = 0; + xml = 0; + process_plaintext = 1; + break; + + case 'v': + verbose_mode++; + break; + + case 'V': /* --version */ + print_version_info (); + puts (""); + puts ("Copyright (C) 2004 Free Software Foundation, Inc."); + printf (_("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")); + xexit (0); + break; + + case 'w': /* --html */ + xml = 0; + docbook = 0; + html = 1; + process_html = 1; + break; + + case 'x': /* --xml */ + splitting = 0; + html = 0; + docbook = 0; + xml = 1; + process_xml = 1; + break; + + case '?': + usage (1); + break; + } + } + + if (macro_expansion_output_stream) + validating = 0; + + if (!validating) + expensive_validation = 0; + + if (optind == argc) + { + /* Check to see if input is a file. If so, process that. */ + if (!isatty (fileno (stdin))) + reading_from_stdin = 1; + else + { + fprintf (stderr, _("%s: missing file argument.\n"), progname); + usage (1); + } + } + + if (no_headers) + { + /* If the user did not specify an output file, use stdout. */ + if (!command_output_filename) + command_output_filename = xstrdup ("-"); + + if (html && splitting && !STREQ (command_output_filename, "-")) + { /* --no-headers --no-split --html indicates confusion. */ + fprintf (stderr, + "%s: can't split --html output to `%s' with --no-headers.\n", + progname, command_output_filename); + usage (1); + } + + /* --no-headers implies --no-split. */ + splitting = 0; + } + + if (process_info == -1) + { /* no explicit --[no-]ifinfo option, so we'll do @ifinfo + if we're generating info or (for compatibility) plain text. */ + process_info = !html && !xml; + } + + if (process_plaintext == -1) + { /* no explicit --[no-]ifplaintext option, so we'll do @ifplaintext + if we're generating plain text. */ + process_plaintext = no_headers && !html && !xml; + } + + if (verbose_mode) + print_version_info (); + + /* Remaining arguments are file names of texinfo files. + Convert them, one by one. */ + if (!reading_from_stdin) + { + while (optind != argc) + convert_from_file (argv[optind++]); + } + else + convert_from_stream (stdin, "stdin"); + + xexit (errors_printed ? 2 : 0); + return 0; /* Avoid bogus warnings. */ +} + +/* Hacking tokens and strings. */ + +/* Return the next token as a string pointer. We cons the string. This + `token' means simply a command name. */ + +/* = is so @alias works. ^ and _ are so macros can be used in math mode + without a space following. Possibly we should simply allow alpha, to + be compatible with TeX. */ +#define COMMAND_CHAR(c) (!cr_or_whitespace(c) \ + && (c) != '{' \ + && (c) != '}' \ + && (c) != '=' \ + && (c) != '_' \ + && (c) != '^' \ + ) + +static char * +read_token (void) +{ + int i, character; + char *result; + + /* If the first character to be read is self-delimiting, then that + is the command itself. */ + character = curchar (); + if (self_delimiting (character)) + { + input_text_offset++; + + if (character == '\n') + line_number++; + + result = xstrdup (" "); + *result = character; + return result; + } + + for (i = 0; ((input_text_offset != input_text_length) + && (character = curchar ()) + && COMMAND_CHAR (character)); + i++, input_text_offset++); + result = xmalloc (i + 1); + memcpy (result, &input_text[input_text_offset - i], i); + result[i] = 0; + return result; +} + +/* Return nonzero if CHARACTER is self-delimiting. */ +int +self_delimiting (int character) +{ + /* @; and @\ are not Texinfo commands, but they are listed here + anyway. I don't know why. --karl, 10aug96. */ + return strchr ("~{|}`^\\@?=;:./-,*\'\" !\n\t", character) != NULL; +} + +/* Clear whitespace from the front and end of string. */ +void +canon_white (char *string) +{ + char *p = string; + unsigned len; + + if (!*p) + return; + + do + { + if (!cr_or_whitespace (*p)) + break; + ++p; + } + while (*p); + + len = strlen (p); + while (len && cr_or_whitespace (p[len-1])) + --len; + + if (p != string) + memmove (string, p, len); + + string[len] = 0; +} + +/* Bash STRING, replacing all whitespace with just one space. */ +void +fix_whitespace (char *string) +{ + char *temp = xmalloc (strlen (string) + 1); + int string_index = 0; + int temp_index = 0; + int c; + + canon_white (string); + + while (string[string_index]) + { + c = temp[temp_index++] = string[string_index++]; + + if (c == ' ' || c == '\n' || c == '\t') + { + temp[temp_index - 1] = ' '; + while ((c = string[string_index]) && (c == ' ' || + c == '\t' || + c == '\n')) + string_index++; + } + } + temp[temp_index] = 0; + strcpy (string, temp); + free (temp); +} + +/* Discard text until the desired string is found. The string is + included in the discarded text. */ +void +discard_until (char *string) +{ + int temp = search_forward (string, input_text_offset); + + int tt = (temp < 0) ? input_text_length : temp + strlen (string); + int from = input_text_offset; + + /* Find out what line we are on. */ + while (from != tt) + if (input_text[from++] == '\n') + line_number++; + + if (temp < 0) + { + /* not found, move current position to end of string */ + input_text_offset = input_text_length; + if (strcmp (string, "\n") != 0) + { /* Give a more descriptive feedback, if we are looking for ``@end '' + during macro execution. That means someone used a multiline + command as an argument to, say, @section ... style commands. */ + char *end_block = xmalloc (8); + sprintf (end_block, "\n%cend ", COMMAND_PREFIX); + if (executing_string && strstr (string, end_block)) + line_error (_("Multiline command %c%s used improperly"), + COMMAND_PREFIX, command); + else + line_error (_("Expected `%s'"), string); + free (end_block); + return; + } + } + else + /* found, move current position to after the found string */ + input_text_offset = temp + strlen (string); +} + +/* Read characters from the file until we are at MATCH. + Place the characters read into STRING. + On exit input_text_offset is after the match string. + Return the offset where the string starts. */ +int +get_until (char *match, char **string) +{ + int len, current_point, x, new_point, tem; + + current_point = x = input_text_offset; + new_point = search_forward (match, input_text_offset); + + if (new_point < 0) + new_point = input_text_length; + len = new_point - current_point; + + /* Keep track of which line number we are at. */ + tem = new_point + (strlen (match) - 1); + while (x != tem) + if (input_text[x++] == '\n') + line_number++; + + *string = xmalloc (len + 1); + + memcpy (*string, &input_text[current_point], len); + (*string)[len] = 0; + + /* Now leave input_text_offset in a consistent state. */ + input_text_offset = tem; + + 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 (int from, int *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; + + /* 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. 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 (int expand, char *match, char **string) +{ + int real_bottom = input_text_length; + int limit = search_forward ("\n", input_text_offset); + if (limit < 0) + limit = input_text_length; + + /* 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. */ + if (expand) + { + replace_with_expansion (input_text_offset, &limit); + } + + real_bottom = input_text_length; + input_text_length = limit; + get_until (match, string); + input_text_length = real_bottom; +} + +void +get_rest_of_line (int expand, char **string) +{ + xml_no_para ++; + 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... */ + { + line_number++; + input_text_offset++; + } + xml_no_para --; +} + +/* Backup the input pointer to the previous character, keeping track + of the current line number. */ +void +backup_input_pointer (void) +{ + if (input_text_offset) + { + input_text_offset--; + if (curchar () == '\n') + line_number--; + } +} + +/* Read characters from the file until we are at MATCH or closing brace. + Place the characters read into STRING. */ +void +get_until_in_braces (char *match, char **string) +{ + char *temp; + int i, brace = 0; + int match_len = strlen (match); + + for (i = input_text_offset; i < input_text_length; i++) + { + if (i < input_text_length - 1 && input_text[i] == '@') + { + i++; /* skip commands like @, and @{ */ + continue; + } + else if (input_text[i] == '{') + brace++; + else if (input_text[i] == '}') + { + brace--; + /* If looking for a brace, don't stop at the interior brace, + like after "baz" in "@foo{something @bar{baz} more}". */ + if (brace == 0) + continue; + } + else if (input_text[i] == '\n') + line_number++; + + if (brace < 0 || + (brace == 0 && strncmp (input_text + i, match, match_len) == 0)) + break; + } + + match_len = i - input_text_offset; + 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 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", + "", + NULL +}; + +static void +initialize_conversion (void) +{ + init_tag_table (); + init_indices (); + init_internals (); + init_paragraph (); + + /* This is used for splitting the output file and for doing section + headings. It was previously initialized in `init_paragraph', but its + use there loses with the `init_paragraph' calls done by the + multitable code; the tag indices get reset to zero. */ + output_position = 0; +} + +/* 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 (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) + +/* Convert the Texinfo file coming from the open stream STREAM. Assume the + source of the stream is named NAME. */ +static void +convert_from_stream (FILE *stream, char *name) +{ + char *buffer = NULL; + int buffer_offset = 0, buffer_size = 0; + + initialize_conversion (); + + /* Read until the end of the stream. This isn't strictly correct, since + the texinfo input may end before the stream ends, but it is a quick + working hueristic. */ + while (!feof (stream)) + { + int count; + + if (buffer_offset + (READ_BUFFER_GROWTH + 1) >= buffer_size) + buffer = (char *) + xrealloc (buffer, (buffer_size += READ_BUFFER_GROWTH)); + + count = fread (buffer + buffer_offset, 1, READ_BUFFER_GROWTH, stream); + + if (count < 0) + { + perror (name); + xexit (1); + } + + buffer_offset += count; + if (count == 0) + break; + } + + /* Set the globals to the new file. */ + input_text = buffer; + input_text_length = buffer_offset; + input_filename = xstrdup (name); + node_filename = xstrdup (name); + 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). + The INPUT_TEXT_LENGTH is one past the actual end of the text. */ + input_text[input_text_length] = '\n'; + + convert_from_loaded_file (name); +} + +static void +convert_from_file (char *name) +{ + int i; + char *filename = xmalloc (strlen (name) + 50); + + /* Prepend file directory to the search path, so relative links work. */ + prepend_to_include_path (pathname_part (name)); + + initialize_conversion (); + + /* Try to load the file specified by NAME, concatenated with our + various suffixes. Prefer files like `makeinfo.texi' to + `makeinfo'. */ + for (i = 0; suffixes[i]; i++) + { + strcpy (filename, name); + strcat (filename, suffixes[i]); + + if (find_and_load (filename, 1)) + break; + + if (!suffixes[i][0] && strrchr (filename, '.')) + { + fs_error (filename); + free (filename); + return; + } + } + + if (!suffixes[i]) + { + fs_error (name); + free (filename); + return; + } + + input_filename = filename; + + convert_from_loaded_file (name); + + /* Pop the prepended path, so multiple filenames in the + command line do not screw each others include paths. */ + pop_path_from_include_path (); +} + +static int +create_html_directory (char *dir, int can_remove_file) +{ + struct stat st; + + /* Already exists. */ + if (stat (dir, &st) == 0) + { + /* And it's a directory, so silently reuse it. */ + if (S_ISDIR (st.st_mode)) + return 1; + /* Not a directory, so move it out of the way if we are allowed. */ + else if (can_remove_file) + { + if (unlink (dir) != 0) + return 0; + } + else + return 0; + } + + if (mkdir (dir, 0777) == 0) + /* Success! */ + return 1; + else + return 0; +} + +/* Given OUTPUT_FILENAME == ``/foo/bar/baz.html'', return + "/foo/bar/baz/baz.html". This routine is called only if html && splitting. + + Split html output goes into the subdirectory of the toplevel + filename, without extension. For example: + @setfilename foo.info + produces output in files foo/index.html, foo/second-node.html, ... + + But if the user said -o foo.whatever on the cmd line, then use + foo.whatever unchanged. */ + +static char * +insert_toplevel_subdirectory (char *output_filename) +{ + static const char index_name[] = "index.html"; + char *dir, *subdir, *base, *basename, *p; + char buf[PATH_MAX]; + const int index_len = sizeof (index_name) - 1; + + strcpy (buf, output_filename); + dir = pathname_part (buf); /* directory of output_filename */ + base = filename_part (buf); /* strips suffix, too */ + basename = xstrdup (base); /* remember real @setfilename name */ + p = dir + strlen (dir) - 1; + if (p > dir && IS_SLASH (*p)) + *p = 0; + p = strrchr (base, '.'); + if (p) + *p = 0; + + /* Split html output goes into subdirectory of toplevel name. */ + if (save_command_output_filename + && STREQ (output_filename, save_command_output_filename)) + subdir = basename; /* from user, use unchanged */ + else + subdir = base; /* implicit, omit suffix */ + + free (output_filename); + output_filename = xmalloc (strlen (dir) + 1 + + strlen (basename) + 1 + + index_len + + 1); + strcpy (output_filename, dir); + if (strlen (dir)) + strcat (output_filename, "/"); + strcat (output_filename, subdir); + + /* First try, do not remove existing file. */ + if (!create_html_directory (output_filename, 0)) + { + /* That failed, try subdir name with .html. + Remove it if it exists. */ + strcpy (output_filename, dir); + if (strlen (dir)) + strcat (output_filename, "/"); + strcat (output_filename, basename); + + if (!create_html_directory (output_filename, 1)) + { + /* Last try failed too :-\ */ + line_error (_("Can't create directory `%s': %s"), + output_filename, strerror (errno)); + xexit (1); + } + } + + strcat (output_filename, "/"); + strcat (output_filename, index_name); + return output_filename; +} + +/* FIXME: this is way too hairy */ +static void +convert_from_loaded_file (char *name) +{ + char *real_output_filename = NULL; + + remember_itext (input_text, 0); + + 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. */ + 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')) + break; + else if (input_text_offset > 0) + input_text_offset++; + } + + if (input_text_offset < 0) + { + if (!command_output_filename) + { +#if defined (REQUIRE_SETFILENAME) + error (_("No `%s' found in `%s'"), setfilename_search, name); + goto finished; +#else + 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); /* read rest of line */ + if (html || xml) + { /* Change any extension to .html or .xml. */ + 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 ? ".html" : ".xml"); + + /* Replace name from @setfilename with the html name. */ + free (output_filename); + output_filename = html_name; + } + } + else + { + if (input_text_offset != -1) + discard_until ("\n"); + else + input_text_offset = 0; + + real_output_filename = output_filename = command_output_filename; + command_output_filename = NULL; /* for included files or whatever */ + } + + canon_white (output_filename); + toplevel_output_filename = xstrdup (output_filename); + + if (real_output_filename && strcmp (real_output_filename, "-") == 0) + { + if (macro_expansion_filename + && strcmp (macro_expansion_filename, "-") == 0) + { + fprintf (stderr, + _("%s: Skipping macro expansion to stdout as Info output is going there.\n"), + progname); + macro_expansion_output_stream = NULL; + } + real_output_filename = xstrdup (real_output_filename); + output_stream = stdout; + splitting = 0; /* Cannot split when writing to stdout. */ + } + else + { + if (html && splitting) + { + if (FILENAME_CMP (output_filename, NULL_DEVICE) == 0 + || FILENAME_CMP (output_filename, ALSO_NULL_DEVICE) == 0) + splitting = 0; + else + output_filename = insert_toplevel_subdirectory (output_filename); + real_output_filename = xstrdup (output_filename); + } + else if (!real_output_filename) + real_output_filename = expand_filename (output_filename, name); + else + real_output_filename = xstrdup (real_output_filename); + + output_stream = fopen (real_output_filename, "w"); + } + + set_current_output_filename (real_output_filename); + + if (xml && !docbook) + xml_begin_document (filename_part (output_filename)); + + if (verbose_mode) + printf (_("Making %s file `%s' from `%s'.\n"), + no_headers ? "text" + : html ? "HTML" + : xml ? "XML" + : "info", + output_filename, input_filename); + + if (output_stream == NULL) + { + fs_error (real_output_filename); + goto finished; + } + + /* Make the displayable filename from output_filename. Only the base + portion of the filename need be displayed. */ + flush_output (); /* in case there was no @bye */ + if (output_stream != stdout) + pretty_output_filename = filename_part (output_filename); + else + pretty_output_filename = xstrdup ("stdout"); + + /* For this file only, count the number of newlines from the top of + the file to here. This way, we keep track of line numbers for + error reporting. Line_number starts at 1, since the user isn't + zero-based. */ + { + int temp = 0; + line_number = 1; + while (temp != input_text_offset) + if (input_text[temp++] == '\n') + line_number++; + } + + /* html fixxme: should output this as trailer on first page. */ + if (!no_headers && !html && !xml) + add_word_args (_("This is %s, produced by makeinfo version %s from %s.\n"), + output_filename, VERSION, input_filename); + + close_paragraph (); + + if (xml && !docbook) + { + /* Just before the real main loop, let's handle the defines. */ + COMMAND_LINE_DEFINE *temp; + + for (temp = command_line_defines; temp; temp = temp->next) + { + handle_variable_internal (temp->action, temp->define); + free(temp->define); + } + } + + reader_loop (); + if (xml) + xml_end_document (); + + +finished: + discard_insertions (0); + close_paragraph (); + flush_file_stack (); + + if (macro_expansion_output_stream) + { + fclose (macro_expansion_output_stream); + if (errors_printed && !force + && strcmp (macro_expansion_filename, "-") != 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); + if (unlink (macro_expansion_filename) < 0) + perror (macro_expansion_filename); + } + } + + if (output_stream) + { + output_pending_notes (); + + if (html) + { + no_indent = 1; + start_paragraph (); + add_word ("</body></html>\n"); + close_paragraph (); + } + + /* maybe we want local variables in info output. */ + { + char *trailer = info_trailer (); + if (!xml && !docbook && trailer) + { + if (html) + insert_string ("<!--"); + insert_string (trailer); + free (trailer); + if (html) + insert_string ("\n-->\n"); + } + } + + /* Write stuff makeinfo generates after @bye, ie. info_trailer. */ + flush_output (); + + if (output_stream != stdout) + fclose (output_stream); + + /* If validating, then validate the entire file right now. */ + if (validating) + validate_file (tag_table); + + handle_delayed_writes (); + + if (tag_table) + { + tag_table = (TAG_ENTRY *) reverse_list ((GENERIC_LIST *) tag_table); + if (!no_headers && !html && !STREQ (current_output_filename, "-")) + write_tag_table (real_output_filename); + } + + if (splitting && !html && (!errors_printed || force)) + { + clean_old_split_files (real_output_filename); + split_file (real_output_filename, split_size); + } + else if (errors_printed + && !force + && strcmp (real_output_filename, "-") != 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); + if (unlink (real_output_filename) < 0) + perror (real_output_filename); + } + } + free (real_output_filename); +} + +/* If enable_encoding is set and @documentencoding is used, return a + Local Variables section (as a malloc-ed string) so that Emacs' + locale features can work. Else return NULL. */ +char * +info_trailer (void) +{ + char *encoding; + + if (!enable_encoding) + return NULL; + + encoding = current_document_encoding (); + + if (encoding && *encoding) + { +#define LV_FMT "\n\037\nLocal Variables:\ncoding: %s\nEnd:\n" + char *lv = xmalloc (sizeof (LV_FMT) + strlen (encoding)); + sprintf (lv, LV_FMT, encoding); + free (encoding); + return lv; + } + + free (encoding); + return NULL; +} + +void +free_and_clear (char **pointer) +{ + if (*pointer) + { + free (*pointer); + *pointer = NULL; + } +} + + /* Initialize some state. */ +static void +init_internals (void) +{ + free_and_clear (&output_filename); + 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 */ + command_index = 0; + in_menu = 0; + in_detailmenu = 0; + top_node_seen = 0; + non_top_node_seen = 0; + node_number = -1; +} + +void +init_paragraph (void) +{ + free (output_paragraph); + 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. */ + +static void +handle_menu_entry (void) +{ + 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); + + 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; + + discard_until ("* "); + + /* The line number was already incremented in reader_loop when we + saw the newline, and discard_until has now incremented again. */ + line_number--; + + if (had_menu_commentary) + { + add_html_block_elt ("<ul class=\"menu\">\n"); + had_menu_commentary = 0; + in_paragraph = 0; + } + + if (in_paragraph) + { + add_html_block_elt ("</p>\n"); + add_html_block_elt ("<ul class=\"menu\">\n"); + in_paragraph = 0; + } + + in_menu_item = 1; + + add_html_block_elt ("<li><a"); + if (next_menu_item_number <= 9) + { + add_word(" accesskey="); + add_word_args("\"%d\"", next_menu_item_number); + next_menu_item_number++; + } + add_word (" href=\""); + string = expansion (tem, 0); + add_anchor_name (string, 1); + add_word ("\">"); + free (string); + + /* 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); + + add_word ("</a>"); + + 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 */ + + /* Insert a colon only if there is a description of this menu item. */ + { + int save_input_text_offset = input_text_offset; + int save_line_number = line_number; + char *test_string; + get_rest_of_line (0, &test_string); + if (strlen (test_string) > 0) + add_word (": "); + input_text_offset = save_input_text_offset; + line_number = save_line_number; + } + } + else if (xml && tem) + { + xml_start_menu_entry (tem); + } + 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 (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 (char *string) +{ + int i; + + for (i = 0; command_table[i].name; i++) + if (strcmp (command_table[i].name, string) == 0) + 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]; + + /* We never heard of this command. */ + return (COMMAND *) -1; +} + +/* input_text_offset is right at the command prefix character. + 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 (void) +{ + COMMAND *entry; + int old_text_offset = input_text_offset++; + + free_and_clear (&command); + command = read_token (); + + /* Check to see if this command is a macro. If so, execute it here. */ + { + MACRO_DEF *def; + + def = find_macro (command); + + if (def) + { + /* We disallow recursive use of a macro call. Inhibit the expansion + of this macro during the life of its execution. */ + if (!(def->flags & ME_RECURSE)) + def->inhibited = 1; + + executing_macro++; + execute_macro (def); + executing_macro--; + + if (!(def->flags & ME_RECURSE)) + def->inhibited = 0; + + return 1; + } + } + + 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 0; + } + + 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; +} + +/* 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 (void) +{ + int character; + int done = 0; + + 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 + && ((!html && !xml) || escape_html) + && (character == '\'' || character == '`') + && input_text[input_text_offset + 1] == character) + { + if (html) + { + input_text_offset += 2; + add_word (character == '`' ? "“" : "”"); + continue; + } + else if (xml) + { + input_text_offset += 2; + xml_insert_entity (character == '`' ? "ldquo" : "rdquo"); + continue; + } + else + { + input_text_offset++; + character = '"'; + } + } + + /* Convert --- to --. */ + if (!only_macro_expansion && character == '-' && !in_fixed_width_font + && ((!html && !xml) || escape_html)) + { + int dash_count = 0; + + /* Get the number of consequtive dashes. */ + while (input_text[input_text_offset] == '-') + { + dash_count++; + input_text_offset++; + } + + /* Eat one dash. */ + dash_count--; + + if (html || xml) + { + if (dash_count == 0) + add_char ('-'); + else + while (dash_count > 0) + { + if (dash_count >= 2) + { + if (html) + add_word ("—"); + else + xml_insert_entity ("mdash"); + dash_count -= 2; + } + else if (dash_count >= 1) + { + if (html) + add_word ("–"); + else + xml_insert_entity ("ndash"); + dash_count--; + } + } + } + else + { + add_char ('-'); + while (--dash_count > 0) + add_char ('-'); + } + + continue; + } + + /* 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 ("&"); + else + add_char (character); + input_text_offset++; + break; + + case '<': + if (html && escape_html) + add_word ("<"); + else if (xml && escape_html) + xml_insert_entity ("lt"); + else + add_char (character); + input_text_offset++; + break; + + case '>': + if (html && escape_html) + add_word (">"); + else if (xml && escape_html) + xml_insert_entity ("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) + { + if (command && !STREQ (command, "math")) + { + line_error (_("Misplaced %c"), '{'); + remember_brace (misplaced_brace); + } + else + /* We don't mind `extra' braces inside @math. */ + remember_brace (cm_no_op); + /* 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); +} + +static void +init_brace_stack (void) +{ + brace_stack = NULL; +} + +/* Remember the current output position here. Save PROC + along with it so you can call it later. */ +static void +remember_brace_1 (COMMAND_FUNCTION (*proc), int position) +{ + BRACE_ELEMENT *new = xmalloc (sizeof (BRACE_ELEMENT)); + new->next = brace_stack; + new->proc = proc; + new->command = command ? xstrdup (command) : ""; + new->pos = position; + new->line = line_number; + new->in_fixed_width_font = in_fixed_width_font; + brace_stack = new; +} + +static void +remember_brace (COMMAND_FUNCTION (*proc)) +{ + if (curchar () != '{') + line_error (_("%c%s expected braces"), COMMAND_PREFIX, command); + else + input_text_offset++; + remember_brace_1 (proc, output_paragraph_offset); +} + +/* Pop the top of the brace stack, and call the associated function + with the args END and POS. */ +static void +pop_and_call_brace (void) +{ + if (brace_stack == NULL) + { + line_error (_("Unmatched }")); + return; + } + + { + 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; + + 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. */ +static void +adjust_braces_following (int here, int amount) +{ + BRACE_ELEMENT *stack = brace_stack; + + while (stack) + { + if (stack->pos >= here) + stack->pos += amount; + stack = stack->next; + } +} + +/* 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 const char * +find_proc_name (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 + I only detect it at the beginning of nodes. */ +void +discard_braces (void) +{ + if (!brace_stack) + return; + + while (brace_stack) + { + if (brace_stack->proc != misplaced_brace) + { + const char *proc_name; + + proc_name = find_proc_name (brace_stack->proc); + file_line_error (input_filename, brace_stack->line, + _("%c%s missing close brace"), COMMAND_PREFIX, + proc_name); + pop_and_call_brace (); + } + else + { + BRACE_ELEMENT *temp; + temp = brace_stack->next; + free (brace_stack); + brace_stack = temp; + } + } +} + +static int +get_char_len (int character) +{ + /* Return the printed length of the character. */ + int len; + + switch (character) + { + case '\t': + len = (output_column + 8) & 0xf7; + if (len > fill_column) + len = fill_column - output_column; + else + len = len - output_column; + break; + + case '\n': + len = fill_column - output_column; + break; + + default: + /* ASCII control characters appear as two characters in the output + (e.g., ^A). But characters with the high bit set are just one + on suitable terminals, so don't count them as two for line + breaking purposes. */ + if (0 <= character && character < ' ') + len = 2; + else + len = 1; + } + return len; +} + +void +#if defined (VA_FPRINTF) && __STDC__ +add_word_args (const char *format, ...) +#else +add_word_args (format, va_alist) + const char *format; + va_dcl +#endif +{ + char buffer[2000]; /* xx no fixed limits */ +#ifdef VA_FPRINTF + va_list ap; +#endif + + VA_START (ap, format); +#ifdef VA_SPRINTF + VA_SPRINTF (buffer, format, ap); +#else + sprintf (buffer, format, a1, a2, a3, a4, a5, a6, a7, a8); +#endif /* not VA_SPRINTF */ + va_end (ap); + add_word (buffer); +} + +/* Add STRING to output_paragraph. */ +void +add_word (char *string) +{ + while (*string) + add_char (*string++); +} + +/* Like add_word, but inhibits conversion of whitespace into . + Use this to output HTML directives with embedded blanks, to make + them @w-safe. */ +void +add_html_elt (char *string) +{ + in_html_elt++; + add_word (string); + in_html_elt--; +} + +/* These two functions below, add_html_block_elt and add_html_block_elt_args, + are mixtures of add_html_elt and add_word_args. They inform makeinfo that + the current HTML element being inserted should not be enclosed in a <p> + element. */ +void +add_html_block_elt (char *string) +{ + in_html_block_level_elt++; + add_word (string); + in_html_block_level_elt--; +} + +void +#if defined (VA_FPRINTF) && __STDC__ +add_html_block_elt_args (const char *format, ...) +#else +add_html_block_elt_args (format, va_alist) + const char *format; + va_dcl +#endif +{ + char buffer[2000]; /* xx no fixed limits */ +#ifdef VA_FPRINTF + va_list ap; +#endif + + VA_START (ap, format); +#ifdef VA_SPRINTF + VA_SPRINTF (buffer, format, ap); +#else + sprintf (buffer, format, a1, a2, a3, a4, a5, a6, a7, a8); +#endif /* not VA_SPRINTF */ + va_end (ap); + add_html_block_elt (buffer); +} + +/* Here is another awful kludge, used in add_char. Ordinarily, macro + expansions take place in the body of the document, and therefore we + should html_output_head when we see one. But there's an exception: a + macro call might take place within @copying, and that does not start + the real output, even though we fully expand the copying text. + + So we need to be able to check if we are defining the @copying text. + We do this by looking back through the insertion stack. */ +static int +defining_copying (void) +{ + INSERTION_ELT *i; + for (i = insertion_stack; i; i = i->next) + { + if (i->insertion == copying) + return 1; + } + return 0; +} + + +/* Add the character to the current paragraph. If filling_enabled is + nonzero, then do filling as well. */ +void +add_char (int character) +{ + if (xml) + { + xml_add_char (character); + return; + } + + /* If we are avoiding outputting headers, and we are currently + 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 + ignore close_paragraph () calls any more. */ + if (must_start_paragraph && character != '\n') + { + must_start_paragraph = 0; + line_already_broken = 0; /* The line is no longer broken. */ + if (current_indent > output_column) + { + indent (current_indent - output_column); + output_column = current_indent; + } + } + + if (non_splitting_words + && !(html && in_html_elt) + && strchr (" \t\n", character)) + { + if (html || docbook) + { /* Seems cleaner to use than an 8-bit char. */ + int saved_escape_html = escape_html; + escape_html = 0; + add_word (" "); + escape_html = saved_escape_html; + character = ';'; + } + else + character = META (' '); /* unmeta-d in flush_output */ + } + + insertion_paragraph_closed = 0; + + switch (character) + { + case '\n': + if (!filling_enabled && !(html && (in_menu || in_detailmenu))) + { + insert ('\n'); + + if (force_flush_right) + { + close_paragraph (); + /* Hack to force single blank lines out in this mode. */ + flush_output (); + } + + output_column = 0; + + if (!no_indent && paragraph_is_open) + indent (output_column = current_indent); + break; + } + else if (end_of_sentence_p ()) + /* CHARACTER is newline, and filling is enabled. */ + { + 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; + if (html) + insert ('\n'); + else + insert (' '); + output_column++; + } + break; + + default: /* not at newline */ + { + int len = get_char_len (character); + int suppress_insert = 0; + + if ((character == ' ') && (last_char_was_newline)) + { + if (!paragraph_is_open) + { + pending_indent++; + return; + } + } + + /* 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_macro || !executing_string) + && !only_macro_expansion + && html && !html_output_head_p && !defining_copying ()) + html_output_head (); + + 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 (!paragraph_start_indent) + indent (pending_indent); + pending_indent = 0; + + /* This check for in_html_block_level_elt prevents <p> from being + inserted when we already have html markup starting a paragraph, + as with <ul> and <h1> and the like. */ + if (html && !in_html_block_level_elt) + { + if ((in_menu || in_detailmenu) && in_menu_item) + { + insert_string ("</li></ul>\n"); + in_menu_item = 0; + } + insert_string ("<p>"); + in_paragraph = 1; + adjust_braces_following (0, 3); /* adjust for <p> */ + } + } + + output_column += len; + if (output_column > fill_column) + { + if (filling_enabled && !html) + { + int temp = output_paragraph_offset; + while (--temp > 0 && output_paragraph[temp] != '\n') + { + /* If we have found a space, we have the place to break + the line. */ + if (output_paragraph[temp] == ' ') + { + /* Remove trailing whitespace from output. */ + while (temp && whitespace (output_paragraph[temp - 1])) + temp--; + + /* 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 + we have decided to break the line. We get rid of + them. */ + { + int t1 = temp; + + for (;; t1++) + { + if (t1 == output_paragraph_offset) + { + if (whitespace (character)) + suppress_insert = 1; + break; + } + if (!whitespace (output_paragraph[t1])) + break; + } + + if (t1 != temp) + { + adjust_braces_following (temp, (- (t1 - temp))); + memmove (&output_paragraph[temp], + &output_paragraph[t1], + output_paragraph_offset - t1); + output_paragraph_offset -= (t1 - temp); + } + } + + /* Filled, but now indent if that is right. */ + if (indented_fill && current_indent > 0) + { + int buffer_len = ((output_paragraph_offset - temp) + + current_indent); + char *temp_buffer = xmalloc (buffer_len); + int indentation = 0; + + /* We have to shift any markers that are in + front of the wrap point. */ + adjust_braces_following (temp, current_indent); + + while (current_indent > 0 && + indentation != current_indent) + temp_buffer[indentation++] = ' '; + + memcpy ((char *) &temp_buffer[current_indent], + (char *) &output_paragraph[temp], + buffer_len - current_indent); + + if (output_paragraph_offset + buffer_len + >= paragraph_buffer_len) + { + unsigned char *tt = xrealloc + (output_paragraph, + (paragraph_buffer_len += buffer_len)); + output_paragraph = tt; + } + memcpy ((char *) &output_paragraph[temp], + temp_buffer, buffer_len); + output_paragraph_offset += current_indent; + free (temp_buffer); + } + output_column = 0; + while (temp < output_paragraph_offset) + output_column += + get_char_len (output_paragraph[temp++]); + output_column += len; + break; + } + } + } + } + + if (!suppress_insert) + { + insert (character); + last_inserted_character = character; + } + last_char_was_newline = 0; + line_already_broken = 0; + } + } +} + +/* Add a character and store its position in meta_char_pos. */ +void +add_meta_char (int character) +{ + meta_char_pos = output_paragraph_offset; + add_char (character); +} + +/* Insert CHARACTER into `output_paragraph'. */ +void +insert (int character) +{ + /* We don't want to strip trailing whitespace in multitables. Otherwise + horizontal separators confuse the font locking in Info mode in Emacs, + because it looks like a @subsection. Adding a trailing space to those + lines fixes it. */ + if (character == '\n' && !html && !xml && !multitable_active) + { + while (output_paragraph_offset + && whitespace (output_paragraph[output_paragraph_offset-1])) + output_paragraph_offset--; + } + + output_paragraph[output_paragraph_offset++] = character; + if (output_paragraph_offset == paragraph_buffer_len) + { + output_paragraph = + xrealloc (output_paragraph, (paragraph_buffer_len += 100)); + } +} + +/* Insert the null-terminated string STRING into `output_paragraph'. */ +void +insert_string (const char *string) +{ + while (*string) + insert (*string++); +} + + +/* Sentences might have these characters after the period (or whatever). */ +#define POST_SENTENCE(c) ((c) == ')' || (c) == '\'' || (c) == '"' \ + || (c) == ']') + +/* Return true if at an end-of-sentence character, possibly followed by + post-sentence punctuation to ignore. */ +static int +end_of_sentence_p (void) +{ + int loc = output_paragraph_offset - 1; + + /* 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 loc != meta_char_pos && sentence_ender (output_paragraph[loc]); +} + + +/* Remove upto COUNT characters of whitespace from the + the current output line. If COUNT is less than zero, + then remove until none left. */ +void +kill_self_indent (int count) +{ + /* Handle infinite case first. */ + if (count < 0) + { + output_column = 0; + while (output_paragraph_offset) + { + if (whitespace (output_paragraph[output_paragraph_offset - 1])) + output_paragraph_offset--; + else + break; + } + } + else + { + while (output_paragraph_offset && count--) + if (whitespace (output_paragraph[output_paragraph_offset - 1])) + output_paragraph_offset--; + else + break; + } +} + +/* Nonzero means do not honor calls to flush_output (). */ +static int flushing_ignored = 0; + +/* Prevent calls to flush_output () from having any effect. */ +void +inhibit_output_flushing (void) +{ + flushing_ignored++; +} + +/* Allow calls to flush_output () to write the paragraph data. */ +void +uninhibit_output_flushing (void) +{ + flushing_ignored--; +} + +void +flush_output (void) +{ + int i; + + if (!output_paragraph_offset || flushing_ignored) + return; + + for (i = 0; i < output_paragraph_offset; i++) + { + if (output_paragraph[i] == '\n') + { + output_line_number++; + node_line_number++; + } + + /* 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 == ' ') + output_paragraph[i] &= 0x7f; + } + } + + fwrite (output_paragraph, 1, output_paragraph_offset, output_stream); + + output_position += output_paragraph_offset; + output_paragraph_offset = 0; + meta_char_pos = 0; +} + +/* How to close a paragraph controlling the number of lines between + this one and the last one. */ + +/* Paragraph spacing is controlled by this variable. It is the number of + blank lines that you wish to appear between paragraphs. A value of + 1 creates a single blank line between paragraphs. */ +int paragraph_spacing = DEFAULT_PARAGRAPH_SPACING; + +static void +close_paragraph_with_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 (void) +{ + close_paragraph_with_lines (0); +} + +/* Close a paragraph after an insertion has ended. */ +void +close_insertion_paragraph (void) +{ + if (!insertion_paragraph_closed) + { + /* Close the current paragraph, breaking the line. */ + close_single_paragraph (); + + /* Start a new paragraph, with the correct indentation for the now + current insertion level (one above the one that we are ending). */ + start_paragraph (); + + /* Tell `close_paragraph' that the previous line has already been + broken, so it should insert one less newline. */ + line_already_broken = 1; + + /* Tell functions such as `add_char' we've already found a newline. */ + ignore_blank_line (); + } + else + { + /* If the insertion paragraph is closed already, then we are seeing + two `@end' commands in a row. Note that the first one we saw was + handled in the first part of this if-then-else clause, and at that + time `start_paragraph' was called, partially to handle the proper + indentation of the current line. However, the indentation level + may have just changed again, so we may have to outdent the current + line to the new indentation level. */ + if (current_indent < output_column) + kill_self_indent (output_column - current_indent); + } + + insertion_paragraph_closed = 1; +} + +/* Close the currently open paragraph. */ +void +close_paragraph (void) +{ + int i; + + /* We don't need these newlines in XML and Docbook outputs for + paragraph seperation. We have <para> element for that. */ + if (xml) + return; + + /* The insertion paragraph is no longer closed. */ + insertion_paragraph_closed = 0; + + if (paragraph_is_open && !must_start_paragraph) + { + int tindex = output_paragraph_offset; + + /* Back up to last non-newline/space character, forcing all such + subsequent characters to be newlines. This isn't strictly + necessary, but a couple of functions use the presence of a newline + to make decisions. */ + for (tindex = output_paragraph_offset - 1; tindex >= 0; --tindex) + { + int c = output_paragraph[tindex]; + + if (c == ' '|| c == '\n') + output_paragraph[tindex] = '\n'; + else + break; + } + + /* All trailing whitespace is ignored. */ + output_paragraph_offset = ++tindex; + + /* Break the line if that is appropriate. */ + if (paragraph_spacing >= 0) + insert ('\n'); + + /* Add as many blank lines as is specified in `paragraph_spacing'. */ + if (!force_flush_right) + { + for (i = 0; i < (paragraph_spacing - line_already_broken); i++) + { + 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 + on the paragraph (really a single line). */ + if (force_flush_right) + do_flush_right_indentation (); + + flush_output (); + paragraph_is_open = 0; + no_indent = 0; + output_column = 0; + } + + ignore_blank_line (); +} + +/* Make the last line just read look as if it were only a newline. */ +void +ignore_blank_line (void) +{ + last_inserted_character = '\n'; + last_char_was_newline = 1; +} + +/* Align the end of the text in output_paragraph with fill_column. */ +static void +do_flush_right_indentation (void) +{ + char *temp; + int temp_len; + + kill_self_indent (-1); + + if (output_paragraph[0] != '\n') + { + output_paragraph[output_paragraph_offset] = 0; + + if (output_paragraph_offset < fill_column) + { + int i; + + if (fill_column >= paragraph_buffer_len) + output_paragraph = + xrealloc (output_paragraph, + (paragraph_buffer_len += fill_column)); + + temp_len = strlen ((char *)output_paragraph); + temp = xmalloc (temp_len + 1); + memcpy (temp, (char *)output_paragraph, temp_len); + + for (i = 0; i < fill_column - output_paragraph_offset; i++) + output_paragraph[i] = ' '; + + memcpy ((char *)output_paragraph + i, temp, temp_len); + free (temp); + output_paragraph_offset = fill_column; + adjust_braces_following (0, i); + } + } +} + +/* Begin a new paragraph. */ +void +start_paragraph (void) +{ + /* First close existing one. */ + if (paragraph_is_open) + close_paragraph (); + + /* In either case, the insertion paragraph is no longer closed. */ + insertion_paragraph_closed = 0; + + /* However, the paragraph is open! */ + paragraph_is_open = 1; + + /* If we MUST_START_PARAGRAPH, that simply means that start_paragraph () + had to be called before we would allow any other paragraph operations + to have an effect. */ + if (!must_start_paragraph) + { + int amount_to_indent = 0; + + /* If doing indentation, then insert the appropriate amount. */ + if (!no_indent) + { + if (inhibit_paragraph_indentation) + { + amount_to_indent = current_indent; + if (inhibit_paragraph_indentation < 0) + inhibit_paragraph_indentation++; + } + else if (paragraph_start_indent < 0) + amount_to_indent = current_indent; + else + amount_to_indent = current_indent + paragraph_start_indent; + + if (amount_to_indent >= output_column) + { + amount_to_indent -= output_column; + indent (amount_to_indent); + output_column += amount_to_indent; + } + } + } + else + must_start_paragraph = 0; +} + +/* Insert the indentation specified by AMOUNT. */ +void +indent (int amount) +{ + /* For every START_POS saved within the brace stack which will be affected + by this indentation, bump that start pos forward. */ + adjust_braces_following (output_paragraph_offset, amount); + + while (--amount >= 0) + insert (' '); +} + +/* Search forward for STRING in input_text. + FROM says where where to start. */ +int +search_forward (char *string, int from) +{ + int len = strlen (string); + + while (from < input_text_length) + { + if (strncmp (input_text + from, string, len) == 0) + return from; + from++; + } + return -1; +} + +/* search_forward until n characters. */ +int +search_forward_until_pos (char *string, int from, int end_pos) +{ + int save_input_text_length = input_text_length; + input_text_length = end_pos; + + from = search_forward (string, from); + + input_text_length = save_input_text_length; + + return from; +} + +/* Return next non-whitespace and non-cr character. */ +int +next_nonwhitespace_character (void) +{ + /* First check the current input_text. Start from the next char because + we already have input_text[input_text_offset] in ``current''. */ + int pos = input_text_offset + 1; + + while (pos < input_text_length) + { + if (!cr_or_whitespace(input_text[pos])) + return input_text[pos]; + pos++; + } + + { /* Can't find a valid character, so go through filestack + in case we are doing @include or expanding a macro. */ + FSTACK *tos = filestack; + + while (tos) + { + int tmp_input_text_length = filestack->size; + int tmp_input_text_offset = filestack->offset; + char *tmp_input_text = filestack->text; + + while (tmp_input_text_offset < tmp_input_text_length) + { + if (!cr_or_whitespace(tmp_input_text[tmp_input_text_offset])) + return tmp_input_text[tmp_input_text_offset]; + tmp_input_text_offset++; + } + + tos = tos->next; + } + } + + return -1; +} + +/* An external image is a reference, kind of. The parsing is (not + coincidentally) similar, anyway. */ +void +cm_image (int arg) +{ + char *name_arg, *w_arg, *h_arg, *alt_arg, *ext_arg; + + if (arg == END) + return; + + name_arg = get_xref_token (1); /* expands all macros in image */ + w_arg = get_xref_token (0); + h_arg = get_xref_token (0); + alt_arg = get_xref_token (1); /* expands all macros in alt text */ + ext_arg = get_xref_token (0); + + if (*name_arg) + { + struct stat file_info; + char *pathname = NULL; + char *fullname = xmalloc (strlen (name_arg) + + (ext_arg && *ext_arg ? strlen (ext_arg) + 1: 4) + 1); + + if (ext_arg && *ext_arg) + { + sprintf (fullname, "%s%s", name_arg, ext_arg); + if (access (fullname, R_OK) != 0) + pathname = get_file_info_in_path (fullname, include_files_path, + &file_info); + + if (pathname == NULL) + { + /* Backwards compatibility (4.6 <= version < 4.7): + try prefixing @image's EXTENSION parameter with a period. */ + sprintf (fullname, "%s.%s", name_arg, ext_arg); + if (access (fullname, R_OK) != 0) + pathname = get_file_info_in_path (fullname, include_files_path, + &file_info); + } + } + else + { + sprintf (fullname, "%s.png", name_arg); + if (access (fullname, R_OK) != 0) { + pathname = get_file_info_in_path (fullname, + include_files_path, &file_info); + if (pathname == NULL) { + sprintf (fullname, "%s.jpg", name_arg); + if (access (fullname, R_OK) != 0) { + sprintf (fullname, "%s.gif", name_arg); + if (access (fullname, R_OK) != 0) { + pathname = get_file_info_in_path (fullname, + include_files_path, &file_info); + } + } + } + } + } + + if (html) + { + int image_in_div = 0; + + if (pathname == NULL && access (fullname, R_OK) != 0) + { + line_error(_("@image file `%s' (for HTML) not readable: %s"), + fullname, strerror (errno)); + return; + } + if (pathname != NULL && access (pathname, R_OK) != 0) + { + line_error (_("No such file `%s'"), + fullname); + return; + } + + if (!paragraph_is_open) + { + add_html_block_elt ("<div class=\"block-image\">"); + image_in_div = 1; + } + + add_html_elt ("<img src="); + add_word_args ("\"%s\"", fullname); + add_html_elt (" alt="); + add_word_args ("\"%s\">", + escape_string (*alt_arg ? text_expansion (alt_arg) : fullname)); + + if (image_in_div) + add_html_block_elt ("</div>"); + } + else if (xml && docbook) + xml_insert_docbook_image (name_arg); + else if (xml) + { + extern int xml_in_para; + extern int xml_no_para; + int elt = xml_in_para ? INLINEIMAGE : IMAGE; + + if (!xml_in_para) + xml_no_para++; + + xml_insert_element_with_attribute (elt, + START, "width=\"%s\" height=\"%s\" name=\"%s\" extension=\"%s\"", + w_arg, h_arg, name_arg, ext_arg); + xml_insert_element (IMAGEALTTEXT, START); + execute_string ("%s", alt_arg); + xml_insert_element (IMAGEALTTEXT, END); + xml_insert_element (elt, END); + + if (!xml_in_para) + xml_no_para--; + } + else + { /* Try to open foo.EXT or foo.txt. */ + FILE *image_file; + char *txtpath = NULL; + char *txtname = xmalloc (strlen (name_arg) + + (ext_arg && *ext_arg + ? strlen (ext_arg) : 4) + 1); + strcpy (txtname, name_arg); + strcat (txtname, ".txt"); + image_file = fopen (txtname, "r"); + if (image_file == NULL) + { + txtpath = get_file_info_in_path (txtname, + include_files_path, &file_info); + if (txtpath != NULL) + image_file = fopen (txtpath, "r"); + } + + if (image_file != NULL + || access (fullname, R_OK) == 0 + || (pathname != NULL && access (pathname, R_OK) == 0)) + { + int ch; + int save_inhibit_indentation = inhibit_paragraph_indentation; + int save_filling_enabled = filling_enabled; + int image_in_brackets = paragraph_is_open; + + /* Write magic ^@^H[image ...^@^H] cookie in the info file, if + there's an accompanying bitmap. Otherwise just include the + text image. In the plaintext output, always include the text + image without the magic cookie. */ + int use_magic_cookie = !no_headers + && access (fullname, R_OK) == 0 && !STREQ (fullname, txtname); + + inhibit_paragraph_indentation = 1; + filling_enabled = 0; + last_char_was_newline = 0; + + if (use_magic_cookie) + { + add_char ('\0'); + add_word ("\010[image"); + + if (access (fullname, R_OK) == 0 + || (pathname != NULL && access (pathname, R_OK) == 0)) + add_word_args (" src=\"%s\"", fullname); + + if (*alt_arg) + add_word_args (" alt=\"%s\"", alt_arg); + } + + if (image_file != NULL) + { + if (use_magic_cookie) + add_word (" text=\""); + + if (image_in_brackets) + add_char ('['); + + /* 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) + { + if (use_magic_cookie && (ch == '"' || ch == '\\')) + add_char ('\\'); + add_char (ch); + } + + if (image_in_brackets) + add_char (']'); + + if (use_magic_cookie) + add_char ('"'); + + if (fclose (image_file) != 0) + perror (txtname); + } + + if (use_magic_cookie) + { + add_char ('\0'); + add_word ("\010]"); + } + + inhibit_paragraph_indentation = save_inhibit_indentation; + filling_enabled = save_filling_enabled; + } + else + warning (_("@image file `%s' (for text) unreadable: %s"), + txtname, strerror (errno)); + } + + free (fullname); + if (pathname) + free (pathname); + } + else + line_error (_("@image missing filename argument")); + + if (name_arg) + free (name_arg); + if (w_arg) + free (w_arg); + if (h_arg) + free (h_arg); + if (alt_arg) + free (alt_arg); + if (ext_arg) + free (ext_arg); +} + +/* Conditionals. */ + +/* A structure which contains `defined' variables. */ +typedef struct defines { + struct defines *next; + char *name; + char *value; +} DEFINE; + +/* The linked list of `set' defines. */ +DEFINE *defines = NULL; + +/* Add NAME to the list of `set' defines. */ +static void +set (char *name, char *value) +{ + DEFINE *temp; + + for (temp = defines; temp; temp = temp->next) + if (strcmp (name, temp->name) == 0) + { + free (temp->value); + temp->value = xstrdup (value); + return; + } + + temp = xmalloc (sizeof (DEFINE)); + temp->next = defines; + temp->name = xstrdup (name); + temp->value = xstrdup (value); + defines = temp; + + if (xml && !docbook) + { + xml_insert_element_with_attribute (SETVALUE, START, "name=\"%s\"", name); + execute_string ("%s", value); + xml_insert_element (SETVALUE, END); + } +} + +/* Remove NAME from the list of `set' defines. */ +static void +clear (char *name) +{ + DEFINE *temp, *last; + + last = NULL; + temp = defines; + + while (temp) + { + if (strcmp (temp->name, name) == 0) + { + if (last) + last->next = temp->next; + else + defines = temp->next; + + free (temp->name); + free (temp->value); + free (temp); + break; + } + last = temp; + temp = temp->next; + } + + if (xml && !docbook) + { + xml_insert_element_with_attribute (CLEARVALUE, START, "name=\"%s\"", name); + xml_insert_element (CLEARVALUE, END); + } +} + +/* Return the value of NAME. The return value is NULL if NAME is unset. */ +static char * +set_p (char *name) +{ + DEFINE *temp; + + for (temp = defines; temp; temp = temp->next) + if (strcmp (temp->name, name) == 0) + return temp->value; + + return NULL; +} + +/* Create a variable whose name appears as the first word on this line. */ +void +cm_set (void) +{ + handle_variable (SET); +} + +/* Remove a variable whose name appears as the first word on this line. */ +void +cm_clear (void) +{ + handle_variable (CLEAR); +} + +void +cm_ifset (void) +{ + handle_variable (IFSET); +} + +void +cm_ifclear (void) +{ + handle_variable (IFCLEAR); +} + +/* This command takes braces, but we parse the contents specially, so we + don't use the standard brace popping code. + + The syntax @ifeq{arg1, arg2, texinfo-commands} performs texinfo-commands + if ARG1 and ARG2 caselessly string compare to the same string, otherwise, + it produces no output. */ +void +cm_ifeq (void) +{ + char **arglist; + + arglist = get_brace_args (0); + + if (arglist) + { + if (array_len (arglist) > 1) + { + if ((strcasecmp (arglist[0], arglist[1]) == 0) && + (arglist[2])) + execute_string ("%s\n", arglist[2]); + } + + free_array (arglist); + } +} + +void +cm_value (int arg, int start_pos, int end_pos) +{ + static int value_level = 0, saved_meta_pos = -1; + + /* xml_add_char() skips any content inside menus when output format is + Docbook, so @value{} is no use there. Also start_pos and end_pos does not + get updated, causing name to be empty string. So just return. */ + if (docbook && in_menu) + return; + + /* 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; + output_paragraph[end_pos] = 0; + name = xstrdup (name); + value = set_p (name); + 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) + { + /* We need to get past the closing brace since the value may + expand to a context-sensitive macro (e.g. @xref) and produce + spurious warnings */ + input_text_offset++; + execute_string ("%s", value); + input_text_offset--; + } + else + { + warning (_("undefined flag: %s"), name); + add_word_args (_("{No value for `%s'}"), name); + } + + free (name); + } +} + +/* Set, clear, or conditionalize based on ACTION. */ +static void +handle_variable (int action) +{ + char *name; + + 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); +} + +static void +handle_variable_internal (int action, char *name) +{ + char *temp; + int delimiter, additional_text_present = 0; + + /* Only the first word of NAME is a valid tag. */ + temp = name; + delimiter = 0; + while (*temp && (delimiter || !whitespace (*temp))) + { +/* #if defined (SET_WITH_EQUAL) */ + if (*temp == '"' || *temp == '\'') + { + if (*temp == delimiter) + delimiter = 0; + else + delimiter = *temp; + } +/* #endif SET_WITH_EQUAL */ + temp++; + } + + if (*temp) + additional_text_present++; + + *temp = 0; + + if (!*name) + line_error (_("%c%s requires a name"), COMMAND_PREFIX, command); + else + { + switch (action) + { + case SET: + { + char *value; + +#if defined (SET_WITH_EQUAL) + /* Allow a value to be saved along with a variable. The value is + the text following an `=' sign in NAME, if any is present. */ + + for (value = name; *value && *value != '='; value++); + + if (*value) + *value++ = 0; + + if (*value == '"' || *value == '\'') + { + value++; + value[strlen (value) - 1] = 0; + } + +#else /* !SET_WITH_EQUAL */ + /* The VALUE of NAME is the remainder of the line sans + whitespace. */ + if (additional_text_present) + { + value = temp + 1; + canon_white (value); + } + else + value = ""; +#endif /* !SET_WITH_VALUE */ + + set (name, value); + } + break; + + case CLEAR: + clear (name); + break; + + case IFSET: + case IFCLEAR: + /* If IFSET and NAME is not set, or if IFCLEAR and NAME is set, + read lines from the the file until we reach a matching + "@end CONDITION". This means that we only take note of + "@ifset/clear" and "@end" commands. */ + { + char condition[8]; + int condition_len; + int orig_line_number = line_number; + + if (action == IFSET) + strcpy (condition, "ifset"); + else + strcpy (condition, "ifclear"); + + condition_len = strlen (condition); + + if ((action == IFSET && !set_p (name)) + || (action == IFCLEAR && set_p (name))) + { + int level = 0, done = 0; + + while (!done && input_text_offset < input_text_length) + { + char *freeable_line, *line; + + get_rest_of_line (0, &freeable_line); + + for (line = freeable_line; whitespace (*line); line++); + + if (*line == COMMAND_PREFIX && + (strncmp (line + 1, condition, condition_len) == 0)) + level++; + else if (strncmp (line, "@end", 4) == 0) + { + char *cname = line + 4; + char *temp; + + while (*cname && whitespace (*cname)) + cname++; + temp = cname; + + while (*temp && !whitespace (*temp)) + temp++; + *temp = 0; + + if (strcmp (cname, condition) == 0) + { + if (!level) + { + done = 1; + } + else + level--; + } + } + free (freeable_line); + } + + if (!done) + file_line_error (input_filename, orig_line_number, + _("Reached eof before matching @end %s"), + condition); + + /* 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. */ + break; + } + else + { + if (action == IFSET) + begin_insertion (ifset); + else + begin_insertion (ifclear); + } + } + break; + } + } +} + +/* Execution of random text not in file. */ +typedef struct { + char *string; /* The string buffer. */ + int size; /* The size of the buffer. */ + int in_use; /* Nonzero means string currently in use. */ +} EXECUTION_STRING; + +static EXECUTION_STRING **execution_strings = NULL; +static int execution_strings_index = 0; +static int execution_strings_slots = 0; + +static EXECUTION_STRING * +get_execution_string (int initial_size) +{ + int i = 0; + EXECUTION_STRING *es = NULL; + + if (execution_strings) + { + for (i = 0; i < execution_strings_index; i++) + if (execution_strings[i] && (execution_strings[i]->in_use == 0)) + { + es = execution_strings[i]; + break; + } + } + + if (!es) + { + if (execution_strings_index + 1 >= execution_strings_slots) + { + execution_strings = xrealloc + (execution_strings, + (execution_strings_slots += 3) * sizeof (EXECUTION_STRING *)); + for (; i < execution_strings_slots; i++) + execution_strings[i] = NULL; + } + + execution_strings[execution_strings_index] = + xmalloc (sizeof (EXECUTION_STRING)); + es = execution_strings[execution_strings_index]; + execution_strings_index++; + + es->size = 0; + es->string = NULL; + es->in_use = 0; + } + + if (initial_size > es->size) + { + es->string = xrealloc (es->string, initial_size); + es->size = initial_size; + } + 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 (char **text, unsigned int 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 (); +} + +/* FIXME: this is an arbitrary limit. */ +#define EXECUTE_STRING_MAX 16*1024 + +/* Execute the string produced by formatting the ARGs with FORMAT. This + is like submitting a new file with @include. */ +void +#if defined (VA_FPRINTF) && __STDC__ +execute_string (char *format, ...) +#else +execute_string (format, va_alist) + char *format; + va_dcl +#endif +{ + EXECUTION_STRING *es; + char *temp_string, *temp_input_filename; +#ifdef VA_FPRINTF + va_list ap; +#endif + int insertion_level_at_start = insertion_level; + + es = get_execution_string (EXECUTE_STRING_MAX); + temp_string = es->string; + es->in_use = 1; + + VA_START (ap, format); +#ifdef VA_SPRINTF + VA_SPRINTF (temp_string, format, ap); +#else + sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8); +#endif /* not VA_SPRINTF */ + va_end (ap); + + pushfile (); + input_text_offset = 0; + input_text = temp_string; + input_text_length = strlen (temp_string); + input_filename = xstrdup (input_filename); + temp_input_filename = input_filename; + + executing_string++; + reader_loop (); + + /* If insertion stack level changes during execution, that means a multiline + command is used inside braces or @section ... kind of commands. */ + if (insertion_level_at_start != insertion_level && !executing_macro) + { + line_error (_("Multiline command %c%s used improperly"), + COMMAND_PREFIX, + command); + /* We also need to keep insertion_level intact to make sure warnings are + issued for @end ... command. */ + while (insertion_level > insertion_level_at_start) + pop_insertion (); + } + + popfile (); + executing_string--; + es->in_use = 0; + free (temp_input_filename); +} + + +/* Return what would be output for STR (in newly-malloced memory), i.e., + expand Texinfo commands according to the current output format. If + IMPLICIT_CODE is set, expand @code{STR}. This is generally used for + short texts; filling, indentation, and html escapes are disabled. */ + +char * +expansion (char *str, int implicit_code) +{ + return maybe_escaped_expansion (str, implicit_code, 0); +} + + +/* Do HTML escapes according to DO_HTML_ESCAPE. Needed in + cm_printindex, q.v. */ + +char * +maybe_escaped_expansion (char *str, int implicit_code, int do_html_escape) +{ + char *result; + + /* 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; + + filling_enabled = 0; + indented_fill = 0; + no_indent = 1; + escape_html = do_html_escape; + + result = full_expansion (str, implicit_code); + + filling_enabled = saved_filling_enabled; + indented_fill = saved_indented_fill; + no_indent = saved_no_indent; + escape_html = saved_escape_html; + + return result; +} + + +/* Expand STR (or @code{STR} if IMPLICIT_CODE is nonzero). No change to + any formatting parameters -- filling, indentation, html escapes, + etc., are not reset. Always returned in new memory. */ + +char * +full_expansion (char *str, int implicit_code) +{ + int length; + char *result; + + /* Inhibit any real output. */ + int start = output_paragraph_offset; + int saved_paragraph_is_open = paragraph_is_open; + int saved_output_column = output_column; + + /* More output state to save. */ + 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; + + inhibit_output_flushing (); + paragraph_is_open = 1; + if (strlen (str) > (implicit_code + ? EXECUTE_STRING_MAX - 1 - sizeof("@code{}") + : EXECUTE_STRING_MAX - 1)) + line_error (_("`%.40s...' is too long for expansion; not expanded"), str); + else + execute_string (implicit_code ? "@code{%s}" : "%s", str); + uninhibit_output_flushing (); + + /* Copy the expansion from the buffer. */ + length = output_paragraph_offset - start; + 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; + + meta_char_pos = saved_meta_pos; + last_inserted_character = saved_last_char; + last_char_was_newline = saved_last_nl; + + return result; +} + + +/* Return text (info) expansion of STR no matter what the current output + format is. */ + +char * +text_expansion (char *str) +{ + char *ret; + int save_html = html; + int save_xml = xml; + int save_docbook = docbook; + + html = 0; + xml = 0; + docbook = 0; + ret = expansion (str, 0); + html = save_html; + xml = save_xml; + docbook = save_docbook; + + return ret; +} + + +/* Set the paragraph indentation variable to the value specified in STRING. + Values can be: + `asis': Don't change existing indentation. + `none': Remove existing indentation. + NUM: Indent NUM spaces at the starts of paragraphs. + If NUM is zero, we assume `none'. + Returns 0 if successful, or nonzero if STRING isn't one of the above. */ +int +set_paragraph_indent (char *string) +{ + if (strcmp (string, "asis") == 0 || strcmp (string, _("asis")) == 0) + paragraph_start_indent = 0; + else if (strcmp (string, "none") == 0 || strcmp (string, _("none")) == 0) + paragraph_start_indent = -1; + else + { + if (sscanf (string, "%d", ¶graph_start_indent) != 1) + return -1; + else + { + if (paragraph_start_indent == 0) + paragraph_start_indent = -1; + } + } + return 0; +} diff --git a/Build/source/utils/texinfo/makeinfo/makeinfo.h b/Build/source/utils/texinfo/makeinfo/makeinfo.h new file mode 100644 index 00000000000..de4d423708b --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/makeinfo.h @@ -0,0 +1,386 @@ +/* makeinfo.h -- declarations for Makeinfo. + $Id: makeinfo.h,v 1.17 2004/11/30 02:03:23 karl Exp $ + + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 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 MAKEINFO_H +#define MAKEINFO_H + +#ifdef COMPILING_MAKEINFO +# define DECLARE(type,var,init) type var = init +#else +# define DECLARE(type,var,init) extern type var +#endif + +/* Hardcoded per GNU standards, not dependent on argv[0]. */ +DECLARE (char *, progname, "makeinfo"); + +/* 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); + +/* Current output stream. */ +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, NULL); + +/* Offset into OUTPUT_PARAGRAPH. */ +DECLARE (int, output_paragraph_offset, 0); + +/* The output paragraph "cursor" horizontal position. */ +DECLARE (int, output_column, 0); + +/* Position in the output file. */ +DECLARE (int, output_position, 0); + +/* Number of lines in the output. */ +DECLARE (int, output_line_number, 1); +DECLARE (int, node_line_number, 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); + +/* The amount of indentation to apply at the start of each line. */ +DECLARE (int, current_indent, 0); + +/* Nonzero means that we suppress the indentation of the first paragraph + following any section heading. */ +DECLARE (int, do_first_par_indent, 0); + +/* Amount by which @example indentation increases/decreases. */ +DECLARE (int, example_indentation_increment, 5); + +/* Amount by which @table, @defun, etc. indentation increases/decreases. */ +DECLARE (int, default_indentation_increment, 5); + +/* Amount by which xml indentation increases/decreases. + Zero means unnecessary whitespace is compressed. */ +DECLARE (int, xml_indentation_increment, 2); + +/* 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 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); + +/* 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. (--html) */ +DECLARE (int, html, 0); + +/* Nonzero means that we're generating XML. (--xml) */ +DECLARE (int, xml, 0); + +/* Nonzero means that we're generating DocBook. (--docbook) */ +DECLARE (int, docbook, 0); + +/* Nonzero means true 8-bit output for Info and plain text. + (--enable-encoding) */ +DECLARE (int, enable_encoding, 0); + +/* Nonzero means escape characters in HTML output. */ +DECLARE (int, escape_html, 1); + +/* Access key number for next menu entry to be generated (1 to 9, or 10 to + mean no access key) */ +DECLARE (int, next_menu_item_number, 1); + +/* 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 we have seen an @titlepage command. */ +DECLARE (int, titlepage_cmd_present, 0); + +/* @copying ... @end copying. */ +DECLARE (char *, copying_text, NULL); + +/* @documentdescription ... @end documentdescription. */ +DECLARE (const char *, document_description, 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, input_text_length, 0); +DECLARE (int, input_text_offset, 0); +DECLARE (int, line_number, 0); +DECLARE (char *, toplevel_output_filename, NULL); +#define curchar() input_text[input_text_offset] + +/* 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); + +/* Name of CSS file to include, if any. (--css-include). */ +DECLARE (char *, css_include, 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 @docbook and @ifdocbook. (--ifdocbook) */ +DECLARE (int, process_docbook, 0); + +/* Nonzero means that we process @html and @rawhtml even when not + generating HTML. (--ifhtml) */ +DECLARE (int, process_html, 0); + +/* Positive means process @ifinfo (even if not generating Info); + zero means don't process @ifinfo (even if we are); + -1 means we don't know yet. (--ifinfo) */ +DECLARE (int, process_info, -1); + +/* Positive means process @ifplaintext (even if not generating plain text); + zero means we don't process @ifplaintext (even if we are); + -1 means we don't know yet. (--ifplaintext) */ +DECLARE (int, process_plaintext, -1); + +/* Nonzero means that we process @tex and @iftex. (--iftex) */ +DECLARE (int, process_tex, 0); + +/* Nonzero means that we process @xml and @ifxml. (--ifxml) */ +DECLARE (int, process_xml, 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, 1.1, etc. (--number-sections) */ +DECLARE (int, number_sections, 1); + +/* Nonzero means split size. When zero, DEFAULT_SPLIT_SIZE is used. */ +DECLARE (int, split_size, 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. */ + +#define coerce_to_upper(c) ((islower(c) ? toupper(c) : (c))) +#define coerce_to_lower(c) ((isupper(c) ? tolower(c) : (c))) + +#define control_character_bit 0x40 /* %01000000, must be off. */ +#define meta_character_bit 0x080/* %10000000, must be on. */ +#define CTL(c) ((c) & (~control_character_bit)) +#define UNCTL(c) coerce_to_upper(((c)|control_character_bit)) +#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) (whitespace(c) || (c) == '\r' || (c) == '\n') + +#ifndef isletter +#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z')) +#endif + +#ifndef isupper +#define isupper(c) ((c) >= 'A' && (c) <= 'Z') +#endif + +#ifndef isdigit +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#endif + +#ifndef digit_value +#define digit_value(c) ((c) - '0') +#endif + +/* These characters are not really HTML-safe (with strict XHTML), + and also there are possible collisions. That's the whole reason we + designed a new conversion scheme in the first place. But we + nevertheless need to generate the old names. See + `add_escaped_anchor_name' in html.c. */ +#define OLD_HTML_SAFE "$-_.+!*'()" +#define OLD_URL_SAFE_CHAR(ch) (strchr (OLD_HTML_SAFE, ch)) + +/* For the current/stable scheme. */ +#define URL_SAFE_CHAR(ch) (isalnum (ch)) + +#define COMMAND_PREFIX '@' + +#define END_VERBATIM "end verbatim" + +/* Stuff for splitting large files. The numbers for Emacs + texinfo-format-buffer are much smaller, but memory capacities have + increased so much, 50k info files seem a bit tiny these days. */ +#define DEFAULT_SPLIT_SIZE 300000 +DECLARE (int, splitting, 1); /* Defaults to true for now. */ + +#define skip_whitespace() \ + while ((input_text_offset != input_text_length) && \ + whitespace (curchar())) \ + input_text_offset++ + +#define skip_whitespace_and_newlines() \ + do { \ + while (input_text_offset != input_text_length \ + && cr_or_whitespace (curchar ())) \ + { \ + if (curchar () == '\n') \ + line_number++; \ + input_text_offset++; \ + } \ + } while (0) + +/* 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) + +/* Any list with a member named `next'. */ +typedef struct generic_list { + struct generic_list *next; +} GENERIC_LIST; + +/* Reverse the order of a list. */ +extern GENERIC_LIST * reverse_list (GENERIC_LIST *list); + +/* Possibly return Local Variables trailer for Info output. */ +extern char *info_trailer (void), + *expansion (char *str, int implicit_code), + *text_expansion (char *str), + *maybe_escaped_expansion (char *str, int implicit_code, int do_escape_html), + *full_expansion (char *str, int implicit_code); + +extern void free_and_clear (char **pointer), + add_word (char *string), + add_char (int character), + add_meta_char (int character), + close_single_paragraph (void), + insert_string (const char *), + insert (int character), + get_rest_of_line (int expand, char **string), + add_html_block_elt (char *string), + get_until_in_braces (char *match, char **string), + get_until_in_line (int expand, char *match, char **string), + canon_white (char *string), + discard_until (char *string), + indent (int amount), + kill_self_indent (int count), + backup_input_pointer (void), + inhibit_output_flushing (void), + uninhibit_output_flushing (void), + flush_output (void), + start_paragraph (void), + close_paragraph (void), + close_insertion_paragraph (void), + init_paragraph (void), + ignore_blank_line (void), + reader_loop (void), + discard_braces (void), + replace_with_expansion (int from, int *to), + fix_whitespace (char *string), + add_html_elt (char *string); + +extern int get_until (char *match, char **string), + set_paragraph_indent (char *string), + self_delimiting (int character), + search_forward (char *string, int from), + search_forward_until_pos (char *string, int from, int end_pos), + next_nonwhitespace_character (void), + fs_error (char *filename); + +#if defined (VA_FPRINTF) && __STDC__ +/* Unfortunately we must use prototypes if we are to use <stdarg.h>. */ +extern void add_word_args (const char *, ...), + add_html_block_elt_args (const char *, ...), + execute_string (char *, ...), + warning (const char *format, ...), + error (const char *format, ...), + line_error (const char *format, ...), + file_line_error (char *infile, int lno, const char *format, ...); +#else +extern void add_word_args (), + add_html_block_elt_args (), + execute_string (), + warning (), + error (), + line_error (), + file_line_error (); +#endif /* no prototypes */ + +#endif /* not MAKEINFO_H */ diff --git a/Build/source/utils/texinfo/makeinfo/makeinfo.rc b/Build/source/utils/texinfo/makeinfo/makeinfo.rc new file mode 100644 index 00000000000..1c4052c2161 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/makeinfo.rc @@ -0,0 +1,36 @@ +/* makeinfo.rc: version number -*- C++ -*- + + Copyright (C) 1996-2003 Fabrice Popineau <fabrice.popineau@supelec.fr> + + This file 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 file 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 file; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#include <texlive-version.h> + +#define VER_FILEVERSION TEXLIVE_MAJOR_VERSION,TEXLIVE_MINOR_VERSION,TEXLIVE_BETA_NUMBER,TEXLIVE_ALPHA_NUMBER +#define VER_FILEVERSION_STR TEXLIVE_PRODUCTVERSION_STR " makeinfo 4.3a" + +#define VER_INTERNALNAME_STR "makeinfo" +#define VER_ORIGINALFILENAME_STR "makeinfo.exe" + +#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 1987, 1992-2003 Free Software Foundation, Inc." + +#define VER_FILEDESCRIPTION_STR "Texinfo Converter" + +#define VER_COMPANYNAME_STR "Free Software Foundation, Inc." + +#include <texlive.version> + +/* makeinfo.rc ends here */ diff --git a/Build/source/utils/texinfo/makeinfo/multi.c b/Build/source/utils/texinfo/makeinfo/multi.c new file mode 100644 index 00000000000..06c548fb5e9 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/multi.c @@ -0,0 +1,638 @@ +/* multi.c -- multiple-column tables (@multitable) for makeinfo. + $Id: multi.c,v 1.8 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004 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. + + Originally written by phr@gnu.org (Paul Rubin). */ + +#include "system.h" +#include "cmds.h" +#include "insertion.h" +#include "makeinfo.h" +#include "multi.h" +#include "xml.h" + +#define MAXCOLS 100 /* remove this limit later @@ */ + + +/* + * Output environments. This is a hack grafted onto existing + * structure. The "output environment" used to consist of the + * global variables `output_paragraph', `fill_column', etc. + * Routines like add_char would manipulate these variables. + * + * Now, when formatting a multitable, we maintain separate environments + * for each column. That way we can build up the columns separately + * and write them all out at once. The "current" output environment" + * is still kept in those global variables, so that the old output + * routines don't have to change. But we provide routines to save + * and restore these variables in an "environment table". The + * `select_output_environment' function switches from one output + * environment to another. + * + * Environment #0 (i.e., element #0 of the table) is the regular + * environment that is used when we're not formatting a multitable. + * + * Environment #N (where N = 1,2,3,...) is the env. for column #N of + * the table, when a multitable is active. + */ + +/* contents of an output environment */ +/* some more vars may end up being needed here later @@ */ +struct env +{ + unsigned char *output_paragraph; + int output_paragraph_offset; + int meta_char_pos; + int output_column; + int paragraph_is_open; + int current_indent; + int fill_column; +} envs[MAXCOLS]; /* the environment table */ + +/* index in environment table of currently selected environment */ +static int current_env_no; + +/* current column number */ +static int current_column_no; + +/* We need to make a difference between template based widths and + @columnfractions for HTML tables' sake. Sigh. */ +static int seen_column_fractions; + +/* column number of last column in current multitable */ +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; + +/* 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 (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 == start || (*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; +} + +/* Direct current output to environment number N. Used when + switching work from one column of a multitable to the next. + Returns previous environment number. */ +static int +select_output_environment (int n) +{ + struct env *e = &envs[current_env_no]; + int old_env_no = current_env_no; + + /* 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; + e->fill_column = fill_column; + + /* now copy new environment into global vars */ + current_env_no = 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; + fill_column = e->fill_column; + return old_env_no; +} + +/* Initialize environment number ENV_NO, of width WIDTH. + The idea is that we're going to use one environment for each column of + a multitable, so we can build them up separately and print them + all out at the end. */ +static int +setup_output_environment (int env_no, int width) +{ + int old_env = select_output_environment (env_no); + + /* clobber old environment and set width of new one */ + init_paragraph (); + + /* make our change */ + fill_column = width; + + /* Save new environment and restore previous one. */ + select_output_environment (old_env); + + return env_no; +} + +/* Read the parameters for a multitable from the current command + line, save the parameters away, and return the + number of columns. */ +static int +setup_multitable_parameters (void) +{ + char *params = insertion_stack->item_function; + int nchars; + float columnfrac; + char command[200]; /* xx no fixed limits */ + int i = 1; + + /* We implement @hsep and @vsep even though TeX doesn't. + We don't get mixing of @columnfractions and templates right, + but TeX doesn't either. */ + hsep = vsep = 0; + + /* Assume no @columnfractions per default. */ + seen_column_fractions = 0; + + while (*params) { + while (whitespace (*params)) + params++; + + if (*params == '@') { + sscanf (params, "%200s", command); + nchars = strlen (command); + params += nchars; + if (strcmp (command, "@hsep") == 0) + hsep++; + else if (strcmp (command, "@vsep") == 0) + vsep++; + else if (strcmp (command, "@columnfractions") == 0) { + seen_column_fractions = 1; + /* Clobber old environments and create new ones, starting at #1. + Environment #0 is the normal output, so don't mess with it. */ + for ( ; i <= MAXCOLS; i++) { + if (sscanf (params, "%f", &columnfrac) < 1) + goto done; + /* 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 about @columnfractions 3foo. Oh well, + it's invalid input anyway. */ + while (*params && *params != ' ' && *params != '\t' + && *params != '\n' && *params != '@') + params++; + + { + /* For html/xml/docbook, translate fractions into integer + percentages, adding .005 to avoid rounding problems. For + info, we want the character width. */ + int width = xml || html ? (columnfrac + .005) * 100 + : (columnfrac * (fill_column - current_indent) + .5); + setup_output_environment (i, width); + } + } + } + + } else if (*params == '{') { + unsigned template_width = find_template_width (¶ms); + + /* This gives us two spaces between columns. Seems reasonable. + How to take into account current_indent here? */ + setup_output_environment (i++, template_width + 2); + + } else { + warning (_("ignoring stray text `%s' after @multitable"), params); + break; + } + } + +done: + flush_output (); + inhibit_output_flushing (); + + last_column = i - 1; + return last_column; +} + +/* 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 (int ch) +{ + if (html || xml) + 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); + } +} + + +static void +draw_horizontal_separator (void) +{ + int i, j, s; + + if (html) + { + add_word ("<hr>"); + return; + } + if (xml) + return; + + for (s = 0; s < envs[0].current_indent; s++) + out_char (' '); + if (vsep) + out_char ('+'); + for (i = 1; i <= last_column; i++) { + for (j = 0; j <= envs[i].fill_column; j++) + out_char ('-'); + if (vsep) + out_char ('+'); + } + out_char (' '); + 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 (void) +{ + int ncolumns; + + if (multitable_active) + { + line_error ("Multitables cannot be nested"); + return; + } + + close_single_paragraph (); + + if (xml) + { + xml_no_para = 1; + if (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + } + + /* 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_html_block_elt ("<p><table summary=\"\">"); + /* else if (docbook)*/ /* 05-08 */ + else if (xml) + { + int *widths = xmalloc (ncolumns * sizeof (int)); + int i; + for (i=0; i<ncolumns; i++) + widths[i] = envs[i+1].fill_column; + xml_begin_multitable (ncolumns, widths); + free (widths); + } + + if (hsep) + draw_horizontal_separator (); + + /* The next @item command will direct stdout into the first column + and start processing. @tab will then switch to the next column, + and @item will flush out the saved output and return to the first + column. Environment #1 is the first column. (Environment #0 is + the normal output) */ + + ++multitable_active; +} + +/* advance to the next environment number */ +static void +nselect_next_environment (void) +{ + if (current_env_no >= last_column) { + line_error (_("Too many columns in multitable item (max %d)"), last_column); + return; + } + select_output_environment (current_env_no + 1); +} + + +/* do anything needed at the beginning of processing a + multitable column. */ +static void +init_column (void) +{ + /* don't indent 1st paragraph in the item */ + cm_noindent (); + + /* throw away possible whitespace after @item or @tab command */ + skip_whitespace (); +} + +static void +output_multitable_row (void) +{ + /* 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; + + /* select the current environment, to make sure the env variables + get updated */ + select_output_environment (current_env_no); + +#define CHAR_ADDR(n) (offset[i] + (n)) +#define CHAR_AT(n) (envs[i].output_paragraph[CHAR_ADDR(n)]) + + /* remove trailing whitespace from each column */ + for (i = 1; i <= last_column; i++) { + 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 + pasted together. Do this til all lines are output from all + columns. */ + for (;;) { + remaining = 0; + /* first, see if there is any work to do */ + for (i = 1; i <= last_column; i++) { + if (CHAR_ADDR (0) < envs[i].output_paragraph_offset) { + remaining = 1; + break; + } + } + if (!remaining) + break; + + for (s = 0; s < envs[0].current_indent; s++) + out_char (' '); + + if (vsep) + out_char ('|'); + + for (i = 1; i <= last_column; i++) { + 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') + break; + out_char (CHAR_AT (j)); + } + offset[i] += j + 1; /* skip last text plus skip the newline */ + + /* 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 (); + + /* Now dispose of the buffered output. */ + for (i = 1; i <= last_column; i++) { + select_output_environment (i); + init_paragraph (); + } +} + +int after_headitem = 0; +int headitem_row = 0; + +/* start a new item (row) of a multitable */ +int +multitable_item (void) +{ + if (!multitable_active) { + line_error ("multitable_item internal error: no active multitable"); + xexit (1); + } + + current_column_no = 1; + + if (html) + { + if (!first_row) + /* <br> for non-tables browsers. */ + add_word_args ("<br></%s></tr>", after_headitem ? "th" : "td"); + + if (seen_column_fractions) + add_word_args ("<tr align=\"left\"><%s valign=\"top\" width=\"%d%%\">", + headitem_flag ? "th" : "td", + envs[current_column_no].fill_column); + else + add_word_args ("<tr align=\"left\"><%s valign=\"top\">", + headitem_flag ? "th" : "td"); + + if (headitem_flag) + after_headitem = 1; + else + after_headitem = 0; + first_row = 0; + headitem_row = headitem_flag; + headitem_flag = 0; + return 0; + } + /* else if (docbook)*/ /* 05-08 */ + else if (xml) + { + xml_end_multitable_row (first_row); + if (headitem_flag) + after_headitem = 1; + else + after_headitem = 0; + first_row = 0; + headitem_flag = 0; + return 0; + } + first_row = 0; + + if (current_env_no > 0) { + output_multitable_row (); + } + /* start at column 1 */ + select_output_environment (1); + if (!output_paragraph) { + line_error (_("[unexpected] cannot select column #%d in multitable"), + current_env_no); + xexit (1); + } + + init_column (); + + if (headitem_flag) + hsep = 1; + else + hsep = 0; + + if (headitem_flag) + after_headitem = 1; + else + after_headitem = 0; + headitem_flag = 0; + + return 0; +} + +#undef CHAR_AT +#undef CHAR_ADDR + +/* select a new column in current row of multitable */ +void +cm_tab (void) +{ + if (!multitable_active) + error (_("ignoring @tab outside of multitable")); + + current_column_no++; + + if (html) + { + if (seen_column_fractions) + add_word_args ("</%s><%s valign=\"top\" width=\"%d%%\">", + headitem_row ? "th" : "td", + headitem_row ? "th" : "td", + envs[current_column_no].fill_column); + else + add_word_args ("</%s><%s valign=\"top\">", + headitem_row ? "th" : "td", + headitem_row ? "th" : "td"); + } + /* else if (docbook)*/ /* 05-08 */ + else if (xml) + xml_end_multitable_column (); + else + nselect_next_environment (); + + init_column (); +} + +/* close a multitable, flushing its output and resetting + whatever needs resetting */ +void +end_multitable (void) +{ + if (!html && !docbook) + 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); + multitable_active = 0; + uninhibit_output_flushing (); + close_insertion_paragraph (); + + if (html) + add_word_args ("<br></%s></tr></table>\n", headitem_row ? "th" : "td"); + /* else if (docbook)*/ /* 05-08 */ + else if (xml) + xml_end_multitable (); + +#if 0 + printf (_("** Multicolumn output from last row:\n")); + for (i = 1; i <= last_column; i++) { + select_output_environment (i); + printf (_("* column #%d: output = %s\n"), i, output_paragraph); + } +#endif +} diff --git a/Build/source/utils/texinfo/makeinfo/multi.h b/Build/source/utils/texinfo/makeinfo/multi.h new file mode 100644 index 00000000000..64311e0f2be --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/multi.h @@ -0,0 +1,28 @@ +/* multi.h -- declarations for multi.c. + $Id: multi.h,v 1.1 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 2004 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 MULTI_H +#define MULTI_H + +extern void do_multitable (void); +extern void end_multitable (void); +extern int multitable_item (void); + +#endif /* !MULTI_H */ diff --git a/Build/source/utils/texinfo/makeinfo/node.c b/Build/source/utils/texinfo/makeinfo/node.c new file mode 100644 index 00000000000..07a37fede2f --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/node.c @@ -0,0 +1,1943 @@ +/* node.c -- nodes for Texinfo. + $Id: node.c,v 1.27 2004/12/20 23:56:07 karl Exp $ + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 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 "float.h" +#include "footnote.h" +#include "macro.h" +#include "makeinfo.h" +#include "node.h" +#include "html.h" +#include "sectioning.h" +#include "insertion.h" +#include "xml.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 node_order = 0; +int current_section = 0; +int outstanding_node = 0; + +/* Adding nodes, and making tags. */ + +/* Start a new tag table. */ +void +init_tag_table (void) +{ + 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 (int indirect_p) +{ + TAG_ENTRY *node; + int old_indent = no_indent; + + if (xml) + { + flush_output (); + return; + } + + 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 (char *filename) +{ + output_stream = fopen (filename, "a"); + if (!output_stream) + { + fs_error (filename); + return; + } + + write_tag_table_internal (0); /* Not indirect. */ + + if (fclose (output_stream) != 0) + fs_error (filename); +} + +static void +write_tag_table_indirect (void) +{ + write_tag_table_internal (1); +} + +/* Convert "top" and friends into "Top". */ +static void +normalize_node_name (char *string) +{ + if (strcasecmp (string, "Top") == 0) + strcpy (string, "Top"); +} + +static char * +get_node_token (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 (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 (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; +} + +/* Look in the tag table for a node whose file name is FNAME, and + return the associated tag_entry. If there's no such node in the + table, return NULL. */ +static TAG_ENTRY * +find_node_by_fname (char *fname) +{ + TAG_ENTRY *tag = tag_table; + while (tag) + { + if (tag->html_fname && FILENAME_CMP (tag->html_fname, fname) == 0) + return tag; + tag = tag->next_ent; + } + + return tag; +} + +/* Remember next, prev, etc. references in a @node command, where we + don't care about most of the entries. */ +static void +remember_node_node_reference (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. */ +static void +remember_node (char *node, char *prev, char *next, char *up, + int position, int line_no, char *fname, int 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; + } + if (fname) + new->html_fname = fname; + else + /* This happens for Top node under split-HTML, for example. */ + new->html_fname + = normalize_filename (filename_part (current_output_filename)); + new->next_ent = tag_table; + + /* Increment the order counter, and save it. */ + node_order++; + new->order = node_order; + + 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 (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 (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 (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; + int 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 (const char *fname) +{ + if (current_output_filename) + free (current_output_filename); + current_output_filename = xstrdup (fname); +} + + +/* Output the <a name="..."></a> constructs for NODE. We output both + the new-style conversion and the old-style, if they are different. + See comments at `add_escaped_anchor_name' in html.c. */ + +static void +add_html_names (char *node) +{ + char *tem = expand_node_name (node); + char *otem = xstrdup (tem); + + /* Determine if the old and new schemes come up with different names; + only output the old scheme if that is so. We don't want to output + the same name twice. */ + canon_white (otem); + { + char *optr = otem; + int need_old = 0; + + for (; *optr; optr++) + { + if (!cr_or_whitespace (*optr) && !URL_SAFE_CHAR (*optr)) + { + need_old = 1; + break; + } + } + + if (need_old) + { + add_word ("<a name=\""); + add_anchor_name (otem, -1); /* old anchor name conversion */ + add_word ("\"></a>\n"); + } + free (otem); + } + + /* Always output the new scheme. */ + canon_white (tem); + add_word ("<a name=\""); + add_anchor_name (tem, 0); + add_word ("\"></a>\n"); + + free (tem); +} + + +/* 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 (void) +{ + static long epilogue_len = 0L; + char *node, *prev, *next, *up; + int new_node_pos, defaulting, this_section; + int no_warn = 0; + char *fname_for_this_node = NULL; + char *tem; + TAG_ENTRY *tag = NULL; + + 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 (); + } + + new_node_pos = output_position; + + 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 (html && splitting + /* If there is a Top node, it always goes into index.html. So + don't start a new HTML file for Top. */ + && (top_node_seen || strcasecmp (node, "Top") != 0)) + { + /* We test *node here so that @node without a valid name won't + start a new file name with a bogus name such as ".html". + This could happen if we run under "--force", where we cannot + simply bail out. Continuing to use the same file sounds like + the best we can do in such cases. */ + if (current_output_filename && output_stream && *node) + { + char *fname_for_prev_node; + + if (current_node) + { + /* NOTE: current_node at this point still holds the name + of the previous node. */ + tem = expand_node_name (current_node); + fname_for_prev_node = nodename_to_filename (tem); + free (tem); + } + else /* could happen if their top node isn't named "Top" */ + fname_for_prev_node = filename_part (current_output_filename); + tem = expand_node_name (node); + fname_for_this_node = nodename_to_filename (tem); + free (tem); + /* Don't close current output file, if next output file is + to have the same name. This may happen at top level, or + if two nodes produce the same file name under --split. */ + if (FILENAME_CMP (fname_for_this_node, fname_for_prev_node) != 0) + { + long pos1 = 0; + + /* End the current split output file. */ + close_paragraph (); + output_pending_notes (); + start_paragraph (); + /* Compute the length of the HTML file's epilogue. We + cannot know the value until run time, due to the + text/binary nuisance on DOS/Windows platforms, where + 2 `\r' characters could be added to the epilogue when + it is written in text mode. */ + if (epilogue_len == 0) + { + flush_output (); + pos1 = ftell (output_stream); + } + add_word ("</body></html>\n"); + close_paragraph (); + if (epilogue_len == 0) + epilogue_len = ftell (output_stream) - pos1; + fclose (output_stream); + output_stream = NULL; + output_position = 0; + tag = find_node_by_fname (fname_for_this_node); + } + free (fname_for_prev_node); + } + } + + filling_enabled = indented_fill = 0; + if (!html || (html && splitting)) + current_footnote_number = 1; + + if (verbose_mode) + printf (_("Formatting node %s...\n"), node); + + if (macro_expansion_output_stream && !executing_string) + remember_itext (input_text, input_text_offset); + + /* Reset the line number in each node for Info output, so that + index entries will save the line numbers of parent node. */ + node_line_number = 0; + + no_indent = 1; + if (xml) + { + xml_begin_document (current_output_filename); + xml_begin_node (); + if (!docbook) + { + xml_insert_element (NODENAME, START); + if (macro_expansion_output_stream && !executing_string) + me_execute_string (node); + else + execute_string ("%s", node); + xml_insert_element (NODENAME, END); + } + else + xml_node_id = xml_id (node); + } + else if (!no_headers && !html) + { + /* Emacs Info reader cannot grok indented escape sequence. */ + kill_self_indent (-1); + + 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, NULL); + + /* 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; + + int bye_offset = search_forward ("\n@bye", input_text_offset); + + /* 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 + && (bye_offset > -1 && input_text_offset < bye_offset) + && 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, + fname_for_this_node, no_warn); + outstanding_node = 1; + } + + if (html) + { + if (splitting && *node && output_stream == NULL) + { + char *dirname; + char filename[PATH_MAX]; + + dirname = pathname_part (current_output_filename); + strcpy (filename, dirname); + strcat (filename, fname_for_this_node); + free (dirname); + + /* See if the node name converted to a file name clashes + with other nodes or anchors. If it clashes with an + anchor, we complain and nuke that anchor's file. */ + if (!tag) + { + output_stream = fopen (filename, "w"); + html_output_head_p = 0; /* so that we generate HTML preamble */ + html_output_head (); + } + else if ((tag->flags & TAG_FLAG_ANCHOR) != 0) + { + line_error (_("Anchor `%s' and node `%s' map to the same file name"), + tag->node, node); + file_line_error (tag->filename, tag->line_no, + _("This @anchor command ignored; references to it will not work")); + file_line_error (tag->filename, tag->line_no, + _("Rename this anchor or use the `--no-split' option")); + /* Nuke the file name recorded in anchor's tag. + Since we are about to nuke the file itself, we + don't want find_node_by_fname to consider this + anchor anymore. */ + free (tag->html_fname); + tag->html_fname = NULL; + output_stream = fopen (filename, "w"); + html_output_head_p = 0; /* so that we generate HTML preamble */ + html_output_head (); + } + else + { + /* This node's file name clashes with another node. + We put them both on the same file. */ + output_stream = fopen (filename, "r+"); + if (output_stream) + { + static char html_end[] = "</body></html>\n"; + char end_line[sizeof(html_end)]; + int fpos = fseek (output_stream, -epilogue_len, + SEEK_END); + + if (fpos < 0 + || fgets (end_line, sizeof (html_end), + output_stream) == NULL + /* Paranoia: did someone change the way HTML + files are finished up? */ + || strcasecmp (end_line, html_end) != 0) + { + line_error (_("Unexpected string at end of split-HTML file `%s'"), + fname_for_this_node); + fclose (output_stream); + xexit (1); + } + fseek (output_stream, -epilogue_len, SEEK_END); + } + } + if (output_stream == NULL) + { + fs_error (filename); + xexit (1); + } + set_current_output_filename (filename); + } + + if (!splitting && no_headers) + { /* cross refs need a name="#anchor" even if not writing headers */ + add_html_names (node); + } + + if (splitting || !no_headers) + { /* Navigation bar. */ + add_html_block_elt ("<div class=\"node\">\n"); + /* The <p> avoids the links area running on with old Lynxen. */ + add_word_args ("<p>%s\n", splitting ? "" : "<hr>"); + + /* In the split HTML case, the filename is wrong for the + old-style converted names, but we'll add them anyway, for + consistency. (And we need them in the normal (not + no_headers) nonsplit case.) */ + add_html_names (node); + + if (next) + { + tem = expansion (next, 0); + add_word ((char *) _("Next:")); + add_word (" "); + + add_word ("<a rel=\"next\" accesskey=\"n\" href=\""); + add_anchor_name (tem, 1); + tem = escape_string (tem); + add_word_args ("\">%s</a>", tem); + + free (tem); + + if (prev || up) + add_word (",\n"); + } + if (prev) + { + tem = expansion (prev, 0); + add_word ((char *) _("Previous:")); + add_word (" "); + add_word ("<a rel=\"previous\" accesskey=\"p\" href=\""); + add_anchor_name (tem, 1); + tem = escape_string (tem); + add_word_args ("\">%s</a>", tem); + free (tem); + + if (up) + add_word (",\n"); + } + if (up) + { + tem = expansion (up, 0); + add_word ((char *) _("Up:")); + add_word (" "); + add_word ("<a rel=\"up\" accesskey=\"u\" href=\""); + add_anchor_name (tem, 1); + tem = escape_string (tem); + add_word_args ("\">%s</a>", tem); + free (tem); + } + /* html fixxme: we want a `top' or `contents' link here. */ + + add_word_args ("\n%s\n", splitting ? "<hr>" : ""); + add_word ("</div>\n"); + } + } + else if (docbook) + ; + else if (xml) + { + if (next) + { + xml_insert_element (NODENEXT, START); + execute_string ("%s", next); + xml_insert_element (NODENEXT, END); + } + if (prev) + { + xml_insert_element (NODEPREV, START); + execute_string ("%s", prev); + xml_insert_element (NODEPREV, END); + } + if (up) + { + xml_insert_element (NODEUP, START); + execute_string ("%s", up); + xml_insert_element (NODEUP, END); + } + } + 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 (int arg) +{ + char *anchor; + char *fname_for_anchor = NULL; + + if (arg == END) + return; + + /* Parse the anchor text. */ + anchor = get_xref_token (1); + + /* Force all versions of "top" to be "Top". */ + normalize_node_name (anchor); + + /* 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) + { + if (!executing_string && html) + html_output_head (); + 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>"); + if (splitting) + { + /* If we are splitting, cm_xref will produce a reference to + a file whose name is derived from the anchor name. So we + must create a file when we see an @anchor, otherwise + xref's to anchors won't work. The file we create simply + redirects to the file of this anchor's node. */ + TAG_ENTRY *tag; + + fname_for_anchor = nodename_to_filename (anchor); + /* See if the anchor name converted to a file name clashes + with other anchors or nodes. */ + tag = find_node_by_fname (fname_for_anchor); + if (tag) + { + if ((tag->flags & TAG_FLAG_ANCHOR) != 0) + line_error (_("Anchors `%s' and `%s' map to the same file name"), + anchor, tag->node); + else + line_error (_("Anchor `%s' and node `%s' map to the same file name"), + anchor, tag->node); + line_error (_("@anchor command ignored; references to it will not work")); + line_error (_("Rename this anchor or use the `--no-split' option")); + free (fname_for_anchor); + /* We will not be creating a file for this anchor, so + set its name to NULL, so that remember_node stores a + NULL and find_node_by_fname won't consider this + anchor for clashes. */ + fname_for_anchor = NULL; + } + else + { + char *dirname, *p; + char filename[PATH_MAX]; + FILE *anchor_stream; + + dirname = pathname_part (current_output_filename); + strcpy (filename, dirname); + strcat (filename, fname_for_anchor); + free (dirname); + + anchor_stream = fopen (filename, "w"); + if (anchor_stream == NULL) + { + fs_error (filename); + xexit (1); + } + /* The HTML magic below will cause the browser to + immediately go to the anchor's node's file. Lynx + seems not to support this redirection, but it looks + like a bug in Lynx, and they can work around it by + clicking on the link once more. */ + fputs ("<meta http-equiv=\"refresh\" content=\"0; url=", + anchor_stream); + /* Make the indirect link point to the current node's + file and anchor's "<a name" label. If we don't have + a valid node name, refer to the current output file + instead. */ + if (current_node && *current_node) + { + char *fn, *tem; + + tem = expand_node_name (current_node); + fn = nodename_to_filename (tem); + free (tem); + fputs (fn, anchor_stream); + free (fn); + } + else + { + char *base = filename_part (current_output_filename); + + fputs (base, anchor_stream); + free (base); + } + fputs ("#", anchor_stream); + for (p = anchor; *p; p++) + { + if (*p == '&') + fputs ("&", anchor_stream); + else if (!URL_SAFE_CHAR (*p)) + fprintf (anchor_stream, "%%%x", (unsigned char) *p); + else + fputc (*p, anchor_stream); + } + fputs ("\">\n", anchor_stream); + fclose (anchor_stream); + } + } + } + else if (xml) + { + xml_insert_element_with_attribute (ANCHOR, START, "name=\"%s\"", anchor); + xml_insert_element (ANCHOR, END); + } + /* Save it in the tag table. */ + remember_node (anchor, NULL, NULL, NULL, + output_position + output_paragraph_offset, + line_number, fname_for_anchor, TAG_FLAG_ANCHOR); +} + +/* Find NODE in REF_LIST. */ +static NODE_REF * +find_node_reference (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 (void) +{ + 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 (void) +{ + 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 (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 (char *tag, int line, const 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' (perhaps incorrect sectioning?)"), 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 const char * +reftype_type_string (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 (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_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 (tem1 && tem2 && STREQ (tem1, tem2)) + you_lose = 0; + free (tem1); + free (tem2); + } + if (you_lose) + { + line_error (_("Next field of node `%s' not pointed to (perhaps incorrect sectioning?)"), + tags->node); + file_line_error (temp_tag->filename, temp_tag->line_no, + _("This node (%s) has the bad Prev"), + temp_tag->node); + 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); + file_line_error (temp_tag->filename, + temp_tag->line_no, + _("This node (%s) has the bad Next"), + temp_tag->node); + 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 (perhaps incorrect sectioning?)"), 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); + file_line_error (temp_tag->filename, temp_tag->line_no, + _("Node `%s' lacks menu item for `%s' despite being its Up target"), + tags->up, tags->node); + } + } + } + } + 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 (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; +} + + +static char * +enumerate_filename (char *pathname, char *basename, int number) +{ + /* Do we need to generate names of subfiles which don't exceed 8+3 limits? */ + const int dos_file_names = !HAVE_LONG_FILENAMES (pathname ? pathname : "."); + unsigned name_len = strlen (basename); + char *filename = xmalloc (10 + strlen (pathname) + name_len); + char *base_filename = xmalloc (10 + name_len); + + sprintf (base_filename, "%s-%d", basename, number); + + if (dos_file_names) + { + char *dot = strchr (base_filename, '.'); + unsigned base_len = strlen (base_filename); + + if (dot) + { /* Make foobar.i1, .., foobar.i99, foobar.100, ... */ + dot[1] = 'i'; + memmove (number <= 99 ? dot + 2 : dot + 1, + base_filename + name_len + 1, + strlen (base_filename + name_len + 1) + 1); + } + else if (base_len > 8) + { + /* Make foobar-1, .., fooba-10, .., foob-100, ... */ + unsigned numlen = base_len - name_len; + + memmove (base_filename + 8 - numlen, base_filename + name_len, numlen + 1); + } + } + + sprintf (filename, "%s%s", pathname, base_filename); + + return filename; +} + +/* Remove previously split files, to avoid + lingering parts of shrinked documents. */ +void +clean_old_split_files (char *filename) +{ + char *root_filename = filename_part (filename); + char *root_pathname = pathname_part (filename); + int i; + + /* We break as soon as we hit an inexistent file, + so looping until large numbers is harmless. */ + for (i = 1; i < 1000; i++) + { + struct stat st; + char *check_file = enumerate_filename (root_pathname, root_filename, i); + + if (stat (check_file, &st) != 0) + break; + else if (!S_ISDIR (st.st_mode)) + { + /* Give feedback if requested, removing a file is important. */ + if (verbose_mode) + printf (_("Removing %s\n"), check_file); + + /* Warn user that we cannot remove the file. */ + if (unlink (check_file) != 0) + warning (_("Can't remove file `%s': %s"), check_file, strerror (errno)); + } + + free (check_file); + } +} + + +/* 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 (char *filename, int size) +{ + char *root_filename, *root_pathname; + char *the_file; + 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) < size)) + return; + file_size = (long) fileinfo.st_size; + + the_file = find_and_load (filename, 0); + 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 = NULL; + + /* Maybe we want a Local Variables section. */ + char *trailer = info_trailer (); + int trailer_len = trailer ? strlen (trailer) : 0; + + /* 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 = enumerate_filename (root_pathname, + root_filename, which_file); + char *split_basename = filename_part (split_filename); + + 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) + || (trailer_len + && write (fd, trailer, trailer_len) != trailer_len) + || 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 the indirect tag table. */ + write_tag_table_indirect (); + + /* preserve local variables in info output. */ + if (trailer) + { + fwrite (trailer, 1, trailer_len, output_stream); + free (trailer); + } + + fclose (output_stream); + free (the_header); + free (the_file); + return; + } + } +} diff --git a/Build/source/utils/texinfo/makeinfo/node.h b/Build/source/utils/texinfo/makeinfo/node.h new file mode 100644 index 00000000000..766c503456e --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/node.h @@ -0,0 +1,129 @@ +/* node.h -- declarations for Node. + $Id: node.h,v 1.2 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1996, 1997, 1998, 1999, 2002 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 + +#include "xref.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. */ + int order; /* The order of the tag, starting from zero. */ + char *html_fname; /* The HTML file to which this node is written + (non-NULL only for HTML splitting). */ +} 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; + +/* Node order counter. */ +extern int node_order; + +/* 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 (char *name); + +/* 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 (int remember_ref, enum reftype ref_type); + +/* Remember a node for later validation. */ +extern void remember_node_reference (char *node, int line, enum reftype type); + +/* Remember the name of the current output file. */ +extern void set_current_output_filename (const char *fname); + +/* Expand macros and commands in the node name and canonicalize + whitespace in the resulting expansion. */ +extern char *expand_node_name (char *node); + +extern int number_of_node (char *node); + +extern void init_tag_table (void); +extern void write_tag_table (char *filename); +extern void free_node_references (void); +extern void free_node_node_references (void); +extern void validate_file (TAG_ENTRY *tag_table); +extern void split_file (char *filename, int size); +extern void clean_old_split_files (char *filename); + +#endif /* NODE_H */ diff --git a/Build/source/utils/texinfo/makeinfo/sectioning.c b/Build/source/utils/texinfo/makeinfo/sectioning.c new file mode 100644 index 00000000000..ce32aeb3a7e --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/sectioning.c @@ -0,0 +1,831 @@ +/* sectioning.c -- for @chapter, @section, ..., @contents ... + $Id: sectioning.c,v 1.25 2004/07/05 22:23:23 karl Exp $ + + Copyright (C) 1999, 2001, 2002, 2003, 2004 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. + + Originally 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" +#include "xml.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 }, + { "centerchap", 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; + +/* These two variables are for @float, @cindex like commands that need to know + in which section they are used. */ +/* Last value returned by get_sectioning_number. */ +static char *last_sectioning_number = ""; +/* Last title used by sectioning_underscore, etc. */ +static char *last_sectioning_title = ""; + +/* 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 */ +static char * +get_sectioning_number (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]); + + /* Poor man's cache :-) */ + if (strlen (last_sectioning_number)) + free (last_sectioning_number); + last_sectioning_number = xstrdup (s); + + return s; +} + + +/* Set the level of @top to LEVEL. Return the old level of @top. */ +int +set_top_section_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 */ +static int +search_sectioning (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 of section present in + TEXT -- 1 for @top, 2 for chapters, ..., 5 for subsubsections (as + specified in section_alist). We take into account any @lowersections + and @raisesections. If SECNAME is non-NULL, also return the + corresponding section name. */ +int +what_section (char *text, char **secname) +{ + 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; + + if (secname) + { + int i; + int alist_size = sizeof (section_alist) / sizeof(section_alist_type); + /* Find location of offset sectioning entry, but don't go off + either end of the array. */ + int index_offset = MAX (index - section_alist_offset, 0); + index_offset = MIN (index_offset, alist_size - 1); + + /* Also make sure we don't go into the next "group" of + sectioning changes, e.g., change from an @appendix to an + @heading or some such. */ +#define SIGN(expr) ((expr) < 0 ? -1 : 1) + for (i = index; i != index_offset; i -= SIGN (section_alist_offset)) + { + /* As it happens, each group has unique .num/.toc values. */ + if (section_alist[i].num != section_alist[index_offset].num + || section_alist[i].toc != section_alist[index_offset].toc) + break; + } + *secname = section_alist[i].name; + } + return return_val; + } + return -1; +} + +/* Returns current top level division (ie. chapter, unnumbered) number. + - For chapters, returns the number. + - For unnumbered sections, returns empty string. + - For appendices, returns A, B, etc. */ +char * +current_chapter_number (void) +{ + if (enum_marker == UNNUMBERED_MAGIC) + return xstrdup (""); + else if (enum_marker == APPENDIX_MAGIC) + { + char s[1]; + sprintf (s, "%c", numbers[0] + 64); + return xstrdup (s); + } + else + { + char s[5]; + sprintf (s, "%d", numbers[0]); + return xstrdup (s); + } +} + +/* Returns number of the last sectioning command used. */ +char * +current_sectioning_number (void) +{ + if (enum_marker == UNNUMBERED_MAGIC || !number_sections) + return xstrdup (""); + else + return xstrdup (last_sectioning_number); +} + +/* Returns arguments of the last sectioning command used. */ +char * +current_sectioning_name (void) +{ + return xstrdup (last_sectioning_title); +} + +/* insert_and_underscore, sectioning_underscore and sectioning_html call this. */ + +static char * +handle_enum_increment (int level, int index) +{ + /* Here is how TeX handles enumeration: + - Anything starting with @unnumbered is not enumerated. + - @majorheading and the like are not enumberated. */ + int i; + + /* First constraint above. */ + if (enum_marker == UNNUMBERED_MAGIC && level == 0) + return xstrdup (""); + + /* Second constraint. */ + if (section_alist[index].num == ENUM_SECT_NO) + return xstrdup (""); + + /* reset all counters which are one level deeper */ + for (i = level; i < 3; i++) + numbers [i + 1] = 0; + + numbers[level]++; + if (section_alist[index].num == ENUM_SECT_NO || enum_marker == UNNUMBERED_MAGIC + || !number_sections) + return xstrdup (""); + else + return xstrdup (get_sectioning_number (level, section_alist[index].num)); +} + + +void +sectioning_underscore (char *cmd) +{ + char *temp, *secname; + int level; + + /* If we're not indenting the first paragraph, we shall make it behave + like @noindent is called directly after the section heading. */ + if (! do_first_par_indent) + cm_noindent (); + + temp = xmalloc (2 + strlen (cmd)); + temp[0] = COMMAND_PREFIX; + strcpy (&temp[1], cmd); + level = what_section (temp, &secname); + level -= 2; + if (level < 0) + level = 0; + free (temp); + + /* If the argument to @top is empty, we try using the one from @settitle. + Warn if both are unusable. */ + if (STREQ (command, "top")) + { + int save_input_text_offset = input_text_offset; + + get_rest_of_line (0, &temp); + + /* Due to get_rest_of_line ... */ + line_number--; + + if (strlen (temp) == 0 && (!title || strlen (title) == 0)) + warning ("Must specify a title with least one of @settitle or @top"); + + input_text_offset = save_input_text_offset; + } + + if (xml) + { + /* If the section appears in the toc, it means it's a real section + unlike majorheading, chapheading etc. */ + if (section_alist[search_sectioning (cmd)].toc == TOC_YES) + { + xml_close_sections (level); + /* Mark the beginning of the section + If the next command is printindex, we will remove + the section and put an Index instead */ + flush_output (); + xml_last_section_output_position = output_paragraph_offset; + + get_rest_of_line (0, &temp); + + /* Use @settitle value if @top parameter is empty. */ + if (STREQ (command, "top") && strlen(temp) == 0) + temp = xstrdup (title ? title : ""); + + /* Docbook does not support @unnumbered at all. So we provide numbers + that other formats use. @appendix seems to be fine though, so we let + Docbook handle that as usual. */ + if (docbook && enum_marker != APPENDIX_MAGIC) + { + if (section_alist[search_sectioning (cmd)].num == ENUM_SECT_NO + && section_alist[search_sectioning (cmd)].toc == TOC_YES) + xml_insert_element_with_attribute (xml_element (secname), + START, "label=\"%s\" xreflabel=\"%s\"", + handle_enum_increment (level, search_sectioning (cmd)), + text_expansion (temp)); + else + xml_insert_element_with_attribute (xml_element (secname), + START, "label=\"%s\"", + handle_enum_increment (level, search_sectioning (cmd))); + } + else + xml_insert_element (xml_element (secname), START); + + xml_insert_element (TITLE, START); + xml_open_section (level, secname); + execute_string ("%s", temp); + xml_insert_element (TITLE, END); + + free (temp); + } + else + { + if (docbook) + { + if (level > 0) + xml_insert_element_with_attribute (xml_element (secname), START, + "renderas=\"sect%d\"", level); + else + xml_insert_element_with_attribute (xml_element (secname), START, + "renderas=\"other\""); + } + else + xml_insert_element (xml_element (secname), START); + + get_rest_of_line (0, &temp); + execute_string ("%s", temp); + free (temp); + + xml_insert_element (xml_element (secname), END); + } + } + else if (html) + sectioning_html (level, secname); + else + insert_and_underscore (level, secname); +} + + +/* 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 (int level, char *cmd) +{ + int i, len; + int index; + int old_no_indent; + unsigned char *starting_pos, *ending_pos; + char *temp; + char with_char = scoring_characters[level]; + + 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); + + /* Use @settitle value if @top parameter is empty. */ + if (STREQ (command, "top") && strlen(temp) == 0) + temp = xstrdup (title ? title : ""); + + starting_pos = output_paragraph + output_paragraph_offset; + + /* Poor man's cache for section title. */ + if (strlen (last_sectioning_title)) + free (last_sectioning_title); + last_sectioning_title = xstrdup (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; + } + + /* 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_args ("%s ", 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 (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; + + /* level 0 (chapter) is <h2>, and we go down from there. */ + add_html_block_elt_args ("<h%d class=\"%s\">", level + 2, cmd); + + /* If we are outside of any node, produce an anchor that + the TOC could refer to. */ + if (!current_node || !*current_node) + { + static const char a_name[] = "<a name=\""; + + starting_pos = output_paragraph + output_paragraph_offset; + add_word_args ("%sTOC%d\">", a_name, toc_ref_count++); + toc_anchor = substring (starting_pos + sizeof (a_name) - 1, + output_paragraph + output_paragraph_offset); + /* This must be added after toc_anchor is extracted, since + toc_anchor cannot include the closing </a>. For details, + see toc.c:toc_add_entry and toc.c:contents_update_html. + + Also, the anchor close must be output before the section name + in case the name itself contains an anchor. */ + add_word ("</a>"); + } + 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); + + /* Use @settitle value if @top parameter is empty. */ + if (STREQ (command, "top") && strlen(temp) == 0) + temp = xstrdup (title ? title : ""); + + 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. */ + { + char *title_number = handle_enum_increment (level, index); + if (strlen (title_number) > 0) + add_word_args ("%s ", title_number); + } + + /* 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 + 2); + close_paragraph(); + filling_enabled = 1; + no_indent = old_no_indent; +} + + +/* Shift the meaning of @section to @chapter. */ +void +cm_raisesections (void) +{ + discard_until ("\n"); + section_alist_offset--; +} + +/* Shift the meaning of @chapter to @section. */ +void +cm_lowersections (void) +{ + discard_until ("\n"); + section_alist_offset++; +} + +/* The command still works, but prints a warning message in addition. */ +void +cm_ideprecated (int arg, int start, int 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 (void) +{ + /* 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) + { + file_line_error (tag->filename, tag->line_no, + _("Here is the %ctop node"), COMMAND_PREFIX); + return; + } + tag = tag->next_ent; + } + } + else + { + top_node_seen = 1; + + /* It is an error to use @top before using @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; + } + + 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, + NULL); + + /* 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 (void) +{ + enum_marker = 0; + sectioning_underscore ("chapter"); +} + +/* The remainder of the text on this line is a section heading. */ +void +cm_section (void) +{ + sectioning_underscore ("section"); +} + +/* The remainder of the text on this line is a subsection heading. */ +void +cm_subsection (void) +{ + sectioning_underscore ("subsection"); +} + +/* The remainder of the text on this line is a subsubsection heading. */ +void +cm_subsubsection (void) +{ + sectioning_underscore ("subsubsection"); +} + +/* The remainder of the text on this line is an unnumbered heading. */ +void +cm_unnumbered (void) +{ + enum_marker = UNNUMBERED_MAGIC; + sectioning_underscore ("unnumbered"); +} + +/* The remainder of the text on this line is an unnumbered section heading. */ +void +cm_unnumberedsec (void) +{ + sectioning_underscore ("unnumberedsec"); +} + +/* The remainder of the text on this line is an unnumbered + subsection heading. */ +void +cm_unnumberedsubsec (void) +{ + sectioning_underscore ("unnumberedsubsec"); +} + +/* The remainder of the text on this line is an unnumbered + subsubsection heading. */ +void +cm_unnumberedsubsubsec (void) +{ + sectioning_underscore ("unnumberedsubsubsec"); +} + +/* The remainder of the text on this line is an appendix heading. */ +void +cm_appendix (void) +{ + /* Reset top level number so we start from Appendix A */ + if (enum_marker != APPENDIX_MAGIC) + numbers [0] = 0; + enum_marker = APPENDIX_MAGIC; + sectioning_underscore ("appendix"); +} + +/* The remainder of the text on this line is an appendix section heading. */ +void +cm_appendixsec (void) +{ + sectioning_underscore ("appendixsec"); +} + +/* The remainder of the text on this line is an appendix subsection heading. */ +void +cm_appendixsubsec (void) +{ + sectioning_underscore ("appendixsubsec"); +} + +/* The remainder of the text on this line is an appendix + subsubsection heading. */ +void +cm_appendixsubsubsec (void) +{ + sectioning_underscore ("appendixsubsubsec"); +} + +/* Compatibility functions substitute for chapter, section, etc. */ +void +cm_majorheading (void) +{ + sectioning_underscore ("majorheading"); +} + +void +cm_chapheading (void) +{ + sectioning_underscore ("chapheading"); +} + +void +cm_heading (void) +{ + sectioning_underscore ("heading"); +} + +void +cm_subheading (void) +{ + sectioning_underscore ("subheading"); +} + +void +cm_subsubheading (void) +{ + sectioning_underscore ("subsubheading"); +} diff --git a/Build/source/utils/texinfo/makeinfo/sectioning.h b/Build/source/utils/texinfo/makeinfo/sectioning.h new file mode 100644 index 00000000000..8c3f2201654 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/sectioning.h @@ -0,0 +1,103 @@ +/* sectioning.h -- all related stuff @chapter, @section... @contents + $Id: sectioning.h,v 1.5 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1999, 2003 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. */ + +/* Level 4. */ +extern void cm_chapter (void), + cm_unnumbered (void), + cm_appendix (void), + cm_top (void); + +/* Level 3. */ +extern void cm_section (void), + cm_unnumberedsec (void), + cm_appendixsec (void); + +/* Level 2. */ +extern void cm_subsection (void), + cm_unnumberedsubsec (void), + cm_appendixsubsec (void); + +/* Level 1. */ +extern void cm_subsubsection (void), + cm_unnumberedsubsubsec (void), + cm_appendixsubsubsec (void); + +/* Headings. */ +extern void cm_heading (void), + cm_chapheading (void), + cm_subheading (void), + cm_subsubheading (void), + cm_majorheading (void); + +extern void cm_raisesections (void), + cm_lowersections (void), + cm_ideprecated (int arg, int start, int end); + +extern void + sectioning_underscore (char *cmd), + insert_and_underscore (int level, char *cmd); + +/* needed in node.c */ +extern int set_top_section_level (int level); + +extern void sectioning_html (int level, char *cmd); +extern int what_section (char *text, char **secname); +extern char *current_chapter_number (void), + *current_sectioning_number (void), + *current_sectioning_name (void); + +/* 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/Build/source/utils/texinfo/makeinfo/tests/Makefile.am b/Build/source/utils/texinfo/makeinfo/tests/Makefile.am new file mode 100644 index 00000000000..6e58451b060 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/Makefile.am @@ -0,0 +1,36 @@ +# $Id: Makefile.am,v 1.5 2004/04/11 17:56:47 karl Exp $ +# Makefile.am for texinfo/tests/makeinfo. +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +TESTS = accent accentenc \ + cond \ + copying \ + defxcond \ + html-docdesc html-extrali html-min html-manuals html-para html-title \ + html-top \ + include-value \ + macro-at menu-whitespace \ + no-headers \ + node-expand node-value node-whitespace \ + top \ + twofiles + +noinst_SCRIPTS = $(TESTS) + +EXTRA_DIST = $(noinst_SCRIPTS) \ + accent.txi accentenc.txi accent-text.txi \ + cond.txi copying.txi \ + defxcond.txi \ + html-docdesc.txi html-extrali.txi html-min.txi html-para.txi html-title.txi \ + html-top.txi \ + include-value.txi incl-incl.txi \ + macro-at.txi menu-whitespace.txi \ + node-expand.txi node-value.txi node-whitespace.txi \ + top.txi # top2.txi diff --git a/Build/source/utils/texinfo/makeinfo/tests/Makefile.in b/Build/source/utils/texinfo/makeinfo/tests/Makefile.in new file mode 100644 index 00000000000..35a0d9f9a33 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/Makefile.in @@ -0,0 +1,447 @@ +# Makefile.in generated by automake 1.9.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# $Id: Makefile.am,v 1.5 2004/04/11 17:56:47 karl Exp $ +# Makefile.am for texinfo/tests/makeinfo. +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = makeinfo/tests +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/codeset.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc21.m4 \ + $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intdiv0.m4 \ + $(top_srcdir)/m4/intmax.m4 $(top_srcdir)/m4/inttypes-pri.m4 \ + $(top_srcdir)/m4/inttypes.m4 $(top_srcdir)/m4/inttypes_h.m4 \ + $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/longdouble.m4 $(top_srcdir)/m4/longlong.m4 \ + $(top_srcdir)/m4/mkstemp.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/onceonly_2_57.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/printf-posix.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/signed.m4 $(top_srcdir)/m4/size_max.m4 \ + $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/strcase.m4 \ + $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ + $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ + $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SCRIPTS = $(noinst_SCRIPTS) +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GENCAT = @GENCAT@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +HAVE_ASPRINTF = @HAVE_ASPRINTF@ +HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@ +HAVE_SNPRINTF = @HAVE_SNPRINTF@ +HAVE_WPRINTF = @HAVE_WPRINTF@ +HELP2MAN = @HELP2MAN@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTALL_WARNINGS_FALSE = @INSTALL_WARNINGS_FALSE@ +INSTALL_WARNINGS_TRUE = @INSTALL_WARNINGS_TRUE@ +INSTOBJEXT = @INSTOBJEXT@ +INTLBISON = @INTLBISON@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TERMLIBS = @TERMLIBS@ +TOOLS_ONLY_FALSE = @TOOLS_ONLY_FALSE@ +TOOLS_ONLY_TRUE = @TOOLS_ONLY_TRUE@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +native_tools = @native_tools@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +TESTS = accent accentenc \ + cond \ + copying \ + defxcond \ + html-docdesc html-extrali html-min html-manuals html-para html-title \ + html-top \ + include-value \ + macro-at menu-whitespace \ + no-headers \ + node-expand node-value node-whitespace \ + top \ + twofiles + +noinst_SCRIPTS = $(TESTS) +EXTRA_DIST = $(noinst_SCRIPTS) \ + accent.txi accentenc.txi accent-text.txi \ + cond.txi copying.txi \ + defxcond.txi \ + html-docdesc.txi html-extrali.txi html-min.txi html-para.txi html-title.txi \ + html-top.txi \ + include-value.txi incl-incl.txi \ + macro-at.txi menu-whitespace.txi \ + node-expand.txi node-value.txi node-whitespace.txi \ + top.txi # top2.txi + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu makeinfo/tests/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu makeinfo/tests/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list='$(TESTS)'; \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *" $$tst "*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + echo "XPASS: $$tst"; \ + ;; \ + *) \ + echo "PASS: $$tst"; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *" $$tst "*) \ + xfail=`expr $$xfail + 1`; \ + echo "XFAIL: $$tst"; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + echo "FAIL: $$tst"; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + echo "SKIP: $$tst"; \ + fi; \ + done; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="All $$all tests passed"; \ + else \ + banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all tests failed"; \ + else \ + banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + skipped="($$skip tests were not run)"; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(SCRIPTS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-TESTS check-am clean clean-generic \ + distclean distclean-generic distdir dvi dvi-am html html-am \ + info info-am install install-am install-data install-data-am \ + install-exec install-exec-am install-info install-info-am \ + install-man install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/Build/source/utils/texinfo/makeinfo/tests/accent b/Build/source/utils/texinfo/makeinfo/tests/accent new file mode 100755 index 00000000000..16c69e8e0d3 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/accent @@ -0,0 +1,34 @@ +#!/bin/sh +# Test accent output. + +unset TEXINFO_OUTPUT +: ${srcdir=.} +input=`basename $0`.txi + +# html. +houtput=`basename $0`.html +../makeinfo --html --no-split -I$srcdir $srcdir/$input +hexit_status=$? +if test $hexit_status = 0; then + grep 'ì' $houtput >/dev/null \ + && grep '´j' $houtput >/dev/null \ + && grep 'Ø' $houtput >/dev/null \ + && grep '/L' $houtput >/dev/null + hexit_status=$? +fi + +# info +ioutput=`basename $0`.info +../makeinfo --no-split -I$srcdir $srcdir/$input +iexit_status=$? +if test $iexit_status = 0; then + grep 'i`' $ioutput >/dev/null \ + && grep 'i"' $ioutput >/dev/null \ + && grep '/L' $ioutput >/dev/null + iexit_status=$? +fi + +rm -f $houtput $ioutput + +exit_status=`expr $hexit_status + $iexit_status` +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/accent-text.txi b/Build/source/utils/texinfo/makeinfo/tests/accent-text.txi new file mode 100644 index 00000000000..4d9ef3ca587 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/accent-text.txi @@ -0,0 +1,73 @@ +@c args with braces, without braces/following whitespace + +should be e`: @`{e} @`e + +should be e': @'{e} @'e + +should be e^: @^{e} @^e + +should be u": @"{u} @"u + +should be i`: @`{i} @`i + +should be i': @'{i} @'i + +should be i^: @^{i} @^i + +should be u": @"{u} @"u + +should be c,: @,{c} @,c + +should be n~: @~{n} @~n + +should be e=: @={e} @=e + +should be e@w{'}': @H{e} @H e + +should be e.: @dotaccent{e} @dotaccent e + +should be e*: @ringaccent{e} @ringaccent e + +should be ee[: @tieaccent{ee} + +should be e(: @u{e} @u e + +should be e_: @ubaraccent{e} @ubaraccent e + +should be .e: @udotaccent{e} @udotaccent e + +should be e<: @v{e} @v e + +upside down: @questiondown{} @exclamdown{} + +A-with-circle: @aa{},@AA{} + +AE, OE ligatures: @ae{} @AE{} @oe{} @OE{} + +dotless i, j: @dotless{i} @dotless{j} + +Polish suppressed-L: @l{} @L{} + +O-with-slash: @o{} @O{} + +es-zet or sharp S: @ss{} + +pounds sterling: @pounds{} + +@c arg is command -- @dotless{i} is special-cased for HTML +should be dotless i`: @`{@dotless{i}} + +should be dotless i': @'{@dotless{i}} + +should be dotless i^: @^{@dotless{i}} + +should be dotless i": @"{@dotless{i}} + +@c arg is command -- @dotless{j} +should be dotless j`: @`{@dotless{j}} + +should be dotless j': @'{@dotless{j}} + +should be dotless j^: @^{@dotless{j}} + +should be dotless j": @"{@dotless{j}} diff --git a/Build/source/utils/texinfo/makeinfo/tests/accent.txi b/Build/source/utils/texinfo/makeinfo/tests/accent.txi new file mode 100644 index 00000000000..3c52a90bde4 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/accent.txi @@ -0,0 +1,10 @@ +\input texinfo +@setfilename accent.info +@settitle Accent test + +@node Top +@top Accent test top + +@include accent-text.txi + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/accentenc b/Build/source/utils/texinfo/makeinfo/tests/accentenc new file mode 100755 index 00000000000..be842c368b8 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/accentenc @@ -0,0 +1,24 @@ +#!/bin/sh +# Test encoded accent info output. + +unset TEXINFO_OUTPUT +: ${srcdir=.} +input=`basename $0`.txi +output=`basename $0`.info + +# we expect two invalid encoded characters: +# accent-text.txi:45: warning: invalid encoded character `#156'. +# accent-text.txi:45: warning: invalid encoded character `#140'. +# These are oe and OE, and they are not supported in Latin 1. +../makeinfo --enable-encoding --no-split -I$srcdir $srcdir/$input 2>/dev/null +exit_status=$? +if test $exit_status = 0; then + grep 'ì' $output >/dev/null \ + && grep 'ï' $output >/dev/null \ + && grep '/L' $output >/dev/null + exit_status=$? +fi + +rm -f $output + +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/accentenc.txi b/Build/source/utils/texinfo/makeinfo/tests/accentenc.txi new file mode 100644 index 00000000000..b6e209c64fa --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/accentenc.txi @@ -0,0 +1,11 @@ +\input texinfo +@setfilename accentenc.info +@settitle Accent encoding test +@documentencoding ISO-8859-1 + +@node Top +@top Accent encoding test top + +@include accent-text.txi + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/cond b/Build/source/utils/texinfo/makeinfo/tests/cond new file mode 100755 index 00000000000..24a1cd4cb3a --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/cond @@ -0,0 +1,33 @@ +#!/bin/sh +# Test conditional text. + +unset TEXINFO_OUTPUT +: ${srcdir=.} + +# Default Info output. +../makeinfo -o cond.out $srcdir/cond.txi || exit 1 +egrep 'This is (ifnothtml|ifinfo|ifnottex) text' cond.out >/dev/null \ + || exit 2 +test `fgrep ' text.' cond.out | wc -l` -eq 3 || exit 3 + +# Default HTML output. +../makeinfo --no-split --html -o cond.out $srcdir/cond.txi || exit 1 +egrep 'This is (html|ifhtml|ifnotinfo|ifnottex) text' cond.out >/dev/null \ + || exit 2 +test `fgrep ' text.' cond.out | wc -l` -eq 4 || exit 3 + +# --ifhtml off, --ifinfo off, --iftex off. +../makeinfo --no-ifhtml --no-ifinfo --no-iftex -o cond.out $srcdir/cond.txi || exit 1 +egrep 'This is ifnot(html|info|tex) text' cond.out >/dev/null \ + || exit 2 +test `fgrep ' text.' cond.out | wc -l` -eq 3 || exit 3 + +# Do we really need to test all the other permutations? + +# --ifhtml on, --ifinfo on, --iftex on. +../makeinfo --ifhtml --ifinfo --iftex -o cond.out $srcdir/cond.txi || exit 1 +egrep 'This is (html|ifhtml|ifinfo|tex|iftex) text' cond.out >/dev/null \ + || exit 2 +test `fgrep ' text.' cond.out | wc -l` -eq 5 || exit 3 + +rm -f cond.out cond.info diff --git a/Build/source/utils/texinfo/makeinfo/tests/cond.txi b/Build/source/utils/texinfo/makeinfo/tests/cond.txi new file mode 100644 index 00000000000..b60242322dc --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/cond.txi @@ -0,0 +1,40 @@ +\input texinfo +@setfilename cond.info + +@node Top + +@html +This is html text. +@end html + +@ifhtml +This is ifhtml text. +@end ifhtml + +@ifnothtml +This is ifnothtml text. +@end ifnothtml + + +@ifinfo +This is ifinfo text. +@end ifinfo + +@ifnotinfo +This is ifnotinfo text. +@end ifnotinfo + + +@tex +This is tex text. +@end tex + +@iftex +This is iftex text. +@end iftex + +@ifnottex +This is ifnottex text. +@end ifnottex + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/copying b/Build/source/utils/texinfo/makeinfo/tests/copying new file mode 100755 index 00000000000..4fa77d607de --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/copying @@ -0,0 +1,13 @@ +#!/bin/sh +# $Id: copying,v 1.2 2004/04/20 13:26:00 karl Exp $ +# Test @copying. The configure script for tramp uses this to make sure +# the makeinfo that is present supports @copying. + +unset TEXINFO_OUTPUT LANG LANGUAGE +LC_ALL=POSIX; export LC_ALL +: ${srcdir=.} + +../makeinfo -o copying.out $srcdir/copying.txi || exit 1 +fgrep 'produced by' copying.out >/dev/null || exit 2 + +rm -f copying.out diff --git a/Build/source/utils/texinfo/makeinfo/tests/copying.txi b/Build/source/utils/texinfo/makeinfo/tests/copying.txi new file mode 100644 index 00000000000..3b836795050 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/copying.txi @@ -0,0 +1,4 @@ +\input texinfo @c -*-texinfo-*- +@copying +@end copying +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/defxcond b/Build/source/utils/texinfo/makeinfo/tests/defxcond new file mode 100755 index 00000000000..e48986785d7 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/defxcond @@ -0,0 +1,16 @@ +#!/bin/sh +# Test conditionalized @deffnx. +# Report from: Akim Demaille <akim@epita.fr>, 14 Aug 2003 12:10:37 +0200. + +unset TEXINFO_OUTPUT +: ${srcdir=.} + +test=defxcond + +../makeinfo -Dbar -o $test.out $srcdir/$test.txi || exit 1 +grep ' -- bar:' $test.out >/dev/null || exit 2 + +../makeinfo -Ubar -o $test.out $srcdir/$test.txi || exit 3 +grep ' -- bar:' $test.out >/dev/null && exit 4 + +rm -f $test.out diff --git a/Build/source/utils/texinfo/makeinfo/tests/defxcond.txi b/Build/source/utils/texinfo/makeinfo/tests/defxcond.txi new file mode 100644 index 00000000000..a7af9e21e75 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/defxcond.txi @@ -0,0 +1,18 @@ +\input texinfo +@setfilename defxcond.info + +@c set this from the command line. +@c set bar + +@c deffnx inside conditional. +@deffn foo + +@ifset bar +@deffnx bar +@end ifset + +Documentation. + +@end deffn + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-docdesc b/Build/source/utils/texinfo/makeinfo/tests/html-docdesc new file mode 100755 index 00000000000..59df74e411b --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-docdesc @@ -0,0 +1,12 @@ +#!/bin/sh +# Test that @documentdescription works. + +if ../makeinfo --html --no-split ${srcdir-.}/html-docdesc.txi; then + grep 'explicit document description' html-docdesc.html >/dev/null + exit_status=$? +else + exit_status=1 +fi + +rm -f html-docdesc.html +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-docdesc.txi b/Build/source/utils/texinfo/makeinfo/tests/html-docdesc.txi new file mode 100644 index 00000000000..0b328dacd2a --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-docdesc.txi @@ -0,0 +1,14 @@ +\input texinfo +@setfilename html-docdesc.info +@settitle HTML docdesc test + +@documentdescription +This is the explicit document description. +@end documentdescription + +@node Top +@top Top of HTML docdesc test + +This is the top. + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-extrali b/Build/source/utils/texinfo/makeinfo/tests/html-extrali new file mode 100755 index 00000000000..c3ec9ca08d5 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-extrali @@ -0,0 +1,15 @@ +#!/bin/sh +# Test no extra <li> from @menu. + +: ${srcdir=.} + +li_count=`../makeinfo --no-split --html -o - $srcdir/html-extrali.txi 2>/dev/null \ +| grep '<li>' \ +| wc -l` + +if test "$li_count" -ne 1; then + echo "$li_count <li>s instead of one." >&2 + exit 1 +else + exit 0 +fi diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-extrali.txi b/Build/source/utils/texinfo/makeinfo/tests/html-extrali.txi new file mode 100644 index 00000000000..d0c17e98785 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-extrali.txi @@ -0,0 +1,11 @@ +\input texinfo +@setfilename menuli.info + +@c extra li generated after <menu> +@c From: Marius Groeger <mag@sysgo.de>, 13nov98. + +@menu +* entry1:: +@end menu + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-manuals b/Build/source/utils/texinfo/makeinfo/tests/html-manuals new file mode 100755 index 00000000000..2ba24f34a44 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-manuals @@ -0,0 +1,13 @@ +#!/bin/sh +# $Id: html-manuals,v 1.3 2004/04/11 17:56:47 karl Exp $ +# Test that all the distribution manuals can be converted to HTML. + +: ${srcdir=.} + +for manual in info.texi info-stnd.texi texinfo.txi; do + base=`echo $manual | sed 's/\.te*xi$//'` + ../makeinfo --html -I$srcdir/../../doc -I../../doc --no-split \ + $srcdir/../../doc/$manual -o $base.html \ + || exit 1 + rm -f $base.html +done diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-min b/Build/source/utils/texinfo/makeinfo/tests/html-min new file mode 100755 index 00000000000..948071a9917 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-min @@ -0,0 +1,8 @@ +#!/bin/sh +# Test that a minimal Texinfo file can be converted to HTML. + +../makeinfo --html --no-split ${srcdir-.}/html-min.txi +exit_status=$? + +rm -f html-min.html +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-min.txi b/Build/source/utils/texinfo/makeinfo/tests/html-min.txi new file mode 100644 index 00000000000..116519e0611 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-min.txi @@ -0,0 +1,12 @@ +\input texinfo +@setfilename html-min.info +@settitle HTML min test + +@node Top +@top Top of HTML min test + +Top. + +Second paragraph. + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-para b/Build/source/utils/texinfo/makeinfo/tests/html-para new file mode 100755 index 00000000000..a9ea2b5a9bd --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-para @@ -0,0 +1,8 @@ +#!/bin/sh +# Test that paragraph beginnings in HTML work ok. + +../makeinfo --no-split --html ${srcdir-.}/html-para.txi +exit_status=$? + +rm -f html-para.html +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-para.txi b/Build/source/utils/texinfo/makeinfo/tests/html-para.txi new file mode 100644 index 00000000000..c6e34fd2513 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-para.txi @@ -0,0 +1,24 @@ +\input texinfo +@setfilename html-para.info +@settitle HTML paragraph beginning test + +@c <p> is emitted at paragraph beginning, which makes the text +@c between START and END not exactly what some cm_xxx functions +@c expect, when they are called by pop_and_call_brace. + +@set val @@value@{@} +@definfoenclose foo,\\,// + +@node Top +@top Top of HTML paragraph test + +@value{val} should work at the beginning of a new paragraph. + +@dotless{i} dotless should not trigger error messages at the beginning +of a new paragraph. + +@sc{small-caps} should work at the beginning of a new paragraph. + +@foo{@@definfoenclose} should work at the beginning of a new paragraph. + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-title b/Build/source/utils/texinfo/makeinfo/tests/html-title new file mode 100755 index 00000000000..54badd51fad --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-title @@ -0,0 +1,13 @@ +#!/bin/sh +# Test that titles with @ commands don't produce markup in the <title>. +# (And that the @ commands get expanded.) + +if ../makeinfo --no-split --html ${srcdir-.}/html-title.txi; then + grep '^<title>@[^<>]*</title>$' html-title.html >/dev/null + exit_status=$? +else + exit_status=1 +fi + +rm -f html-title.html +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-title.txi b/Build/source/utils/texinfo/makeinfo/tests/html-title.txi new file mode 100644 index 00000000000..2e2f25c579f --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-title.txi @@ -0,0 +1,12 @@ +\input texinfo +@setfilename html-title.info +@settitle @@title @sc{html} @code{test} + +@node Top +@top Top of @@title @sc{html} @code{test} + +Top. + +Second paragraph. + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-top b/Build/source/utils/texinfo/makeinfo/tests/html-top new file mode 100755 index 00000000000..038404a49d1 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-top @@ -0,0 +1,13 @@ +#!/bin/sh +# Test that a bare top node does not crash with --html. + +: ${srcdir=.} + +# But this input file is erroneous, so throw away errors. +../makeinfo --no-split --force -o html-top.html --html $srcdir/html-top.txi \ +2>/dev/null +test -s html-top.html +exit_status=$? + +rm -f html-top.html +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/html-top.txi b/Build/source/utils/texinfo/makeinfo/tests/html-top.txi new file mode 100644 index 00000000000..ade7214b0c2 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/html-top.txi @@ -0,0 +1,7 @@ +\input texinfo +@setfilename top.info + +@node start +@top + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/incl-incl.txi b/Build/source/utils/texinfo/makeinfo/tests/incl-incl.txi new file mode 100644 index 00000000000..4efea484317 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/incl-incl.txi @@ -0,0 +1 @@ +This is the @emph{included} file (include-value2.txi). diff --git a/Build/source/utils/texinfo/makeinfo/tests/include-value b/Build/source/utils/texinfo/makeinfo/tests/include-value new file mode 100755 index 00000000000..2c4ca60eff5 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/include-value @@ -0,0 +1,22 @@ +#!/bin/sh +# $Id: include-value,v 1.3 2004/04/11 17:56:47 karl Exp $ +# Test @value expansion in @include and @verbatiminclude names. + +unset TEXINFO_OUTPUT +: ${srcdir=.} + +../makeinfo -I $srcdir $srcdir/include-value.txi +exit_status=$? + +if test $exit_status = 0; then + # should have three instances of _included_, + # and three of {included}. + count=`grep _included_ include-value.info | wc -l` + test $count = 3 || exit_status=`expr $exit_status + 1` + + count=`grep '{included}' include-value.info | wc -l` + test $count = 3 || exit_status=`expr $exit_status + 1` +fi + +rm -f include-value.info +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/include-value.txi b/Build/source/utils/texinfo/makeinfo/tests/include-value.txi new file mode 100644 index 00000000000..1c7f9b93d16 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/include-value.txi @@ -0,0 +1,32 @@ +\input texinfo +@setfilename include-value.info +@c $Id: include-value.txi,v 1.2 2004/04/11 17:56:47 karl Exp $ + +@set testvar incl-incl.txi + +@c test - in the variable name, and concatenation of text after. +@set test-var incl-incl.tx + +@c test - in the variable name, and concatenation of text before and after. +@set test_var ncl-incl.tx + + +@node Top + +testvar include: @include @value{testvar} + +testvar verbatiminclude: @verbatiminclude @value{testvar} + + +test-var include: @include @value{test-var}i + +test-var verbatiminclude: @verbatiminclude @value{test-var}i + + +test_var include: @include i@value{test_var}i + +test_var verbatiminclude: @verbatiminclude i@value{test_var}i + + +@bye + diff --git a/Build/source/utils/texinfo/makeinfo/tests/macro-at b/Build/source/utils/texinfo/makeinfo/tests/macro-at new file mode 100755 index 00000000000..a9dfdab3be9 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/macro-at @@ -0,0 +1,8 @@ +#!/bin/sh +# Test @@ in macro expansions, etc. --eliz, 14nov99. + +unset TEXINFO_OUTPUT +: ${srcdir=.} +../makeinfo $srcdir/macro-at.txi || exit 1 + +rm -f macro-at.info diff --git a/Build/source/utils/texinfo/makeinfo/tests/macro-at.txi b/Build/source/utils/texinfo/makeinfo/tests/macro-at.txi new file mode 100644 index 00000000000..24b91013456 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/macro-at.txi @@ -0,0 +1,38 @@ +\input texinfo @c -*- texinfo -*- +@setfilename macro-at.info +@settitle AUTHORS -- who did what on GNU LilyPond + +@macro foo +foo-expansion +@end macro + +@macro bar +bar-expansion +@end macro + +@node Top, , AUTHORS -- who did what on GNU LilyPond, (dir) +@top +@menu +* AUTHORS -- who did what on GNU LilyPond:: AUTHORS -- who did what. +@end menu + +@node AUTHORS -- who did what on GNU LilyPond, Top, , Top +@chapter AUTHORS -- who did what on GNU LilyPond? + +This file lists authors of GNU LilyPond, and what they wrote. +It also uses foobar@{. + +@itemize @bullet +@item @email{pinard@@iro.montreal.ca, Fran@,{c}ois Pinard}, + parts of Documentation. +@item @email{foobar@@baz@@, The Foobar}, + the usual foobarical thing. +@item @email{another@@foobar@{, Buzzer}, + buzzed all the way. +@item @email{@foo{}@@@bar{}}, + also helped. +@item @email{tomcato@@xoommail.com, Tom Cato Amundsen}, + cembalo-partita in mundela. +@end itemize + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/menu-whitespace b/Build/source/utils/texinfo/makeinfo/tests/menu-whitespace new file mode 100755 index 00000000000..a01a38d5c04 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/menu-whitespace @@ -0,0 +1,72 @@ +#!/bin/sh +# Bug where whitespace after @menu caused confusion. + +unset TEXINFO_OUTPUT +: ${srcdir=.} +input=`basename $0`.txi + +../makeinfo -o /dev/null $srcdir/$input +exit $? + +Date: 07 Dec 1998 11:23:44 +0100 +From: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> +To: bug-texinfo@gnu.org +Subject: Makeinfo mishandles defaulted node links + +The following example demonstrates a bug in makeinfo: + +$ cat top.texi +@setfilename top.info + +@node Top +@top Top + +@menu +* first:: +@end menu + +@node first +@chapter first + +@menu @c +* second:: +@end menu + +@node second +@section second +$ makeinfo top.texi +Making info file `top.info' from `top.texi'. +./top.texi:3: Next field of node `Top' not pointed to. +./top.texi:17: This node (second) has the bad Prev. +makeinfo: Removing output file `/home/as/test/top.info' due to errors; use --force to preserve. + +Makeinfo is being confused by the whitespace after @menu, or rather by its +absence. + + +1998-12-06 Andreas Schwab <schwab@issan.cs.uni-dortmund.de> + + * makeinfo/node.c (cm_node): When searching for @menu don't + require a space after it. + +--- texinfo-3.12b/makeinfo/node.c.~1~ Mon Oct 26 23:14:59 1998 ++++ texinfo-3.12b/makeinfo/node.c Sun Dec 6 00:23:59 1998 +@@ -523,9 +523,10 @@ + orig_size = size_of_input_text; + + input_text_offset = +- search_forward ("\n@menu ", orig_offset); ++ search_forward ("\n@menu", orig_offset); + +- if (input_text_offset > -1) ++ if (input_text_offset > -1 ++ && cr_or_whitespace (input_text[input_text_offset + 6])) + { + char *nodename_from_menu = NULL; + + +-- +Andreas Schwab "And now for something +schwab@issan.cs.uni-dortmund.de completely different" +schwab@gnu.org + diff --git a/Build/source/utils/texinfo/makeinfo/tests/menu-whitespace.txi b/Build/source/utils/texinfo/makeinfo/tests/menu-whitespace.txi new file mode 100644 index 00000000000..fd1c39f7ebf --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/menu-whitespace.txi @@ -0,0 +1,18 @@ +@setfilename top.info + +@node Top +@top Top + +@menu +* first:: +@end menu + +@node first +@chapter first + +@menu @c +* second:: +@end menu + +@node second +@section second diff --git a/Build/source/utils/texinfo/makeinfo/tests/no-headers b/Build/source/utils/texinfo/makeinfo/tests/no-headers new file mode 100755 index 00000000000..e0718713f32 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/no-headers @@ -0,0 +1,9 @@ +#!/bin/sh +# Test that info.texi works with --no-headers (this includes node +# pointer defaulting). + +unset TEXINFO_OUTPUT +: ${srcdir=.} +docdir=$srcdir/../../doc + +../makeinfo --no-headers -o /dev/null -I$docdir info.texi diff --git a/Build/source/utils/texinfo/makeinfo/tests/node-expand b/Build/source/utils/texinfo/makeinfo/tests/node-expand new file mode 100755 index 00000000000..26dee246478 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/node-expand @@ -0,0 +1,12 @@ +#!/bin/sh +# Test command expansion in node names. + +unset TEXINFO_OUTPUT +: ${srcdir=.} + +../makeinfo --commands-in-node-names $srcdir/node-expand.txi +test -s node-expand.info +exit_status=$? + +rm -f node-expand.info +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/node-expand.txi b/Build/source/utils/texinfo/makeinfo/tests/node-expand.txi new file mode 100644 index 00000000000..c31be5a4ebc --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/node-expand.txi @@ -0,0 +1,64 @@ +\input texinfo.tex @c -*-texinfo-*- + +@setfilename node-expand.info + +@c Makeinfo should expand non-macros such as @@ and @value +@c in node names and node references, including menus. +@c This file deliberately references "Node 1" both via +@c @value and directly; this should not trigger any errors, +@c as long as --commands-in-node-names is used. +@c Index entries should all be expanded as well. + +@set node1 Node 1 + +@ifnottex + +@node Top, (dir), (dir), (dir) +@top Expansion in Node Names + +@end ifnottex + +@menu +* @value{node1} :: +* @@node `2':: +* ``node'' with---tricks:: +@end menu + +@xref{@@node `2'}. + +@node @value{node1}, @@node `2', Top, Top +@chapter Chapter 1 + +@cindex entry for chapter 1 +This is chapter 1. +@xref{@@node `2'}. + +@set sec1 Section 1.1 + +@menu +* @value{sec1}:: +@end menu + +@node Section 1.1, , Node 1, Node 1 +@comment node-name, next, previous, up + +@cindex entry for section 1.1 +This is section 1.1. + +@node @@node `2', ``node'' with---tricks, @value{node1}, Top +@comment node-name, next, previous, up +@chapter Node 2 + +@cindex entry for chapter 2 +This is chapter 2. +@xref{@value{node1}}. @xref{Node 1}. +@xref{``node'' with---tricks, Node with some tricks}. + +@node ``node'' with---tricks, , @@node `2', Top + +@cindex tricks +Another node. + +@printindex cp + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/node-value b/Build/source/utils/texinfo/makeinfo/tests/node-value new file mode 100755 index 00000000000..aff0be22dea --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/node-value @@ -0,0 +1,12 @@ +#!/bin/sh +# Test @value expansion in node names. + +unset TEXINFO_OUTPUT +: ${srcdir=.} + +../makeinfo $srcdir/node-value.txi +grep -v "No Value" node-value.info >/dev/null +exit_status=$? + +rm -f node-value.info +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/node-value.txi b/Build/source/utils/texinfo/makeinfo/tests/node-value.txi new file mode 100644 index 00000000000..ba1173f9a89 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/node-value.txi @@ -0,0 +1,15 @@ +\input texinfo +@setfilename node-value.info +@set a--foo bar + +@node Top, @value{a--foo}, (dir), (dir) +@top Var @value{a--foo} +@value{a--foo} + +@node @value{a--foo}, BarFoo, Top, (dir) +@chapter BarFoo + +@node BarFoo, , @value{a--foo}, (dir) +@chapter bar + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/node-whitespace b/Build/source/utils/texinfo/makeinfo/tests/node-whitespace new file mode 100755 index 00000000000..e4801089884 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/node-whitespace @@ -0,0 +1,12 @@ +#!/bin/sh +# Test whitespace collapse in node names. + +unset TEXINFO_OUTPUT +: ${srcdir=.} + +../makeinfo $srcdir/node-whitespace.txi +test -s node-whitespace.info +exit_status=$? + +rm -f node-whitespace.info +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/node-whitespace.txi b/Build/source/utils/texinfo/makeinfo/tests/node-whitespace.txi new file mode 100644 index 00000000000..04f0339a8c8 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/node-whitespace.txi @@ -0,0 +1,30 @@ +\input texinfo.tex @c -*-texinfo-*- + +@setfilename node-whitespace.info + +@c Makeinfo should collapse whitespace in node names. + +@ifnottex + +@node Top +@top Whitespace in Node Names + +@end ifnottex + +@menu +* Chap 1.3 :: +* Chap 1.4 :Chap 1.4. +@end menu + +@node Chap 1.3 +@chapter Chap 1.3 + +Can I reach here? + +@node Chap 1.4 +@chapter Another space test + +How about here? +@xref{Chap 1.3}. + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/top b/Build/source/utils/texinfo/makeinfo/tests/top new file mode 100755 index 00000000000..c1288f39fed --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/top @@ -0,0 +1,11 @@ +#!/bin/sh +# Test that a top node can be ignored. + +unset TEXINFO_OUTPUT +: ${srcdir=.} +../makeinfo $srcdir/top.txi || exit 1 + +# Expected warnings due to use of @ifinfo instead of @ifnottex. +../makeinfo --no-split --no-warn --html $srcdir/top.txi -o top.html || exit 1 + +rm -f top*.html top.info diff --git a/Build/source/utils/texinfo/makeinfo/tests/top.txi b/Build/source/utils/texinfo/makeinfo/tests/top.txi new file mode 100644 index 00000000000..e8c3cbbc078 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/top.txi @@ -0,0 +1,25 @@ +\input texinfo +@setfilename top.info +@settitle top test + +@c This traditional top node uses @ifinfo for testing. +@c Therefore there will be warnings when processing with --html. +@c The solution is to use @ifnottex instead. + +@ifinfo +@node Top +@top Top test + +Typical top node. +@end ifinfo + +@menu +* Subnode:: +@end menu + +@node Subnode +@chapter Subnode + +Subnode. + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/top2 b/Build/source/utils/texinfo/makeinfo/tests/top2 new file mode 100755 index 00000000000..7bc27c14c4a --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/top2 @@ -0,0 +1,12 @@ +#!/bin/sh +# Test that a bare top node does not crash with --html. + +: ${srcdir=.} + +# But this input file is erroneous, so throw away errors. +../makeinfo --no-split --force -o top2.html --html $srcdir/top2.txi 2>/dev/null +test -s top2.html +exit_status=$? + +rm -f top2.html +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/tests/top2.txi b/Build/source/utils/texinfo/makeinfo/tests/top2.txi new file mode 100644 index 00000000000..ade7214b0c2 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/top2.txi @@ -0,0 +1,7 @@ +\input texinfo +@setfilename top.info + +@node start +@top + +@bye diff --git a/Build/source/utils/texinfo/makeinfo/tests/twofiles b/Build/source/utils/texinfo/makeinfo/tests/twofiles new file mode 100755 index 00000000000..22c477c9d57 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/tests/twofiles @@ -0,0 +1,23 @@ +#!/bin/sh +# $Id: twofiles,v 1.3 2004/04/11 17:56:47 karl Exp $ +# Test that an existing and nonexisting file doesn't cause a +# segmentation fault. +# From: Arkadiusz Miskiewicz <misiek@pld.ORG.PL>, 15 Feb 2003 13:22:49 +0100. + +unset TEXINFO_OUTPUT +: ${srcdir=.} + +outfile=outfile +errfile=errfile +trap 'status=$?; rm -f $outfile $errfile && exit $status' 0 + +../makeinfo -o /dev/null $srcdir/html-min.txi /nonexistent.texinfo \ +>$outfile 2>$errfile +exit_status=$? + +# we expect one error message about /nonexistent.texinfo and bad exit status. +test $exit_status -ne 0 \ +&& grep /nonexistent $errfile >/dev/null \ +&& exit_status=0 + +exit $exit_status diff --git a/Build/source/utils/texinfo/makeinfo/texinfo.dtd b/Build/source/utils/texinfo/makeinfo/texinfo.dtd new file mode 100644 index 00000000000..bdd34c95f54 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/texinfo.dtd @@ -0,0 +1,337 @@ +<!-- $Id: texinfo.dtd,v 1.2 2002/12/17 16:34:22 karl Exp $ + Document Type Definition for Texinfo. + + Author: Philippe Martin (feloy@free.fr) + Contributors: + Karl Eichwalder (keichwa@gmx.net) + + Copyright (C) 2001, 02 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. */ +--> + +<!-- ENTITIES --> + +<!-- Meta-information --> +<!ENTITY % metainformation "setfilename | settitle | titlefont | dircategory"> + +<!-- block --> +<!-- ***** --> +<!ENTITY % block "menu | para | quotation | example | smallexample | lisp + | smalllisp | cartouche | copying + | format | smallformat | display + | smalldisplay | itemize | enumerate | sp | center | group + | table | multitable"> + +<!-- Sectioning --> +<!-- ********** --> +<!ENTITY % section.level1 "top | chapter | unnumbered | appendix + | majorheading | chapheading"> + +<!ENTITY % section.level2 "section | unnumberedsec | appendixsec | heading"> + +<!ENTITY % section.level3 "subsection | unnumberedsubsec | appendixsubsec + | subheading"> + +<!ENTITY % section.level4 "subsubsection | unnumberedsubsubsec + | appendixsubsubsec | subsubheading"> + +<!ENTITY % section.all "%section.level1; | %section.level2; | %section.level3; + | %section.level4;"> + + +<!ENTITY % section.level1.content "(%block; + | %section.level2; + | %section.level3; + | %section.level4; + | printindex)*"> + +<!ENTITY % section.level2.content "(%block; + | %section.level3; + | %section.level4;)*"> + +<!ENTITY % section.level3.content "(%block; + | %section.level4;)*"> + +<!ENTITY % section.level4.content "(%block;)*"> + + +<!-- Inline --> +<!-- ****** --> +<!ENTITY % Inline.emphasize "strong | emph"> +<!ENTITY % Inline.smallcaps "sc"> +<!ENTITY % Inline.fonts "i | b | tt | r"> +<!ENTITY % Inline.markup "code | dfn | cite | key | kbd | var | acronym | url"> +<!ENTITY % Inline.reference "xref | inforef | indexterm | email | uref"> + +<!ENTITY % Inline.phrase + "%Inline.emphasize; | %Inline.smallcaps; | %Inline.fonts; + | %Inline.markup; | %Inline.reference; "> + + +<!-- ************ --> +<!-- * ELEMENTS * --> +<!-- ************ --> + +<!-- TOP Level Element --> +<!-- ***************** --> +<!ELEMENT texinfo ((%metainformation; | node | %block;)* )> + +<!-- meta-information --> +<!ELEMENT setfilename (#PCDATA)> +<!ELEMENT settitle (#PCDATA)> +<!ELEMENT titlefont (#PCDATA)> +<!ELEMENT dircategory (#PCDATA)> + +<!-- NODES --> +<!-- ***** --> +<!ELEMENT node (nodename, nodenext?, nodeprev?, nodeup?, + (%section.all; | %block;)*) > + +<!ELEMENT nodename (#PCDATA)> +<!ELEMENT nodenext (#PCDATA)> +<!ELEMENT nodeprev (#PCDATA)> +<!ELEMENT nodeup (#PCDATA)> + +<!-- SECTIONING --> +<!-- ********** --> + +<!ELEMENT top (title?, %section.level1.content;)> + +<!ELEMENT chapter (title?, %section.level1.content;)> +<!ELEMENT section (title?, %section.level2.content;)> +<!ELEMENT subsection (title?, %section.level3.content;)> +<!ELEMENT subsubsection (title?, %section.level4.content;)> + +<!ELEMENT unnumbered (title?, %section.level1.content;)> +<!ELEMENT unnumberedsec (title?, %section.level2.content;)> +<!ELEMENT unnumberedsubsec (title?, %section.level3.content;)> +<!ELEMENT unnumberedsubsubsec (title?, %section.level4.content;)> + +<!ELEMENT appendix (title?, %section.level1.content;)> +<!ELEMENT appendixsec (title?, %section.level2.content;)> +<!ELEMENT appendixsubsec (title?, %section.level3.content;)> +<!ELEMENT appendixsubsubsec (title?, %section.level4.content;)> + +<!ELEMENT majorheading (title?, %section.level1.content;)> +<!ELEMENT chapheading (title?, %section.level1.content;)> +<!ELEMENT heading (title?, %section.level2.content;)> +<!ELEMENT subheading (title?, %section.level3.content;)> +<!ELEMENT subsubheading (title?, %section.level4.content;)> + +<!ELEMENT title (#PCDATA | %Inline.phrase; | footnote)*> + +<!-- BLOCK Elements --> +<!-- ************** --> + +<!ELEMENT quotation (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT example (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT smallexample (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT lisp (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT smalllisp (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT cartouche (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT copying (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT format (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT smallformat (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT display (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT smalldisplay (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT center (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT group (#PCDATA | %block; | %Inline.phrase;)*> +<!ELEMENT image (#PCDATA)> + +<!ELEMENT para (#PCDATA | %Inline.phrase; | footnote)*> + +<!ELEMENT menu ((menuentry | para)*)> +<!ELEMENT menuentry (menunode?, menutitle?, menucomment?)> +<!ELEMENT menunode (#PCDATA)> +<!ELEMENT menutitle (#PCDATA)> +<!ELEMENT menucomment (#PCDATA | para)*> + +<!-- Lists --> +<!ELEMENT itemize (itemfunction, (item | itemize | enumerate | indexterm)*)> +<!ELEMENT enumerate (enumarg?, (item | itemize | enumerate)*)> +<!ATTLIST enumerate + first CDATA #IMPLIED> + +<!ELEMENT item (%block;)*> +<!ELEMENT enumarg (#PCDATA)> + +<!ELEMENT itemfunction (#PCDATA | %Inline.phrase;)*> + +<!-- Tables --> +<!ELEMENT table (tableitem | indexterm)+> +<!ELEMENT tableitem (tableterm+, item)> +<!ELEMENT tableterm (#PCDATA | %Inline.phrase;)*> + +<!ELEMENT multitable (columnfraction*, row*)> +<!ELEMENT columnfraction (#PCDATA)> +<!ELEMENT row (entry*)> +<!ELEMENT entry (#PCDATA | %Inline.phrase;)*> + +<!-- INLINE Elements --> +<!-- *************** --> + +<!-- Emphasize --> +<!ELEMENT strong (#PCDATA | %Inline.phrase;)*> +<!ELEMENT emph (#PCDATA | %Inline.phrase;)*> + +<!-- small caps --> +<!ELEMENT sc (#PCDATA | %Inline.phrase;)*> + +<!-- fonts --> +<!ELEMENT i (#PCDATA | %Inline.phrase;)*> +<!ELEMENT b (#PCDATA | %Inline.phrase;)*> +<!ELEMENT tt (#PCDATA | %Inline.phrase;)*> +<!ELEMENT r (#PCDATA | %Inline.phrase;)*> +<!ELEMENT notfixedwidth (#PCDATA | %Inline.phrase;)*> + +<!-- markup --> +<!ELEMENT code (#PCDATA | %Inline.phrase;)*> +<!ELEMENT dfn (#PCDATA | %Inline.phrase;)*> +<!ELEMENT cite (#PCDATA | %Inline.phrase;)*> +<!ELEMENT key (#PCDATA | %Inline.phrase;)*> +<!ELEMENT kbd (#PCDATA | %Inline.phrase;)*> +<!ELEMENT var (#PCDATA | %Inline.phrase;)*> +<!ELEMENT acronym (#PCDATA | %Inline.phrase;)*> +<!ELEMENT url (#PCDATA | %Inline.phrase;)*> + +<!-- reference --> +<!ELEMENT anchor EMPTY> +<!ATTLIST anchor + name CDATA #IMPLIED> + +<!ELEMENT xref (xrefnodename | xrefinfoname | xrefinfofile + | xrefprintedname | xrefprinteddesc)*> +<!ELEMENT xrefnodename (#PCDATA | %Inline.phrase;)*> +<!ELEMENT xrefinfoname (#PCDATA | %Inline.phrase;)*> +<!ELEMENT xrefinfofile (#PCDATA | %Inline.phrase;)*> +<!ELEMENT xrefprintedname (#PCDATA | %Inline.phrase;)*> +<!ELEMENT xrefprinteddesc (#PCDATA | %Inline.phrase;)*> + +<!ELEMENT inforef (inforefnodename | inforefrefname | inforefinfoname)*> +<!ELEMENT inforefnodename (#PCDATA | %Inline.phrase;)*> +<!ELEMENT inforefrefname (#PCDATA | %Inline.phrase;)*> +<!ELEMENT inforefinfoname (#PCDATA | %Inline.phrase;)*> + +<!ELEMENT indexterm (#PCDATA | %Inline.phrase;)*> +<!ATTLIST indexterm + index CDATA #IMPLIED> + +<!ELEMENT email (emailaddress, emailname?)> +<!ELEMENT emailaddress (#PCDATA | %Inline.phrase;)*> +<!ELEMENT emailname (#PCDATA | %Inline.phrase;)*> + +<!ELEMENT uref (urefurl, urefdesc?, urefreplacement?)> +<!ELEMENT urefurl (#PCDATA | %Inline.phrase;)*> +<!ELEMENT urefdesc (#PCDATA | %Inline.phrase;)*> +<!ELEMENT urefreplacement (#PCDATA | %Inline.phrase;)*> + +<!ELEMENT footnote (para)> + + + +<!ENTITY tex "TeX"> +<!ENTITY ellipsis ""> +<!ENTITY lt ""> +<!ENTITY gt ""> +<!ENTITY bullet ""> +<!ENTITY copyright ""> +<!ENTITY minus ""> +<!ENTITY linebreak ""> +<!ENTITY space ""> +<!ENTITY dots ""> +<!ENTITY enddots ""> +<!ENTITY amp ""> + +<!ENTITY auml ""> +<!ENTITY ouml ""> +<!ENTITY uuml ""> +<!ENTITY Auml ""> +<!ENTITY Ouml ""> +<!ENTITY Uuml ""> +<!ENTITY Euml ""> +<!ENTITY euml ""> +<!ENTITY Iuml ""> +<!ENTITY iuml ""> +<!ENTITY yuml ""> +<!ENTITY uml ""> + +<!ENTITY Aacute ""> +<!ENTITY Eacute ""> +<!ENTITY Iacute ""> +<!ENTITY Oacute ""> +<!ENTITY Uacute ""> +<!ENTITY Yacute ""> +<!ENTITY aacute ""> +<!ENTITY eacute ""> +<!ENTITY iacute ""> +<!ENTITY oacute ""> +<!ENTITY uacute ""> +<!ENTITY yacute ""> + +<!ENTITY ccedil ""> +<!ENTITY Ccedil ""> + +<!ENTITY Acirc ""> +<!ENTITY Ecirc ""> +<!ENTITY Icirc ""> +<!ENTITY Ocirc ""> +<!ENTITY Ucirc ""> +<!ENTITY acirc ""> +<!ENTITY ecirc ""> +<!ENTITY icirc ""> +<!ENTITY ocirc ""> +<!ENTITY ucirc ""> + +<!ENTITY Agrave ""> +<!ENTITY Egrave ""> +<!ENTITY Igrave ""> +<!ENTITY Ograve ""> +<!ENTITY Ugrave ""> +<!ENTITY agrave ""> +<!ENTITY egrave ""> +<!ENTITY igrave ""> +<!ENTITY ograve ""> +<!ENTITY ugrave ""> + +<!ENTITY Atilde ""> +<!ENTITY Ntilde ""> +<!ENTITY Otilde ""> +<!ENTITY atilde ""> +<!ENTITY ntilde ""> +<!ENTITY otilde ""> + +<!ENTITY oslash ""> +<!ENTITY Oslash ""> + +<!ENTITY iexcl ""> +<!ENTITY pound ""> +<!ENTITY iquest ""> +<!ENTITY AElig ""> +<!ENTITY aelig ""> +<!ENTITY Aring ""> +<!ENTITY aring ""> +<!ENTITY szlig ""> + +<!ENTITY macr ""> + + +<!-- fixxme: not yet classified --> + +<!ELEMENT sp (#PCDATA)> +<!ATTLIST sp + lines CDATA #IMPLIED> +<!ELEMENT printindex (#PCDATA)> + diff --git a/Build/source/utils/texinfo/makeinfo/texinfo.xsl b/Build/source/utils/texinfo/makeinfo/texinfo.xsl new file mode 100644 index 00000000000..efe36e94824 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/texinfo.xsl @@ -0,0 +1,242 @@ +<?xml version='1.0'?> +<!-- $Id: texinfo.xsl,v 1.1 2002/08/25 23:38:39 karl Exp $ --> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<xsl:output method="html" indent="yes"/> + +<!-- root rule --> +<xsl:template match="/"> + <html> + <head><title> + <xsl:apply-templates select="TEXINFO/SETTITLE" mode="head"/> + </title></head> + <body bgcolor="#FFFFFF"><xsl:apply-templates/> +</body></html> +</xsl:template> + + +<xsl:template match="TEXINFO"> + <xsl:apply-templates/> +</xsl:template> + + +<xsl:template match="TEXINFO/SETFILENAME"> +</xsl:template> + +<xsl:template match="TEXINFO/SETTITLE" mode="head"> + <xsl:apply-templates/> +</xsl:template> + +<xsl:template match="TEXINFO/SETTITLE"> + <h1><xsl:apply-templates/></h1> +</xsl:template> + + +<xsl:template match="TEXINFO/DIRCATEGORY"> +</xsl:template> + +<xsl:template match="//PARA"> + <p><xsl:apply-templates/></p> +</xsl:template> + +<xsl:template match="//EMPH"> + <i><xsl:apply-templates/></i> +</xsl:template> + +<!-- The node --> +<xsl:template match="TEXINFO/NODE"> + <hr/> + <p> + <xsl:apply-templates select="NODENAME" mode="select"/> + <xsl:apply-templates select="NODEPREV" mode="select"/> + <xsl:apply-templates select="NODEUP" mode="select"/> + <xsl:apply-templates select="NODENEXT" mode="select"/> + <xsl:apply-templates/> + <h2>Footnotes</h2> + <ol> + <xsl:apply-templates select=".//FOOTNOTE" mode="footnote"/> + </ol> + </p> +</xsl:template> + +<xsl:template match="TEXINFO/NODE/NODENAME" mode="select"> +<h2> + <a> + <xsl:attribute name="name"> + <xsl:apply-templates/> + </xsl:attribute> + <xsl:apply-templates/> + </a> +</h2> +</xsl:template> + +<xsl:template match="TEXINFO/NODE/NODENAME"/> + + +<xsl:template match="TEXINFO/NODE/NODEPREV" mode="select"> + [ <b>Previous: </b> + <a> + <xsl:attribute name="href"> + <xsl:text>#</xsl:text> + <xsl:apply-templates/> + </xsl:attribute> + <xsl:apply-templates/> + </a> ] +</xsl:template> + +<xsl:template match="TEXINFO/NODE/NODEPREV"/> + +<xsl:template match="TEXINFO/NODE/NODEUP" mode="select"> + [ <b>Up: </b> + <a> + <xsl:attribute name="href"> + <xsl:text>#</xsl:text> + <xsl:apply-templates/> + </xsl:attribute> + <xsl:apply-templates/> + </a> ] +</xsl:template> + +<xsl:template match="TEXINFO/NODE/NODEUP"/> + +<xsl:template match="TEXINFO/NODE/NODENEXT" mode="select"> + [ <b>Next: </b> + <a> + <xsl:attribute name="href"> + <xsl:text>#</xsl:text> + <xsl:apply-templates/> + </xsl:attribute> + <xsl:apply-templates/> + </a> ] +</xsl:template> + +<xsl:template match="TEXINFO/NODE/NODENEXT"/> + +<!-- Menu --> +<xsl:template match="//MENU"> + <h3>Menu</h3> + <xsl:apply-templates/> +</xsl:template> + +<xsl:template match="//MENU/MENUENTRY"> + <a> + <xsl:attribute name="href"> + <xsl:text>#</xsl:text> + <xsl:apply-templates select="MENUNODE"/> + </xsl:attribute> + <xsl:apply-templates select="MENUTITLE"/> + </a>: + <xsl:apply-templates select="MENUCOMMENT"/> + <br/> +</xsl:template> + +<xsl:template match="//MENU/MENUENTRY/MENUNODE"> + <xsl:apply-templates/> +</xsl:template> + +<xsl:template match="//MENU/MENUENTRY/MENUTITLE"> + <xsl:apply-templates/> +</xsl:template> + +<xsl:template match="//MENU/MENUENTRY/MENUCOMMENT"> + <xsl:apply-templates mode="menucomment"/> +</xsl:template> + +<xsl:template match="PARA" mode="menucomment"> + <xsl:apply-templates/> +</xsl:template> + +<xsl:template match="//PARA"> + <p><xsl:apply-templates/></p> +</xsl:template> + +<!-- LISTS --> +<xsl:template match="//ITEMIZE"> + <ul> + <xsl:apply-templates/> + </ul> +</xsl:template> + +<xsl:template match="//ITEMIZE/ITEM"> + <li> + <xsl:apply-templates/> + </li> +</xsl:template> + +<xsl:template match="//ENUMERATE"> + <ol> + <xsl:apply-templates/> + </ol> +</xsl:template> + +<xsl:template match="//ENUMERATE/ITEM"> + <li> + <xsl:apply-templates/> + </li> +</xsl:template> + +<!-- INLINE --> +<xsl:template match="//CODE"> + <tt> + <xsl:apply-templates/> + </tt> +</xsl:template> + +<xsl:template match="//DFN"> + <i><b> + <xsl:apply-templates/> + </b></i> +</xsl:template> + +<xsl:template match="//STRONG"> + <b> + <xsl:apply-templates/> + </b> +</xsl:template> + +<xsl:template match="//CENTER"> + <center> + <xsl:apply-templates/> + </center> +</xsl:template> + +<xsl:template match="//VAR"> + <i> + <xsl:apply-templates/> + </i> +</xsl:template> + +<xsl:template match="//KBD"> + <tt> + <xsl:apply-templates/> + </tt> +</xsl:template> + +<xsl:template match="//KEY"> + <b> + <xsl:apply-templates/> + </b> +</xsl:template> + +<!-- BLOCKS --> +<xsl:template match="//DISPLAY"> + <pre> + <xsl:apply-templates/> + </pre> +</xsl:template> + + +<!-- INDEX --> +<xsl:template match="//INDEXTERM"> +</xsl:template> + +<!-- FOOTNOTE --> +<xsl:template match="//FOOTNOTE"> +</xsl:template> + +<xsl:template match="//FOOTNOTE" mode="footnote"> + <li><xsl:apply-templates/></li> +</xsl:template> + +</xsl:stylesheet> diff --git a/Build/source/utils/texinfo/makeinfo/toc.c b/Build/source/utils/texinfo/makeinfo/toc.c new file mode 100644 index 00000000000..fa3d8e07382 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/toc.c @@ -0,0 +1,388 @@ +/* toc.c -- table of contents handling. + $Id: toc.c,v 1.6 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1999, 2000, 2001, 2002, 2003 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. + + Originally 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 "html.h" +#include "lang.h" +#include "makeinfo.h" +#include "sectioning.h" +#include "toc.h" +#include "xml.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; + +/* Routine to add an entry to the table of contents */ +int +toc_add_entry (char *tocname, int level, char *node_name, char *anchor) +{ + char *tocname_and_node, *expanded_node, *d; + char *s = NULL; + char *filename = NULL; + + 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; + if (splitting) + { + if (!anchor) + filename = nodename_to_filename (expanded_node); + else + filename = filename_part (current_output_filename); + } + /* 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 "&". 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 (cr_or_whitespace (*s)) + *d++ = '-'; + else if (! URL_SAFE_CHAR (*s)) + { + sprintf (d, "_00%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; + toc_entry_alist[toc_counter]->html_file = filename; + + /* 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 (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 (void) +{ + 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. */ + +static void +contents_update_html (void) +{ + int i; + int k; + int last_level; + + /* does exist any toc? */ + if (!toc_counter) + /* no, so return to sender ;-) */ + return; + + add_html_block_elt_args ("\n<div class=\"contents\">\n<h2>%s</h2>\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++) + add_html_block_elt ("<ul>\n"); + } + 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++) + add_word ("</li></ul>\n"); + } + + /* No double entries in TOC. */ + if (!(i && strcmp (toc_entry_alist[i]->name, + toc_entry_alist[i-1]->name) == 0)) + { + /* each toc entry is a list item. */ + add_word ("<li>"); + + /* Insert link -- to an external file if splitting, or + within the current document if not splitting. */ + add_word ("<a "); + /* For chapters (only), insert an anchor that the short contents + will link to. */ + if (toc_entry_alist[i]->level == 0) + { + char *p = toc_entry_alist[i]->name; + + /* toc_entry_alist[i]->name has the form `foo">bar', + that is, it includes both the node name and anchor + text. We need to find where `foo', the node name, + ends, and use that in toc_FOO. */ + while (*p && *p != '"') + p++; + add_word_args ("name=\"toc_%.*s\" ", + p - toc_entry_alist[i]->name, toc_entry_alist[i]->name); + } + add_word_args ("href=\"%s#%s</a>\n", + splitting ? toc_entry_alist[i]->html_file : "", + 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++) + add_word ("</li></ul>\n"); + + add_word ("</li></ul>\n</div>\n\n"); +} + +/* print table of contents in ASCII (--no-headers) + May be we should create a new command line switch --ascii ? */ +static void +contents_update_info (void) +{ + int i; + int k; + + if (!toc_counter) + return; + + insert_string ((char *) _("Table of Contents")); + insert ('\n'); + for (i = 0; i < strlen (_("Table of Contents")); i++) + insert ('*'); + insert_string ("\n\n"); + + for (i = 0; i < toc_counter; i++) + { + if (toc_entry_alist[i]->level == 0) + add_char ('\n'); + + /* indention with two spaces per level, should this + changed? */ + for (k = 0; k < toc_entry_alist[i]->level; k++) + insert_string (" "); + + insert_string (toc_entry_alist[i]->name); + insert ('\n'); + } + insert_string ("\n\n"); +} + +/* shortcontents in HTML; Should this produce a standalone file? */ +static void +shortcontents_update_html (char *contents_filename) +{ + int i; + char *toc_file = NULL; + + /* does exist any toc? */ + if (!toc_counter) + return; + + add_html_block_elt_args ("\n<div class=\"shortcontents\">\n<h2>%s</h2>\n<ul>\n", _("Short Contents")); + + if (contents_filename) + toc_file = filename_part (contents_filename); + + for (i = 0; i < toc_counter; i++) + { + char *name = toc_entry_alist[i]->name; + + if (toc_entry_alist[i]->level == 0) + { + if (contents_filename) + add_word_args ("<li><a href=\"%s#toc_%s</a></li>\n", + splitting ? toc_file : "", name); + else + add_word_args ("<a href=\"%s#%s</a>\n", + splitting ? toc_entry_alist[i]->html_file : "", name); + } + } + add_word ("</ul>\n</div>\n\n"); + if (contents_filename) + free (toc_file); +} + +/* short contents in ASCII (--no-headers). */ +static void +shortcontents_update_info (void) +{ + int i; + + if (!toc_counter) + return; + + insert_string ((char *) _("Short Contents")); + insert ('\n'); + for (i = 0; i < strlen (_("Short Contents")); i++) + insert ('*'); + insert_string ("\n\n"); + + for (i = 0; i < toc_counter; i++) + { + if (toc_entry_alist[i]->level == 0) + { + insert_string (toc_entry_alist[i]->name); + insert ('\n'); + } + } + insert_string ("\n\n"); +} + +void +cm_contents (int arg) +{ + /* the file where we found the @contents directive */ + static char *contents_filename; + + /* No need to mess with delayed stuff for XML and Docbook. */ + if (xml) + { + if (arg == START) + { + int elt = STREQ (command, "contents") ? CONTENTS : SHORTCONTENTS; + xml_insert_element (elt, START); + xml_insert_element (elt, END); + } + } + else if (!handling_delayed_writes) + { + register_delayed_write (STREQ (command, "contents") + ? "@contents" : "@shortcontents"); + + if (html && STREQ (command, "contents")) + { + if (contents_filename) + free (contents_filename); + contents_filename = xstrdup (current_output_filename); + } + } + else if (html) + STREQ (command, "contents") + ? contents_update_html () : shortcontents_update_html (contents_filename); + else if (no_headers) + STREQ (command, "contents") + ? contents_update_info () : shortcontents_update_info (); +} diff --git a/Build/source/utils/texinfo/makeinfo/toc.h b/Build/source/utils/texinfo/makeinfo/toc.h new file mode 100644 index 00000000000..854f6fc7ddc --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/toc.h @@ -0,0 +1,45 @@ +/* toc.h -- table of contents handling. + $Id: toc.h,v 1.2 2004/04/11 17:56:47 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 + +/* Structure to hold one entry for the toc. */ +typedef struct toc_entry_elt { + char *name; + char *containing_node; /* Name of node containing this section. */ + char *html_file; /* Name of HTML node-file in split-HTML mode */ + 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 (char *tocname, int level, + char *node_name, char *anchor); /* return the number for the toc-entry */ +extern void toc_free (void); +extern char *toc_find_section_of_node (char *node); + +extern void cm_contents (int arg); + +#endif /* not TOC_H */ diff --git a/Build/source/utils/texinfo/makeinfo/win32.mak b/Build/source/utils/texinfo/makeinfo/win32.mak new file mode 100644 index 00000000000..d5b3cdabd4f --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/win32.mak @@ -0,0 +1,66 @@ +################################################################################ +# +# Makefile : TeXInfo/makeinfo +# Author : Fabrice Popineau <Fabrice.Popineau@supelec.fr> +# Platform : Win32, Microsoft VC++ 6.0, depends upon fpTeX 0.5 sources +# Time-stamp: <02/11/14 20:21:20 popineau> +# +################################################################################ +root_srcdir = ..\..\.. +!ifdef DEVELOPMENT +INCLUDE=$(INCLUDE);$(root_srcdir)\texk.development +!else +INCLUDE=$(INCLUDE);$(root_srcdir)\texk +!endif + +GNU = 1 +USE_GNUW32 = 1 + +!include <msvc/common.mak> + +programs = $(objdir)\makeinfo.exe +objects = \ + $(objdir)\cmds.obj \ + $(objdir)\defun.obj \ + $(objdir)\files.obj \ + $(objdir)\footnote.obj \ + $(objdir)\html.obj \ + $(objdir)\index.obj \ + $(objdir)\insertion.obj \ + $(objdir)\lang.obj \ + $(objdir)\macro.obj \ + $(objdir)\makeinfo.obj \ + $(objdir)\multi.obj \ + $(objdir)\node.obj \ + $(objdir)\sectioning.obj \ + $(objdir)\toc.obj \ + $(objdir)\xml.obj + +libtxi = ..\lib\$(objdir)\libtxi.lib + +DEFS = -I.. -DHAVE_CONFIG_H $(DEFS) -I..\lib + +default: all + +all: $(objdir) $(programs) + +$(objdir)\makeinfo.exe: $(objects) $(libtxi) $(gnuw32lib) + $(link) $(**) $(conlibs) + +$(libtxi): + pushd ..\lib & $(make) $(makeflags) all & popd + +!include <msvc/config.mak> +!include <msvc/install.mak> + +install:: install-exec + +!include <msvc/clean.mak> +!include <msvc/version.mak> + +!include <msvc/rdepend.mak> +!include "./depend.mak" +# +# Local Variables: +# mode: makefile +# End:
\ No newline at end of file diff --git a/Build/source/utils/texinfo/makeinfo/xml.c b/Build/source/utils/texinfo/makeinfo/xml.c new file mode 100644 index 00000000000..cdbec1fc525 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/xml.c @@ -0,0 +1,2328 @@ +/* xml.c -- xml output. + $Id: xml.c,v 1.52 2004/12/19 17:02:23 karl Exp $ + + Copyright (C) 2001, 2002, 2003, 2004 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. + + Originally written by Philippe Martin <feloy@free.fr>. */ + +#include "system.h" +#include "makeinfo.h" +#include "insertion.h" +#include "files.h" +#include "float.h" +#include "macro.h" +#include "cmds.h" +#include "lang.h" + +#include "xml.h" + +/* Options */ +int xml_index_divisions = 1; + +typedef struct _element +{ + char name[32]; + int contains_para; + int contained_in_para; + int keep_space; +} element; + +element texinfoml_element_list [] = { + { "texinfo", 1, 0, 0 }, + { "setfilename", 0, 0, 0 }, + { "titlefont", 0, 0, 0 }, + { "settitle", 0, 0, 0 }, + { "documentdescription", 1, 0, 0 }, + + { "node", 1, 0, 0 }, + { "nodenext", 0, 0, 0 }, + { "nodeprev", 0, 0, 0 }, + { "nodeup", 0, 0, 0 }, + + { "chapter", 1, 0, 0 }, + { "section", 1, 0, 0 }, + { "subsection", 1, 0, 0 }, + { "subsubsection", 1, 0, 0 }, + + { "top", 1, 0, 0 }, + { "unnumbered", 1, 0, 0 }, + { "unnumberedsec", 1, 0, 0 }, + { "unnumberedsubsec", 1, 0, 0 }, + { "unnumberedsubsubsec", 1, 0, 0 }, + + { "appendix", 1, 0, 0 }, + { "appendixsec", 1, 0, 0 }, + { "appendixsubsec", 1, 0, 0 }, + { "appendixsubsubsec", 1, 0, 0 }, + + { "majorheading", 0, 0, 0 }, + { "chapheading", 0, 0, 0 }, + { "heading", 0, 0, 0 }, + { "subheading", 0, 0, 0 }, + { "subsubheading", 0, 0, 0 }, + + { "titlepage", 1, 0, 0 }, + { "author", 0, 0, 0 }, + { "booktitle", 0, 0, 0 }, + { "booksubtitle", 0, 0, 0 }, + + { "menu", 1, 0, 0 }, + { "detailmenu", 1, 0, 0 }, + { "menuentry", 0, 0, 0 }, + { "menutitle", 0, 0, 0 }, + { "menucomment", 0, 0, 0 }, + { "menunode", 0, 0, 0 }, + { "nodename", 0, 0, 0 }, + + { "acronym", 0, 1, 0 }, + { "acronymword", 0, 1, 0 }, + { "acronymdesc", 0, 1, 0 }, + + { "abbrev", 0, 1, 0 }, + { "abbrevword", 0, 1, 0 }, + { "abbrevdesc", 0, 1, 0 }, + + { "tt", 0, 1, 0 }, + { "code", 0, 1, 0 }, + { "command", 0, 1, 0 }, + { "env", 0, 1, 0 }, + { "file", 0, 1, 0 }, + { "option", 0, 1, 0 }, + { "samp", 0, 1, 0 }, + { "kbd", 0, 1, 0 }, + { "url", 0, 1, 0 }, + { "key", 0, 1, 0 }, + { "var", 0, 1, 0 }, + { "sc", 0, 1, 0 }, + { "dfn", 0, 1, 0 }, + { "emph", 0, 1, 0 }, + { "strong", 0, 1, 0 }, + { "cite", 0, 1, 0 }, + { "notfixedwidth", 0, 1, 0 }, + { "i", 0, 1, 0 }, + { "b", 0, 1, 0 }, + { "r", 0, 1, 0 }, + { "slanted", 0, 1, 0 }, + { "sansserif", 0, 1, 0 }, + + { "exdent", 0, 0, 0 }, + + { "title", 0, 0, 0 }, + { "ifinfo", 1, 0, 0 }, + { "sp", 0, 0, 0 }, + { "center", 1, 0, 0 }, + { "dircategory", 0, 0, 0 }, + { "quotation", 1, 0, 0 }, + { "example", 0, 0, 1 }, + { "smallexample", 0, 0, 1 }, + { "lisp", 0, 0, 1 }, + { "smalllisp", 0, 0, 1 }, + { "cartouche", 1, 0, 0 }, + { "copying", 1, 0, 0 }, + { "format", 0, 0, 1 }, + { "smallformat", 0, 0, 1 }, + { "display", 0, 0, 1 }, + { "smalldisplay", 0, 0, 1 }, + { "verbatim", 0, 0, 1 }, + { "footnote", 0, 1, 0 }, + { "", 0, 1, 0 }, /* LINEANNOTATION (docbook) */ + + { "", 1, 0, 0 }, /* TIP (docbook) */ + { "", 1, 0, 0 }, /* NOTE (docbook) */ + { "", 1, 0, 0 }, /* IMPORTANT (docbook) */ + { "", 1, 0, 0 }, /* WARNING (docbook) */ + { "", 1, 0, 0 }, /* CAUTION (docbook) */ + + { "itemize", 0, 0, 0 }, + { "itemfunction", 0, 0, 0 }, + { "item", 1, 0, 0 }, + { "enumerate", 0, 0, 0 }, + { "table", 0, 0, 0 }, + { "tableitem", 0, 0, 0 }, + { "tableterm", 0, 0, 0 }, + + { "indexterm", 0, 1, 0 }, + + { "math", 0, 1, 0 }, + + { "dmn", 0, 1, 0 }, + + { "xref", 0, 1, 0 }, + { "xrefnodename", 0, 1, 0 }, + { "xrefinfoname", 0, 1, 0 }, + { "xrefprinteddesc", 0, 1, 0 }, + { "xrefinfofile", 0, 1, 0 }, + { "xrefprintedname", 0, 1, 0 }, + + { "inforef", 0, 1, 0 }, + { "inforefnodename", 0, 1, 0 }, + { "inforefrefname", 0, 1, 0 }, + { "inforefinfoname", 0, 1, 0 }, + + { "uref", 0, 1, 0 }, + { "urefurl", 0, 1, 0 }, + { "urefdesc", 0, 1, 0 }, + { "urefreplacement", 0, 1, 0 }, + + { "email", 0, 1, 0 }, + { "emailaddress", 0, 1, 0 }, + { "emailname", 0, 1, 0 }, + + { "group", 0, 0, 0 }, + { "float", 1, 0, 0 }, + { "floattype", 0, 0, 0 }, + { "floatpos", 0, 0, 0 }, + { "caption", 0, 0, 0 }, + { "shortcaption", 0, 0, 0 }, + + { "", 0, 0, 0 }, /* TABLE (docbook) */ + { "", 0, 0, 0 }, /* FIGURE (docbook) */ + { "", 0, 0, 0 }, /* EXAMPLE (docbook) */ + { "", 1, 0, 0 }, /* SIDEBAR (docbook) */ + + { "printindex", 0, 0, 0 }, + { "listoffloats", 0, 0, 0 }, + { "anchor", 0, 1, 0 }, + + { "image", 0, 0, 0 }, + { "inlineimage", 0, 1, 0 }, + { "alttext", 0, 1, 0 }, + + { "", 0, 1, 0 }, /* PRIMARY (docbook) */ + { "", 0, 1, 0 }, /* SECONDARY (docbook) */ + { "", 0, 0, 0 }, /* INFORMALFIGURE (docbook) */ + { "", 0, 0, 0 }, /* MEDIAOBJECT (docbook) */ + { "", 0, 0, 0 }, /* IMAGEOBJECT (docbook) */ + { "", 0, 0, 0 }, /* IMAGEDATA (docbook) */ + { "", 0, 0, 0 }, /* TEXTOBJECT (docbook) */ + { "", 0, 0, 0 }, /* INDEXENTRY (docbook) */ + { "", 0, 0, 0 }, /* PRIMARYIE (docbook) */ + { "", 0, 0, 0 }, /* SECONDARYIE (docbook) */ + { "", 0, 0, 0 }, /* INDEXDIV (docbook) */ + { "multitable", 0, 0, 0 }, + { "", 0, 0, 0 }, /* TGROUP (docbook) */ + { "columnfraction", 0, 0, 0 }, + { "thead", 0, 0, 0 }, + { "tbody", 0, 0, 0 }, + { "entry", 0, 0, 0 }, + { "row", 0, 0, 0 }, + { "", 0, 0, 0 }, /* BOOKINFO (docbook) */ + { "", 0, 0, 0 }, /* ABSTRACT (docbook) */ + { "", 0, 0, 0 }, /* REPLACEABLE (docbook) */ + { "", 0, 0, 0 }, /* ENVAR (docbook) */ + { "", 0, 0, 0 }, /* COMMENT (docbook) */ + { "", 0, 0, 0 }, /* FUNCTION (docbook) */ + { "", 0, 0, 0 }, /* LEGALNOTICE (docbook) */ + + { "contents", 0, 0, 0 }, + { "shortcontents", 0, 0, 0 }, + { "documentlanguage", 0, 0, 0 }, + + { "setvalue", 0, 0, 0 }, + { "clearvalue", 0, 0, 0 }, + + { "definition", 0, 0, 0 }, + { "definitionterm", 0, 0, 0 }, + { "definitionitem", 1, 0, 0 }, + { "defcategory", 0, 0, 0 }, + { "deffunction", 0, 0, 0 }, + { "defvariable", 0, 0, 0 }, + { "defparam", 0, 0, 0 }, + { "defdelimiter", 0, 0, 0 }, + { "deftype", 0, 0, 0 }, + { "defparamtype", 0, 0, 0 }, + { "defdatatype", 0, 0, 0 }, + { "defclass", 0, 0, 0 }, + { "defclassvar", 0, 0, 0 }, + { "defoperation", 0, 0, 0 }, + + { "para", 0, 0, 0 } /* Must be last */ + /* name / contains para / contained in para / preserve space */ +}; + +element docbook_element_list [] = { + { "book", 0, 0, 0 }, /* TEXINFO */ + { "", 0, 0, 0 }, /* SETFILENAME */ + { "", 0, 0, 0 }, /* TITLEINFO */ + { "title", 0, 0, 0 }, /* SETTITLE */ + { "", 1, 0, 0 }, /* DOCUMENTDESCRIPTION (?) */ + + { "", 1, 0, 0 }, /* NODE */ + { "", 0, 0, 0 }, /* NODENEXT */ + { "", 0, 0, 0 }, /* NODEPREV */ + { "", 0, 0, 0 }, /* NODEUP */ + + { "chapter", 1, 0, 0 }, + { "sect1", 1, 0, 0 }, /* SECTION */ + { "sect2", 1, 0, 0 }, /* SUBSECTION */ + { "sect3", 1, 0, 0 }, /* SUBSUBSECTION */ + + { "chapter", 1, 0, 0 }, /* TOP */ + { "chapter", 1, 0, 0 }, /* UNNUMBERED */ + { "sect1", 1, 0, 0 }, /* UNNUMBEREDSEC */ + { "sect2", 1, 0, 0 }, /* UNNUMBEREDSUBSEC */ + { "sect3", 1, 0, 0 }, /* UNNUMBEREDSUBSUBSEC */ + + { "appendix", 1, 0, 0 }, + { "sect1", 1, 0, 0 }, /* APPENDIXSEC */ + { "sect2", 1, 0, 0 }, /* APPENDIXSUBSEC */ + { "sect3", 1, 0, 0 }, /* APPENDIXSUBSUBSEC */ + + { "bridgehead", 0, 0, 0 }, /* MAJORHEADING */ + { "bridgehead", 0, 0, 0 }, /* CHAPHEADING */ + { "bridgehead", 0, 0, 0 }, /* HEADING */ + { "bridgehead", 0, 0, 0 }, /* SUBHEADING */ + { "bridgehead", 0, 0, 0 }, /* SUBSUBHEADING */ + + { "", 0, 0, 0 }, /* TITLEPAGE */ + { "", 0, 0, 0 }, /* AUTHOR */ + { "", 0, 0, 0 }, /* BOOKTITLE */ + { "", 0, 0, 0 }, /* BOOKSUBTITLE */ + + { "", 1, 0, 0 }, /* MENU */ + { "", 1, 0, 0 }, /* DETAILMENU */ + { "", 1, 0, 0 }, /* MENUENTRY */ + { "", 0, 0, 0 }, /* MENUTITLE */ + { "", 1, 0, 0 }, /* MENUCOMMENT */ + { "", 0, 0, 0 }, /* MENUNODE */ + { "anchor", 0, 0, 0 }, /* NODENAME */ + + { "acronym", 0, 1, 0 }, + { "", 0, 1, 0 }, /* ACRONYMWORD */ + { "", 0, 1, 0 }, /* ACRONYMDESC */ + + { "abbrev", 0, 1, 0 }, + { "", 0, 1, 0 }, /* ABBREVWORD */ + { "", 0, 1, 0 }, /* ABBREVDESC */ + + { "literal", 0, 1, 0 }, /* TT */ + { "literal", 0, 1, 0 }, /* CODE */ + { "command", 0, 1, 0 }, /* COMMAND */ + { "envar", 0, 1, 0 }, /* ENV */ + { "filename", 0, 1, 0 }, /* FILE */ + { "option", 0, 1, 0 }, /* OPTION */ + { "literal", 0, 1, 0 }, /* SAMP */ + { "userinput", 0, 1, 0 }, /* KBD */ + { "wordasword", 0, 1, 0 }, /* URL */ + { "keycap", 0, 1, 0 }, /* KEY */ + { "replaceable", 0, 1, 0 }, /* VAR */ + { "", 0, 1, 0 }, /* SC */ + { "firstterm", 0, 1, 0 }, /* DFN */ + { "emphasis", 0, 1, 0 }, /* EMPH */ + { "emphasis", 0, 1, 0 }, /* STRONG */ + { "citetitle", 0, 1, 0 }, /* CITE */ + { "", 0, 1, 0 }, /* NOTFIXEDWIDTH */ + { "wordasword", 0, 1, 0 }, /* I */ + { "emphasis", 0, 1, 0 }, /* B */ + { "", 0, 1, 0 }, /* R */ + + { "", 0, 0, 0 }, /* EXDENT */ + + { "title", 0, 0, 0 }, + { "", 1, 0, 0 }, /* IFINFO */ + { "", 0, 0, 0 }, /* SP */ + { "", 1, 0, 0 }, /* CENTER */ + { "", 0, 0, 0 }, /* DIRCATEGORY */ + { "blockquote", 1, 0, 0 }, /* QUOTATION */ + { "screen", 0, 0, 1 }, /* EXAMPLE */ + { "screen", 0, 0, 1 }, /* SMALLEXAMPLE */ + { "programlisting", 0, 0, 1 }, /* LISP */ + { "programlisting", 0, 0, 1 }, /* SMALLLISP */ + { "", 1, 0, 0 }, /* CARTOUCHE */ + { "", 1, 0, 0 }, /* COPYING */ + { "screen", 0, 1, 1 }, /* FORMAT */ + { "screen", 0, 1, 1 }, /* SMALLFORMAT */ + { "literallayout", 0, 1, 1 }, /* DISPLAY */ + { "literallayout", 0, 1, 1 }, /* SMALLDISPLAY */ + { "screen", 0, 0, 1 }, /* VERBATIM */ + { "footnote", 0, 1, 0 }, + { "lineannotation", 0, 1, 0 }, + + { "tip", 1, 0, 0 }, + { "note", 1, 0, 0 }, + { "important", 1, 0, 0 }, + { "warning", 1, 0, 0 }, + { "caution", 1, 0, 0 }, + + { "itemizedlist", 0, 0, 0 }, /* ITEMIZE */ + { "", 0, 0, 0 }, /* ITEMFUNCTION */ + { "listitem", 1, 0, 0 }, /* ITEM */ + { "orderedlist", 0, 0, 0 }, /* ENUMERATE */ + { "variablelist", 0, 0, 0 }, /* TABLE */ + { "varlistentry", 0, 0, 0 }, /* TABLEITEM */ + { "term", 0, 0, 0 }, /* TABLETERM */ + + { "indexterm", 0, 1, 0 }, /* INDEXTERM */ + + { "", 0, 1, 0 }, /* MATH */ + + { "", 0, 1, 0 }, /* DIMENSION */ + + { "xref", 0, 1, 0 }, /* XREF */ + { "link", 0, 1, 0 }, /* XREFNODENAME */ + { "", 0, 1, 0 }, /* XREFINFONAME */ + { "", 0, 1, 0 }, /* XREFPRINTEDDESC */ + { "", 0, 1, 0 }, /* XREFINFOFILE */ + { "", 0, 1, 0 }, /* XREFPRINTEDNAME */ + + { "", 0, 1, 0 }, /* INFOREF */ + { "", 0, 1, 0 }, /* INFOREFNODENAME */ + { "", 0, 1, 0 }, /* INFOREFREFNAME */ + { "", 0, 1, 0 }, /* INFOREFINFONAME */ + + { "ulink", 0, 1, 0 }, /* UREF */ + { "", 0, 1, 0 }, /* UREFURL */ + { "", 0, 1, 0 }, /* UREFDESC */ + { "", 0, 1, 0 }, /* UREFREPLACEMENT */ + + { "ulink", 0, 1, 0 }, /* EMAIL */ + { "", 0, 1, 0 }, /* EMAILADDRESS */ + { "", 0, 1, 0 }, /* EMAILNAME */ + + { "", 0, 0, 0 }, /* GROUP */ + { "", 1, 0, 0 }, /* FLOAT */ + { "", 0, 0, 0 }, /* FLOATTYPE */ + { "", 0, 0, 0 }, /* FLOATPOS */ + { "", 0, 0, 0 }, /* CAPTION */ + { "", 0, 0, 0 }, /* SHORTCAPTION */ + + { "table", 0, 1, 0 }, + { "figure", 0, 1, 0 }, + { "example", 1, 1, 0 }, + { "sidebar", 1, 0, 0 }, + + { "index", 0, 1, 0 }, /* PRINTINDEX */ + { "", 0, 1, 0 }, /* LISTOFFLOATS */ + { "", 0, 1, 0 }, /* ANCHOR */ + + { "", 0, 0, 0 }, /* IMAGE */ + { "inlinemediaobject", 0, 1, 0 }, /* INLINEIMAGE */ + { "", 0, 0, 0 }, /* IMAGEALTTEXT */ + + { "primary", 0, 1, 0 }, /* PRIMARY */ + { "secondary", 0, 1, 0 }, + { "informalfigure", 0, 0, 0 }, + { "mediaobject", 0, 0, 0 }, + { "imageobject", 0, 1, 0 }, + { "imagedata", 0, 1, 0 }, + { "textobject", 0, 1, 0 }, + { "indexentry", 0, 0, 0 }, + { "primaryie", 0, 0, 0 }, + { "secondaryie", 0, 0, 0 }, + { "indexdiv", 0, 0, 0 }, + { "informaltable", 0, 0, 0 }, + { "tgroup", 0, 0, 0 }, + { "colspec", 0, 0, 0 }, + { "thead", 0, 0, 0 }, + { "tbody", 0, 0, 0 }, + { "entry", 0, 0, 0 }, + { "row", 0, 0, 0 }, + { "bookinfo", 0, 0, 0 }, + { "abstract", 1, 0, 0 }, + { "replaceable", 0, 0, 0 }, + { "envar", 0, 1, 0 }, + { "comment", 0, 0, 0 }, + { "function", 0, 1, 0 }, + { "legalnotice", 1, 0, 0 }, + + { "", 0, 0, 0 }, /* CONTENTS (xml) */ + { "", 0, 0, 0 }, /* SHORTCONTENTS (xml) */ + { "", 0, 0, 0 }, /* DOCUMENT LANGUAGE (xml) */ + + { "", 0, 0, 0 }, /* SETVALUE (xml) */ + { "", 0, 0, 0 }, /* CLEARVALUE (xml) */ + + { "blockquote", 1, 0, 0 }, /* DEFINITION */ + { "screen", 0, 0, 1 }, /* DEFINITIONTERM */ + { "", 0, 0, 0 }, /* DEFINITIONITEM (xml) */ + { "", 0, 0, 0 }, /* DEFCATEGORY (xml) */ + { "function", 0, 0, 0 }, /* DEFFUNCTION */ + { "varname", 0, 0, 0 }, /* DEFVARIABLE */ + { "varname", 0, 0, 0 }, /* DEFPARAM */ + { "", 0, 0, 0 }, /* DEFDELIMITER (xml) */ + { "returnvalue", 0, 0, 0 }, /* DEFTYPE */ + { "type", 0, 0, 0 }, /* DEFPARAMTYPE */ + { "structname", 0, 0, 0 }, /* DEFDATATYPE */ + { "classname", 0, 0, 0 }, /* DEFCLASS */ + { "property", 0, 0, 0 }, /* DEFCLASSVAR */ + { "methodname", 0, 0, 0 }, /* DEFOPERATION */ + + { "para", 0, 0, 0 } /* Must be last */ + /* name / contains para / contained in para / preserve space */ +}; + +element *xml_element_list = NULL; + + +typedef struct _replace_element +{ + int element_to_replace; + int element_containing; + int element_replacing; +} replace_element; + +/* Elements to replace - Docbook only + ------------------- + if `element_to_replace' have to be inserted + as a child of `element_containing,' + use `element_replacing' instead. + + A value of `-1' for element_replacing means `do not use any element.' +*/ + +replace_element replace_elements [] = { + { I, TABLETERM, EMPH }, + { B, TABLETERM, EMPH }, + { TT, CODE, -1 }, + { EXAMPLE, DISPLAY, -1 }, + { CODE, DFN, -1 }, + { CODE, VAR, -1 }, + { EMPH, CODE, REPLACEABLE }, + { VAR, VAR, -1}, + { VAR, B, EMPH}, + { B, CODE, ENVAR}, + { CODE, I, EMPH}, + { SAMP, VAR, -1 }, + { FORMAT, BOOKINFO, ABSTRACT }, + { QUOTATION, ABSTRACT, -1}, + { LINEANNOTATION, LINEANNOTATION, -1 }, + { LEGALNOTICE, ABSTRACT, -1 }, + { QUOTATION, QUOTATION, -1 }, + /* Formal versions of table and image elements. */ + { MULTITABLE, FLOAT, FLOATTABLE }, + { INFORMALFIGURE, FLOAT, FLOATFIGURE }, + { CARTOUCHE, FLOAT, FLOATCARTOUCHE }, + /* Unnecessary markup in @defun blocks. */ + { VAR, DEFPARAM, -1 }, + { CODE, DEFTYPE, -1 }, + /* Add your elements to replace here */ + {-1, 0, 0} +}; + +int xml_in_menu_entry = 0; +int xml_in_menu_entry_comment = 0; +int xml_node_open = 0; +int xml_node_level = -1; +int xml_in_para = 0; +int xml_just_after_element = 0; +int xml_keep_space = 0; + +int xml_no_indent = 0; + +int xml_no_para = 0; +char *xml_node_id = NULL; +int xml_sort_index = 0; + +int xml_in_xref_token = 0; +int xml_in_bookinfo = 0; +int xml_in_book_title = 0; +int xml_in_abstract = 0; + +/* Non-zero if we are handling an element that can appear between + @item and @itemx, @deffn and @deffnx. */ +int xml_dont_touch_items_defs = 0; + +/* We need to keep footnote state, because elements inside footnote may try + to close the previous parent para. */ +static int xml_in_footnote = 0; + +static int xml_after_table_term = 0; +static int book_started = 0; +static int first_section_opened = 0; + +static int xml_in_tableitem[256]; +static int xml_in_item[256]; +static int xml_table_level = 0; + +static int xml_in_def_item[256]; +static int xml_definition_level = 0; +int xml_after_def_term = 0; + +static int in_table_title = 0; + +static int in_indexentry = 0; +static int in_secondary = 0; +static int in_indexterm = 0; + +char * +xml_id (char *id) +{ + char *tem = xmalloc (strlen (id) + 1); + char *p = tem; + strcpy (tem, id); + while (*p) + { /* Check if a character is allowed in ID attributes. This list differs + slightly from XML specs that it doesn't contain underscores. + See http://xml.coverpages.org/sgmlsyn/sgmlsyn.htm, ``9.3 Name'' */ + if (!strchr ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.", *p)) + *p = '-'; + p++; + } + p = tem; + /* First character can only be a letter. */ + if (!strchr ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", *p)) + *p = 'i'; + return tem; +} + +int +xml_element (char *name) +{ + int i; + for (i=0; i<=PARA; i++) + { + if (strcasecmp (name, texinfoml_element_list[i].name) == 0) + return i; + } + printf ("Error xml_element\n"); + return -1; +} + +void +xml_begin_document (char *output_filename) +{ + if (book_started) + return; + + book_started = 1; + + /* Make sure this is the very first string of the output document. */ + output_paragraph_offset = 0; + + insert_string ("<?xml version=\"1.0\""); + + /* At this point, we register a delayed writing for document encoding, + so in the end, proper encoding attribute will be inserted here. + Since the user is unaware that we are implicitly executing this + command, we should disable warnings temporarily, in order to avoid + possible confusion. (ie. if the output is not seekable, + register_delayed_write issues a warning.) */ + { + extern int print_warnings; + int save_print_warnings = print_warnings; + print_warnings = 0; + register_delayed_write ("@documentencoding"); + print_warnings = save_print_warnings; + } + + insert_string ("?>\n"); + + if (docbook) + { + insert_string ("<!DOCTYPE book PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\" \"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\" [\n <!ENTITY tex \"TeX\">\n <!ENTITY latex \"LaTeX\">\n]>"); + xml_element_list = docbook_element_list; + } + else + { + insert_string ("<!DOCTYPE texinfo PUBLIC \"-//GNU//DTD TexinfoML V"); + insert_string (VERSION); + insert_string ("//EN\" \"http://www.gnu.org/software/texinfo/dtd/"); + insert_string (VERSION); + insert_string ("/texinfo.dtd\">"); + xml_element_list = texinfoml_element_list; + } + if (language_code != last_language_code) + { + if (docbook) + xml_insert_element_with_attribute (TEXINFO, START, "lang=\"%s\"", language_table[language_code].abbrev); + else + xml_insert_element_with_attribute (TEXINFO, START, "xml:lang=\"%s\"", language_table[language_code].abbrev); + } + if (!docbook) + { + xml_insert_element (SETFILENAME, START); + insert_string (output_filename); + xml_insert_element (SETFILENAME, END); + } +} + +/* */ +static int element_stack[256]; +static int element_stack_index = 0; + +static int +xml_current_element (void) +{ + return element_stack[element_stack_index-1]; +} + +static void +xml_push_current_element (int elt) +{ + element_stack[element_stack_index++] = elt; + if (element_stack_index > 200) + printf ("*** stack overflow (%d - %s) ***\n", + element_stack_index, + xml_element_list[elt].name); +} + +static void +xml_pop_current_element (void) +{ + element_stack_index--; + if (element_stack_index < 0) + printf ("*** stack underflow (%d - %d) ***\n", + element_stack_index, + xml_current_element()); +} + +int +xml_current_stack_index (void) +{ + return element_stack_index; +} + +void +xml_end_current_element (void) +{ + xml_insert_element (xml_current_element (), END); +} + +static void +xml_indent (void) +{ + if (xml_indentation_increment > 0) + { + int i; + if (output_paragraph[output_paragraph_offset-1] != '\n') + insert ('\n'); + for (i = 0; i < element_stack_index * xml_indentation_increment; i++) + insert (' '); + } +} + +void +xml_start_para (void) +{ + if (xml_in_para || xml_in_footnote + || !xml_element_list[xml_current_element()].contains_para) + return; + + while (output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + xml_indent (); + + insert_string ("<para"); + if (xml_no_indent) + insert_string (" role=\"continues\""); + insert_string (">"); + xml_no_indent = 0; + xml_in_para = 1; +} + +void +xml_end_para (void) +{ + if (!xml_in_para || xml_in_footnote) + return; + + while (cr_or_whitespace(output_paragraph[output_paragraph_offset-1])) + output_paragraph_offset--; + + insert_string ("</para>"); + if (xml_indentation_increment > 0) + insert ('\n'); + xml_in_para = 0; +} + +void +xml_end_document (void) +{ + if (xml_node_open) + { + if (xml_node_level != -1) + { + xml_close_sections (xml_node_level); + xml_node_level = -1; + } + xml_insert_element (NODE, END); + } + else + xml_close_sections (xml_node_level); + + xml_insert_element (TEXINFO, END); + if (xml_indentation_increment == 0) + insert ('\n'); + insert_string ("<!-- Keep this comment at the end of the file\n\ +Local variables:\n\ +mode: sgml\n\ +sgml-indent-step:1\n\ +sgml-indent-data:nil\n\ +End:\n\ +-->\n"); + if (element_stack_index != 0) + error ("Element stack index : %d\n", element_stack_index); +} + +/* MUST be 0 or 1, not true or false values */ +static int start_element_inserted = 1; + +/* NOTE: We use `elt' rather than `element' in the argument list of + the next function, since otherwise the Solaris SUNWspro compiler + barfs because `element' is a typedef declared near the beginning of + this file. */ +void +#if defined (VA_FPRINTF) && __STDC__ +xml_insert_element_with_attribute (int elt, int arg, char *format, ...) +#else +xml_insert_element_with_attribute (elt, arg, format, va_alist) + int elt; + int arg; + char *format; + va_dcl +#endif +{ + /* Look at the replace_elements table to see if we have to change the element */ + if (xml_sort_index) + return; + if (docbook) + { + replace_element *element_list = replace_elements; + while (element_list->element_to_replace >= 0) + { + if ( ( (arg == START) && + (element_list->element_containing == xml_current_element ()) && + (element_list->element_to_replace == elt) ) || + ( (arg == END) && + (element_list->element_containing == element_stack[element_stack_index-1-start_element_inserted]) && + (element_list->element_to_replace == elt) ) ) + { + elt = element_list->element_replacing; + break; + } + element_list ++; + } + + /* Forget the element */ + if (elt < 0) + { + if (arg == START) + start_element_inserted = 0; + else + /* Replace the default value, for the next time */ + start_element_inserted = 1; + return; + } + } + + if (!book_started) + return; + + if (!xml_dont_touch_items_defs && arg == START) + { + if (xml_after_table_term && elt != TABLETERM && xml_table_level + && !xml_in_item[xml_table_level]) + { + xml_after_table_term = 0; + xml_insert_element (ITEM, START); + xml_in_item[xml_table_level] = 1; + } + else if (xml_after_def_term && elt != DEFINITIONTERM) + { + xml_after_def_term = 0; + xml_insert_element (DEFINITIONITEM, START); + xml_in_def_item[xml_definition_level] = 1; + } + } + + if (docbook && !only_macro_expansion && (in_menu || in_detailmenu)) + return; + + if (executing_string && arg == END) + switch (elt) + { + case TABLEITEM: + xml_in_tableitem[xml_table_level] = 0; + break; + case ITEM: + xml_in_item[xml_table_level] = 0; + break; + case DEFINITIONTERM: + xml_in_def_item[xml_definition_level] = 0; + break; + } + + /* We are special-casing FIGURE element for docbook. It does appear in + the tag stack, but not in the output. This is to make element replacement + work beautifully. */ + if (docbook && elt == FLOAT) + { + if (arg == START) + xml_push_current_element (elt); + else + xml_pop_current_element (); + return; + } + + if (!xml_element_list[elt].name || !strlen (xml_element_list[elt].name)) + { + /*printf ("Warning: Inserting empty element %d\n", elt);*/ + return; + } + + if (arg == START && !xml_in_para && !xml_no_para + && xml_element_list[elt].contained_in_para) + xml_start_para (); + + if (arg == START && xml_in_para && !xml_element_list[elt].contained_in_para) + xml_end_para (); + + if (arg == END && xml_in_para && !xml_element_list[elt].contained_in_para) + xml_end_para (); + + if (docbook && xml_table_level && !in_table_title + && !xml_in_tableitem[xml_table_level] && !xml_in_item[xml_table_level] + && arg == START && elt != TABLEITEM && elt != TABLETERM + && !in_indexterm && xml_current_element() == TABLE) + { + in_table_title = 1; + xml_insert_element (TITLE, START); + } + + if (arg == START && !xml_in_para && !xml_keep_space + && !xml_element_list[elt].contained_in_para) + xml_indent (); + + if (arg == START) + xml_push_current_element (elt); + else + xml_pop_current_element (); + + /* Eat one newline before </example> and the like. */ + if (!docbook && arg == END + && (xml_element_list[elt].keep_space || elt == GROUP) + && output_paragraph[output_paragraph_offset-1] == '\n') + output_paragraph_offset--; + + /* And eat whitespace before </entry> in @multitables. */ + if (arg == END && elt == ENTRY) + while (cr_or_whitespace(output_paragraph[output_paragraph_offset-1])) + output_paragraph_offset--; + + /* Indent elements that can contain <para>. */ + if (arg == END && !xml_in_para && !xml_keep_space + && xml_element_list[elt].contains_para) + xml_indent (); + + /* Here are the elements we want indented. These do not contain <para> + directly. */ + if (arg == END && (elt == MENUENTRY || elt == ITEMIZE || elt == ENUMERATE + || elt == TABLEITEM || elt == TABLE + || elt == MULTITABLE || elt == TGROUP || elt == THEAD || elt == TBODY + || elt == ROW || elt == INFORMALFIGURE + || (!docbook && (elt == DEFINITION || elt == DEFINITIONTERM)))) + xml_indent (); + + insert ('<'); + if (arg == END) + insert ('/'); + insert_string (xml_element_list[elt].name); + + /* printf ("%s ", xml_element_list[elt].name);*/ + + if (format) + { + char temp_string[2000]; /* xx no fixed limits */ +#ifdef VA_SPRINTF + va_list ap; +#endif + + VA_START (ap, format); +#ifdef VA_SPRINTF + VA_SPRINTF (temp_string, format, ap); +#else + sprintf (temp_string, format, a1, a2, a3, a4, a5, a6, a7, a8); +#endif + insert (' '); + insert_string (temp_string); + va_end (ap); + } + + if (arg == START && xml_node_id && elt != NODENAME) + { + insert_string (" id=\""); + insert_string (xml_node_id); + insert ('"'); + free (xml_node_id); + xml_node_id = NULL; + } + + if (xml_element_list[elt].keep_space) + { + if (arg == START) + { + if (!docbook) + insert_string (" xml:space=\"preserve\""); + xml_keep_space++; + } + else + xml_keep_space--; + } + + insert ('>'); + + if (!xml_in_para && !xml_element_list[elt].contained_in_para + && xml_element_list[elt].contains_para && xml_indentation_increment > 0) + insert ('\n'); + + xml_just_after_element = 1; +} + +/* See the NOTE before xml_insert_element_with_attribute, for why we + use `elt' rather than `element' here. */ +void +xml_insert_element (int elt, int arg) +{ + xml_insert_element_with_attribute (elt, arg, NULL); +} + +void +xml_insert_entity (char *entity_name) +{ + int saved_escape_html = escape_html; + + if (!book_started) + return; + if (docbook && !only_macro_expansion && (in_menu || in_detailmenu)) + return; + + if (!xml_in_para && !xml_no_para && !only_macro_expansion + && xml_element_list[xml_current_element ()].contains_para + && !in_fixed_width_font) + xml_start_para (); + + escape_html = 0; + add_char ('&'); + escape_html = saved_escape_html; + insert_string (entity_name); + add_char (';'); +} + +typedef struct _xml_section xml_section; +struct _xml_section { + int level; + char *name; + xml_section *prev; +}; + +xml_section *last_section = NULL; + +void +xml_begin_node (void) +{ + first_section_opened = 1; + if (xml_in_abstract) + { + xml_insert_element (ABSTRACT, END); + xml_in_abstract = 0; + } + if (xml_in_bookinfo) + { + xml_insert_element (BOOKINFO, END); + xml_in_bookinfo = 0; + } + if (xml_node_open && ! docbook) + { + if (xml_node_level != -1) + { + xml_close_sections (xml_node_level); + xml_node_level = -1; + } + xml_insert_element (NODE, END); + } + xml_insert_element (NODE, START); + xml_node_open = 1; +} + +void +xml_close_sections (int level) +{ + if (!first_section_opened) + { + if (xml_in_abstract) + { + xml_insert_element (ABSTRACT, END); + xml_in_abstract = 0; + } + if (xml_in_bookinfo) + { + xml_insert_element (BOOKINFO, END); + xml_in_bookinfo = 0; + } + first_section_opened = 1; + } + + while (last_section && last_section->level >= level) + { + xml_section *temp = last_section; + xml_insert_element (xml_element(last_section->name), END); + temp = last_section; + last_section = last_section->prev; + free (temp->name); + free (temp); + } +} + +void +xml_open_section (int level, char *name) +{ + xml_section *sect = (xml_section *) xmalloc (sizeof (xml_section)); + + sect->level = level; + sect->name = xmalloc (1 + strlen (name)); + strcpy (sect->name, name); + sect->prev = last_section; + last_section = sect; + + if (xml_node_open && xml_node_level == -1) + xml_node_level = level; +} + +void +xml_start_menu_entry (char *tem) +{ + char *string; + discard_until ("* "); + + /* The line number was already incremented in reader_loop when we + saw the newline, and discard_until has now incremented again. */ + line_number--; + + if (xml_in_menu_entry) + { + if (xml_in_menu_entry_comment) + { + xml_insert_element (MENUCOMMENT, END); + xml_in_menu_entry_comment=0; + } + xml_insert_element (MENUENTRY, END); + xml_in_menu_entry=0; + } + xml_insert_element (MENUENTRY, START); + xml_in_menu_entry=1; + + xml_insert_element (MENUNODE, START); + string = expansion (tem, 0); + add_word (string); + xml_insert_element (MENUNODE, END); + free (string); + + /* The menu item may use macros, so expand them now. */ + xml_insert_element (MENUTITLE, START); + only_macro_expansion++; + get_until_in_line (1, ":", &string); + only_macro_expansion--; + execute_string ("%s", string); /* get escaping done */ + xml_insert_element (MENUTITLE, END); + free (string); + + 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 */ + skip_whitespace_and_newlines(); + xml_insert_element (MENUCOMMENT, START); + xml_in_menu_entry_comment ++; +} + +void +xml_end_menu (void) +{ + if (xml_in_menu_entry) + { + if (xml_in_menu_entry_comment) + { + xml_insert_element (MENUCOMMENT, END); + xml_in_menu_entry_comment --; + } + xml_insert_element (MENUENTRY, END); + xml_in_menu_entry--; + } + xml_insert_element (MENU, END); +} + +static int xml_last_character; + +void +xml_add_char (int character) +{ + if (!book_started) + return; + if (docbook && !only_macro_expansion && (in_menu || in_detailmenu)) + return; + + if (docbook && xml_table_level && !in_table_title + && !xml_in_item[xml_table_level] && !xml_in_tableitem[xml_table_level] + && !cr_or_whitespace (character) && !in_indexterm) + { + in_table_title = 1; + xml_insert_element (TITLE, START); + } + + if (!first_section_opened && !xml_in_abstract && !xml_in_book_title + && !xml_no_para && character != '\r' && character != '\n' + && character != ' ' && !is_in_insertion_of_type (copying)) + { + if (!xml_in_bookinfo) + { + xml_insert_element (BOOKINFO, START); + xml_in_bookinfo = 1; + } + xml_insert_element (ABSTRACT, START); + xml_in_abstract = 1; + } + + if (!xml_sort_index && !xml_in_xref_token && !xml_dont_touch_items_defs) + { + if (xml_after_table_term && xml_table_level + && !xml_in_item[xml_table_level]) + { + xml_after_table_term = 0; + xml_insert_element (ITEM, START); + xml_in_item[xml_table_level] = 1; + } + else if (xml_after_def_term) + { + xml_after_def_term = 0; + xml_insert_element (DEFINITIONITEM, START); + xml_in_def_item[xml_definition_level] = 1; + } + } + + if (xml_just_after_element && !xml_in_para && !inhibit_paragraph_indentation) + { + if (character == '\r' || character == '\n' || character == '\t' || character == ' ') + return; + xml_just_after_element = 0; + } + + if (xml_element_list[xml_current_element()].contains_para + && !xml_in_para && !only_macro_expansion && !xml_no_para + && !cr_or_whitespace (character) && !in_fixed_width_font) + xml_start_para (); + + if (xml_in_para && character == '\n' && xml_last_character == '\n' + && !only_macro_expansion && !xml_no_para + && xml_element_list[xml_current_element()].contains_para ) + { + xml_end_para (); + xml_just_after_element = 1; + return; + } + + if (xml_in_menu_entry_comment && character == '\n' && xml_last_character == '\n') + { + xml_insert_element (MENUCOMMENT, END); + xml_in_menu_entry_comment = 0; + xml_insert_element (MENUENTRY, END); + xml_in_menu_entry = 0; + } + + if (xml_in_menu_entry_comment && whitespace(character) + && cr_or_whitespace(xml_last_character)) + return; + + if (character == '\n' && !xml_in_para && !inhibit_paragraph_indentation) + return; + + xml_last_character = character; + + if (character == '&' && escape_html) + insert_string ("&"); + else if (character == '<' && escape_html) + insert_string ("<"); + else if (character == '\n' && !xml_keep_space) + { + if (!xml_in_para && xml_just_after_element && !multitable_active) + return; + else + insert (docbook ? '\n' : ' '); + } + else + insert (character); + + return; +} + +void +xml_insert_footnote (char *note) +{ + if (!xml_in_para) + xml_start_para (); + + xml_in_footnote = 1; + xml_insert_element (FOOTNOTE, START); + insert_string ("<para>"); + execute_string ("%s", note); + insert_string ("</para>"); + xml_insert_element (FOOTNOTE, END); + xml_in_footnote = 0; +} + +/* We need to keep the quotation stack ourself, because insertion_stack + loses item_function when we are closing the block, so we don't know + what to close then. */ +typedef struct quotation_elt +{ + struct quotation_elt *next; + char *type; +} QUOTATION_ELT; + +static QUOTATION_ELT *quotation_stack = NULL; + +void +xml_insert_quotation (char *type, int arg) +{ + int quotation_started = 0; + + if (arg == START) + { + QUOTATION_ELT *new = xmalloc (sizeof (QUOTATION_ELT)); + new->type = xstrdup (type); + new->next = quotation_stack; + quotation_stack = new; + } + else + type = quotation_stack->type; + + /* Make use of special quotation styles of Docbook if we can. */ + if (docbook && strlen(type)) + { + /* Let's assume it started. */ + quotation_started = 1; + + if (strcasecmp (type, "tip") == 0) + xml_insert_element (TIP, arg); + else if (strcasecmp (type, "note") == 0) + xml_insert_element (NOTE, arg); + else if (strcasecmp (type, "important") == 0) + xml_insert_element (IMPORTANT, arg); + else if (strcasecmp (type, "warning") == 0) + xml_insert_element (WARNING, arg); + else if (strcasecmp (type, "caution") == 0) + xml_insert_element (CAUTION, arg); + else + /* Didn't find a known quotation type :\ */ + quotation_started = 0; + } + + if (!quotation_started) + { + xml_insert_element (QUOTATION, arg); + if (strlen(type) && arg == START) + execute_string ("@b{%s:} ", type); + } + + if (arg == END) + { + QUOTATION_ELT *temp = quotation_stack; + if (temp == NULL) + return; + quotation_stack = quotation_stack->next; + free(temp->type); + free(temp); + } +} + +/* Starting generic docbook floats. Just starts elt with correct label + and id attributes, and inserts title. */ +void +xml_begin_docbook_float (int elt) +{ + if (current_float_used_title ()) /* in a nested float */ + { + xml_insert_element (elt, START); /* just insert the tag */ + return; + } + + + /* OK, need the title, tag, etc. */ + if (elt == CARTOUCHE) /* no labels on <sidebar> */ + { + if (strlen (current_float_id ()) == 0) + xml_insert_element (elt, START); + else + xml_insert_element_with_attribute (elt, START, + "id=\"%s\"", xml_id (current_float_id ())); + } + else if (strlen (current_float_id ()) == 0) + xml_insert_element_with_attribute (elt, START, "label=\"\""); + else + xml_insert_element_with_attribute (elt, START, + "id=\"%s\" label=\"%s\"", xml_id (current_float_id ()), + current_float_number ()); + + xml_insert_element (TITLE, START); + execute_string ("%s", current_float_title ()); + xml_insert_element (TITLE, END); + + current_float_set_title_used (); /* mark this title, tag, etc used */ +} + +/* + * Lists and Tables + */ +void +xml_begin_table (int type, char *item_function) +{ + switch (type) + { + case ftable: + case vtable: + case table: + /*if (docbook)*/ /* 05-08 */ + { + xml_insert_element (TABLE, START); + xml_table_level ++; + xml_in_tableitem[xml_table_level] = 0; + xml_in_item[xml_table_level] = 0; + xml_after_table_term = 0; + } + break; + case itemize: + if (!docbook) + { + xml_insert_element (ITEMIZE, START); + xml_table_level ++; + xml_in_item[xml_table_level] = 0; + xml_insert_element (ITEMFUNCTION, START); + if (*item_function == COMMAND_PREFIX + && item_function[strlen (item_function) - 1] != '}' + && command_needs_braces (item_function + 1)) + execute_string ("%s{}", item_function); + else + execute_string ("%s", item_function); + xml_insert_element (ITEMFUNCTION, END); + } + else + { + xml_insert_element_with_attribute (ITEMIZE, START, + "mark=\"%s\"", + (*item_function == COMMAND_PREFIX) ? + &item_function[1] : item_function); + xml_table_level ++; + xml_in_item[xml_table_level] = 0; + } + break; + } +} + +void +xml_end_table (int type) +{ + switch (type) + { + case ftable: + case vtable: + case table: + if (xml_in_item[xml_table_level]) + { + xml_insert_element (ITEM, END); + xml_in_item[xml_table_level] = 0; + } + if (xml_in_tableitem[xml_table_level]) + { + xml_insert_element (TABLEITEM, END); + xml_in_tableitem[xml_table_level] = 0; + } + xml_insert_element (TABLE, END); + xml_after_table_term = 0; + xml_table_level --; + + break; + case itemize: + if (xml_in_item[xml_table_level]) + { + xml_insert_element (ITEM, END); + xml_in_item[xml_table_level] = 0; + } + /* gnat-style manual contains an itemized list without items! */ + if (in_table_title) + { + xml_insert_element (TITLE, END); + in_table_title = 0; + } + xml_insert_element (ITEMIZE, END); + xml_table_level --; + break; + } +} + +void +xml_begin_item (void) +{ + if (xml_in_item[xml_table_level]) + xml_insert_element (ITEM, END); + + xml_insert_element (ITEM, START); + xml_in_item[xml_table_level] = 1; +} + +void +xml_begin_table_item (void) +{ + if (!xml_after_table_term) + { + if (xml_in_item[xml_table_level]) + xml_insert_element (ITEM, END); + if (xml_in_tableitem[xml_table_level]) + xml_insert_element (TABLEITEM, END); + + if (in_table_title) + { + in_table_title = 0; + xml_insert_element (TITLE, END); + } + xml_insert_element (TABLEITEM, START); + } + xml_insert_element (TABLETERM, START); + xml_in_tableitem[xml_table_level] = 1; + xml_in_item[xml_table_level] = 0; + xml_after_table_term = 0; +} + +void +xml_continue_table_item (void) +{ + xml_insert_element (TABLETERM, END); + xml_after_table_term = 1; + xml_in_item[xml_table_level] = 0; +} + +void +xml_begin_enumerate (char *enum_arg) +{ + if (!docbook) + xml_insert_element_with_attribute (ENUMERATE, START, "first=\"%s\"", enum_arg); + else + { + if (isdigit (*enum_arg)) + { + int enum_val = atoi (enum_arg); + + /* Have to check the value, not just the first digit. */ + if (enum_val == 0) + xml_insert_element_with_attribute (ENUMERATE, START, + "numeration=\"arabic\" role=\"0\"", NULL); + else if (enum_val == 1) + xml_insert_element_with_attribute (ENUMERATE, START, + "numeration=\"arabic\"", NULL); + else + xml_insert_element_with_attribute (ENUMERATE, START, + "continuation=\"continues\" numeration=\"arabic\"", NULL); + } + else if (isupper (*enum_arg)) + { + if (enum_arg[0] == 'A') + xml_insert_element_with_attribute (ENUMERATE, START, + "numeration=\"upperalpha\"", NULL); + else + xml_insert_element_with_attribute (ENUMERATE, START, + "continuation=\"continues\" numeration=\"upperalpha\"", NULL); + } + else + { + if (enum_arg[0] == 'a') + xml_insert_element_with_attribute (ENUMERATE, START, + "numeration=\"loweralpha\"", NULL); + else + xml_insert_element_with_attribute (ENUMERATE, START, + "continuation=\"continues\" numeration=\"loweralpha\"", NULL); + } + } + xml_table_level ++; + xml_in_item[xml_table_level] = 0; +} + +void +xml_end_enumerate (void) +{ + if (xml_in_item[xml_table_level]) + { + xml_insert_element (ITEM, END); + xml_in_item[xml_table_level] = 0; + } + xml_insert_element (ENUMERATE, END); + xml_table_level --; +} + +static void +xml_insert_text_file (char *name_arg) +{ + char *fullname = xmalloc (strlen (name_arg) + 4 + 1); + FILE *image_file; + 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; + + xml_insert_element (TEXTOBJECT, START); + xml_insert_element (DISPLAY, START); + + 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; + + xml_insert_element (DISPLAY, END); + xml_insert_element (TEXTOBJECT, END); + + if (fclose (image_file) != 0) + perror (fullname); + } + else + warning (_("@image file `%s' unreadable: %s"), fullname, + strerror (errno)); + + free (fullname); +} + +/* If NAME.EXT is accessible or FORCE is nonzero, insert a docbook + imagedata element for FMT. Return 1 if inserted something, 0 else. */ + +static int +try_docbook_image (const char *name, const char *ext, const char *fmt, + int force) +{ + int used = 0; + char *fullname = xmalloc (strlen (name) + 1 + strlen (ext) + 1); + sprintf (fullname, "%s.%s", name, ext); + + if (force || access (fullname, R_OK) == 0) + { + xml_insert_element (IMAGEOBJECT, START); + xml_insert_element_with_attribute (IMAGEDATA, START, + "fileref=\"%s\" format=\"%s\"", fullname, fmt); + xml_insert_element (IMAGEDATA, END); + xml_insert_element (IMAGEOBJECT, END); + used = 1; + } + + free (fullname); + return used; +} + + +void +xml_insert_docbook_image (char *name_arg) +{ + int found = 0; + int elt = xml_in_para ? INLINEIMAGE : MEDIAOBJECT; + + if (is_in_insertion_of_type (floatenv)) + xml_begin_docbook_float (INFORMALFIGURE); + else if (!xml_in_para) + xml_insert_element (INFORMALFIGURE, START); + + xml_no_para++; + + xml_insert_element (elt, START); + + /* A selected few from http://docbook.org/tdg/en/html/imagedata.html. */ + if (try_docbook_image (name_arg, "eps", "EPS", 0)) + found++; + if (try_docbook_image (name_arg, "gif", "GIF", 0)) + found++; + if (try_docbook_image (name_arg, "jpg", "JPG", 0)) + found++; + if (try_docbook_image (name_arg, "jpeg", "JPEG", 0)) + found++; + if (try_docbook_image (name_arg, "pdf", "PDF", 0)) + found++; + if (try_docbook_image (name_arg, "png", "PNG", 0)) + found++; + if (try_docbook_image (name_arg, "svg", "SVG", 0)) + found++; + + /* If no luck so far, just assume we'll eventually have a jpg. */ + if (!found) + try_docbook_image (name_arg, "jpg", "JPG", 1); + + xml_insert_text_file (name_arg); + xml_insert_element (elt, END); + + xml_no_para--; + + if (elt == MEDIAOBJECT) + xml_insert_element (INFORMALFIGURE, END); +} + +void +xml_asterisk (void) +{ +} + + +/* + * INDEX + */ +/* Used to separate primary and secondary entries in an index -- we need + to have real multilivel indexing support, not just string analysis. */ +#define INDEX_SEP "@this string will never appear@" /* was , */ + +typedef struct +{ + char *from; + char *to; +} XML_SYNONYM; + +static XML_SYNONYM **xml_synonyms = NULL; +static int xml_synonyms_count = 0; + +void +xml_insert_indexterm (char *indexterm, char *index) +{ + /* @index commands can appear between @item and @itemx, @deffn and @deffnx. */ + if (!docbook) + { + /* Check to see if we need to do index redirection per @synindex. */ + int i; + for (i = 0; i < xml_synonyms_count; i++) + { + if (STREQ (xml_synonyms[i]->from, index)) + index = xstrdup (xml_synonyms[i]->to); + } + + xml_dont_touch_items_defs++; + xml_insert_element_with_attribute (INDEXTERM, START, "index=\"%s\"", index); + in_indexterm = 1; + execute_string ("%s", indexterm); + xml_insert_element (INDEXTERM, END); + in_indexterm = 0; + xml_dont_touch_items_defs--; + } + else + { + char *primary = NULL, *secondary = NULL; + if (strstr (indexterm+1, INDEX_SEP)) + { + primary = xmalloc (strlen (indexterm) + 1); + strcpy (primary, indexterm); + secondary = strstr (primary+1, INDEX_SEP); + *secondary = '\0'; + secondary += strlen (INDEX_SEP); + } + xml_insert_element_with_attribute (INDEXTERM, START, "role=\"%s\"", index); + in_indexterm = 1; + xml_insert_element (PRIMARY, START); + if (primary) + execute_string ("%s", primary); + else + execute_string ("%s", indexterm); + xml_insert_element (PRIMARY, END); + if (primary) + { + xml_insert_element (SECONDARY, START); + execute_string ("%s", secondary); + xml_insert_element (SECONDARY, END); + } + xml_insert_element (INDEXTERM, END); + in_indexterm = 0; + } +} + + +int xml_last_section_output_position = 0; +static char last_division_letter = ' '; +static char index_primary[2000]; /** xx no fixed limit */ +static int indexdivempty = 0; + +static void +xml_close_indexentry (void) +{ + if (!in_indexentry) + return; + if (in_secondary) + xml_insert_element (SECONDARYIE, END); + xml_insert_element (INDEXENTRY, END); + in_secondary = 0; + in_indexentry = 0; +} + +void +xml_begin_index (void) +{ + typedef struct xml_index_title { + struct xml_index_title *next; + char *title; + } XML_INDEX_TITLE; + + static XML_INDEX_TITLE *xml_index_titles = NULL; + + if (!handling_delayed_writes) + { /* We assume that we just opened a section, and so that the last output is + <SECTION ID="node-name"><TITLE>Title</TITLE> + where SECTION can be CHAPTER, ... */ + + XML_INDEX_TITLE *new = xmalloc (sizeof (XML_INDEX_TITLE)); + xml_section *temp = last_section; + + int l = output_paragraph_offset-xml_last_section_output_position; + char *tmp = xmalloc (l+1); + char *p = tmp; + strncpy (tmp, (char *) output_paragraph, l); + + /* We remove <SECTION */ + tmp[l] = '\0'; + while (*p != '<') + p++; + while (*p != ' ') + p++; + /* ... and its label attribute. */ + if (strncmp (p, " label=", 7) == 0) + { + p++; + while (*p != ' ') + p++; + } + + output_paragraph_offset = xml_last_section_output_position; + xml_last_section_output_position = 0; + + xml_pop_current_element (); /* remove section element from elements stack */ + + if (last_section) + last_section = last_section->prev; /* remove section from sections stack */ + if (temp) + { + free (temp->name); + free (temp); + } + + new->title = xstrdup (p); + new->next = xml_index_titles; + xml_index_titles = new; + } + else + { + static int xml_index_titles_reversed = 0; + + if (!xml_index_titles_reversed) + { + xml_index_titles = (XML_INDEX_TITLE *) reverse_list + ((GENERIC_LIST *) xml_index_titles); + xml_index_titles_reversed = 1; + } + + /* We put <INDEX> */ + xml_insert_element (PRINTINDEX, START); + if (xml_index_titles) + { + /* Remove the final > */ + output_paragraph_offset--; + /* and put ID="node-name"><TITLE>Title</TITLE> */ + insert_string (xml_index_titles->title); + free (xml_index_titles->title); + xml_index_titles = xml_index_titles->next; + } + + if (xml_index_divisions) + { + xml_insert_element (INDEXDIV, START); + indexdivempty = 1; + } + } +} + +void +xml_end_index (void) +{ + xml_close_indexentry (); + if (xml_index_divisions) + xml_insert_element (INDEXDIV, END); + xml_insert_element (PRINTINDEX, END); +} + +static void +xml_index_divide (char *entry) +{ + char c; + if (strlen (entry) > (strlen (xml_element_list[CODE].name) + 2) && + strncmp (entry+1, xml_element_list[CODE].name, strlen (xml_element_list[CODE].name)) == 0) + c = entry[strlen (xml_element_list[CODE].name)+2]; + else + c = entry[0]; + if (tolower (c) != last_division_letter && isalpha (c)) + { + last_division_letter = tolower (c); + xml_close_indexentry (); + if (!indexdivempty) + { + xml_insert_element (INDEXDIV, END); + xml_insert_element (INDEXDIV, START); + } + xml_insert_element (TITLE, START); + insert (toupper (c)); + xml_insert_element (TITLE, END); + } +} + +void +xml_insert_indexentry (char *entry, char *node) +{ + char *primary = NULL, *secondary; + if (xml_index_divisions) + xml_index_divide (entry); + + indexdivempty = 0; + if (strstr (entry+1, INDEX_SEP)) + { + primary = xmalloc (strlen (entry) + 1); + strcpy (primary, entry); + secondary = strstr (primary+1, INDEX_SEP); + *secondary = '\0'; + secondary += strlen (INDEX_SEP); + + if (in_secondary && strcmp (primary, index_primary) == 0) + { + xml_insert_element (SECONDARYIE, END); + xml_insert_element (SECONDARYIE, START); + execute_string ("%s", secondary); + } + else + { + xml_close_indexentry (); + xml_insert_element (INDEXENTRY, START); + in_indexentry = 1; + xml_insert_element (PRIMARYIE, START); + execute_string ("%s", primary); + xml_insert_element (PRIMARYIE, END); + xml_insert_element (SECONDARYIE, START); + execute_string ("%s", secondary); + in_secondary = 1; + } + } + else + { + xml_close_indexentry (); + xml_insert_element (INDEXENTRY, START); + in_indexentry = 1; + xml_insert_element (PRIMARYIE, START); + execute_string ("%s", entry); + } + add_word (", "); + + /* Don't link to @unnumbered sections directly. + We are disabling warnings temporarily, otherwise these xrefs + will cause bogus warnings about missing punctuation. */ + { + extern int print_warnings; + int save_print_warnings = print_warnings; + print_warnings = 0; + execute_string ("%cxref{%s}", COMMAND_PREFIX, xstrdup (node)); + print_warnings = save_print_warnings; + } + + if (primary) + { + strcpy (index_primary, primary); + /* xml_insert_element (SECONDARYIE, END);*/ + /* *(secondary-1) = ',';*/ /* necessary ? */ + free (primary); + } + else + xml_insert_element (PRIMARYIE, END); + + /* xml_insert_element (INDEXENTRY, END); */ +} + +void +xml_synindex (char *from, char *to) +{ + int i, slot; + + slot = -1; + for (i = 0; i < xml_synonyms_count; i++) + if (!xml_synonyms[i]) + { + slot = i; + break; + } + + if (slot < 0) + { + slot = xml_synonyms_count; + xml_synonyms_count++; + + xml_synonyms = (XML_SYNONYM **) xrealloc (xml_synonyms, + (xml_synonyms_count + 1) * sizeof (XML_SYNONYM *)); + } + + xml_synonyms[slot] = xmalloc (sizeof (XML_SYNONYM)); + xml_synonyms[slot]->from = xstrdup (from); + xml_synonyms[slot]->to = xstrdup (to); +} + +/* + * MULTITABLE + */ + +static int multitable_columns_count; +static int *multitable_column_widths; + +void +xml_begin_multitable (int ncolumns, int *column_widths) +{ + int i; + if (docbook) + { + if (is_in_insertion_of_type (floatenv)) + xml_begin_docbook_float (MULTITABLE); + else + xml_insert_element (MULTITABLE, START); + + multitable_columns_count = ncolumns; + multitable_column_widths = xmalloc (sizeof (int) * ncolumns); + memcpy (multitable_column_widths, column_widths, + sizeof (int) * ncolumns); + + xml_no_para = 1; + } + else + { + xml_insert_element (MULTITABLE, START); + for (i=0; i<ncolumns; i++) + { + xml_insert_element (COLSPEC, START); + add_word_args ("%d", column_widths[i]); + xml_insert_element (COLSPEC, END); + } + xml_no_para = 1; + } +} + +static void +xml_begin_multitable_group (void) +{ + int i; + + xml_insert_element_with_attribute (TGROUP, START, "cols=\"%d\"", + multitable_columns_count); + + for (i=0; i < multitable_columns_count; i++) + { + xml_insert_element_with_attribute (COLSPEC, START, + "colwidth=\"%d*\"", multitable_column_widths[i]); + xml_insert_element (COLSPEC, END); + } +} + +void +xml_end_multitable_row (int first_row) +{ + if (!first_row) + { + xml_insert_element (ENTRY, END); + xml_insert_element (ROW, END); + } + + if (headitem_flag) + { + if (!first_row) + { + if (after_headitem) + xml_insert_element (THEAD, END); + else + xml_insert_element (TBODY, END); + xml_insert_element (TGROUP, END); + } + + xml_begin_multitable_group (); + xml_insert_element (THEAD, START); + } + else if (first_row) + { + xml_begin_multitable_group (); + xml_insert_element (TBODY, START); + } + else if (after_headitem) + { + xml_insert_element (THEAD, END); + xml_insert_element (TBODY, START); + } + else if (first_row) + xml_insert_element (TBODY, START); + + xml_insert_element (ROW, START); + xml_insert_element (ENTRY, START); +} + +void +xml_end_multitable_column (void) +{ + xml_insert_element (ENTRY, END); + xml_insert_element (ENTRY, START); +} + +void +xml_end_multitable (void) +{ + xml_insert_element (ENTRY, END); + xml_insert_element (ROW, END); + + if (after_headitem) + { + if (docbook) + warning (_("@headitem as the last item of @multitable produces invalid Docbook documents")); + xml_insert_element (THEAD, END); + } + else + xml_insert_element (TBODY, END); + + if (docbook) + xml_insert_element (TGROUP, END); + + xml_insert_element (MULTITABLE, END); + xml_no_para = 0; +} + +/* + * Parameters in @def definitions + */ + +#define DEFUN_SELF_DELIMITING(c) \ + ((c) == '(' || (c) == ')' || (c) == '[' || (c) == ']') + +void +xml_process_defun_args (char **defun_args, int auto_var_p) +{ + int pending_space = 0; + int just_after_paramtype = 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])) + { + xml_insert_element (DEFDELIMITER, START); + add_char (defun_arg[0]); + xml_insert_element (DEFDELIMITER, END); + just_after_paramtype = 0; + } + else if (defun_arg[0] == '&') + { + xml_insert_element (DEFPARAM, START); + add_word (defun_arg); + xml_insert_element (DEFPARAM, END); + just_after_paramtype = 0; + } + else if (defun_arg[0] == COMMAND_PREFIX || just_after_paramtype) + { + xml_insert_element (DEFPARAM, START); + execute_string ("%s", defun_arg); + xml_insert_element (DEFPARAM, END); + just_after_paramtype = 0; + } + else if (defun_arg[0] == ',' || defun_arg[0] == ';') + { + xml_insert_element (DEFDELIMITER, START); + add_word (defun_arg); + xml_insert_element (DEFDELIMITER, END); + just_after_paramtype = 0; + } + else if (auto_var_p) + { + xml_insert_element (DEFPARAM, START); + add_word (defun_arg); + xml_insert_element (DEFPARAM, END); + just_after_paramtype = 0; + } + else + { + xml_insert_element (DEFPARAMTYPE, START); + add_word (defun_arg); + xml_insert_element (DEFPARAMTYPE, END); + just_after_paramtype = 1; + } + } +} + +void +xml_begin_definition (void) +{ + xml_insert_element (DEFINITION, START); + xml_definition_level ++; + xml_in_def_item[xml_definition_level] = 0; +} + +void +xml_end_definition (void) +{ + if (xml_in_def_item[xml_definition_level]) + { + xml_insert_element (DEFINITIONITEM, END); + xml_in_def_item[xml_definition_level] = 0; + } + xml_after_def_term = 0; + xml_insert_element (DEFINITION, END); + xml_definition_level --; +} + +void +xml_begin_def_term (int base_type, const char *category, + char *defined_name, char *type_name, char *type_name2) +{ + xml_after_def_term = 0; + xml_insert_element (DEFINITIONTERM, START); + + /* Index entry */ + 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 deftypecv: + case deftypeivar: + execute_string ("@vindex %s %s %s\n", defined_name, _("of"), type_name); + break; + case deftypemethod: + case defop: + case deftypeop: + execute_string ("@findex %s %s %s\n", defined_name, _("on"), type_name); + break; + case deftp: + execute_string ("@tindex %s\n", defined_name); + break; + } + + /* Start with category. */ + xml_insert_element (DEFCATEGORY, START); + execute_string (docbook ? "--- %s:" : "%s", category); + xml_insert_element (DEFCATEGORY, END); + add_char(' '); + + /* Output type name first for typed definitions. */ + switch (base_type) + { + case deffn: + case defvr: + case deftp: + break; + + case deftypefn: + case deftypevr: + xml_insert_element (DEFTYPE, START); + execute_string ("%s", type_name); + xml_insert_element (DEFTYPE, END); + add_char (' '); + break; + + case deftypecv: + case deftypeivar: + case deftypemethod: + case deftypeop: + xml_insert_element (DEFTYPE, START); + execute_string ("%s", type_name2); + xml_insert_element (DEFTYPE, END); + add_char (' '); + break; + + default: + xml_insert_element (DEFCLASS, START); + execute_string ("%s", type_name); + xml_insert_element (DEFCLASS, END); + add_char (' '); + break; + } + + /* Categorize rest of the definitions. */ + switch (base_type) + { + case deffn: + case deftypefn: + xml_insert_element (DEFFUNCTION, START); + execute_string ("%s", defined_name); + xml_insert_element (DEFFUNCTION, END); + break; + + case defvr: + case deftypevr: + xml_insert_element (DEFVARIABLE, START); + execute_string ("%s", defined_name); + xml_insert_element (DEFVARIABLE, END); + break; + + case deftp: + xml_insert_element (DEFDATATYPE, START); + execute_string ("%s", defined_name); + xml_insert_element (DEFDATATYPE, END); + break; + + case defcv: + case deftypecv: + case deftypeivar: + xml_insert_element (DEFCLASSVAR, START); + execute_string ("%s", defined_name); + xml_insert_element (DEFCLASSVAR, END); + break; + + case defop: + case deftypeop: + case deftypemethod: + /* Operation / Method */ + xml_insert_element (DEFOPERATION, START); + execute_string ("%s", defined_name); + xml_insert_element (DEFOPERATION, END); + break; + } +} + +void +xml_end_def_term (void) +{ + xml_insert_element (DEFINITIONTERM, END); + xml_after_def_term = 1; +} diff --git a/Build/source/utils/texinfo/makeinfo/xml.h b/Build/source/utils/texinfo/makeinfo/xml.h new file mode 100644 index 00000000000..f82b483e381 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/xml.h @@ -0,0 +1,159 @@ +/* xml.h -- xml output declarations. + $Id: xml.h,v 1.24 2004/11/26 00:48:35 karl Exp $ + + Copyright (C) 2001, 2002, 2003, 2004 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. + + Originally written by Philippe Martin <feloy@free.fr>. */ + +#ifndef XML_H +#define XML_H + +/* Options. */ + +/* Separate index entries into divisions for each letters. */ +extern int xml_index_divisions; +extern int xml_sort_index; + +extern int xml_no_indent; + +extern int xml_node_open; +extern int xml_no_para; +extern char *xml_node_id; +extern int xml_last_section_output_position; + +extern int xml_in_xref_token; +extern int xml_in_bookinfo; +extern int xml_in_book_title; +extern int xml_in_abstract; + +/* Non-zero if we are handling an element that can appear between + @item and @itemx, @deffn and @deffnx. */ +extern int xml_dont_touch_items_defs; + +/* Non-zero if whitespace in the source document should be kept as-is. */ +extern int xml_keep_space; + +enum xml_element +{ + TEXINFO=0, SETFILENAME, TITLEFONT, SETTITLE, DOCUMENTDESCRIPTION, + /* Node */ + NODE, NODENEXT, NODEPREV, NODEUP, + /* Structuring */ + CHAPTER, SECTION, SUBSECTION, SUBSUBSECTION, + TOP, UNNUMBERED, UNNUMBEREDSEC, UNNUMBEREDSUBSEC, + UNNUMBEREDSUBSUBSEC, + APPENDIX, APPENDIXSEC, APPENDIXSUBSEC, APPENDIXSUBSUBSEC, + MAJORHEADING, CHAPHEADING, HEADING, SUBHEADING, SUBSUBHEADING, + /* Titlepage */ + TITLEPAGE, AUTHOR, BOOKTITLE, BOOKSUBTITLE, + /* Menu */ + MENU, DETAILMENU, MENUENTRY, MENUTITLE, MENUCOMMENT, MENUNODE, + NODENAME, + /* -- */ + ACRONYM, ACRONYMWORD, ACRONYMDESC, + ABBREV, ABBREVWORD, ABBREVDESC, + TT, CODE, COMMAND_TAG, ENV, FILE_TAG, OPTION, SAMP, KBD, URL, KEY, + VAR, SC, DFN, EMPH, STRONG, CITE, NOTFIXEDWIDTH, I, B, R, SLANTED, SANSSERIF, + EXDENT, + TITLE, + IFINFO, + SP, CENTER, + DIRCATEGORY, + QUOTATION, EXAMPLE, SMALLEXAMPLE, LISP, SMALLLISP, CARTOUCHE, + COPYING, FORMAT, SMALLFORMAT, DISPLAY, SMALLDISPLAY, VERBATIM, + FOOTNOTE, LINEANNOTATION, + TIP, NOTE, IMPORTANT, WARNING, CAUTION, + ITEMIZE, ITEMFUNCTION, ITEM, ENUMERATE, TABLE, TABLEITEM, TABLETERM, + INDEXTERM, + MATH, DIMENSION, + XREF, XREFNODENAME, XREFINFONAME, XREFPRINTEDDESC, XREFINFOFILE, + XREFPRINTEDNAME, + INFOREF, INFOREFNODENAME, INFOREFREFNAME, INFOREFINFONAME, + UREF, UREFURL, UREFDESC, UREFREPLACEMENT, + EMAIL, EMAILADDRESS, EMAILNAME, + GROUP, FLOAT, FLOATTYPE, FLOATPOS, CAPTION, SHORTCAPTION, + FLOATTABLE, FLOATFIGURE, FLOATEXAMPLE, FLOATCARTOUCHE, + PRINTINDEX, LISTOFFLOATS, + ANCHOR, + IMAGE, INLINEIMAGE, IMAGEALTTEXT, + PRIMARY, SECONDARY, INFORMALFIGURE, MEDIAOBJECT, IMAGEOBJECT, + IMAGEDATA, TEXTOBJECT, + INDEXENTRY, PRIMARYIE, SECONDARYIE, INDEXDIV, + MULTITABLE, TGROUP, COLSPEC, THEAD, TBODY, ENTRY, ROW, + BOOKINFO, ABSTRACT, REPLACEABLE, ENVAR, COMMENT, FUNCTION, LEGALNOTICE, + CONTENTS, SHORTCONTENTS, DOCUMENTLANGUAGE, + SETVALUE, CLEARVALUE, + DEFINITION, DEFINITIONTERM, DEFINITIONITEM, + DEFCATEGORY, DEFFUNCTION, DEFVARIABLE, DEFPARAM, DEFDELIMITER, DEFTYPE, + DEFPARAMTYPE, DEFDATATYPE, DEFCLASS, DEFCLASSVAR, DEFOPERATION, + PARA +}; + +extern void xml_add_char (int character), + xml_asterisk (void), + xml_insert_element (int elt, int arg), + xml_insert_entity (char *entity_name), + xml_insert_footnote (char *note), + xml_insert_quotation (char *type, int arg), + xml_insert_indexentry (char *entry, char *node), + xml_insert_indexterm (char *indexterm, char *index), + xml_insert_docbook_image (char *name_arg), + xml_synindex (char *from, char *to), + xml_start_para (void), + xml_end_para (void), + xml_begin_document (char *output_filename), + xml_end_document (void), + xml_start_menu_entry (char *tem), + xml_end_menu (void), + xml_end_current_element (void), + xml_open_section (int level, char *name), + xml_close_sections (int level), + xml_begin_node (void), + xml_begin_index (void), + xml_end_index (void), + xml_begin_multitable (int ncolumns, int *column_widths), + xml_end_multitable (void), + xml_end_multitable_row (int first_row), + xml_end_multitable_column (void), + xml_begin_table (int type, char *item_function), + xml_end_table (int type), + xml_begin_item (void), + xml_begin_table_item (void), + xml_continue_table_item (void), + xml_begin_enumerate (char *enum_arg), + xml_end_enumerate (void), + xml_begin_docbook_float (int elt); + +extern char *xml_id (char *id); + +extern void xml_begin_definition (void), + xml_end_definition (void), + xml_process_defun_args (char **defun_args, int auto_var_p), + xml_begin_def_term (int base_type, const char *category, + char *defined_name, char *type_name, char *type_name2), + xml_end_def_term (void); + +extern int xml_current_stack_index (void), + xml_element (char *name); + +#if defined (VA_FPRINTF) && __STDC__ +void xml_insert_element_with_attribute (int elt, int arg, char *format, ...); +#else +void xml_insert_element_with_attribute (); +#endif + +#endif /* XML_H */ diff --git a/Build/source/utils/texinfo/makeinfo/xref.c b/Build/source/utils/texinfo/makeinfo/xref.c new file mode 100644 index 00000000000..314d4a0fb64 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/xref.c @@ -0,0 +1,620 @@ +/* xref.c -- cross references for Texinfo. + $Id: xref.c,v 1.4 2004/12/21 17:28:35 karl Exp $ + + Copyright (C) 2004 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 "float.h" +#include "html.h" +#include "index.h" +#include "macro.h" +#include "makeinfo.h" +#include "node.h" +#include "xml.h" +#include "xref.h" + +/* Flags which control initial output string for xrefs. */ +int px_ref_flag = 0; +int ref_flag = 0; + +/* Called in the multiple-argument case to make sure we generate a valid + Info reference. In the single-argument case, the :: we output + suffices for the Info readers to find the end of the reference. */ +static void +add_xref_punctuation (void) +{ + if (px_ref_flag || ref_flag) /* user inserts punct after @xref */ + { + /* Check if there's already punctuation. */ + int next_char = next_nonwhitespace_character (); + + if (next_char == -1) + /* EOF while looking for punctuation, let's + insert a period instead of crying. */ + add_char ('.'); + else if (next_char != ',' && next_char != '.') + /* period and comma terminate xrefs, and nothing else. Instead + of generating an Info reference that can't be followed, + though, just insert a period. Not pretty, but functional. */ + add_char ('.'); + } +} + +/* 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_xref_token (int expand) +{ + char *string = 0; + + if (docbook) + xml_in_xref_token = 1; + + if (expand) + { + int old_offset = input_text_offset; + int old_lineno = line_number; + + get_until_in_braces ("}", &string); + if (curchar () == '}') /* as opposed to end of text */ + input_text_offset++; + if (input_text_offset > old_offset) + { + int limit = input_text_offset; + + input_text_offset = old_offset; + line_number = old_lineno; + only_macro_expansion++; + replace_with_expansion (input_text_offset, &limit); + only_macro_expansion--; + } + free (string); + } + + get_until_in_braces (",", &string); + if (curchar () == ',') + input_text_offset++; + fix_whitespace (string); + + if (docbook) + xml_in_xref_token = 0; + + return 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 +cm_xref (int arg) +{ + if (arg == START) + { + 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; + + /* "@xref{,Foo,, Bar, Baz} is not valid usage of @xref. The + first argument must never be blank." --rms. + We hereby comply by disallowing such constructs. */ + if (!*arg1) + line_error (_("First argument to cross-reference may not be empty")); + + if (docbook) + { + if (!ref_flag) + add_word (px_ref_flag || printing_index + ? (char *) _("see ") : (char *) _("See ")); + + if (!*arg4 && !*arg5) + { + char *arg1_id = xml_id (arg1); + + if (*arg2 || *arg3) + { + xml_insert_element_with_attribute (XREFNODENAME, START, + "linkend=\"%s\"", arg1_id); + free (arg1_id); + execute_string ("%s", *arg3 ? arg3 : arg2); + xml_insert_element (XREFNODENAME, END); + } + else + { + xml_insert_element_with_attribute (XREF, START, + "linkend=\"%s\"", arg1_id); + xml_insert_element (XREF, END); + free (arg1_id); + } + } + else if (*arg5) + { + add_word_args (_("See section ``%s'' in "), *arg3 ? arg3 : arg1); + xml_insert_element (CITE, START); + add_word (arg5); + xml_insert_element (CITE, END); + } + else if (*arg4) + { + /* Very sad, we are losing xrefs made to ``info only'' books. */ + } + } + else if (xml) + { + if (!ref_flag) + add_word_args ("%s", px_ref_flag ? _("see ") : _("See ")); + + xml_insert_element (XREF, START); + xml_insert_element (XREFNODENAME, START); + execute_string ("%s", arg1); + xml_insert_element (XREFNODENAME, END); + if (*arg2) + { + xml_insert_element (XREFINFONAME, START); + execute_string ("%s", arg2); + xml_insert_element (XREFINFONAME, END); + } + if (*arg3) + { + xml_insert_element (XREFPRINTEDDESC, START); + execute_string ("%s", arg3); + xml_insert_element (XREFPRINTEDDESC, END); + } + if (*arg4) + { + xml_insert_element (XREFINFOFILE, START); + execute_string ("%s", arg4); + xml_insert_element (XREFINFOFILE, END); + } + if (*arg5) + { + xml_insert_element (XREFPRINTEDNAME, START); + execute_string ("%s", arg5); + xml_insert_element (XREFPRINTEDNAME, END); + } + xml_insert_element (XREF, END); + } + else 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 (!xml) + { + if (*arg5 || *arg4) + { + /* arg1 - node name + arg2 - reference name + arg3 - title or topic (and reference name if arg2 is NULL) + arg4 - info file name + arg5 - printed manual title */ + char *ref_name; + + if (!*arg2) + { + if (*arg3) + ref_name = arg3; + else + ref_name = arg1; + } + else + ref_name = arg2; + + if (html) + { /* More to do eventually, down to Unicode + Normalization Form C. See the HTML Xref nodes in + the manual. */ + char *file_arg = arg4; + add_html_elt ("<a href="); + + { + /* If there's a directory part, ignore it. */ + char *p = strrchr (file_arg, '/'); + if (p) + file_arg = p + 1; + + /* If there's a dot, make it a NULL terminator, so the + extension does not get into the way. */ + p = strrchr (file_arg , '.'); + if (p != NULL) + *p = 0; + } + + if (! *file_arg) + warning (_("Empty file name for HTML cross reference in `%s'"), + arg4); + + /* Note that if we are splitting, and the referenced + tag is an anchor rather than a node, we will + produce a reference to a file whose name is + derived from the anchor name. However, only + nodes create files, so we are referencing a + non-existent file. cm_anchor, which see, deals + with that problem. */ + if (splitting) + execute_string ("\"../%s/", file_arg); + else + execute_string ("\"%s.html", file_arg); + /* Do not collapse -- to -, etc., in references. */ + in_fixed_width_font++; + tem = expansion (arg1, 0); /* expand @-commands in node */ + in_fixed_width_font--; + add_anchor_name (tem, 1); + free (tem); + add_word ("\">"); + execute_string ("%s",ref_name); + add_word ("</a>"); + } + else + { + execute_string ("%s:", ref_name); + in_fixed_width_font++; + execute_string (" (%s)%s", arg4, arg1); + add_xref_punctuation (); + in_fixed_width_font--; + } + + /* Free all of the arguments found. */ + if (arg1) free (arg1); + if (arg2) free (arg2); + if (arg3) free (arg3); + if (arg4) free (arg4); + if (arg5) free (arg5); + return; + } + else + remember_node_reference (arg1, line_number, followed_reference); + + if (*arg3) + { + if (html) + { + add_html_elt ("<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:", *arg2 ? arg2 : arg3); + in_fixed_width_font++; + execute_string (" %s", arg1); + add_xref_punctuation (); + in_fixed_width_font--; + } + } + else + { + if (html) + { + add_html_elt ("<a href=\""); + in_fixed_width_font++; + tem = expansion (arg1, 0); + in_fixed_width_font--; + add_anchor_name (tem, 1); + free (tem); + add_word ("\">"); + if (*arg2) + execute_string ("%s", arg2); + else + { + char *fref = get_float_ref (arg1); + execute_string ("%s", fref ? fref : arg1); + free (fref); + } + add_word ("</a>"); + } + else + { + if (*arg2) + { + execute_string ("%s:", arg2); + in_fixed_width_font++; + execute_string (" %s", arg1); + add_xref_punctuation (); + in_fixed_width_font--; + } + else + { + char *fref = get_float_ref (arg1); + if (fref) + { /* Reference is being made to a float. */ + execute_string ("%s:", fref); + in_fixed_width_font++; + execute_string (" %s", arg1); + add_xref_punctuation (); + in_fixed_width_font--; + } + else + { + in_fixed_width_font++; + execute_string ("%s::", arg1); + in_fixed_width_font--; + } + } + } + } + } + /* Free all of the arguments found. */ + if (arg1) free (arg1); + if (arg2) free (arg2); + if (arg3) free (arg3); + if (arg4) free (arg4); + if (arg5) free (arg5); + } + else + { /* Check 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 + command. This is not used for @pxref or @ref, since we insert + the necessary punctuation above, if needed. */ + int temp = next_nonwhitespace_character (); + + if (temp == -1) + warning (_("End of file reached while looking for `.' or `,'")); + else if (temp != '.' && temp != ',') + warning (_("`.' or `,' must follow @%s, not `%c'"), command, temp); + } +} + +void +cm_pxref (int arg) +{ + if (arg == START) + { + px_ref_flag++; + cm_xref (arg); + px_ref_flag--; + } + /* 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 cm_xref generates the required + character itself (when needed) if px_ref_flag is set. */ +} + +void +cm_ref (int arg) +{ + /* See the comments in cm_pxref about the checks for punctuation. */ + if (arg == START) + { + ref_flag++; + cm_xref (arg); + ref_flag--; + } +} + +void +cm_inforef (int arg) +{ + if (arg == START) + { + char *node = get_xref_token (1); /* expands all macros in inforef */ + char *pname = get_xref_token (0); + char *file = get_xref_token (0); + + /* (see comments at cm_xref). */ + if (!*node) + line_error (_("First argument to @inforef may not be empty")); + + if (xml && !docbook) + { + xml_insert_element (INFOREF, START); + xml_insert_element (INFOREFNODENAME, START); + execute_string ("%s", node); + xml_insert_element (INFOREFNODENAME, END); + if (*pname) + { + xml_insert_element (INFOREFREFNAME, START); + execute_string ("%s", pname); + xml_insert_element (INFOREFREFNAME, END); + } + xml_insert_element (INFOREFINFONAME, START); + execute_string ("%s", file); + xml_insert_element (INFOREFINFONAME, END); + + xml_insert_element (INFOREF, END); + } + else if (html) + { + char *tem; + + add_word ((char *) _("see ")); + /* html fixxme: revisit this */ + add_html_elt ("<a href="); + if (splitting) + execute_string ("\"../%s/", file); + else + execute_string ("\"%s.html", file); + tem = expansion (node, 0); + add_anchor_name (tem, 1); + add_word ("\">"); + execute_string ("%s", *pname ? pname : tem); + add_word ("</a>"); + free (tem); + } + else + { + if (*pname) + execute_string ("*note %s: (%s)%s", pname, file, node); + else + execute_string ("*note (%s)%s::", file, node); + } + + free (node); + free (pname); + free (file); + } +} + +/* A URL reference. */ +void +cm_uref (int arg) +{ + if (arg == START) + { + 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 (docbook) + { + xml_insert_element_with_attribute (UREF, START, "url=\"%s\"", + text_expansion (url)); + if (*replacement) + execute_string ("%s", replacement); + else if (*desc) + execute_string ("%s", desc); + else + execute_string ("%s", url); + xml_insert_element (UREF, END); + } + else if (xml) + { + xml_insert_element (UREF, START); + xml_insert_element (UREFURL, START); + execute_string ("%s", url); + xml_insert_element (UREFURL, END); + if (*desc) + { + xml_insert_element (UREFDESC, START); + execute_string ("%s", desc); + xml_insert_element (UREFDESC, END); + } + if (*replacement) + { + xml_insert_element (UREFREPLACEMENT, START); + execute_string ("%s", replacement); + xml_insert_element (UREFREPLACEMENT, END); + } + xml_insert_element (UREF, END); + } + else if (html) + { /* never need to show the url */ + add_html_elt ("<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 (int arg) +{ + if (arg == START) + { + char *addr = get_xref_token (1); /* expands all macros in email */ + char *name = get_xref_token (0); + + if (xml && docbook) + { + xml_insert_element_with_attribute (EMAIL, START, "url=\"mailto:%s\"", addr); + if (*name) + execute_string ("%s", name); + xml_insert_element (EMAIL, END); + } + else if (xml) + { + xml_insert_element (EMAIL, START); + xml_insert_element (EMAILADDRESS, START); + execute_string ("%s", addr); + xml_insert_element (EMAILADDRESS, END); + if (*name) + { + xml_insert_element (EMAILNAME, START); + execute_string ("%s", name); + xml_insert_element (EMAILNAME, END); + } + xml_insert_element (EMAIL, END); + } + else if (html) + { + add_html_elt ("<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 + { + execute_string ("%s%s", name, *name ? " " : ""); + in_fixed_width_font++; + execute_string ("<%s>", addr); + in_fixed_width_font--; + } + + if (addr) + free (addr); + if (name) + free (name); + } +} diff --git a/Build/source/utils/texinfo/makeinfo/xref.h b/Build/source/utils/texinfo/makeinfo/xref.h new file mode 100644 index 00000000000..8f2711b63af --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/xref.h @@ -0,0 +1,30 @@ +/* xref.h -- declarations for the cross references. + $Id: xref.h,v 1.1 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 2004 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 XREF_H +#define XREF_H + +enum reftype +{ + menu_reference, followed_reference +}; + +extern char *get_xref_token (int expand); + +#endif /* not XREF_H */ |