code:
# -*-perl-*-
# vim: set filetype=perl:
######################################################################
# File: texi2html.pm
#
# Default values for command-line arguments and for various customizable
# procedures are set in this file.
#
# A copy of this file is pasted into the beginning of texi2html by
# running './configure'.
#
# Copy this file, rename it and make changes to it, if you like.
# Afterwards, load the file with command-line
# option --init-file <your_init_file>
#
# This file is in the public domain. Thus it may easily be used as an
# example for further customizations.
#
# Originally written by Olaf Bachmann in 2000.
#
# Those values may be overrided by values set in $sysconfdir/texi2html/Config
# and then by values set in $HOME/texi2html/Config.
#
# $Id$

##################################################################
# The following variables can also be set by command-line options
#
# command line switches may override these values, and values set in files
# specified by --init-file are also taken into account.
#
# options common with makeinfo
# -I
# add a directory to the list of directories where @include files are
# searched for (besides the directory of the file). additional '-I'
# args are appended to this list.
# (APA: Don't implicitely search ., to conform with the docs!)
# my @INCLUDE_DIRS = (".");

use strict;

@INCLUDE_DIRS = ();

# -P
# prepend a directory to the list of directories where @include files are
# searched for before the directory of the file. additional '-P'
# args are prepended to this list.
@PREPEND_DIRS = ();

# --split section|chapter|node|none
# if $SPLIT is set to 'section' (resp. 'chapter') one html file per section
# (resp. chapter) is generated. If $SPLIT is set to 'node' one html file per
# node or sectioning element is generated. In all these cases separate pages
# for Top, Table of content (Toc), Overview and About are generated.
# Otherwise a monolithic html file that contains the whole document is
# created.
set_default('SPLIT', '');

# --separated-footnotes
# if this is set footnotes are on a separated page. Otherwise they are at
# the end of each file (if the document is split).
set_default('footnotestyle', 'end');

# --fill-column
set_default('FILLCOLUMN', 72);

# --number | --no-number
# if this is set the sections are numbered, and section names and numbers
# are used in references and menus (instead of node names).
set_default('NUMBER_SECTIONS', 1);

# --headers
# if this is set then navigation panels are printed at the beginning of each
# section.
# If the document is split at nodes then navigation panels are
# printed at the end if there were more than WORDS_IN_PAGE words on page.
#
# Navigation panels are always printed at the beginning of output files.
#
# This is most useful if you do not want to have section navigation
# with --split chapter. There will be chapter navigation panel at the
# beginning and at the end of chapters anyway.
# this is mostly not used in the default case, important for html.
set_default('HEADERS', 0);

# -o filename
# If this is set a monolithic document is outputted into $filename.
set_default('OUT', undef);
set_default('OUTFILE', undef);

# --split-size
# if undef, the info output is not split
set_default('SPLIT_SIZE', 300000);

# --internal-links
set_default('INTERNAL_LINKS', undef);

# --no-validate
# suppress node cross-reference validation
set_default('novalidate', 0);

# --documentlanguage
# use gdt('my string') if you want to have translations of 'my string'.
# Translations are in texinfo/po_document/
# This is used for the initial language, it is overriden during
# document processing if there is a @documentlanguage.
# It is ignored if the language is passed on the command line.
set_default('documentlanguage', 'en');

# --transliterate-file-names
# transliterate node names for external refs (and internal if NODE_FILES)
set_default('TRANSLITERATE_FILE_NAMES', 1);

# --error-limit
# quit after NUM errors (default 100).
set_default('ERROR_LIMIT', 100);

# --css-include
# All the specified css files are used. More precisely the @import sections
# are added to the beginning of the CSS_LINES the remaining is added at
# the end of the CSS_LINES (after the css rules generated by the program).
# cf texinfo manual for more info.
# - means STDIN
@CSS_FILES = ();

# --css-ref
# the specified url are used as stylesheet links
@CSS_REFS = ();

# --paragraph-indent
set_default('paragraphindent',3);

# --enable-encoding
set_default('ENABLE_ENCODING', 0);

# --force
set_default('FORCE', 0);

# --no-warn
set_default('NO_WARN', 0);

# --number-footnotes
set_default('NUMBER_FOOTNOTES', 1);

# --batch
set_default('BATCH', 0);

# --silent/--quiet
set_default('SILENT', 0);

# --Xopt
@TEXI2DVI_ARGUMENTS = ();

# not in makeinfo but in texi2dvi
# --command
@COMMANDS = ();

##################################################################
# option specific of texi2html
# --debug
# The integer value specifies what kind of debugging output is generated.
set_default('DEBUG', 0);

# --doctype
# The value is the 'SystemLiteral' which identifies the canonical DTD
# for the document.
# Definition: The SystemLiteral is called the entity's system
# identifier. It is a URI, which may be used to retrieve the entity.
# See http://www.xml.com/axml/target.html#NT-ExternalID
set_default('DOCTYPE', '');

# --frameset-doctype
# When frames are used, this SystemLiteral identifies the DTD used for
# the file containing the frame description.
set_default('FRAMESET_DOCTYPE', '');

# --test
# If this value is true, some variables which should be dynamically generated
# (the date, the user running texi2html, the version of texi2html) are set to
# fix and given values. This is usefull in case the resulting manual is
# compared with a reference. For example this is used in the tests.
set_default('TEST', 0);

# --dump-texi
# This value is usefull for debugging purposes. The result of the first pass is
# put in <document name>.passtexi, the result of the second pass is put in
# <document name>.passfirst.
set_default('DUMP_TEXI', 0);

# --expand
# the @EXPAND array contains the expanded section names.
@EXPAND = ();

# --iso
# if this value is true, ISO8859 characters are used for quotes.
# --iso does more than what USE_ISO does.
set_default('USE_ISO', 0);

# --conf-dir
# append to the files searched for init files.
@CONF_DIRS = ();

# --top-file
# This file name is used for the top-level file.
# The extension is set appropriately, if necessary.
# If empty, <basename of document>.html is used.
# Typically, you would set this to "index.html".
set_default('TOP_FILE', '');

# --toc-file
# This file name is used for the table of contents.  The
# extension is set appropriately, if necessary.
# If empty, <basename of document>_toc.html is used.
set_default('TOC_FILE', '');

# --frames
# if the value is true, HTML 4.0 "frames" are used.
# A file describing the frame layout is generated, together with a file
# with the short table of contents.
set_default('FRAMES', 0);

# --menu | --no-menu
# if the value is true the Texinfo menus are shown.
# this is defined in all the formats
set_default('SHOW_MENU', 1);

# --use-nodes
# if this is set the nodes are used as sectioning elements.
# Otherwise the nodes are incorporated in sections.
set_default('USE_NODES', 1);

# --node-files
# if this is set one file per node is generated, which can be a target for
# cross manual references.
set_default('NODE_FILES', undef);

# --toc-links
# if this is set, links from headings to toc entries are created.
set_default('TOC_LINKS', 0);

# --subdir
# If this is set, then put result files into the specified directory.
# If not set, then result files are put into the current directory.
#$SUBDIR = 'html';
set_default('SUBDIR', undef);

# --short-extn
# If this is set, then all HTML files will have extension ".htm" instead of
# ".html". This is helpful when shipping the document to DOS-based systems.
set_default('SHORTEXTN', 0);

# --prefix
# This set the output file prefix, prepended to all .html, .gif and .pl files.
# By default, this is the basename of the document.
set_default('PREFIX', '');

# --short-ref
# if this is set cross-references are given without section.
set_default('SHORT_REF', 1);

# --idx-sum
# if value is set, then for each @printindex <index name>
# <document name>_<index name>.idx is created which contains lines of the form
# key ref sorted alphabetically (case matters).
set_default('IDX_SUMMARY', 0);

# --def-table
# If this is set a table construction for @def.... instead of definition
# lists.
# (New Option: 27.07.2000 Karl Heinz Marbaise)
set_default('DEF_TABLE', 0);

# --verbose
# if this is set chatter about what we are doing.
set_default('VERBOSE', '');

# --ignore-preamble-text
# If this is set the text before @node and sectioning commands is ignored.
set_default('IGNORE_PREAMBLE_TEXT', 0);

# --html-xref-prefix
# base directory for external manuals. Obsolete.
set_default('EXTERNAL_DIR', undef);

# --l2h
# if this is set, latex2html is used for generation of math content.
set_default('L2H', '');

# --monolithic
# output only one file including ToC. It only makes sense when not split
set_default('MONOLITHIC', 1);

######################
# The following options are only relevant if $L2H is set
#
# --l2h-l2h
# name/location of latex2html program
set_default('L2H_L2H', 'latex2html');

# --l2h-skip
# If this is set the actual call to latex2html is skipped. The previously
# generated content is reused, instead.
# If set to 0, the cache is not used.
# If undef the cache is used for as many tex fragments as possible
# and for the remaining the command is run.
set_default('L2H_SKIP', undef);

# --l2h-tmp
# If this is set l2h uses the specified directory for temporary files. The path
# leading to this directory may not contain a dot (i.e., a ".");
# otherwise, l2h will fail.
set_default('L2H_TMP', '');

# --l2h-file
# If set, l2h uses the file as latex2html init file
set_default('L2H_FILE', undef);

# --l2h-clean
# if this is set the intermediate files generated by texi2html in relation with
# latex2html are cleaned (they all have the prefix <document name>_l2h_).
set_default('L2H_CLEAN', 1);

##############################################################################
#
# The following can only be set in the init file
#
##############################################################################

@INPUT_FILE_SUFFIXES = ('.txi','.texinfo','.texi','.txinfo','');

set_default('firstparagraphindent', 'none');

@T2H_FORMAT_EXPAND = ('plaintext');

# In file encoding. The @documentencoding allows autodetection of
# that variable.
set_default('documentencoding', undef);

# In file encoding, understandable by perl. Set according to documentencoding
set_default('IN_ENCODING', undef);

# Formatted document encoding name. If undef, set in init_out based on
# OUT_ENCODING or documentencoding if they are defined
set_default('ENCODING_NAME', undef);

# Out files encoding, understandable by perl. If undef, set in init_out
# using ENCODING_NAME or IN_ENCODING if they are defined
set_default('OUT_ENCODING', undef);

# if undef set to @documentdescription. If there is no @documentdescription,
# set in page_head.
set_default('documentdescription', undef);

# EXTERNAL_CROSSREF_SPLIT at the document level set to 1 if SPLIT,
# to 0 otherwise
set_default('EXTERNAL_CROSSREF_SPLIT', undef);

# output as @today, and also as the date. Set automatically if not set
# otherwise.
set_default('today', undef);

# simple headers formatting, not in a table and using node names.
set_default('HEADER_IN_TABLE', 0);

# output the generation date in the header.
set_default('DATE_IN_HEADER', 0);

# use table for indentation of complex formats
set_default('COMPLEX_FORMAT_IN_TABLE', 0);

# if set, node names are used to construct file names
# if undef, it is set if split at node, or NODE_FILES is set.
set_default('NODE_FILENAMES', undef);

# If true do table of contents even if there is no @content
set_default('contents', undef);

# If true do short table of contents even if there is no @shortcontent
set_default('shortcontents', undef);

# set by @setcontentsaftertitlepage/@setshortcontentsaftertitlepage
set_default('setcontentsaftertitlepage', undef);
set_default('setshortcontentsaftertitlepage', undef);

# corresponds with @kbdinputstyle
set_default('kbdinputstyle', 'distinct');

# corresponds with @frenchspacing
set_default('frenchspacing', 'off');

# correspond with @allowcodebreaks
set_default('allowcodebreaks', 'true');

# corresponds with @setfilename. Set with caution.
set_default('setfilename', undef);

# if unset, don't show a title
set_default('SHOW_TITLE', 1);

# if set style is added in attribute.
set_default('INLINE_CSS_STYLE', 0);

# if set, no css is used.
set_default('NO_CSS', 0);

# if set, the image files are completed to be relative from the
# document directory, to the source manual directory and then to
# the image
set_default('COMPLETE_IMAGE_PATHS', 0);

# if true, begin outputting at @setfilename, if this command is present.
set_default('IGNORE_BEFORE_SETFILENAME', 1);

# if true the link in Overview link to the corresponding Toc entry.
set_default('OVERVIEW_LINK_TO_TOC', 1);

# if set, use node anchors for sections targets
set_default('USE_NODE_TARGET', 1);

# new style for crossrefs
set_default('NEW_CROSSREF_STYLE', 1);

# top heading is always at the beginning of the element.
# FIXME looks like a no-op
set_default('TOP_HEADING_AT_BEGINNING', 0);

# use titlepage for the title instead of a simplest title
set_default('USE_TITLEPAGE_FOR_TITLE', 0);

# used as identation for block enclosing command @example, etc
# If not empty, must be enclosed in
$EXAMPLE_INDENT_CELL = '';

# same as above, only for @small
$SMALL_EXAMPLE_INDENT_CELL = '';

# unused
$SMALL_FONT_SIZE = '-1';

# horizontal rules
# not used
$SMALL_RULE = '';
$MIDDLE_RULE = '';
# used in html
$DEFAULT_RULE = '';
$BIG_RULE = '';

# output the program name in the footer
set_default('PROGRAM_NAME_IN_FOOTER', 0);

# if non-empty, and no @..heading appeared in Top node, then
# use this as header for top node/section, otherwise use value of
# @settitle or @shorttitle (in that order)
$TOP_HEADING = '';

# if set, use this chapter for 'Index' button, else
# use first chapter with @printindex
$INDEX_CHAPTER = '';

set_default('SIMPLE_MENU', 1);

set_default('OPEN_QUOTE_SYMBOL', '`');
set_default('CLOSE_QUOTE_SYMBOL', "'");

$NO_NUMBER_FOOTNOTE_SYMBOL = '*';

# if true put a $MENU_SYMBOL before unnumbered in menus
$UNNUMBERED_SYMBOL_IN_MENU = 0;

# extension for nodes files when NODE_FILES is true
set_default('NODE_FILE_EXTENSION', 'txt');

# extension
set_default('EXTENSION', 'txt');

# file name used for Top node when NODE_FILES is true
#TOP_NODE_FILE = 'index';
set_default('TOP_NODE_FILE', undef);

# file name used for Top node in references
set_default('TOP_NODE_FILE_TARGET', 'index');

# file used as document basename, when input file is -
$STDIN_DOCU_NAME = 'stdin';

# file used as document output basename, when output file is -
$STDOUT_DOCU_NAME = 'stdout';

# node name used for Top node when automatic node directions are used
set_default('TOP_NODE_UP', '(dir)');

# this controls the pre style for menus
$MENU_PRE_STYLE = 'font-family: serif';

# on bug-texinfo is has been said the the style is not code_style
# for menus (except for the node name).
# this controls the menu preformatted format
# FIXME this is not dynamic, so change in MENU_PRE_STYLE is not taken
# into account.
# This is used if the menu appears within a preformatted format (which
# is certainly an invalid construct), and SIMPLE_MENU is not set.
$MENU_PRE_COMPLEX_FORMAT = {
              'class' => 'menu-preformatted',
#              'style' => 'code'
   };

# This controls the ul style for toc
$NO_BULLET_LIST_STYLE = '';
$NO_BULLET_LIST_ATTRIBUTE = '';

# These lines are inserted before and after the shortcontents
$BEFORE_OVERVIEW = "";
$AFTER_OVERVIEW = "";

# These lines are inserted before and after the contents
$BEFORE_TOC_LINES = "";
$AFTER_TOC_LINES = "";

# text inserted after
$AFTER_BODY_OPEN = '';

# text inserted before , this will be automatically inside

$PRE_BODY_CLOSE = '';

# this is added inside  after <title> and some <meta name>
# stuff, it can be used for eg.


code:
Name: texi2html
Version: @PACKAGE_VERSION@
Release: 1
# GPLv2+ is for the code
# OFSFDL (Old FSF Documentation License) for the documentation
# CC-BY-SA or GPLv2 for the images
License: GPLv2+ and OFSFDL and (CC-BY-SA or GPLv2)
Group: Applications/Text
Summary: A highly customizable texinfo to HTML and other formats translator
Source0: http://download.savannah.nongnu.org/releases/%{name}/%{name}-%{version}.tar.bz2
URL: http://www.nongnu.org/texi2html/
Requires(post): /sbin/install-info
Requires(preun): /sbin/install-info
# perl is picked up automatically in most cases and the package may have
# a different name so it is better not to require it. Moreover such old perl
# is unlikely to show up in a rpm based distribution.
#Requires: perl >= 5.004
Requires: latex2html
BuildRequires: perl(Text::Unidecode)
# not detected automatically because it is required at runtime based on
# user configuration
Requires: perl(Text::Unidecode)
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildArch: noarch

%description
The basic purpose of texi2html is to convert Texinfo documents into HTML,
and other formats.  Configuration files written in perl provide fine degree
of control over the final output, allowing most every aspect of the final
output not specified in the Texinfo input file to be specified.

%prep
%setup -q

%build
%configure
make %{?_smp_mflags}

%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
rm -f $RPM_BUILD_ROOT%{_infodir}/dir

ln -s texi2any $RPM_BUILD_ROOT%{_bindir}/texi2html

rm -rf __dist_examples
mkdir -p __dist_examples
cp -a examples __dist_examples
rm -f __dist_examples/examples/Makefile*

# directories shared by all the texinfo implementations for common
# config files, like htmlxref.cnf
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/texinfo

%clean
rm -rf $RPM_BUILD_ROOT

%post
/sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || :

%preun
if [ $1 = 0 ]; then
  /sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || :
fi

%files
%defattr(-,root,root,-)
%doc AUTHORS COPYING ChangeLog NEWS README TODO %{name}.pm
%doc __dist_examples/examples/
%{_bindir}/%{name}
%{_bindir}/texi2any
%{_mandir}/man*/%{name}*
%{_infodir}/%{name}.info*
%dir %{_datadir}/texinfo/
%dir %{_datadir}/texinfo/init
%{_datadir}/texinfo/init/*.pm
%{_datadir}/texinfo/html/%{name}.html
%dir %{_datadir}/%{name}/i18n/
%{_datadir}/%{name}/i18n/*
%dir %{_datadir}/%{name}/images/
%{_datadir}/%{name}/images/*
%dir %{_sysconfdir}/texinfo

%changelog
* Sun Sep  9 2007 Patrice Dumas <pertusus@free.fr> @PACKAGE_VERSION@-1
- update to @PACKAGE_VERSION@

* Mon Nov 14 2005 Patrice Dumas <pertusus@free.fr> 1.77-1
- cleanups

* Mon Mar 23 2004 Patrice Dumas <pertusus@free.fr> 0:1.69-0.fdr.1
- Initial build.

repo_name: mthl/texinfo

license: mit


code:
<html>
<body>
This is the default content.
</body>
</html>


code:
2015-02-27         Arnold D. Robbins     <arnold@skeeve.com>

	* jrweave, jrtangle: Updated to current version. In particular,
	jrtangle should work out of the box on Windows, thanks to
	Eli Zaretskii.

2015-01-08  Karl Berry  <karl@gnu.org>

	* version.texi: remove, no easy way to automatically update it.
	* ti.twjr,
	* Makefile.am (do_subst, texindex.awk, ti.texi): use substitutions
	for @VERSION@ and @UPDATED@ instead.

	* texindex.in: also look for ../share/texinfo/texindex.awk,
	relative to dirname $0.

	* ti.twjr (Invocation_name): new global, renamed from Prgname.
	(usage): use it, a la coreutils.
	* texindex.in: pass it (value $0), with -v.

	* Makefile.am (EXTRA_DIST): dek_idx.png rename.

2015-01-06  Karl Berry  <karl@gnu.org>

	first merge into automake:
	* texindex/Makefile.am: new file.
	* texindex/texindex.in: new file.
	* texindex/README: update.
	(see also ../ChangeLog.)

2014-12-30         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Remove `@xrefautomaticsectiontitle on'. It's now
	supplied by jrweave.
	* jrweave: Updated.

2014-12-26         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Restore use of `@xrefautomaticsectiontitle on'.
	And restore support for vim editing.

2014-12-15  Karl Berry  <karl@gnu.org>

	* ti.twjr: convert to minimal Texinfo conventions
	instead of Arnold's published-book conventions.

2014-12-13         Arnold D. Robbins     <arnold@skeeve.com>

	* jrtangle, jrweave: Updated with versions that include
	github location.

2014-08-07         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Typo fix in an index entry. Change the update month
	and increase version to 0.95.

2014-05-30         Arnold D. Robbins     <arnold@skeeve.com>

	* README: New file.
	* tests: New directory with some regression tests.
	* jrtangle, jrweave: Copied from TexiWebJr to have standalone.

	*****

	* All: Pushed to https://github.com/arnoldrobbins/texindex.

2014-04-26         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Remove summaries appendix. Not needed with better
	formatting from jrweave.  Bump version to 0.94.

2014-04-16         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Bug fix. Multiple files had junk in second and
	subsequent output files. Needed to clear out more data between
	files. Bump version to 0.93.

2014-03-21         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: General cleanup and finalizatio of the text. Bump
	version to 0.92.

2014-03-17         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Fix case in chunk names.

2014-03-14         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Add a few commands to make the PDF nicer.

2014-03-04         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Polished up. Add an XKCD cartoon. Bump version to 0.9.
	* donald_knuth.jpg: New file.

2014-03-03         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Rework where initial extraction is done. Set up to
	produce \{ and \}. Works when used with itself to sort the
	index!  Woo hoo!

2014-02-27         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Revise extraction of the initial as per Karl.
	Still needs more documentation but I think we've hit
	functionally complete.

2014-02-26         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Sorting in and seems to work well. Still need to add
	more descriptive prose.  Did some cleanup and added menus.

2014-02-25         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr: Just about done, except for sorting.

2014-02-24         Arnold D. Robbins     <arnold@skeeve.com>

	* ti.twjr, texinfo.tex, Makefile: Initial check-in.

Copyright 2014, 2015 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.

path: texindex/ChangeLog


code:
# $Id$
# Makefile.am for texinfo/texindex.
# Run automake in .. to produce Makefile.in from this.
#
# Copyright 2015 Free Software Foundation, Inc.
#
# 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.

# basic plan: what users invoke will be texindex, a shell script wrapper
# created from texindex.in by configure.
# texindex.awk does the real work; it is created from ti.twjr
# using rules here invoking the texiwebjr utilities.

# what we want installed in $(bindir).
dist_bin_SCRIPTS = texindex

# since it's generated, have to clean it explicitly.
CLEANFILES = texindex

# and mention the original sources explicitly.
EXTRA_DIST = texindex.in ti.twjr

# let's install the awk script in $(sharedir)/texinfo.
dist_pkgdata_SCRIPTS = texindex.awk

# since we generate it, have to clean it (at maintainer-clean) explicitly.
MAINTAINERCLEANFILES = texindex.awk

# mention the texiwebjr utilities. they are maintained in another
# repository (see their sources), and updated here manually (see
# ../util/srclist.txt).
noinst_SCRIPTS = jrtangle jrweave
EXTRA_DIST += $(noinst_SCRIPTS)

# configure-time variables we use in texindex.in or ti.twjr.
# Unlike regular Automake, we have to allow for @@VERSION@@,
# which jrweave generates in the code segment.
do_subst = sed -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \
               -e 's,[@]AWK[@],$(AWK),g' \
               -e 's,[@]PACKAGE[@],$(PACKAGE),g' \
               -e 's,[@][@]*VERSION[@][@]*,$(VERSION),g'

# build the texindex shell wrapper from texindex.in, following automake.
texindex: texindex.in Makefile
	$(do_subst) <$(srcdir)/texindex.in >texindex
	chmod +x texindex

# build texindex.awk from ti.twjr using jrtangle; that creates
# texindex.awk (hardwired).  Then we substitute configure-time variables
# to avoid manual updates of the version number.
texindex.awk: ti.twjr
	$(AWK) -f $(srcdir)/jrtangle $(srcdir)/ti.twjr || rm -f texindex.awk
	$(do_subst) <texindex.awk >texindex.awk-tmp
	mv texindex.awk-tmp texindex.awk

# how to build the pdf of the program-as-document.
ti.pdf: ti.texi
	texi2pdf --tidy ti.texi
ti.info: ti.texi
	makeinfo --no-split ti.texi -o ti.info
ti.html: ti.texi
	makeinfo --no-split --html ti.texi -o ti.html

# unlike jrtangle, jrweave outputs to stdout; use the usual UPDATED string.
ti.texi: ti.twjr
	UPDATED=`$(top_srcdir)/build-aux/mdate-sh $(srcdir)/ti.twjr`; \
	  $(AWK) -f $(srcdir)/jrweave $(srcdir)/ti.twjr \
	  | $(do_subst) -e "s,[@]UPDATED[@],$$UPDATED,g" \
	  >ti.texi || rm -f ti.texi

# a fun cartoon used in the literate program.
EXTRA_DIST += dek_idx.png

TESTS = \
        tests/ti-helpversion.sh
EXTRA_DIST += $(TESTS)


code:
$Id$

This is texindex.awk, a replacement for the texindex.c implementation
previously used in Texinfo.  It's written in a literate style using TexiWebJr.

ChangeLog		-- What it looks like
Makefile.am		-- What it looks like
README			-- What it looks like
dek_idx.png		-- A cute cartoon
jrtangle		-- TexiWeb Jr tangle program
jrweave			-- TexiWeb Jr weave program
texindex.in		-- texindex shell script wrapper, for automake
ti.twjr			-- TexiWeb Jr source file

texindex (shell wrapper) is created from texindex.in, and
texindex.awk (the program) is created from ti.twjr.

tests/gawk.cp		-- Gawk manual unsorted index, test input
tests/gawk.cps-cvers	-- Output of same from C version
tests/gawk.cps-good	-- Output of same from awk version
tests/texinfo.cp	-- Texinfo manual unsorted index, test input
tests/texinfo.cps-cvers	-- Output of same from C version
tests/texinfo.cps-good	-- Output of same from awk version
tests/texinfo.fn	-- Texinfo manual unsorted index, test input
tests/texinfo.fns-cvers	-- Output of same from C version
tests/texinfo.fns-good	-- Output of same from awk version
tests/texinfo.tex	-- What it looks like

path: texindex/README


code:
# $Id$
# Public domain.
# This little Makefile is written by hand.  Left in just in case it ends
# up being convenient to use for development instead of the automade version.

SOURCE = ti.twjr
TEXI = ti.texi
AWK = texindex.awk

all: $(AWK) html ti.pdf

$(TEXI): $(SOURCE)
	rm -f $@; $(GAWK) ./jrweave $(SOURCE) >$(TEXI) || rm -f $@; chmod a-w $@

$(AWK): $(SOURCE)
	rm -f $@; ./jrtangle $(SOURCE) || rm -f $@

ti.pdf: $(TEXI)
	texi2dvi --pdf --build-dir=ti.t2p -o ti.pdf $(TEXI)

html: texindex.html

texindex.html: $(TEXI)
	makeinfo --no-split --html $(TEXI)

check: $(AWK)
	texindex $(ttests)/idxmarkup.cp
	cat $(ttests)/idxmarkup.cps


code:
#! /usr/local/bin/gawk -f
#
# Copyright (C) 2013, 2014, 2015 Arnold David Robbins
#
# This file is part of TexiWeb Jr., a literate programming system.
#
# TexiWeb Jr. 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 3 of the License, or
# (at your option) any later version.
#
# TexiWeb Jr. 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
#
# Up-to-date source code for TexiWeb Jr. can be obtained via
# Git from github:
#
#	git clone http://github.com/arnoldrobbins/texiwebjr
#
BEGIN {
	TRUE = 1
	FALSE = 0
	File_chunk_pattern = "^@\\(([^)]+)@\\)[[:space:]]*=[[:space:]]*$"
	Code_chunk_pattern = "^@" "<(.+)" "@>[[:space:]]*=[[:space:]]*$"
	Chunk_name_pattern = "@<[^>\n]+@>"
}
# Error checking:

# Use brackets to avoid triggering the warning on ourselves!
/(^<[@])|(>[@]([[:space:]]*=[[:space:]]*)?$)/	{
	# Ditto, with concatenation
	warning("<" "@ or >" "@ used instead of @" "< or @" ">\n\t%s\n",
			$0)
}

END {
	check_unfinished()
}
# check_unfinished --- print a fatal error when an unfinished code or
#			file chunk is detected. Also ifweave / iftangle.

function check_unfinished()
{
	if (Flags["file chunk"])
		fatal(_"unfinished file chunk (started at %s)\n",
			Line_numbers["file chunk"])
	else if (Flags["code chunk"])
		fatal(_"unfinished code chunk (started at %s)\n",
			Line_numbers["code chunk"])

	if ("ifweave" in Line_numbers)
		fatal(_"unfinished @ifweave section (started at %s)\n",
			Line_numbers["ifweave"])

	if ("iftangle" in Line_numbers)
		fatal(_"unfinished @iftangle section (started at %s)\n",
			Line_numbers["iftangle"])
}
# strip_out_name --- get the name from name

function strip_out_name(name,	l)
{
	l = length(name)
	name = substr(name, 3, l - 4)

	return name
}
# Helper functions

# message --- write a particular kind of message out to stderr

function message(msg, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
{
	printf("%s:%d: %s: " format, FILENAME, FNR, msg,
		a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) > "/dev/stderr"

	if (substr(format, length(format), 1) != "\n")
		printf("\n") > "/dev/stderr"
}

# fatal --- print a fatal error message and exit.
#	 No varargs, so fake it with lots of parameters.

function fatal(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
{
	message(_"fatal", format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
	exit 1
}

# warning --- print a warning message to stderr
#	 No varargs, so fake it with lots of parameters.

function warning(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
{
	message(_"warning", format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
}

# join.awk --- join an array into a string
#
# Arnold Robbins, arnold@skeeve.com, Public Domain
# May 1993

function join(array, start, end, sep,    result, i)
{
	if (sep == "")
		sep = " "
	else if (sep == SUBSEP) # magic value
		sep = ""
	result = array[start]
	for (i = start + 1; i <= end; i++)
		result = result sep array[i]
	return result
}
# ifweave lines should be removed

/^@ifweave[[:space:]]*$/, /^@end ifweave[[:space:]]*$/ {
	if ("iftangle" in Line_numbers)
		fatal(_"cannot nest @ifweave inside @iftangle\n")

	# start of construct, save line number
	if (/^@ifweave[[:space:]]*$/)
		Line_numbers["ifweave"] = (FILENAME ":" FNR)

	# end of construct, delete line number
	if (/^@end ifweave[[:space:]]*$/)
		delete Line_numbers["ifweave"]

	# simply skip these lines, this is tangling
	next
}

# For tangling we remove the bracketing control lines and let anything
# in between fall through.

/^@iftangle[[:space:]]*$/, /^@end iftangle[[:space:]]*$/ {
	if ("ifweave" in Line_numbers)
		fatal(_"cannot nest @iftangle inside @ifweave\n")

	# start of construct, save line number, skip this line
	if (/^@iftangle[[:space:]]*$/) {
		Line_numbers["iftangle"] = (FILENAME ":" FNR)
		next
	}

	# end of construct, delete line number, skip this line
	if (/^@end iftangle[[:space:]]*$/) {
		delete Line_numbers["iftangle"]
		next
	}

	# otherwise fall through into the rest of the code
}
$0 ~ Code_chunk_pattern {
	Chunk_type = "code chunk"
	Pattern = Code_chunk_pattern
	Debug_pat = "code"
	new_chunk = gensub(Pattern, "\\1", 1)
	if (Flags[Chunk_type]) {
		fatal(_"%s start of %s found while still collecting %s\n",
			Chunk_type, new_chunk, Current_chunk)
	}
	check_unfinished()

	Flags[Chunk_type] = TRUE
	Line_numbers[Chunk_type] = (FILENAME ":" FNR)
	Current_chunk = new_chunk
	Chunk_info[Current_chunk]["type"] = Chunk_type

	if (Debug ~ Debug_pat)
		printf("saw new %s %s\n", Debug_pat, Current_chunk) > "/dev/stderr"
	next
}
$0 ~ File_chunk_pattern {
	Chunk_type = "file chunk"
	Pattern = File_chunk_pattern
	Debug_pat = "filename"
	new_chunk = gensub(Pattern, "\\1", 1)
	if (Flags[Chunk_type]) {
		fatal(_"%s start of %s found while still collecting %s\n",
			Chunk_type, new_chunk, Current_chunk)
	}
	check_unfinished()

	Flags[Chunk_type] = TRUE
	Line_numbers[Chunk_type] = (FILENAME ":" FNR)
	Current_chunk = new_chunk
	Chunk_info[Current_chunk]["type"] = Chunk_type

	if (Debug ~ Debug_pat)
		printf("saw new %s %s\n", Debug_pat, Current_chunk) > "/dev/stderr"
	next
}
/^@[[:space:]]*$/ {
	if (Flags["file chunk"])
		end_file_gathering()
	else if (Flags["code chunk"])
		end_code_gathering()
	else
		warning(_"unmatched terminating @-sign: ignored\n")

	Chunk_lines = ""
	Flags[Chunk_type] = FALSE
	Line_numbers[Chunk_type] = ""
	Chunk_type = ""

	next
}
Flags["file chunk"] || Flags["code chunk"] {
	if (Chunk_lines == "")
		Chunk_lines = $0
	else
		Chunk_lines = Chunk_lines "\n" $0

	next
}
# end_file_gathering ---finish up collecting a file

function end_file_gathering()
{
	if (Current_chunk in File_contents)
		File_contents[Current_chunk] = \
			File_contents[Current_chunk] "\n" Chunk_lines
	else
		File_contents[Current_chunk] = Chunk_lines

	if (Debug ~ /filename/)
		printf("finished collecting file %s\n",
						Current_chunk) > "/dev/stderr"
}
# end_code_gathering --- complete collecting lines of the code chunk

function end_code_gathering()
{
	if (Current_chunk in Code_contents)
		Code_contents[Current_chunk] = \
			Code_contents[Current_chunk] "\n" Chunk_lines
	else
		Code_contents[Current_chunk] = Chunk_lines

	if (Debug ~ /code/)
		printf("finished collecting %s\n",
					Current_chunk) > "/dev/stderr"
}
# Finishing off code is easy, at least from 10,000 feet.

END {
	if (length(Initial_setup) > 0) {
		Initial_setup = Initial_setup "\n"
		system(Shell_debug Initial_setup)
	}

	dump_files()

	if (Debug ~ /code/)
		dump_chunks()
}
# dump_files --- create files and update them as needed

function dump_files(	i, s, update_recipe)
{
	for (i in File_contents) {
		s = expand_code_chunks(File_contents[i])

		create_update_recipe(i, update_recipe)
		printf("%s\n", s) > update_recipe["output"]
		close(update_recipe["output"])

		# update the file if necessary
		update_recipe["recipe"] = (Shell_debug update_recipe["recipe"])
		system(update_recipe["recipe"])

		# run any "post create" command (such as changing mode)
		if (i in Post_create_commands)
			system(Shell_debug Post_create_commands[i])
	}
}
# expand_code_chunks --- expand embedded code chunks.

function expand_code_chunks(contents)
{
	delete Currently_expanding

	return do_expand_code_chunks(contents)
}
# do_expand_code_chunks --- do the actual work to expand code chunks

function do_expand_code_chunks(contents,
								nlines, lines, results, i, j) # locals
{
	nlines = split(contents, lines, "\n")

	for (i = 1; i <= nlines; i++) {
		if (lines[i] !~ Chunk_name_pattern) {
			results[i] = lines[i]
		} else
			results[i] = expand_one_line(lines[i])
	}

	return join(results, 1, nlines, "\n")
}
# expand_one_line --- expand a line with code chunk references

function expand_one_line(input_line,	parts, chunk_names, nparts,
										num_names, code_lines, i, j)
{
	nparts = split(input_line, parts, Chunk_name_pattern, chunk_names)
	num_names = length(chunk_names)
	# check for recursive expansion
	for (i = 1; i <= num_names; i++) {
		j = strip_out_name(chunk_names[i])

		if (! (j in Code_contents))
			fatal(_"expand_one_line: code chunk `%s' used but not defined\n",
				chunk_names[i])

		if (j in Currently_expanding)
			fatal(_"expand_one_line: code chunk `%s' expands itself recursively\n",
				chunk_names[i])
		else
			Currently_expanding[j] = TRUE
	}
	code_lines = code_body(chunk_names[1])
	delete Currently_expanding[strip_out_name(chunk_names[1])]

	if (input_line !~ ("^" Chunk_name_pattern)) {
		if (parts[1] ~ /^[[:space:]]+$/) {
			# insert leading white space on all lines to get indentation
			gsub(/^|\n/, ("&" parts[1]), code_lines)
		} else {
			code_lines = parts[1] code_lines
		}
	}
	for (i = 2; i <= nparts; i++) {
		code_lines = code_lines parts[i]
		if (i in chunk_names) {
			code_lines = code_lines code_body(chunk_names[i])
			delete Currently_expanding[strip_out_name(chunk_names[i])]
		}
	}

	if (code_lines ~ Chunk_name_pattern) {
		# get any further code chunks, recursively
		return do_expand_code_chunks(code_lines)
	} else
		return code_lines
}
# code_body --- get the code body associated with name

function code_body(name)
{
	return Code_contents[strip_out_name(name)]
}
/^@initial_setup[[:space:]]*$/, /^@end initial_setup[[:space:]]*$/ {
	if (/^@initial_setup[[:space:]]*$/) {
		# start of construct, save line number, skip this line
		if ("initial_setup" in Line_numbers)
			fatal(_"cannot nest one @initial_setup inside another\n")
		Line_numbers["initial_setup"] = (FILENAME ":" FNR)
		Initial_setup = ""
	} else if (/^@end initial_setup[[:space:]]*$/) {
		# end of construct, delete line number, skip this line
		delete Line_numbers["initial_setup"]
	} else
		Initial_setup = Initial_setup "\n" $0

	next
}
BEGIN {
	# This condition should distinguish between the native and
	# MSYS (POSIX-ish) Gawk.  We rely on the fact that MSYS mounts
	# /tmp and sets $TEMP to point to it, but resets the value
	# back to the native C:/Foo/Bar value when invoking native
	# programs.
	if (ENVIRON["TEMP"] ~ /^[A-Z]:[\\\/]/) {
		# MS-Windows recipe
		Update_recipe = \
			"fc /B \"@DIR@\\@FILE@\" \"@DIR@\\@FILE@@SUFFIX@\" >nul 2>&1 || move /Y \"@DIR@\\@FILE@\" \"@DIR@\\@FILE@@SUFFIX@\" >nul"
	} else {
		# POSIX recipe
		Update_recipe = \
			"PATH=/bin:/usr/bin\n" \
			"export PATH\n" \
			"destname=\"@DIR@/@FILE@\"\n" \
			"outname=\"${destname}@SUFFIX@\"\n" \
			"if [ ! -f \"$destname\" ]\n" \
			"then\n" \
			"\tmv \"$outname\" \"$destname\"\n" \
			"elif cmp -s \"$outname\" \"$destname\" > /dev/null\n" \
			"then\n" \
			"\trm \"$outname\"\n" \
			"else\n" \
			"\tmv \"$outname\" \"$destname\"\n" \
			"fi\n"
	}
}
/^@file_update_recipe[[:space:]]*$/,
			/^@end file_update_recipe[[:space:]]*$/ {
	if (/^@file_update_recipe[[:space:]]*$/) {
		# start of construct, save line number, skip this line
		if ("file_update_recipe" in Line_numbers)
			fatal(_"cannot nest one @file_update_recipe inside another\n")
		Line_numbers["file_update_recipe"] = (FILENAME ":" FNR)
		Update_recipe = ""
	} else if (/^@end file_update_recipe[[:space:]]*$/) {
		# end of construct, delete line number, skip this line
		delete Line_numbers["file_update_recipe"]
	} else
		Update_recipe = Update_recipe "\n" $0

	next
}
BEGIN {
	# @default is an unlikely name for a real file
	Update_value["@default"]["DIR"] = "."	# current directory
	Update_value["@default"]["SUFFIX"] = ".tangle_tmp"	# unlikely suffix
	# No default for filename, jrtangle knows it!
}
/^@file_update[[:space:]]/ {
	if (NF != 4)
		fatal(_"usage: @file_update name dir suffix\n")

	if ($4 == "\"\"")
		$4 = ""
	Update_value[$2]["DIR"] = $3
	Update_value[$2]["SUFFIX"] = $4

	next
}
# create_update_recipe --- create update recipe per file,
#							return dest filename

function create_update_recipe(file, results,
							source_file, dir, suffix, recipe) # locals
{
	if (file in Update_value)
		source_file = file
	else
		source_file = "@default"

	dir = Update_value[source_file]["DIR"]
	suffix = Update_value[source_file]["SUFFIX"]

	delete results

	recipe = Update_recipe
	gsub(/@DIR@/, dir, recipe)
	gsub(/@FILE@/, file, recipe)
	gsub(/@SUFFIX@/, suffix, recipe)

	results["recipe"] = recipe
	results["output"] = (dir "/" file suffix)
}
BEGIN {
	if (Debug ~ /shell/ && ENVIRON["TEMP"] !~ /^[A-Z]:[\\\/]/)
		if (length(Shell_debug) == 0)
			Shell_debug = "set -x; "
}
/^@post_create[[:space:]]+/ {
	if (NF < 3)
		fatal(_"usage: @post_create filename command\n")
	check_unfinished()

	name = $2
	$1 = $2 = ""
	$0 = $0
	Post_create_commands[name] = $0
}
# dump_chunks --- print out all the chunks

function dump_chunks(	i, format)
{
	format = "@<%s"
	format = format "@>=\n%s@\n\n"
	for (i in Code_contents)
		printf(format, i, Code_contents[i]) > "/dev/stderr"
}

path: texindex/jrtangle


code:
#! /usr/local/bin/gawk -f
#
# Copyright (C) 2013, 2014, 2015 Arnold David Robbins
#
# This file is part of TexiWeb Jr., a literate programming system.
#
# TexiWeb Jr. 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 3 of the License, or
# (at your option) any later version.
#
# TexiWeb Jr. 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
#
# Up-to-date source code for TexiWeb Jr. can be obtained via
# Git from github:
#
#	git clone http://github.com/arnoldrobbins/texiwebjr
#
BEGIN {
	TRUE = 1
	FALSE = 0
	File_chunk_pattern = "^@\\(([^)]+)@\\)[[:space:]]*=[[:space:]]*$"
	Code_chunk_pattern = "^@" "<(.+)" "@>[[:space:]]*=[[:space:]]*$"
	Chunk_name_pattern = "@<[^>\n]+@>"
}
# Error checking:

# Use brackets to avoid triggering the warning on ourselves!
/(^<[@])|(>[@]([[:space:]]*=[[:space:]]*)?$)/	{
	# Ditto, with concatenation
	warning("<" "@ or >" "@ used instead of @" "< or @" ">\n\t%s\n",
			$0)
}

END {
	check_unfinished()
}
BEGIN {
	if (ARGC < 2)
		fatal(_"usage: jrweave file.twjr [...]\n")

	Pass = 1
	n = ARGC
	ARGV[ARGC++] = "Pass=2"
	for (i = 1; i < n; i++) {
		if (ARGV[i] == "-" || ARGV[i] == "/dev/stdin")
			fatal(_"jrweave: standard input not allowed\n")
		ARGV[ARGC++] = ARGV[i]
	}
}
Pass == 2 && FNR == 1 && Debug ~ /pass2/ {
	junk++
}
BEGIN {
	print_do_not_edit(ARGV[1])
}

# print_do_not_edit --- create and print warning

function print_do_not_edit(filename,	i, pl, pr, l, s, t)
{
	t = _"DO NOT EDIT THIS FILE!!!!"
	if (ARGC > 4)	# more than one file
		s = sprintf(_"It was created by jrweave from `%s' (or maybe others).",
				filename)
	else
		s = sprintf(_"It was created by jrweave from `%s'.", filename)

	l = length(s)
	pl = (l - length(t)) / 2	# padding on left side
	pr = l - (pl + length(t))	# padding on right side
	if (pl * 2 < l)				# account for odd lengths
		pr++
	for (i = 1; i <= l + 4; i++)
		printf("%%")
	printf "\n"

	# print the titles with their padding
	printf("%% %*s%s%*s %%\n", pl, " ", t, pr, " ")
	printf("%% %s %%\n", s)

	for (i = 1; i <= l + 4; i++)
		printf("%%")
	printf "\n"
}
# check_unfinished --- print a fatal error when an unfinished code or
#			file chunk is detected. Also ifweave / iftangle.

function check_unfinished()
{
	if (Flags["file chunk"])
		fatal(_"unfinished file chunk (started at %s)\n",
			Line_numbers["file chunk"])
	else if (Flags["code chunk"])
		fatal(_"unfinished code chunk (started at %s)\n",
			Line_numbers["code chunk"])

	if ("ifweave" in Line_numbers)
		fatal(_"unfinished @ifweave section (started at %s)\n",
			Line_numbers["ifweave"])

	if ("iftangle" in Line_numbers)
		fatal(_"unfinished @iftangle section (started at %s)\n",
			Line_numbers["iftangle"])
}
# strip_out_name --- get the name from name

function strip_out_name(name,	l)
{
	l = length(name)
	name = substr(name, 3, l - 4)

	return name
}
# Helper functions

# message --- write a particular kind of message out to stderr

function message(msg, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
{
	printf("%s:%d: %s: " format, FILENAME, FNR, msg,
		a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) > "/dev/stderr"

	if (substr(format, length(format), 1) != "\n")
		printf("\n") > "/dev/stderr"
}

# fatal --- print a fatal error message and exit.
#	 No varargs, so fake it with lots of parameters.

function fatal(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
{
	message(_"fatal", format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
	exit 1
}

# warning --- print a warning message to stderr
#	 No varargs, so fake it with lots of parameters.

function warning(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
{
	message(_"warning", format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
}

# join.awk --- join an array into a string
#
# Arnold Robbins, arnold@skeeve.com, Public Domain
# May 1993

function join(array, start, end, sep,    result, i)
{
	if (sep == "")
		sep = " "
	else if (sep == SUBSEP) # magic value
		sep = ""
	result = array[start]
	for (i = start + 1; i <= end; i++)
		result = result sep array[i]
	return result
}
# iftangle lines should be removed

/^@iftangle[[:space:]]*$/, /^@end iftangle[[:space:]]*$/ {
	if (Pass == 1)
		next

	if ("ifweave" in Line_numbers)
		fatal(_"cannot nest @iftangle inside @ifweave\n")

	# start of construct, save line number
	if (/^@iftangle[[:space:]]*$/)
		Line_numbers["iftangle"] = (FILENAME ":" FNR)

	# end of construct, delete line number
	if (/^@end iftangle[[:space:]]*$/)
		delete Line_numbers["iftangle"]

	# simply skip these lines, this is weaving
	next
}

# For weaving we remove the bracketing control lines and let anything
# in between fall through.

/^@ifweave[[:space:]]*$/, /^@end ifweave[[:space:]]*$/ {
	if (Pass == 1)
		next

	if ("iftangle" in Line_numbers)
		fatal(_"cannot nest @ifweave inside @iftangle\n")

	# start of construct, save line number, skip this line
	if (/^@ifweave[[:space:]]*$/) {
		Line_numbers["ifweave"] = (FILENAME ":" FNR)
		next
	}

	# end of construct, delete line number, skip this line
	if (/^@end ifweave[[:space:]]*$/) {
		delete Line_numbers["ifweave"]
		next
	}

	# otherwise fall through into the rest of the code
}
/^@file_update_recipe[[:space:]]*$/,
		/^@end file_update_recipe[[:space:]]*$/ {
	next
}
/^@file_update[[:space:]]/ {
	next
}
/^@post_create[[:space:]]+/ {
	next
}
BEGIN {
	Example_start = "@example"
	Example_end = "@end example"
}
Pass == 2 && /^@use_smallexample[[:space:]]*$/ {
	Example_start = "@smallexample"
	Example_end = "@end smallexample"
	next
}

Pass == 2 && /^@use_example[[:space:]]*$/ {
	Example_start = "@example"
	Example_end = "@end example"
	next
}
Pass == 2 && /^@titlepage/ {
	print "@c Let texinfo.tex give us full section titles"
	print "@xrefautomaticsectiontitle on"
	print ""
	print "@c Start extra commands added by jrweave\n"
	print "@c For HTML, spell out email addresses, to avoid problems with"
	print "@c address harvesters for spammers."
	print "@ifhtml"
	print "@macro EMAIL{real,spelled}"
	print "``\\spelled\\''"
	print "@end macro"
	print "@end ifhtml"
	print "@ifnothtml"
	print "@macro EMAIL{real,spelled}"
	print "@email{\\real\\}"
	print "@end macro"
	print "@end ifnothtml"
	print ""
	print "@macro FIXME{text}"
	print "@strong{FIXME}: \\text\\"
	print "@end macro"
	print ""
	print "@macro oldnum{value}"
	print "\\value\\"
	print "@end macro"
	print ""
	print "@tex"
	print "\\gdef\\oldnum#1{\\begingroup\\oldstyle #1\\endgroup}%"
	print "@end tex"
	print "\n@c End extra commands added by jrweave"

	print ""
	print	# print the line

	next
}
/^@numberedchunks[[:space:]]*$/ {
	if (Pass == 1)
		Numbered_chunks = TRUE
	next
}
/^@file_chunk_full_defs[[:space:]]*$/ {
	if (Pass == 1)
		Print_file_full_defs = TRUE
	next
}
Pass == 2 && /^@sidebar[[:space:]]+/ {
	sub(/^@sidebar[[:space:]]+/, "", $0)
	Sidebar_title = $0
	Sidebar_body = ""
	Collecting_sidebar = TRUE
	next
}

Pass == 2 && /^@end[[:space:]]+sidebar[[:space:]]*$/ {
	Collecting_sidebar = FALSE
	printf "@cindex sidebar, %s\n", Sidebar_title
	printf "@ifdocbook\n"
		printf "@docbook\n"
		printf "<sidebar><title>%s</title>\n", Sidebar_title
		printf "@end docbook\n"
			print Sidebar_body
		print ""
		printf "@docbook\n"
		printf "</sidebar>\n"
		printf "@end docbook\n"
	printf "@end ifdocbook\n\n"

	printf "@ifnotdocbook\n"
		printf "@cartouche\n"
		printf "@center @b{%s}\n\n", Sidebar_title
			print "@noindent"
			sub(/^\n*/, "", Sidebar_body)	# remove initial newlines
			print Sidebar_body
		printf "@end cartouche\n"
	printf "@end ifnotdocbook\n"
	Sidebar_body = ""
	next
}

Pass == 2 && Collecting_sidebar {
	Sidebar_body = Sidebar_body "\n" $0
	next
}
Pass == 2 && /^@dquotexrefs[[:space:]]*$/ {
	print "@tex"
#	print "%\\gdef\\xrefprintnodename#1{{\\it #1}}"
	print "\\gdef\\xrefprintnodename#1{``#1''}"
	print "@end tex"

	next
}
Pass == 2 && /^@pdflinkcolor[[:space:]]*.*$/ {
	if (NF != 1 && NF != 4)
		fatal(_"@pdflinkcolor: wrong number of arguments\n")

	if (NF == 1)
		Link_color = Dark_red
	else {
		$1 = ""
		$0 = $0
		Link_color = $0
	}

	print "@tex"
	print "\\gdef\\linkcolor{" Link_color "}"
	print "@end tex"

	next
}
Pass == 2 && /^@urllinkcolor[[:space:]]*.*$/ {
	if (NF != 1 && NF != 4)
		fatal(_"@urllinkcolor: wrong number of arguments\n")

	if (NF == 1)
		URL_color = Dark_red
	else {
		$1 = ""
		$0 = $0
		URL_color = $0
	}

	print "@tex"
	print "\\gdef\\urlcolor{" URL_color "}"
	print "@end tex"

	next
}
Pass == 2 && /^@hideurls[[:space:]]*$/ {
	print "@tex"
	print "\\global\\urefurlonlylinktrue"	# NOTE: *not* \gdef
	print "@end tex"

	next
}
Pass == 2 && /^@allowindexbraces[[:space:]]*$/ {
	print "@tex"
	print "\\global\\usebracesinindexestrue"	# NOTE: *not* \gdef
	print "@end tex"

	next
}
BEGIN {
	Dark_red = "0.5 0.09 0.12"
}
Pass == 2 && /^@c %\*\*end of header/ {
	print	# print the line

	print "\n@c Extra indices added by jrweave"
	print "@defindex cd   @c chunk definition"
	print "@defindex cr   @c chunk reference"

	next
}
$0 ~ File_chunk_pattern {
	Chunk_type = "file chunk"
	Pattern = File_chunk_pattern
	Debug_pat = "filename"
	new_chunk = gensub(Pattern, "\\1", 1)
	if (Flags[Chunk_type]) {
		fatal(_"%s start of %s found while still collecting %s\n",
			Chunk_type, new_chunk, Current_chunk)
	}
	check_unfinished()

	Flags[Chunk_type] = TRUE
	Line_numbers[Chunk_type] = (FILENAME ":" FNR)
	Current_chunk = new_chunk
	Chunk_info[Current_chunk]["type"] = Chunk_type

	if (Debug ~ Debug_pat)
		printf("saw new %s %s\n", Debug_pat, Current_chunk) > "/dev/stderr"
	next
}
$0 ~ Code_chunk_pattern {
	Chunk_type = "code chunk"
	Pattern = Code_chunk_pattern
	Debug_pat = "code"
	new_chunk = gensub(Pattern, "\\1", 1)
	if (Flags[Chunk_type]) {
		fatal(_"%s start of %s found while still collecting %s\n",
			Chunk_type, new_chunk, Current_chunk)
	}
	check_unfinished()

	Flags[Chunk_type] = TRUE
	Line_numbers[Chunk_type] = (FILENAME ":" FNR)
	Current_chunk = new_chunk
	Chunk_info[Current_chunk]["type"] = Chunk_type

	if (Debug ~ Debug_pat)
		printf("saw new %s %s\n", Debug_pat, Current_chunk) > "/dev/stderr"
	next
}
/^@[[:space:]]*$/ {
	if (Flags["file chunk"])
		end_file_gathering()
	else if (Flags["code chunk"])
		end_code_gathering()
	else
		warning(_"unmatched terminating @-sign: ignored\n")

	Chunk_lines = ""
	Flags[Chunk_type] = FALSE
	Line_numbers[Chunk_type] = ""
	Chunk_type = ""

	next
}
Flags["file chunk"] || Flags["code chunk"] {
	if (Chunk_lines == "")
		Chunk_lines = $0
	else
		Chunk_lines = Chunk_lines "\n" $0

	next
}
function end_chunk_gathering()
{
	if (Pass == 1) {
		collect_chunk_info()
		Chunk_lines = ""
		Flags[Chunk_type] = FALSE
	} else
		print_out_chunk()
}

function end_file_gathering()
{
	end_chunk_gathering()
}
function collect_chunk_info(	i, n, x, called, junk)
{
	# Current_chunk, Chunk_type already set by initial code
	# Chunk number:
	if (! ("chunk number" in Chunk_info[Current_chunk])) {
		Chunk_info[Current_chunk]["chunk number"] = \
								++Chunk_numbers[Chunk_type]
	}

	# Definition instance
	Chunk_info[Current_chunk]["defn"]++

	# Get names of called chunks into called
	n = split(Chunk_lines, junk, Chunk_name_pattern, called)

	# Add ourselves to the callers
	for (i in called) {
		x = strip_out_name(called[i])
		Chunk_info[x]["callers"][Current_chunk] = TRUE
	}
}
function print_out_chunk(	x, y, n, i, parts, names,
							name, anchor, chunk_being_used)
{
	# Redefinition instance
	Chunk_info[Current_chunk]["redefn"]++

	print "@need 400"
	anchor = format_anchor(Current_chunk,
				Chunk_info[Current_chunk]["redefn"],
				Chunk_info[Current_chunk]["defn"])
	printf("%s\n", anchor)
	x = expand_tabs(Chunk_lines, Tabstop)
	# extract code chunks
	n = split(x, parts, Chunk_name_pattern, names)

	# escape special chars in parts of code that aren't chunk names
	for (i = 1; i in parts; i++)
		gsub(/[@{}]/, "@&", parts[i])
	y = parts[1]
	if (n > 1) {	# embedded chunk names
		for (i = 1; i in names; i++) {
			name = strip_out_name(names[i])
			chunk_being_used = \
				format_chunk_name(name, Chunk_info[name]["chunk number"],
					Chunk_info[name]["type"])
			printf("@crindex %s, use\n", chunk_being_used)
			y = y chunk_being_used
			y = y parts[i+1]
		}
	}
	chunk_being_defined = \
		format_chunk_name(Current_chunk,
							Chunk_info[Current_chunk]["chunk number"],
							Chunk_type)
	printf("@cdindex %s, definition\n", chunk_being_defined)
	printf("@noindent\n%s %s@equiv{}\n",
		chunk_being_defined,
		Chunk_info[Current_chunk]["redefn"] == 1 ? "" : "+")
	print Example_start
	printf("%s\n", y)
	print Example_end
	for (i in names)
		names[i] = strip_out_name(names[i])	# remove delimiters

	print "@iftex"
	print "@smallfonts @rm"
	print "@end iftex"
	# Print other definition sites for code chunks, or for file
	# chunk if Print_file_full_defs is true
	if (Chunk_type == "code chunk" || Print_file_full_defs) {
		print_other_defns(Current_chunk,
				Chunk_info[Current_chunk]["defn"],
				Chunk_info[Current_chunk]["redefn"])
	}
	# Print callers for code chunks
	if (Chunk_type == "code chunk") {
		if ("callers" in Chunk_info[Current_chunk]) {
			print ""
			asorti(Chunk_info[Current_chunk]["callers"], my_callers)
			if (length(my_callers) > 1) {
				print "@noindent"
				print "This chunk is called by the following chunks:\n"
				print_ref_table(my_callers)
			} else {
				n = Chunk_info[my_callers[1]]["defn"]

				print "@noindent"
				printf("This chunk is called by %s; see its first definition at %s.\n",
					format_chunk_name(my_callers[1],
								Chunk_info[my_callers[1]]["chunk number"],
								Chunk_info[my_callers[1]]["type"]),
					format_xref(my_callers[1], n > 1 ? 1 : 0))
			}
		} else
			warning(_"chunk %s has no callers\n", Current_chunk)
	}
	sort_and_remove_duplicates(names)
	switch (length(names)) {
	case 0:
		break
	case 1:
		print "\n@noindent"
		printf("The called chunk %s is first defined at\n%s.\n",
				format_chunk_name(names[1],
							Chunk_info[names[1]]["chunk number"],
							Chunk_info[names[1]]["type"]),
							format_xref(names[1],
								(Chunk_info[names[1]]["defn"] > 1) ? 1 : 0))
		break;
	default:
		print "\n@noindent"
		printf("The following table lists called chunk definition points.\n")
		print_ref_table(names)
		break;
	}
	print "@iftex"
	print "@textfonts @rm"
	print "@end iftex"
}
function print_other_defns(chunk, total_defns, current_defn,
							other_defns, i, j)	# locals
{
		if (total_defns == 1)
			return

		print ""
		print "@noindent"
		print "This chunk is also defined in"

		for (i = j = 1; i <= total_defns; i++) {
			if (i == current_defn)
				continue

			other_defns[j++] = i
		}

		for (i = 1; i < j; i++) {
			printf("%s", format_xref(chunk, other_defns[i]))
			if (i + 2 == j)
				print ", and"
			else if (i + 2 < j)
				print ","
		}
		print "."
}
function print_ref_table(chunklist,		i, x, n)
{
	print "@multitable @columnfractions .35 .65"
	print "@headitem Chunk name @tab First definition point"

	for (i = 1; i in chunklist; i++) {
		x = chunklist[i]
		n = (Chunk_info[x]["defn"] > 1) ? 1 : 0
		printf("@item %s @tab See %s.\n",
			format_chunk_name(x,
				Chunk_info[x]["chunk number"],
				Chunk_info[x]["type"]),
			format_xref(x, n))
	}

	print "@end multitable"
}
function sort_and_remove_duplicates(names,	i, dups)
{
	for (i in names)
		dups[names[i]] = 1

	asorti(dups)
	delete names
	for (i in dups)
		names[i] = dups[i]
}
function end_code_gathering()
{
	end_chunk_gathering()

	if (Debug ~ /code/)
		printf("finished formatting code %s\n",
					Code_chunk) > "/dev/stderr"
}
Pass == 2 && /^@print_file_defs[[:space:]]*$/ {
	delete Sorted_file_names
	j = 1
	for (i in Chunk_info) {
		if (Chunk_info[i]["type"] == "file chunk")
			Sorted_file_names[j++] = i
	}
	asort(Sorted_file_names)	# Sorted by value
	print "@table @asis"
	for (i = 1; i in Sorted_file_names; i++) {
		name = Sorted_file_names[i]
		x = format_chunk_name(name,
					Chunk_info[name]["chunk number"],
					Chunk_info[name]["type"])
		printf("@item %s\n", x)
		n = Chunk_info[name]["defn"]
		if (n == 1) {
			printf("This chunk is defined in\n")
			printf("%s.\n", format_xref(name, 0))
		} else {
			printf("Multiple definitions occur in\n")
			for (j = 1; j <= n; j++) {
				printf("%s", format_xref(name, j))
				if (j == n - 1)
					printf(",\nand\n")
				else if (j < n - 1)
					printf(",\n")
			}
			print ".\n"
		}
	}
	print "@end table"
	next
}
Pass == 2 && /^@print_code_defs[[:space:]]*$/ {
	delete Sorted_code_names
	j = 1
	for (i in Chunk_info) {
		if (Chunk_info[i]["type"] == "code chunk")
			Sorted_code_names[j++] = i
	}
	asort(Sorted_code_names)	# Sorted by value
	print "@table @asis"
	for (i = 1; i in Sorted_code_names; i++) {
		name = Sorted_code_names[i]
		x = format_chunk_name(name,
					Chunk_info[name]["chunk number"],
					Chunk_info[name]["type"])
		printf("@item %s\n", x)
		n = Chunk_info[name]["defn"]
		if (n == 1) {
			printf("This chunk is defined in\n")
			printf("%s.\n", format_xref(name, 0))
		} else {
			printf("Multiple definitions occur in\n")
			for (j = 1; j <= n; j++) {
				printf("%s", format_xref(name, j))
				if (j == n - 1)
					printf(",\nand\n")
				else if (j < n - 1)
					printf(",\n")
			}
			print ".\n"
		}
	}
	print "@end table"
	next
}
Pass == 2 && /^@print_code_refs[[:space:]]*$/ {
	delete Sorted_code_names
	j = 1
	for (i in Chunk_info) {
		if (Chunk_info[i]["type"] == "code chunk")
			Sorted_code_names[j++] = i
	}
	asort(Sorted_code_names)	# Sorted by value
	print "@table @asis"
	for (i = 1; i in Sorted_code_names; i++) {
		name = Sorted_code_names[i]

		n = Chunk_info[name]["defn"]
		if (n == 0)		# warning printed elsewhere
			continue

		fmt_name = format_chunk_name(name, Chunk_info[name]["chunk number"],
								Chunk_info[name]["type"])
		printf("@item %s\n", fmt_name)

		Current_chunk = name	# for use by next chunk
		if ("callers" in Chunk_info[Current_chunk]) {
			print ""
			asorti(Chunk_info[Current_chunk]["callers"], my_callers)
			if (length(my_callers) > 1) {
				print "@noindent"
				print "This chunk is called by the following chunks:\n"
				print_ref_table(my_callers)
			} else {
				n = Chunk_info[my_callers[1]]["defn"]

				print "@noindent"
				printf("This chunk is called by %s; see its first definition at %s.\n",
					format_chunk_name(my_callers[1],
								Chunk_info[my_callers[1]]["chunk number"],
								Chunk_info[my_callers[1]]["type"]),
					format_xref(my_callers[1], n > 1 ? 1 : 0))
			}
		} else
			warning(_"chunk %s has no callers\n", Current_chunk)
	}
	print "@end table"
	next
}
/^@print_initial_setup([[:space:]]+.*|[[:space:]]*)$/ {
	Print_initial_setup = TRUE
	if (NF > 1) {
		$1 = ""
		$0 = $0
		Initial_setup_name = $0
	}
	else
		Initial_setup_name = "Initial setup"

	next
}

/^@initial_setup[[:space:]]*$/, /^@end initial_setup[[:space:]]*$/ {
	if (Pass == 1 || ! Print_initial_setup)
		next

	Chunk_info[Initial_setup_name]["type"] = "code chunk"
	Chunk_info[Initial_setup_name]["defn"] = 1
	if (/^@initial_setup[[:space:]]*$/) {
		print "@need 400"
		printf("%s\n", format_anchor(Initial_setup_name, 0))
		printf("@noindent\n%s @equiv{}\n",
			format_chunk_name(Initial_setup_name, 0, "code chunk"))
		print Example_start
	} else if (/^@end initial_setup[[:space:]]*$/) {
		print Example_end
	} else {
		x = expand_tabs($0, Tabstop)
		gsub(/[@{}]/, "@&", x)
		print x
	}

	next
}
Pass == 2 { print }
BEGIN {
	if (Tabstop == 0)
		Tabstop = 4		# default tab stops
}
# expand_tabs --- expand tabs in the string

function expand_tabs(string, tabstop,	chars, out, i, j, k, n)
{
	if (tabstop < 2)
		fatal(_"expand_tabs: tabstop %d < 2\n", tabstop)

	n = split(string, chars, "")
	j = k = 0
	for (i = 1; i <= n;) {
		if (chars[i] == "\n") {
			out[j++] = chars[i++]
			k = 0
			continue
		}

		if (chars[i] != "\t") {
			out[j++] = chars[i++]
			k++
			continue
		}
		i++	# skip the tab

		do {
			out[j++] = " "
			k++
		} while (and(k, tabstop-1) != 0)
	}

	return join(out, 0, j, SUBSEP)
}
function sanitize_name(name)
{
	gsub(/[^[:alnum:]]/, "-", name)

	return name
}
function format_anchor_or_ref(type, name, defn,
								clean_name, result)	# locals
{
	clean_name = sanitize_name(name)
	if (defn > 0)
		result = sprintf("@%s{%s-%d}", type, clean_name, defn)
	else
		result = sprintf("@%s{%s}", type, clean_name)

	return result
}

function format_xref(name, defn)
{
	return format_anchor_or_ref("ref", name, defn)
}
function format_anchor(name, cur_defn, total_defns,		defn)
{
	if (total_defns == 1)
		defn = 0
	else if (cur_defn <= total_defns)
		defn = cur_defn
	return format_anchor_or_ref("anchor", name, defn)
}
function format_chunk_name(name, count, type,
							result, left, right, style) # locals
{
	if (type == "file chunk") {
		left = "@{"
		right = "@}"
		style = "file"
	} else if (type == "code chunk") {
		left = "<"
		right = ">"
		style = "i"
	} else
		fatal(_"format_chunk_name: Unknown chunk type `%s'\n", type)

	if (count > 0 && Numbered_chunks)
		result = sprintf("@r{%s@%s{%s} @oldnum{%d}%s}",
						left, style, name, count, right)
	else
		result = sprintf("@r{%s@%s{%s}%s}", left, style, name, right)

	return result
}

path: texindex/jrweave