texinfo-3.7/ 40777 11732 13 0 6067136363 11147 5 ustar bfox user texinfo-3.7/makeinfo/ 40777 11732 13 0 6067136356 12742 5 ustar bfox user texinfo-3.7/makeinfo/macros/ 40777 11732 13 0 6067136336 14224 5 ustar bfox user texinfo-3.7/makeinfo/macros/example.texi 100666 11732 13 16456 5764641157 16710 0 ustar bfox user \input texinfo @c -*-texinfo-*-
@comment %**start of header
@setfilename example.info
@set VERSION 1.58
@paragraphindent none
@comment %**end of header
@include simpledoc.texi
@document {@makeinfo{}, Brian J. Fox,
This file is an extract from the @cite{@texinfo{}} manual.@*
It documents @makeinfo{}\, a program that converts @texinfo{} files into
Info files.
}
@menu
* What is @makeinfo{}?::
* Controlling Paragraph Formats::
* Command Line Options::
* Pointer Validation::
@end menu
@section What is @makeinfo{}?
@iftex
This file documents the use of the @code{makeinfo} program, versions
@value{VERSION} and later. It is an extract from the @cite{TeXinfo} manual.
@end iftex
@makeinfo{} is a program for converting @dfn{@texinfo{}} files into
@dfn{@Info{}} files. @texinfo{} is a documentation system that uses a
single source file to produce both on-line information and printed output.
You can read the on-line information using @Info{}; type @code{info} to
learn about @Info{}.
@ifinfo
@xref{Top, Texinfo, Overview of Texinfo, texinfo, Texinfo},
@end ifinfo
@iftex
See the @cite{TeXinfo} manual,
@end iftex
to learn about the TeXinfo documentation system.
@section Controlling Paragraph Formats
In general, @makeinfo{} @dfn{fills} the paragraphs that it outputs
to an @Info{} file. Filling is the process of breaking and connecting
lines so that lines are the same length as or shorter than the number
specified as the fill column. Lines are broken between words. With
@makeinfo{}, you can control:
@itemize @bullet
@item
The width of each paragraph (the @dfn{fill-column}).
@item
The amount of indentation that the first line of
each paragraph receives (the @dfn{paragraph-indentation}).
@end itemize
@section Command Line Options
The following command line options are available for @makeinfo{}.
@need 100
@table @code
@item -D @var{var}
Cause @var{var} to be defined. This is equivalent to
@code{@@set @var{var}} in the Texinfo file.
@need 150
@item --error-limit @var{limit}
Set the maximum number of errors that @makeinfo{} will report
before exiting (on the assumption that continuing would be useless).
The default number of errors that can be reported before
@makeinfo{} gives up is 100.@refill
@need 150
@item --fill-column @var{width}
Specify the maximum number of columns in a line; this is the right-hand
edge of a line. Paragraphs that are filled will be filled to this
width. The default value for @code{fill-column} is 72.
@item --footnote-style @var{style}
Set the footnote style to @var{style}, either @samp{end} for the end
node style or @samp{separate} for the separate node style. The value
set by this option overrides the value set in a Texinfo file by an
@code{@@footnotestyle} command. When the footnote style is
@samp{separate}, @makeinfo{} makes a new node containing the
footnotes found in the current node. When the footnote style is
@samp{end}, @makeinfo{} places the footnote references at the end
of the current node.
@need 150
@item -I @var{dir}
Add @code{dir} to the directory search list for finding files that are
included using the @code{@@include} command. By default,
@makeinfo{} searches only the current directory.
@need 150
@item --no-headers
Do not include menus or node lines in the output. This results in an
@sc{ascii} file that you cannot read in Info since it does not contain
the requisite nodes or menus; but you can print such a file in a
single, typewriter-like font and produce acceptable output.
@need 150
@item --no-split
Suppress the splitting stage of @makeinfo{}. Normally, large
output files (where the size is greater than 70k bytes) are split into
smaller subfiles, each one approximately 50k bytes. If you specify
@samp{--no-split}, @makeinfo{} will not split up the output
file.
@need 100
@item --no-pointer-validate
@item --no-validate
Suppress the pointer-validation phase of @makeinfo{}. Normally,
after a Texinfo file is processed, some consistency checks are made to
ensure that cross references can be resolved, etc.
@xref{Pointer Validation}.
@need 150
@item --no-warn
Suppress the output of warning messages. This does @emph{not}
suppress the output of error messages, only warnings. You might
want this if the file you are creating has examples of Texinfo cross
references within it, and the nodes that are referenced do not actually
exist.
@item --no-number-footnotes
Supress automatic footnote numbering. By default, @makeinfo{}
numbers each footnote sequentially in a single node, resetting the
current footnote number to 1 at the start of each node.
@need 150
@item --output @var{file}
@itemx -o @var{file}
Specify that the output should be directed to @var{file} and not to the
file name specified in the @code{@@setfilename} command found in the Texinfo
source. @var{file} can be the special token @samp{-}, which specifies
standard output.
@need 150
@item --paragraph-indent @var{indent}
Set the paragraph indentation style to @var{indent}. The value set by
this option overrides the value set in a Texinfo file by an
@code{@@paragraphindent} command. The value of @var{indent} is
interpreted as follows:
@itemize @bullet
@item
If the value of @var{indent} is @samp{asis}, do not change the
existing indentation at the starts of paragraphs.
@item
If the value of @var{indent} is zero, delete any existing
indentation.
@item
If the value of @var{indent} is greater than zero, indent each
paragraph by that number of spaces.
@end itemize
@need 100
@item --reference-limit @var{limit}
Set the value of the number of references to a node that
@makeinfo{} will make without reporting a warning. If a node has more
than this number of references in it, @makeinfo{} will make the
references but also report a warning.
@need 150
@item -U @var{var}
Cause @var{var} to be undefined. This is equivalent to
@code{@@clear @var{var}} in the Texinfo file.
@need 100
@item --verbose
Cause @makeinfo{} to display messages saying what it is doing.
Normally, @makeinfo{} only outputs messages if there are errors or
warnings.
@need 100
@item --version
Report the version number of this copy of @makeinfo{}.
@end table
@section Pointer Validation
@cindex Pointer validation with @makeinfo{}
@cindex Validation of pointers
If you do not suppress pointer-validation (by using the
@samp{--no-pointer-validation} option), @makeinfo{}
will check the validity of the final Info file. Mostly,
this means ensuring that nodes you have referenced
really exist. Here is a complete list of what is
checked:
@enumerate
@item
If a `Next', `Previous', or `Up' node reference is a reference to a
node in the current file and is not an external reference such as to
@file{(dir)}, then the referenced node must exist.
@item
In every node, if the `Previous' node is different from the `Up' node,
then the `Previous' node must also be pointed to by a `Next' node.
@item
Every node except the `Top' node must have an `Up' pointer.
@item
The node referenced by an `Up' pointer must contain a reference to the
current node in some manner other than through a `Next' reference.
This includes menu entries and cross references.
@item
If the `Next' reference of a node is not the same as the `Next' reference
of the `Up' reference, then the node referenced by the `Next' pointer
must have a `Previous' pointer that points back to the current node.
This rule allows the last node in a section to point to the first node
of the next chapter.
@end enumerate
@bye
texinfo-3.7/makeinfo/macros/html.texi 100666 11732 13 15507 5764641157 16215 0 ustar bfox user @c html.texi: -*- Texinfo -*- Macros which support HTML output.
@c Copyright (c) 1995 Brian Fox (bfox@ai.mit.edu)
@c Author: Brian J. Fox (bfox@ai.mit.edu) Sat Apr 1 20:30:54 1995.
@c
@c I didn't want to write this myself, because I wanted some HTML wizard
@c to get everything exactly right. However, rms continues to believe
@c that the macro system is not a good idea. I couldn't disagree more,
@c so I am writing this as an example of how useful such macros can be.
@macro html
@set html
@end macro
@c
@c The first step is to define the macros which really only have meaning
@c when producing output for HTML.
@c
@c @anchor{Brian Fox, http://www.ua.com/users/bfox/}
@c
@macro anchor{text, link}
@ifset html
\text\
@end ifset
@ifclear html
\text\
@end ifclear
@end macro
@macro pre{}
@ifset html
@end ifset
@end macro
@macro endpre{}
@ifset html
@end ifset
@end macro
@macro TeX
@ifset html
TeX
@end ifset
@ifclear html
@TeX{}
@end ifclear
@end macro
@macro paragraph{}
@ifset html
@end ifset
@end macro
@c
@c @email{bfox@@ai.mit.edu}
@c
@macro email{address}
@anchor{mailto:\address\, \address\}
@end macro
@c
@c Redefine the TeXinfo commands which have direct HTML counterparts.
@c
@macro html-define-0arg{command, html-insertion}
@macro \command\
@ifset html
\html-insertion\
@end ifset
@ifclear html
@\command\
@end ifclear
@end macro
@end macro
@macro html-define-1arg{command, html-insertion}
@macro \command\{arg}
@ifset html
\html-insertion\
@end ifset
@ifclear html
@\command\{\arg\}
@end ifclear
@end macro
@end macro
@macro html-define-line{command, html-insertion}
@macro \command\{line}
@ifset html
\html-insertion\
@end ifset
@ifclear html
@\command\ \line\
@end ifclear
@end macro
@end macro
@html-define-0arg{*,
}
@html-define-1arg{b, \\arg\\}
@html-define-1arg{code, \\arg\\}
@html-define-line{itemize,
}
@html-define-line{item,- }
@html-define-line{heading,
\\line\\
}
@html-define-0arg{bye, }
@c
@c Define into nothing the macros which do nothing in html.
@c
@html-define-line{group,}
@c
@c Define a macro which is used to define other macros. This one makes
@c a macro which creates an HTML header line. No sectioning commands
@c are used. This takes advantage of the non-recursion feature of
@c macro execution.
@macro node_define{orig-name, header-style}
@macro \orig-name\{title}
@ifset html
@node \title\
<\header-style\>\title\\header-style\>
@end ifset
@ifclear html
@\orig-name\ \title\
@end ifclear
@end macro
@end macro
@c
@c The same as NODE_DEFINE, but italicized.
@macro inode_define{orig-name, header-style}
@macro \orig-name\{title}
@ifset html
@node \title\
<\header-style\>\title\\header-style\>
@end ifset
@ifclear html
@\orig-name\ \title\
@end ifclear
@end macro
@end macro
@c Ignore @node commands.
@html-define-line{node,}
@c Here is a special one for "@top".
@macro top{title}
@end macro
@c Now actually define a new set of sectioning commands.
@node_define {appendix, h1}
@node_define {appendixsec, h2}
@node_define {appendixsubsec, h3}
@node_define {appendixsubsubsec, h4}
@node_define {chapter, h1}
@node_define {section, h2}
@node_define {subsection, h3}
@node_define {subsubsec, h4}
@node_define {unnumbered, h1}
@node_define {unnumberedsec, h2}
@node_define {unnumberedsubsec, h3}
@node_define {unnumberedsubsubsec, h4}
@c The italicized analogues.
@inode_define {iappendix, h1}
@inode_define {iappendixsec, h2}
@inode_define {iappendixsubsec, h3}
@inode_define {iappendixsubsubsec, h4}
@inode_define {ichapter, h1}
@inode_define {isection, h2}
@inode_define {isubsection, h3}
@inode_define {isubsubsec, h4}
@inode_define {iunnumbered, h1}
@inode_define {iunnumberedsec, h2}
@inode_define {iunnumberedsubsec, h3}
@inode_define {iunnumberedsubsubsec, h4}
@c Manual starter:
@c
@c Pass arguments of TITLE, AUTHOR, and a short DESCRIPTION.
@c Immediately following, insert the Top node's menu.
@c
@c Typical usage:
@c
@c @document{Makeinfo, Brian J. Fox, This file documents the use of the
@c @code{makeinfo} program\, versions 1.61 and later.}
@c
@c @menu
@c * What is @makeinfo{}?::
@c @end menu
@macro document{title, author, description}
@ifinfo
\description\
Copyright @copyright{} 1995 \author\
Copyright @copyright{} 1995 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
Permission is granted to process this file through TeX and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the copyright holders.
@end ifinfo
@titlepage
@title \title\
@author \author\
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1995 \author\
Copyright @copyright{} 1995 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the copyright holders.
@end titlepage
@top{\title\}
\description\
@end macro
@html-define-line{end,
@ifeq{"\\line\\"\, "ifinfo"\, @end ifinfo}
@ifeq{"\\line\\"\, "ifset"\, @end ifset}
@ifeq{"\\line\\"\, "ifclear"\, @end ifclear}
@ifeq{"\\line\\"\, "cartouche"\, @end cartouche}
@ifeq{"\\line\\"\, "menu"\, @end menu}
@ifeq{"\\line\\"\, "itemize"\,
}
@ifeq{"\\line\\"\, "enumerate"\, }
@ifeq{"\\line\\"\, "table"\, }
@ifeq{"\\line\\"\, "ftable"\, }
@ifeq{"\\line\\"\, "vtable"\, }
@ifeq{"\\line\\"\, "menu"\, xxx}
@ifeq{"\\line\\"\, "quotation"\, }
@ifeq{"\\line\\"\, "example"\, }
@ifeq{"\\line\\"\, "smallexample"\, }
@ifeq{"\\line\\"\, "lisp"\, }
@ifeq{"\\line\\"\, "format"\, }
@ifeq{"\\line\\"\, "display"\, }
@ifeq{"\\line\\"\, "group"}}
texinfo-3.7/makeinfo/macros/multifmt.texi 100644 11732 13 2143 5764641157 17056 0 ustar bfox user @c multiformat.texi: -*- Texinfo -*- \input texinfo.tex
@c Copyright (c) 1995 Universal Access, Inc
@c Author: Brian J. Fox (bfox@ua.com) Sun Apr 2 07:56:23 1995.
@setfilename multiformat.info
@include html.texi
@ifset html
@html
@end ifset
@node First Node, First Section, (dir), (dir)
@chapter First Chapter
Here is some text that belongs in the first chapter. Nothing very
exciting happens here, but this is enough text to span a couple of
lines, and we feel that is important.
@paragraph
This is the second paragraph of the first chapter. Note that the
formatting commands in @code{HTML} seem to do the right thing, as do the
commands when invoked in @code{Texinfo} mode and in @TeX{}.
@node First Section, , First Node, First Node
@isection First Section
Here is some text in the first section of the first chapter. We are
trying very hard to examine the output here to see exactly how proper it
is. If I wasn't so tired, we could probably see it already.
@paragraph
Here is a list of items:
@paragraph
@itemize @bullet
@item Here is the first item.
@item Here is the second item.
@end itemize
@bye
texinfo-3.7/makeinfo/macros/res-samp.texi 100666 11732 13 1546 5764641157 16756 0 ustar bfox user \input texinfo.tex
@setfilename resume-example.info
@include resume.texi
@name Brian J. Fox
@email bfox@@ai.mit.edu
@street 116 Barranca Ave, Ste. B
@city Santa Barbara
@state CA
@zip 93109
@phone (805) 564-2192
@resume
@block{EDUCATION}
@entry{
12/11/59,
12/11/63,
My Mom's House,
Learning at home with my mother.,
This was the most learning I ever did.}
@entry{12/11/63, 12/11/77, Brookline\, MA, Learning in the public school system.}
@entry{12/11/78, 12/11/81, Santa Barbara\, CA, Learning in life
experience\, and three months at Santa Barbara City College.}
@block{WORK EXPERIENCE}
@entry{12/11/59, 12/11/75, Mom's house, Various and sundry tasks\,
including washing dishes and clothes\, and toilet training.}
@entry{3 months ago, present, Terrapin\, Inc., hacking up Unix systems\, breaking @code{LOGO} worlds\, terrorizing surrounding neighborhood.}
@bye
texinfo-3.7/makeinfo/macros/resume.texi 100666 11732 13 2517 5764641160 16520 0 ustar bfox user @c
@c Reusme writing macros. Produce a very specific format.
@c
@c A macro which creates a macro. The resultant macro can be called to
@c set a variable which has the same name as the macro. Use
@c @value{name} to get the value set in @name{}.
@macro make-var-macro{macro-name}
@macro \macro-name\{value}
@quote-arg
@set \macro-name\ \value\
@end macro
@end macro
@make-var-macro{name}
@make-var-macro{street}
@make-var-macro{city}
@make-var-macro{state}
@make-var-macro{zip}
@make-var-macro{phone}
@make-var-macro{email}
@c Give all of the above variable/macros a null value to start.
@name
@street
@city
@state
@zip
@phone
@email
@c A typical heading for a resume block is a non-indented line.
@macro block{title}
@paragraphindent none
@comment @noindent
@heading \title\
@end macro
@c A typical entry in a resume has a from-date, a to-date, a location,
@c a job title, and a longer descrition body.
@macro entry{from-date, to-date, where, what, body}
@paragraphindent 8
@b{\where\: \what\ (\from-date\ --- \to-date\)}
@paragraphindent 3
\body\
@paragraphindent none
@end macro
@macro address{}
@value{name}@*
@value{street}@*
@value{city}, @value{state}@*
@value{zip}@*
@value{phone}
@end macro
@macro resume{}
@center @value{name}@*
@center @value{street}@*
@center @value{city}, @value{state} @value{zip}@*
@center @value{email}
@end macro
texinfo-3.7/makeinfo/macros/simpledoc.texi 100666 11732 13 7757 5764641160 17212 0 ustar bfox user
@comment Here are some useful examples of the macro facility.
@c Simply insert the right version of the texinfo name.
@macro texinfo{}
TeXinfo
@end macro
@c Define a macro which expands to a pretty version of the name of the
@c Makeinfo program.
@macro makeinfo{}
@code{Makeinfo}
@end macro
@c Simple insert the right version of the Info name.
@macro Info{}
@code{Info}
@end macro
@c Define a macro which is used to define other macros. This one makes
@c a macro which creates a node and gives it a sectioning command. Note
@c that the created macro uses the original definition within the
@c expansion text. This takes advantage of the non-recursion feature of
@c macro execution.
@macro node_define{orig-name}
@macro \orig-name\{title}
@node \title\
@\orig-name\ \title\
@end macro
@end macro
@c Here is a special one for "@top", causing the node name to be "Top",
@c but leaving the section name as the specified title.
@macro top{title}
@node Top
@top \title\
@end macro
@c Now actually define a new set of sectioning commands.
@node_define {appendix}
@node_define {appendixsec}
@node_define {appendixsubsec}
@node_define {appendixsubsubsec}
@node_define {chapter}
@node_define {section}
@node_define {subsection}
@node_define {subsubsec}
@node_define {unnumbered}
@node_define {unnumberedsec}
@node_define {unnumberedsubsec}
@node_define {unnumberedsubsubsec}
@c The italicized analogues.
@node_define {iappendix}
@node_define {iappendixsec}
@node_define {iappendixsubsec}
@node_define {iappendixsubsubsec}
@node_define {ichapter}
@node_define {isection}
@node_define {isubsection}
@node_define {isubsubsec}
@node_define {iunnumbered}
@node_define {iunnumberedsec}
@node_define {iunnumberedsubsec}
@node_define {iunnumberedsubsubsec}
@c Manual starter:
@c
@c Pass arguments of TITLE, AUTHOR, and a short DESCRIPTION.
@c Immediately following, insert the Top node's menu.
@c
@c Typical usage:
@c
@c @document{Makeinfo, Brian J. Fox, This file documents the use of the
@c @code{makeinfo} program\, versions 1.58 and later.}
@c
@c @menu
@c * What is @makeinfo{}?::
@c @end menu
@macro document{title, author, description}
@ifinfo
\description\
Copyright @copyright{} 1994 \author\
Copyright @copyright{} 1994 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
Permission is granted to process this file through TeX and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the copyright holders.
@end ifinfo
@titlepage
@title \title\
@author \author\
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1994 \author\
Copyright @copyright{} 1994 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the copyright holders.
@end titlepage
@top{\title\}
\description\
@end macro
texinfo-3.7/makeinfo/Makefile.in 100666 11732 13 5533 6067063752 15111 0 ustar bfox user # Makefile for GNU makeinfo. -*- Indented-Text -*-
# Copyright (C) 1993 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.
#### Start of system configuration section. ####
srcdir = @srcdir@
VPATH = $(srcdir):$(common)
common = $(srcdir)/../libtxi
CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
LN = ln
RM = rm -f
TAR = tar
MKDIR = mkdir
COMPRESS= compress
DEFS = @DEFS@
LIBS = -L../libtxi -ltxi @LIBS@
LOADLIBES = $(LIBS)
SHELL = /bin/sh
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = $(exec_prefix)/bin
# Prefix for each installed program, normally empty or `g'.
binprefix =
libdir = $(prefix)/lib
# Prefix for each installed man page, normally empty or `g'.
manprefix =
mandir = $(prefix)/man/man1
manext = 1
infodir = $(prefix)/info
#### End of system configuration section. ####
SRCS = makeinfo.c
OBJS = makeinfo.o
PROGS = makeinfo
all: $(PROGS) makeinfo.info
sub-all: all
.c.o:
$(CC) -c $(CPPFLAGS) -I. -I$(srcdir) -I$(common) $(DEFS) $(CFLAGS) $<
makeinfo: $(OBJS) ../libtxi/libtxi.a
$(CC) $(LDFLAGS) -o makeinfo $(OBJS) $(LOADLIBES)
../libtxi/libtxi.a:
(cd ../libtxi; $(MAKE) $(MFLAGS) libtxi.a)
makeinfo.o: makeinfo.c $(common)/getopt.h
makeinfo.info: ./makeinfo makeinfo.texi macro.texi
./makeinfo --no-split -I$(srcdir) makeinfo.texi
# makeinfo.texi: ./makeinfo makeinfo.mki
# ./makeinfo -E makeinfo.texi -I$(srcdir) makeinfo.mki
makeinfo.dvi: ./makeinfo makeinfo.texi macro.texi
./makeinfo -E makeinfo.txi -I$(srcdir) makeinfo.texi
$(srcdir)/../util/texi2dvi makeinfo.txi
install: all
for f in $(PROGS); do $(INSTALL_PROGRAM) $$f $(bindir)/$(binprefix)$$f; done
-d=$(srcdir); test -f ./makeinfo.info && d=.; $(INSTALL_DATA) $$d/makeinfo.info $(infodir)/makeinfo.info
uninstall:
for f in $(PROGS); do rm -f $(bindir)/$(binprefix)$$f; done
rm -f $(infodir)/makeinfo.info
TAGS: $(SRCS)
etags $(SRCS)
clean:
rm -f *.o a.out core core.* $(PROGS)
mostlyclean: clean
distclean: clean
rm -f TAGS Makefile config.status *.info */*.info
realclean: distclean
Makefile: Makefile.in ../config.status
cd ..; sh config.status
# Prevent GNU make v3 from overflowing arg limit on SysV.
.NOEXPORT:
# eof
texinfo-3.7/makeinfo/macro.texi 100666 11732 13 12004 5764641160 15045 0 ustar bfox user @c This file is included in makeinfo.texi.
@c
@ifinfo
@comment Here are some useful examples of the macro facility.
@c Simply insert the right version of the texinfo name.
@macro texinfo{}
TeXinfo
@end macro
@macro dfn{text}
@dfn{\text\}
@cpindex \text\
@end macro
@c Define a macro which expands to a pretty version of the name of the
@c Makeinfo program.
@macro makeinfo{}
@code{Makeinfo}
@end macro
@c Define a macro which is used to define other macros. This one makes
@c a macro which creates a node and gives it a sectioning command. Note
@c that the created macro uses the original definition within the
@c expansion text. This takes advantage of the non-recursion feature of
@c macro execution.
@macro node_define{orig-name}
@macro \orig-name\{title}
@node \title\
@\orig-name\ \title\
@end macro
@end macro
@c Now actually define a new set of sectioning commands.
@node_define {chapter}
@node_define {section}
@node_define {subsection}
@end ifinfo
@chapter The Macro Facility
This chapter describes the new macro facility.
A @dfn{macro} is a command that you define in terms of other commands.
It doesn't exist as a @texinfo{} command until you define it as part of
the input file to @makeinfo{}. Once the command exists, it behaves much
as any other @texinfo{} command. Macros are a useful way to ease the
details and tedium of writing a `correct' info file. The following
sections explain how to write and invoke macros.
@menu
* How to Use Macros in @texinfo{}::
How to use the macro facility.
* Using Macros Recursively::
How to write a macro which does (or doesn't) recurse.
* Using @texinfo{} Macros As Arguments::
Passing a macro as an argument.
@end menu
@section How to Use Macros in @texinfo{}
Using macros in @texinfo{} is easy. First you define the macro. After
that, the macro command is available as a normal @texinfo{} command.
Here is what a definition looks like:
@example
@@macro @var{name}@{@var{arg1}, @var{@dots{}} @var{argn}@}
@var{@texinfo{} commands@dots{}}
@@end macro
@end example
The arguments that you specify that the macro takes are expanded with
the actual parameters used when calling the macro if they are seen
surrounded by backslashes. For example, here is a definition of
@code{@@codeitem}, a macro which can be used wherever @code{@@item} can
be used, but which surrounds its argument with @code{@@code@{@dots{}@}}.
@example
@@macro codeitem@{item@}
@@item @@code@{\item\@}
@@end macro
@end example
When the macro is expanded, all of the text between the @code{@@macro}
and @code{@@end macro} is inserted into the document at the expansion
point, with the actual parameters substituted for the named parameters.
So, a call to the above macro might look like:
@example
@@codeitem@{Foo@}
@end example
and @makeinfo{} would execute the following code:
@example
@@item @@code@{Foo@}
@end example
A special case is made for macros which only take a single argument, and
which are invoked without any brace characters (i.e.,
@samp{@{}@dots{}@samp{@}}) surrounding an argument; the rest of the line
is supplied as is as the sole argument to the macro. This special case
allows one to redefine some standard @texinfo{} commands without
modifying the input file. Along with the non-recursive action of macro
invocation, one can easily redefine the sectioning commands to also
provide index entries:
@example
@@macro chapter@{name@}
@@chapter \name\
@@findex \name\
@@end macro
@end example
Thus, the text:
@example
@@chapter strlen
@end example
will expand to:
@example
@@chapter strlen
@@findex strlen
@end example
@section Using Macros Recursively
Normally, while a particular macro is executing, any call to that macro
will be seen as a call to a builtin @texinfo{} command. This allows one
to redefine a builtin @texinfo{} command as a macro, and then use that
command within the definition of the macro itself. For example, one
might wish to make sure that whereever a term was defined with
@code{@@dfn@{@dots{}@}}, the location of the definition would appear
in the concept index for the manual. Here is a macro which redefines
@code{@@dfn} to do just that:
@example
@@macro dfn@{text@}
@@dfn@{\text\@}
@@cpindex \text\
@@end macro
@end example
Note that we used the builtin @texinfo{} command @code{@@dfn} within our
overriding macro definition.
This behaviour itself can be overridden for macro execution by writing a
special @dfn{macro control command} in the definition of the macro. The
command is considered special because it doesn't affect the output text
directly, rather, it affects the way in which the macro is defined. One
such special command is @code{@@allow-recursion}.
@example
@@macro silly@{arg@}
@@allow-recursion
\arg\
@@end macro
@end example
Now @code{@@silly} is a macro that can be used within a call to itself:
@example
This text @@silly@{@@silly@{some text@}@} is ``some text''.
@end example
@section Using @texinfo{} Macros As Arguments
@printindex cp
How to use @texinfo{} macros as arguments to other @texinfo{} macros.
@bye
texinfo-3.7/makeinfo/makeinfo.c 100666 11732 13 663525 6067100075 15042 0 ustar bfox user /* Makeinfo -- convert texinfo format files into info files.
Copyright (C) 1987, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
This file is part of GNU Info.
Makeinfo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY. No author or distributor accepts
responsibility to anyone for the consequences of using it or for
whether it serves any particular purpose or works at all, unless he
says so in writing. Refer to the GNU Emacs General Public License
for full details.
Everyone is granted permission to copy, modify and redistribute
Makeinfo, but only under the conditions described in the GNU Emacs
General Public License. A copy of this license is supposed to
have been given to you along with GNU Emacs so you can know your
rights and responsibilities. It should be in a file named COPYING.
Among other things, the copyright notice and this notice must be
preserved on all copies. */
/* This is Makeinfo version 1.64. If you change the version number of
Makeinfo, please change it here and at the lines reading:
int major_version = 1;
int minor_version = 64;
in the code below.
Makeinfo is authored by Brian Fox (bfox@ai.mit.edu). */
/* You can change some of the behaviour 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 DEFAULT_INDENTATION_INCREMENT as an integer which is the amount
that @example should increase indentation by. This incremement is used
for all insertions which indent the enclosed text. */
#define DEFAULT_INDENTATION_INCREMENT 5
/* Define PARAGRAPH_START_INDENT to be the amount of indentation that
the first lines of paragraphs receive by default, where no other
value has been specified. Users can change this value on the command
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
/* Define HAVE_MACROS to enable the macro facility of TeXinfo. Using this
facility, users can create their own command procedures with arguments. */
#define HAVE_MACROS
/* **************************************************************** */
/* */
/* Include File Declarations */
/* */
/* **************************************************************** */
/* Indent #pragma so that older Cpp's don't try to parse it. */
#if defined (_AIX)
# pragma alloca
#endif /* _AIX */
#include
#include
#include
#include
#include
#include
#if defined (HAVE_VARARGS_H)
#include
#endif /* HAVE_VARARGS_H */
#include "getopt.h"
#if defined (HAVE_UNISTD_H)
#include
#endif /* HAVE_UNISTD_H */
#if defined (VMS)
#include
#endif
#if defined (HAVE_STRING_H)
#include
#else
#include
#endif /* !HAVE_STRING_H */
#if defined (TM_IN_SYS_TIME)
#include
#else
#include
#endif /* !TM_IN_SYS_TIME */
#if defined (HAVE_SYS_FCNTL_H)
#include
#else
#include
#endif /* !HAVE_SYS_FCNTL_H */
#if defined (HAVE_SYS_FILE_H)
#include
#endif /* HAVE_SYS_FILE_H */
#if defined (__GNUC__)
#define alloca __builtin_alloca
#else
#if defined(HAVE_ALLOCA_H)
#include
#else /* !HAVE_ALLOCA_H */
#if !defined (_AIX)
extern char *alloca ();
#endif /* !_AIX */
#endif /* !HAVE_ALLOCA_H */
#endif /* !__GNUC__ */
void *xmalloc (), *xrealloc ();
#if defined (__osf__)
extern void *malloc (), *realloc ();
#endif /* __osf__ */
char **get_brace_args ();
int array_len ();
void free_array ();
static void isolate_nodename ();
#if !defined (HAVE_MEMMOVE)
# define memmove(dst, src, len) bcopy (src, dst, len)
#endif
/* Non-zero means that we are currently hacking the insides of an
insertion which would use a fixed width font. */
static int in_fixed_width_font = 0;
/* Non-zero means that start_paragraph () MUST be called before we pay
any attention to close_paragraph () calls. */
int must_start_paragraph = 0;
/* Non-zero means a string is in execution, as opposed to a file. */
static int executing_string = 0;
#if defined (HAVE_MACROS)
/* If non-NULL, this is an output stream to write the full macro expansion
of the input text to. The resultant file is another texinfo file, but
missing @include, @infoinclude, @macro, and macro invocations. Instead,
all of the text is placed within the file. */
FILE *macro_expansion_output_stream = (FILE *)NULL;
/* Here is a structure used to remember input text strings and offsets
within them. */
typedef struct {
char *pointer; /* Pointer to the input text. */
int offset; /* Offset of the last character output. */
} ITEXT;
static ITEXT **itext_info = (ITEXT **)NULL;
static int itext_size = 0;
/* Non-zero means to inhibit the writing of macro expansions to the output
stream. This is used in special cases where the output has already been
written. */
int me_inhibit_expansion = 0;
ITEXT *remember_itext ();
void forget_itext (), me_append_before_this_command ();
void append_to_expansion_output (), write_region_to_macro_output ();
void maybe_write_itext (), me_execute_string ();
#endif /* HAVE_MACROS */
/* Some systems don't declare this function in pwd.h. */
struct passwd *getpwnam ();
/* **************************************************************** */
/* */
/* Global Defines */
/* */
/* **************************************************************** */
/* Error levels */
#define NO_ERROR 0
#define SYNTAX 2
#define FATAL 4
/* C's standard macros don't check to make sure that the characters being
changed are within range. So I have to check explicitly. */
/* GNU Library doesn't have toupper(). Until GNU gets this fixed, I will
have to do it. */
#ifndef toupper
#define toupper(c) ((c) - 32)
#endif
#define coerce_to_upper(c) ((islower(c) ? toupper(c) : (c)))
#define coerce_to_lower(c) ((isupper(c) ? tolower(c) : (c)))
#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) (((c) == '\t') || ((c) == ' ') || ((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
#define member(c, s) (strchr (s, c) != NULL)
#define COMMAND_PREFIX '@'
/* Stuff for splitting large files. */
#define SPLIT_SIZE_THRESHOLD 70000 /* What's good enough for Stallman... */
#define DEFAULT_SPLIT_SIZE 50000 /* Is probably good enough for me. */
int splitting = 1; /* Always true for now. */
typedef void COMMAND_FUNCTION (); /* So I can say COMMAND_FUNCTION *foo; */
/* **************************************************************** */
/* */
/* Global Variables */
/* */
/* **************************************************************** */
/* Global pointer to argv[0]. */
char *progname;
/* The current input file state. */
char *input_filename;
char *input_text;
int size_of_input_text;
int input_text_offset;
int line_number;
#define curchar() input_text[input_text_offset]
#define command_char(c) ((!whitespace(c)) && \
((c) != '\n') && \
((c) != '{') && \
((c) != '}') && \
((c) != '='))
#define skip_whitespace() while (input_text_offset != size_of_input_text \
&& whitespace(curchar()))\
input_text_offset++
#define skip_whitespace_and_newlines() \
do { \
while (input_text_offset != size_of_input_text \
&& (whitespace (curchar ()) \
|| (curchar () == '\n'))) \
{ \
if (curchar () == '\n') \
line_number++; \
input_text_offset++; \
} \
} while (0)
/* Return non-zero if STRING is the text at input_text + input_text_offset,
else zero. */
#define looking_at(string) \
(strncmp (input_text + input_text_offset, string, strlen (string)) == 0)
/* And writing to the output. */
/* The output file name. */
char *output_filename = (char *)NULL;
char *pretty_output_filename;
/* Name of the output file that the user elected to pass on the command line.
Such a name overrides any name found with the @setfilename command. */
char *command_output_filename = (char *)NULL;
/* A colon separated list of directories to search for files included
with @include. This can be controlled with the `-I' option to makeinfo. */
char *include_files_path = (char *)NULL;
/* Current output stream. */
FILE *output_stream;
/* Position in the output file. */
int output_position;
/* Output paragraph buffer. */
unsigned char *output_paragraph;
/* Offset into OUTPUT_PARAGRAPH. */
int output_paragraph_offset;
/* The output paragraph "cursor" horizontal position. */
int output_column = 0;
/* Non-zero means output_paragraph contains text. */
int paragraph_is_open = 0;
#define INITIAL_PARAGRAPH_SPACE 5000
int paragraph_buffer_len = INITIAL_PARAGRAPH_SPACE;
/* Filling.. */
/* Non-zero indicates that filling will take place on long lines. */
int filling_enabled = 1;
/* Non-zero means that words are not to be split, even in long lines. This
gets changed for cm_w (). */
int non_splitting_words = 0;
/* Non-zero indicates that filling a line also indents the new line. */
int indented_fill = 0;
/* The column at which long lines are broken. */
int fill_column = 72;
/* The amount of indentation to apply at the start of each line. */
int current_indent = 0;
/* The amount of indentation to add at the starts of paragraphs.
0 means don't change existing indentation at paragraph starts.
> 0 is amount to indent new paragraphs by.
< 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;
/* Non-zero means that the use of paragraph_start_indent is inhibited.
@example uses this to line up the left columns of the example text.
A negative value for this variable is incremented each time it is used.
@noindent uses this to inhibit indentation for a single paragraph. */
int inhibit_paragraph_indentation = 0;
/* Indentation that is pending insertion. We have this for hacking lines
which look blank, but contain whitespace. We want to treat those as
blank lines. */
int pending_indent = 0;
/* The amount that indentation increases/decreases by. */
int default_indentation_increment = DEFAULT_INDENTATION_INCREMENT;
/* Non-zero indicates that indentation is temporarily turned off. */
int no_indent = 1;
/* Non-zero means forcing output text to be flushright. */
int force_flush_right = 0;
/* Non-zero means that the footnote style for this document was set on
the command line, which overrides any other settings. */
int footnote_style_preset = 0;
/* Non-zero means that we automatically number footnotes that have no
specified marker. */
int number_footnotes = 1;
/* The current footnote number in this node. Each time a new node is
started this is reset to 1. */
int current_footnote_number = 1;
/* Command name in the process of being hacked. */
char *command;
/* The index in our internal command table of the currently
executing command. */
int command_index;
/* A search string which is used to find a line defining a node. */
char node_search_string[] =
{ '\n', COMMAND_PREFIX, 'n', 'o', 'd', 'e', ' ', '\0' };
/* A search string which is used to find a line defining a menu. */
char menu_search_string[] =
{ '\n', COMMAND_PREFIX, 'm', 'e', 'n', 'u', '\0' };
/* A search string which is used to find the first @setfilename. */
char setfilename_search[] =
{ COMMAND_PREFIX,
's', 'e', 't', 'f', 'i', 'l', 'e', 'n', 'a', 'm', 'e', '\0' };
/* A stack of file information records. If a new file is read in with
"@input", we remember the old input file state on this stack. */
typedef struct fstack
{
struct fstack *next;
char *filename;
char *text;
int size;
int offset;
int line_number;
} FSTACK;
FSTACK *filestack = (FSTACK *) NULL;
/* Stuff for nodes. */
/* The current nodes node name. */
char *current_node = (char *)NULL;
/* The current nodes section level. */
int current_section = 0;
/* The filename of the current input file. This is never freed. */
char *node_filename = (char *)NULL;
/* What we remember for each node. */
typedef struct tentry
{
struct tentry *next_ent;
char *node; /* name of this node. */
char *prev; /* name of "Prev:" for this node. */
char *next; /* name of "Next:" for this node. */
char *up; /* name of "Up:" for this node. */
int position; /* output file position of this node. */
int line_no; /* defining line in source file. */
char *filename; /* The file that this node was found in. */
int touched; /* non-zero means this node has been referenced. */
int flags; /* Room for growth. Right now, contains 1 bit. */
} TAG_ENTRY;
/* If node-a has a "Next" for node-b, but node-b has no "Prev" for node-a,
we turn on this flag bit in node-b's tag entry. This means that when
it is time to validate node-b, we don't report an additional error
if there was no "Prev" field. */
#define PREV_ERROR 0x1
#define NEXT_ERROR 0x2
#define UP_ERROR 0x4
#define NO_WARN 0x8
#define IS_TOP 0x10
TAG_ENTRY *tag_table = (TAG_ENTRY *) NULL;
#if defined (HAVE_MACROS)
#define ME_RECURSE 0x01
#define ME_QUOTE_ARG 0x02
/* Macro definitions for user-defined commands. */
typedef struct {
char *name; /* Name of the macro. */
char **arglist; /* Args to replace when executing. */
char *body; /* Macro body. */
char *source_file; /* File where this macro is defined. */
int source_lineno; /* Line number within FILENAME. */
int inhibited; /* Non-zero means make find_macro () fail. */
int flags; /* ME_RECURSE, ME_QUOTE_ARG, etc. */
} MACRO_DEF;
void add_macro (), execute_macro ();
MACRO_DEF *find_macro (), *delete_macro ();
#endif /* HAVE_MACROS */
/* Menu reference, *note reference, and validation hacking. */
/* The various references that we know about. */
enum reftype
{
menu_reference, followed_reference
};
/* A structure to remember references with. A reference to a node is
either an entry in a menu, or a cross-reference made with [px]ref. */
typedef struct node_ref
{
struct node_ref *next;
char *node; /* Name of node referred to. */
char *containing_node; /* Name of node containing this reference. */
int line_no; /* Line number where the reference occurs. */
int section; /* Section level where the reference occurs. */
char *filename; /* Name of file where the reference occurs. */
enum reftype type; /* Type of reference, either menu or note. */
} NODE_REF;
/* The linked list of such structures. */
NODE_REF *node_references = (NODE_REF *) NULL;
/* Flag which tells us whether to examine menu lines or not. */
int in_menu = 0;
/* Non-zero means that we have seen "@top" once already. */
int top_node_seen = 0;
/* Non-zero means that we have seen a non-"@top" node already. */
int non_top_node_seen = 0;
/* Flags controlling the operation of the program. */
/* Default is to notify users of bad choices. */
int print_warnings = 1;
/* Default is to check node references. */
int validating = 1;
/* Non-zero means do not output "Node: Foo" for node separations. */
int no_headers = 0;
/* Number of errors that we tolerate on a given fileset. */
int max_error_level = 100;
/* Maximum number of references to a single node before complaining. */
int reference_warning_limit = 1000;
/* Non-zero means print out information about what is going on when it
is going on. */
int verbose_mode = 0;
/* Non-zero means to be relaxed about the input file. This is useful when
we can successfully format the input, but it doesn't strictly match our
somewhat pedantic ideas of correctness. Right now, it affects what
@table and @itemize do without arguments. */
int allow_lax_format = 0;
/* The list of commands that we hack in texinfo. Each one
has an associated function. When the command is encountered in the
text, the associated function is called with START as the argument.
If the function expects arguments in braces, it remembers itself on
the stack. When the corresponding close brace is encountered, the
function is called with END as the argument. */
#define START 0
#define END 1
typedef struct brace_element
{
struct brace_element *next;
COMMAND_FUNCTION *proc;
int pos, line;
} BRACE_ELEMENT;
BRACE_ELEMENT *brace_stack = (BRACE_ELEMENT *) NULL;
/* Forward declarations. */
#if !defined (HAVE_STRDUP)
extern char *strdup ();
#endif /* HAVE_STRDUP */
void print_version_info ();
void usage ();
void push_node_filename (), pop_node_filename ();
void remember_error ();
void convert_from_stream (), convert_from_file (), convert_from_loaded_file ();
void init_internals (), init_paragraph (), init_brace_stack ();
void init_insertion_stack (), init_indices ();
void init_tag_table (), write_tag_table (), write_tag_table_internal ();
void validate_file (), validate_other_references (), split_file ();
void free_node_references (), do_enumeration (), handle_variable ();
void handle_variable_internal ();
void execute_string ();
void normalize_node_name ();
void undefindex (), top_defindex (), gen_defindex ();
void define_user_command ();
void free_pending_notes (), output_pending_notes ();
void reader_loop (), read_command ();
void remember_brace (), remember_brace_1 ();
void pop_and_call_brace (), discard_braces ();
void add_word_args (), add_word (), add_char (), insert (), flush_output ();
void close_paragraph_with_lines (), close_paragraph ();
void ignore_blank_line ();
void do_flush_right_indentation ();
void start_paragraph (), indent ();
void insert_self (), cm_ignore_line ();
void
cm_asterisk (), cm_dots (), cm_bullet (), cm_TeX (),
cm_copyright (), cm_code (), cm_samp (), cm_file (), cm_kbd (),
cm_key (), cm_ctrl (), cm_var (), cm_dfn (), cm_emph (), cm_strong (),
cm_cite (), cm_italic (), cm_bold (), cm_roman (), cm_title (), cm_w (),
cm_refill (), cm_titlefont ();
void
cm_chapter (), cm_unnumbered (), cm_appendix (), cm_top (),
cm_section (), cm_unnumberedsec (), cm_appendixsec (),
cm_subsection (), cm_unnumberedsubsec (), cm_appendixsubsec (),
cm_subsubsection (), cm_unnumberedsubsubsec (), cm_appendixsubsubsec (),
cm_heading (), cm_chapheading (), cm_subheading (), cm_subsubheading (),
cm_majorheading (), cm_raisesections (), cm_lowersections ();
/* All @defxxx commands map to cm_defun (). */
void cm_defun ();
void
cm_node (), cm_menu (), cm_xref (), cm_ftable (), cm_vtable (), cm_pxref (),
cm_inforef (), cm_quotation (), cm_display (), cm_itemize (),
cm_enumerate (), cm_table (), cm_itemx (), cm_noindent (), cm_setfilename (),
cm_br (), cm_sp (), cm_page (), cm_group (), cm_center (), cm_include (),
cm_bye (), cm_item (), cm_end (), cm_infoinclude (), cm_ifinfo (),
cm_kindex (), cm_cindex (), cm_findex (), cm_pindex (), cm_vindex (),
cm_tindex (), cm_asis (), cm_synindex (), cm_printindex (), cm_minus (),
cm_footnote (), cm_force_abbreviated_whitespace (), cm_example (),
cm_smallexample (), cm_lisp (), cm_format (), cm_exdent (), cm_defindex (),
cm_defcodeindex (), cm_sc (), cm_result (), cm_expansion (), cm_equiv (),
cm_print (), cm_error (), cm_point (), cm_today (), cm_flushleft (),
cm_flushright (), cm_smalllisp (), cm_finalout (), cm_math (),
cm_cartouche (), cm_ignore_sentence_ender ();
/* Conditionals. */
void cm_set (), cm_clear (), cm_ifset (), cm_ifclear ();
void cm_value (), cm_ifeq ();
#if defined (HAVE_MACROS)
/* Define a user-defined command which is simple substitution. */
void cm_macro (), cm_unmacro ();
#endif /* HAVE_MACROS */
/* Options. */
void cm_paragraphindent (), cm_footnotestyle ();
/* Internals. */
void do_nothing (), command_name_condition ();
void misplaced_brace (), cm_obsolete ();
typedef struct
{
char *name;
COMMAND_FUNCTION *proc;
int argument_in_braces;
} COMMAND;
/* Stuff for defining commands on the fly. */
COMMAND **user_command_array = (COMMAND **) NULL;
int user_command_array_len = 0;
#define NO_BRACE_ARGS 0
#define BRACE_ARGS 1
static COMMAND CommandTable[] = {
{ "!", cm_ignore_sentence_ender, NO_BRACE_ARGS },
{ "'", insert_self, NO_BRACE_ARGS },
{ "*", cm_asterisk, NO_BRACE_ARGS },
{ ".", cm_ignore_sentence_ender, NO_BRACE_ARGS },
{ ":", cm_force_abbreviated_whitespace, NO_BRACE_ARGS },
{ "?", cm_ignore_sentence_ender, NO_BRACE_ARGS },
{ "|", do_nothing, NO_BRACE_ARGS },
{ "@", insert_self, NO_BRACE_ARGS },
{ " ", insert_self, NO_BRACE_ARGS },
{ "\n", insert_self, NO_BRACE_ARGS },
{ "TeX", cm_TeX, BRACE_ARGS },
{ "`", insert_self, NO_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_asis, BRACE_ARGS },
{ "b", cm_bold, BRACE_ARGS },
{ "br", cm_br, NO_BRACE_ARGS },
{ "bullet", cm_bullet, BRACE_ARGS },
{ "bye", cm_bye, NO_BRACE_ARGS },
{ "c", cm_ignore_line, NO_BRACE_ARGS },
{ "cartouche", cm_cartouche, NO_BRACE_ARGS },
{ "center", cm_center, NO_BRACE_ARGS },
{ "chapheading", cm_chapheading, NO_BRACE_ARGS },
{ "chapter", cm_chapter, NO_BRACE_ARGS },
{ "cindex", cm_cindex, NO_BRACE_ARGS },
{ "cite", cm_cite, BRACE_ARGS },
{ "clear", cm_clear, NO_BRACE_ARGS },
{ "code", cm_code, BRACE_ARGS },
{ "comment", cm_ignore_line, NO_BRACE_ARGS },
{ "contents", do_nothing, NO_BRACE_ARGS },
{ "copyright", cm_copyright, BRACE_ARGS },
{ "ctrl", cm_ctrl, BRACE_ARGS },
{ "defcodeindex", cm_defcodeindex, NO_BRACE_ARGS },
{ "defindex", cm_defindex, NO_BRACE_ARGS },
{ "dfn", cm_dfn, BRACE_ARGS },
/* The `def' commands. */
{ "deffn", cm_defun, NO_BRACE_ARGS },
{ "deffnx", cm_defun, NO_BRACE_ARGS },
{ "defun", cm_defun, NO_BRACE_ARGS },
{ "defunx", cm_defun, NO_BRACE_ARGS },
{ "defmac", cm_defun, NO_BRACE_ARGS },
{ "defmacx", cm_defun, NO_BRACE_ARGS },
{ "defspec", cm_defun, NO_BRACE_ARGS },
{ "defspecx", cm_defun, NO_BRACE_ARGS },
{ "defvr", cm_defun, NO_BRACE_ARGS },
{ "defvrx", cm_defun, NO_BRACE_ARGS },
{ "defvar", cm_defun, NO_BRACE_ARGS },
{ "defvarx", cm_defun, NO_BRACE_ARGS },
{ "defopt", cm_defun, NO_BRACE_ARGS },
{ "defoptx", 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 },
{ "deftypevr", cm_defun, NO_BRACE_ARGS },
{ "deftypevrx", cm_defun, NO_BRACE_ARGS },
{ "deftypevar", cm_defun, NO_BRACE_ARGS },
{ "deftypevarx", cm_defun, NO_BRACE_ARGS },
{ "defcv", cm_defun, NO_BRACE_ARGS },
{ "defcvx", cm_defun, NO_BRACE_ARGS },
{ "defivar", cm_defun, NO_BRACE_ARGS },
{ "defivarx", cm_defun, NO_BRACE_ARGS },
{ "defop", cm_defun, NO_BRACE_ARGS },
{ "defopx", cm_defun, NO_BRACE_ARGS },
{ "defmethod", cm_defun, NO_BRACE_ARGS },
{ "defmethodx", cm_defun, NO_BRACE_ARGS },
{ "deftypemethod", cm_defun, NO_BRACE_ARGS },
{ "deftypemethodx", cm_defun, NO_BRACE_ARGS },
{ "deftp", cm_defun, NO_BRACE_ARGS },
{ "deftpx", cm_defun, NO_BRACE_ARGS },
/* The end of the `def' commands. */
{ "display", cm_display, NO_BRACE_ARGS },
{ "dots", cm_dots, BRACE_ARGS },
{ "dmn", do_nothing, BRACE_ARGS },
{ "emph", cm_emph, BRACE_ARGS },
{ "end", cm_end, NO_BRACE_ARGS },
{ "enumerate", cm_enumerate, NO_BRACE_ARGS },
{ "equiv", cm_equiv, BRACE_ARGS },
{ "error", cm_error, BRACE_ARGS },
{ "example", cm_example, NO_BRACE_ARGS },
{ "exdent", cm_exdent, NO_BRACE_ARGS },
{ "expansion", cm_expansion, BRACE_ARGS },
{ "file", cm_file, BRACE_ARGS },
{ "findex", cm_findex, NO_BRACE_ARGS },
{ "finalout", do_nothing, NO_BRACE_ARGS },
{ "flushleft", cm_flushleft, NO_BRACE_ARGS },
{ "flushright", cm_flushright, 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 },
{ "i", cm_italic, BRACE_ARGS },
{ "iappendix", cm_appendix, NO_BRACE_ARGS },
{ "iappendixsection", cm_appendixsec, NO_BRACE_ARGS },
{ "iappendixsec", cm_appendixsec, NO_BRACE_ARGS },
{ "iappendixsubsec", cm_appendixsubsec, NO_BRACE_ARGS },
{ "iappendixsubsubsec", cm_appendixsubsubsec, NO_BRACE_ARGS },
{ "ichapter", cm_chapter, NO_BRACE_ARGS },
{ "ifclear", cm_ifclear, NO_BRACE_ARGS },
{ "ifeq", cm_ifeq, NO_BRACE_ARGS },
{ "ifhtml", command_name_condition, NO_BRACE_ARGS },
{ "ifinfo", cm_ifinfo, NO_BRACE_ARGS },
{ "ifset", cm_ifset, NO_BRACE_ARGS },
{ "iftex", command_name_condition, NO_BRACE_ARGS },
{ "ignore", command_name_condition, NO_BRACE_ARGS },
{ "include", cm_include, NO_BRACE_ARGS },
{ "inforef", cm_inforef, BRACE_ARGS },
{ "input", cm_include, NO_BRACE_ARGS },
{ "isection", cm_section, NO_BRACE_ARGS },
{ "isubsection", cm_subsection, NO_BRACE_ARGS },
{ "isubsubsection", cm_subsubsection, NO_BRACE_ARGS },
{ "item", cm_item, NO_BRACE_ARGS },
{ "itemize", cm_itemize, NO_BRACE_ARGS },
{ "itemx", cm_itemx, NO_BRACE_ARGS },
{ "iunnumbered", cm_unnumbered, NO_BRACE_ARGS },
{ "iunnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS },
{ "iunnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS },
{ "iunnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS },
{ "kbd", cm_kbd, BRACE_ARGS },
{ "key", cm_key, BRACE_ARGS },
{ "kindex", cm_kindex, NO_BRACE_ARGS },
{ "lowersections", cm_lowersections, NO_BRACE_ARGS },
{ "lisp", cm_lisp, NO_BRACE_ARGS },
#if defined (HAVE_MACROS)
{ "macro", cm_macro, NO_BRACE_ARGS },
#endif
{ "majorheading", cm_majorheading, NO_BRACE_ARGS },
{ "math", cm_math, BRACE_ARGS },
{ "medbreak", cm_br, NO_BRACE_ARGS },
{ "menu", cm_menu, NO_BRACE_ARGS },
{ "minus", cm_minus, BRACE_ARGS },
{ "need", cm_ignore_line, NO_BRACE_ARGS },
{ "node", cm_node, NO_BRACE_ARGS },
{ "noindent", cm_noindent, NO_BRACE_ARGS },
{ "nwnode", cm_node, NO_BRACE_ARGS },
{ "overfullrule", cm_ignore_line, NO_BRACE_ARGS },
{ "page", do_nothing, NO_BRACE_ARGS },
{ "pindex", cm_pindex, NO_BRACE_ARGS },
{ "point", cm_point, BRACE_ARGS },
{ "print", cm_print, BRACE_ARGS },
{ "printindex", cm_printindex, NO_BRACE_ARGS },
{ "pxref", cm_pxref, BRACE_ARGS },
{ "quotation", cm_quotation, NO_BRACE_ARGS },
{ "r", cm_roman, BRACE_ARGS },
{ "raisesections", cm_raisesections, NO_BRACE_ARGS },
{ "ref", cm_xref, BRACE_ARGS },
{ "refill", cm_refill, NO_BRACE_ARGS },
{ "result", cm_result, BRACE_ARGS },
{ "samp", cm_samp, 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_ignore_line, NO_BRACE_ARGS },
{ "setfilename", cm_setfilename, NO_BRACE_ARGS },
{ "settitle", cm_ignore_line, NO_BRACE_ARGS },
{ "shortcontents", do_nothing, NO_BRACE_ARGS },
{ "shorttitlepage", cm_ignore_line, NO_BRACE_ARGS },
{ "smallbook", cm_ignore_line, NO_BRACE_ARGS },
{ "smallbreak", cm_br, NO_BRACE_ARGS },
{ "smallexample", cm_smallexample, NO_BRACE_ARGS },
{ "smalllisp", cm_smalllisp, NO_BRACE_ARGS },
{ "sp", cm_sp, NO_BRACE_ARGS },
{ "strong", cm_strong, BRACE_ARGS },
{ "subheading", cm_subheading, NO_BRACE_ARGS },
{ "subsection", cm_subsection, NO_BRACE_ARGS },
{ "subsubheading", cm_subsubheading, NO_BRACE_ARGS },
{ "subsubsection", cm_subsubsection, NO_BRACE_ARGS },
{ "summarycontents", do_nothing, NO_BRACE_ARGS },
{ "syncodeindex", cm_synindex, NO_BRACE_ARGS },
{ "synindex", cm_synindex, NO_BRACE_ARGS },
{ "t", cm_title, BRACE_ARGS },
{ "table", cm_table, NO_BRACE_ARGS },
{ "tex", command_name_condition, NO_BRACE_ARGS },
{ "tindex", cm_tindex, NO_BRACE_ARGS },
{ "titlefont", cm_titlefont, BRACE_ARGS },
{ "titlepage", command_name_condition, NO_BRACE_ARGS },
{ "titlespec", command_name_condition, NO_BRACE_ARGS },
{ "today", cm_today, BRACE_ARGS },
{ "top", cm_top, NO_BRACE_ARGS },
#if defined (HAVE_MACROS)
{ "unmacro", cm_unmacro, NO_BRACE_ARGS },
#endif
{ "unnumbered", cm_unnumbered, NO_BRACE_ARGS },
{ "unnumberedsec", cm_unnumberedsec, NO_BRACE_ARGS },
{ "unnumberedsubsec", cm_unnumberedsubsec, NO_BRACE_ARGS },
{ "unnumberedsubsubsec", cm_unnumberedsubsubsec, NO_BRACE_ARGS },
{ "value", cm_value, BRACE_ARGS },
{ "var", cm_var, BRACE_ARGS },
{ "vindex", cm_vindex, NO_BRACE_ARGS },
{ "vtable", cm_vtable, NO_BRACE_ARGS },
{ "w", cm_w, BRACE_ARGS },
{ "xref", cm_xref, BRACE_ARGS },
{ "{", insert_self, NO_BRACE_ARGS },
{ "}", insert_self, NO_BRACE_ARGS },
/* Some obsoleted commands. */
{ "infotop", cm_obsolete, NO_BRACE_ARGS },
{ "infounnumbered", cm_obsolete, NO_BRACE_ARGS },
{ "infounnumberedsec", cm_obsolete, NO_BRACE_ARGS },
{ "infounnumberedsubsec", cm_obsolete, NO_BRACE_ARGS },
{ "infounnumberedsubsubsec", cm_obsolete, NO_BRACE_ARGS },
{ "infoappendix", cm_obsolete, NO_BRACE_ARGS },
{ "infoappendixsec", cm_obsolete, NO_BRACE_ARGS },
{ "infoappendixsubsec", cm_obsolete, NO_BRACE_ARGS },
{ "infoappendixsubsubsec", cm_obsolete, NO_BRACE_ARGS },
{ "infochapter", cm_obsolete, NO_BRACE_ARGS },
{ "infosection", cm_obsolete, NO_BRACE_ARGS },
{ "infosubsection", cm_obsolete, NO_BRACE_ARGS },
{ "infosubsubsection", cm_obsolete, NO_BRACE_ARGS },
/* Now @include does what this was supposed to. */
{ "infoinclude", cm_infoinclude, NO_BRACE_ARGS },
{ "footnote", cm_footnote, NO_BRACE_ARGS}, /* self-arg eater */
{ "footnotestyle", cm_footnotestyle, NO_BRACE_ARGS },
{ "paragraphindent", cm_paragraphindent, NO_BRACE_ARGS },
{(char *) NULL, (COMMAND_FUNCTION *) NULL}, NO_BRACE_ARGS};
int major_version = 1;
int minor_version = 64;
struct option long_options[] =
{
{ "error-limit", 1, 0, 'e' }, /* formerly -el */
{ "fill-column", 1, 0, 'f' }, /* formerly -fc */
{ "footnote-style", 1, 0, 's' }, /* formerly -ft */
{ "no-headers", 0, &no_headers, 1 }, /* Do not output Node: foo */
{ "no-pointer-validate", 0, &validating, 0 }, /* formerly -nv */
{ "no-validate", 0, &validating, 0 }, /* formerly -nv */
{ "no-split", 0, &splitting, 0 }, /* formerly -ns */
{ "no-warn", 0, &print_warnings, 0 }, /* formerly -nw */
#if defined (HAVE_MACROS)
{ "macro-expand", 1, 0, 'E' },
#endif /* HAVE_MACROS */
{ "number-footnotes", 0, &number_footnotes, 1 },
{ "no-number-footnotes", 0, &number_footnotes, 0 },
{ "output", 1, 0, 'o' },
{ "paragraph-indent", 1, 0, 'p' }, /* formerly -pi */
{ "reference-limit", 1, 0, 'r' }, /* formerly -rl */
{ "verbose", 0, &verbose_mode, 1 }, /* formerly -verbose */
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'V' },
{NULL, 0, NULL, 0}
};
/* Values for calling handle_variable_internal (). */
#define SET 1
#define CLEAR 2
#define IFSET 3
#define IFCLEAR 4
/* **************************************************************** */
/* */
/* Main () Start of code */
/* */
/* **************************************************************** */
/* For each file mentioned in the command line, process it, turning
texinfo commands into wonderfully formatted output text. */
int
main (argc, argv)
int argc;
char **argv;
{
extern int errors_printed;
char *filename_part ();
int c, ind;
int reading_from_stdin = 0;
/* The name of this program is the last filename in argv[0]. */
progname = filename_part (argv[0]);
/* Parse argument flags from the input line. */
while ((c = getopt_long
(argc, argv,
#if defined (HAVE_MACROS)
"D:E:U:I:f:o:p:e:r:s:V",
#else
"D:U:I:f:o:p:e:r:s:V",
#endif /* !HAVE_MACROS */
long_options, &ind))
!= EOF)
{
if (c == 0 && long_options[ind].flag == 0)
c = long_options[ind].val;
switch (c)
{
/* User specified variable to set or clear? */
case 'D':
case 'U':
handle_variable_internal ((c == 'D') ? SET : CLEAR, optarg);
break;
#if defined (HAVE_MACROS)
/* Use specified a macro expansion output file? */
case 'E':
if (!macro_expansion_output_stream)
{
macro_expansion_output_stream = fopen (optarg, "w");
if (!macro_expansion_output_stream)
error ("Couldn't open macro expansion output \"%s\"", optarg);
}
else
error ("Cannot specify more than one macro expansion output");
break;
#endif /* HAVE_MACROS */
/* User specified include file path? */
case 'I':
if (!include_files_path)
include_files_path = strdup (".");
include_files_path = (char *)
xrealloc (include_files_path,
2 + strlen (include_files_path) + strlen (optarg));
strcat (include_files_path, ":");
strcat (include_files_path, optarg);
break;
/* User specified fill_column? */
case 'f':
if (sscanf (optarg, "%d", &fill_column) != 1)
usage (stderr, FATAL);
break;
/* User specified output file? */
case 'o':
command_output_filename = strdup (optarg);
break;
/* User specified paragraph indent (paragraph_start_index)? */
case 'p':
if (set_paragraph_indent (optarg) < 0)
usage (stderr, FATAL);
break;
/* User specified error level? */
case 'e':
if (sscanf (optarg, "%d", &max_error_level) != 1)
usage (stderr, FATAL);
break;
/* User specified reference warning limit? */
case 'r':
if (sscanf (optarg, "%d", &reference_warning_limit) != 1)
usage (stderr, FATAL);
break;
/* User specified footnote style? */
case 's':
if (set_footnote_style (optarg) < 0)
usage (stderr, FATAL);
footnote_style_preset = 1;
break;
case 'h':
usage (stdout, NO_ERROR);
break;
/* User requested version info? */
case 'V':
print_version_info ();
exit (NO_ERROR);
break;
case '?':
usage (stderr, FATAL);
break;
}
}
if (optind == argc)
{
/* Check to see if input is a file. If so, process that. */
if (!isatty (fileno (stdin)))
reading_from_stdin = 1;
else
usage (stderr, FATAL);
}
/* If the user has specified --no-headers, this should imply --no-split.
Do that here. I think it might also imply that we should ignore the
setfilename at the top of the file, but this might break some FSF things,
so I will hold off on that. */
if (no_headers)
{
splitting = 0;
/* If the user has not specified an output file, then use stdout by
default. */
if (!command_output_filename)
command_output_filename = strdup ("-");
}
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");
if (errors_printed)
return (SYNTAX);
else
return (NO_ERROR);
}
/* Display the version info of this invocation of Makeinfo. */
void
print_version_info ()
{
printf ("This is GNU Makeinfo version %d.%d, from texinfo-3.7.\n",
major_version, minor_version);
}
/* **************************************************************** */
/* */
/* Generic Utilities */
/* */
/* **************************************************************** */
#if !defined (HAVE_STRDUP)
char *
strdup (string)
char *string;
{
char *result;
result = (char *)xmalloc (1 + strlen (string));
strcpy (result, string);
return (result);
}
#endif /* !HAVE_STRDUP */
static void
memory_error (callers_name, bytes_wanted)
char *callers_name;
int bytes_wanted;
{
char printable_string[80];
sprintf (printable_string,
"Virtual memory exhausted in %s ()! Needed %d bytes.",
callers_name, bytes_wanted);
error (printable_string);
abort ();
}
/* Just like malloc, but kills the program in case of fatal error. */
void *
xmalloc (nbytes)
unsigned int nbytes;
{
void *temp = (void *) malloc (nbytes);
if (nbytes && temp == (void *)NULL)
memory_error ("xmalloc", nbytes);
return (temp);
}
/* Like realloc (), but barfs if there isn't enough memory. */
void *
xrealloc (pointer, nbytes)
void *pointer;
unsigned int nbytes;
{
void *temp;
if (!pointer)
temp = (void *)xmalloc (nbytes);
else
temp = (void *)realloc (pointer, nbytes);
if (nbytes && !temp)
memory_error ("xrealloc", nbytes);
return (temp);
}
/* Tell the user how to use this program.
Print the message to STREAM, and then exit with EXIT_VALUE. */
void
usage (stream, exit_value)
FILE *stream;
int exit_value;
{
fprintf (stream, "Usage: %s [options] texinfo-file...\n\
\n\
This program accepts as input files of texinfo commands and text\n\
and outputs a file suitable for reading with GNU Info.\n\
\n\
Options:\n\
`-I DIR' add DIR to the directory search list for including\n\
files with the `@include' command.\n\
-D VAR define a variable, as with `@set'.\n\
-U VAR undefine a variable, as with `@clear'.\n\
-E MACRO-OFILE process macros, and output texinfo source code for TeX.\n\
--no-validate suppress node cross reference validation.\n\
--no-warn suppress warning messages (errors are still output).\n\
--no-split suppress the splitting of large files.\n\
--no-headers suppress the output of Node: Foo headers.\n\
--verbose print information about what is being done.\n\
--version print the version number of Makeinfo.\n\
--output FILE or -o FILE\n\
specify the output file. When you specify the\n\
output file in this way, any `@setfilename' in the\n\
input file is ignored.\n\
--paragraph-indent NUM\n\
set the paragraph indent to NUM (default %d).\n\
--fill-column NUM set the filling column to NUM (default %d).\n\
--error-limit NUM set the error limit to NUM (default %d).\n\
--reference-limit NUM\n\
set the reference warning limit to NUM (default %d).\n\
--footnote-style STYLE\n\
set the footnote style to STYLE. STYLE should\n\
either be `separate' to place footnotes in their own\n\
node, or `end', to place the footnotes at the end of\n\
the node in which they are defined (the default).\n\
--help print this message and exit.\n\n",
progname, paragraph_start_indent,
fill_column, max_error_level, reference_warning_limit);
exit (exit_value);
}
/* **************************************************************** */
/* */
/* Manipulating Lists */
/* */
/* **************************************************************** */
typedef struct generic_list {
struct generic_list *next;
} GENERIC_LIST;
/* Reverse the chain of structures in LIST. Output the new head
of the chain. You should always assign the output value of this
function to something, or you will lose the chain. */
GENERIC_LIST *
reverse_list (list)
register GENERIC_LIST *list;
{
register GENERIC_LIST *next;
register GENERIC_LIST *prev = (GENERIC_LIST *) NULL;
while (list)
{
next = list->next;
list->next = prev;
prev = list;
list = next;
}
return (prev);
}
/* **************************************************************** */
/* */
/* Pushing and Popping Files */
/* */
/* **************************************************************** */
/* Find and load the file named FILENAME. Return a pointer to
the loaded file, or NULL if it can't be loaded. */
char *
find_and_load (filename)
char *filename;
{
struct stat fileinfo;
long file_size;
int file = -1, n, i, count = 0;
char *fullpath, *result, *get_file_info_in_path ();
result = fullpath = (char *)NULL;
fullpath = get_file_info_in_path (filename, include_files_path, &fileinfo);
if (!fullpath)
goto error_exit;
filename = fullpath;
file_size = (long) fileinfo.st_size;
file = open (filename, O_RDONLY);
if (file < 0)
goto error_exit;
/* Load the file. */
result = (char *)xmalloc (1 + file_size);
/* VMS stat lies about the st_size value. The actual number of
readable bytes is always less than this value. The arcane
mysteries of VMS/RMS are too much to probe, so this hack
suffices to make things work. */
#if defined (VMS)
while ((n = read (file, result + count, file_size)) > 0)
count += n;
if (n == -1)
#else /* !VMS */
count = file_size;
if (read (file, result, file_size) != file_size)
#endif /* !VMS */
error_exit:
{
if (result)
free (result);
if (fullpath)
free (fullpath);
if (file != -1)
close (file);
return ((char *) NULL);
}
close (file);
/* Set the globals to the new file. */
input_text = result;
size_of_input_text = count;
input_filename = fullpath;
node_filename = strdup (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).
The SIZE_OF_INPUT_TEXT is one past the actual end of the text. */
input_text[size_of_input_text] = '\n';
return (result);
}
/* Save the state of the current input file. */
void
pushfile ()
{
FSTACK *newstack = (FSTACK *) xmalloc (sizeof (FSTACK));
newstack->filename = input_filename;
newstack->text = input_text;
newstack->size = size_of_input_text;
newstack->offset = input_text_offset;
newstack->line_number = line_number;
newstack->next = filestack;
filestack = newstack;
push_node_filename ();
}
/* Make the current file globals be what is on top of the file stack. */
void
popfile ()
{
FSTACK *tos = filestack;
if (!tos)
abort (); /* My fault. I wonder what I did? */
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
{
maybe_write_itext (input_text, input_text_offset);
forget_itext (input_text);
}
#endif /* HAVE_MACROS */
/* Pop the stack. */
filestack = filestack->next;
/* Make sure that commands with braces have been satisfied. */
if (!executing_string)
discard_braces ();
/* Get the top of the stack into the globals. */
input_filename = tos->filename;
input_text = tos->text;
size_of_input_text = tos->size;
input_text_offset = tos->offset;
line_number = tos->line_number;
free (tos);
/* Go back to the (now) current node. */
pop_node_filename ();
}
/* Flush all open files on the file stack. */
void
flush_file_stack ()
{
while (filestack)
{
char *fname = input_filename;
char *text = input_text;
popfile ();
free (fname);
free (text);
}
}
int node_filename_stack_index = 0;
int node_filename_stack_size = 0;
char **node_filename_stack = (char **)NULL;
void
push_node_filename ()
{
if (node_filename_stack_index + 1 > node_filename_stack_size)
{
if (!node_filename_stack)
node_filename_stack =
(char **)xmalloc ((node_filename_stack_size += 10)
* sizeof (char *));
else
node_filename_stack =
(char **)xrealloc (node_filename_stack,
(node_filename_stack_size + 10)
* sizeof (char *));
}
node_filename_stack[node_filename_stack_index] = node_filename;
node_filename_stack_index++;
}
void
pop_node_filename ()
{
node_filename = node_filename_stack[--node_filename_stack_index];
}
/* Return just the simple part of the filename; i.e. the
filename without the path information, or extensions.
This conses up a new string. */
char *
filename_part (filename)
char *filename;
{
char *basename;
basename = strrchr (filename, '/');
if (!basename)
basename = filename;
else
basename++;
basename = strdup (basename);
#if defined (REMOVE_OUTPUT_EXTENSIONS)
/* See if there is an extension to remove. If so, remove it. */
{
char *temp;
temp = strrchr (basename, '.');
if (temp)
*temp = '\0';
}
#endif /* REMOVE_OUTPUT_EXTENSIONS */
return (basename);
}
/* Return the pathname part of filename. This can be NULL. */
char *
pathname_part (filename)
char *filename;
{
char *expand_filename ();
char *result = (char *) NULL;
register int i;
filename = expand_filename (filename, "");
i = strlen (filename) - 1;
while (i && filename[i] != '/')
i--;
if (filename[i] == '/')
i++;
if (i)
{
result = (char *)xmalloc (1 + i);
strncpy (result, filename, i);
result[i] = '\0';
}
free (filename);
return (result);
}
char *
filename_non_directory (name)
char *name;
{
register int i;
for (i = strlen (name) - 1; i; i--)
if (name[i] == '/')
return (strdup (name + i + 1));
return (strdup (name));
}
/* Return the expansion of FILENAME. */
char *
expand_filename (filename, input_name)
char *filename, *input_name;
{
register int i;
char *full_pathname ();
if (filename)
filename = full_pathname (filename);
else
{
filename = filename_non_directory (input_name);
if (!*filename)
{
free (filename);
filename = strdup ("noname.texi");
}
for (i = strlen (filename) - 1; i; i--)
if (filename[i] == '.')
break;
if (!i)
i = strlen (filename);
if (i + 6 > (strlen (filename)))
filename = (char *)xrealloc (filename, i + 6);
strcpy (filename + i, ".info");
return (filename);
}
if (filename[0] == '.' || filename[0] == '/')
return (filename);
if (filename[0] != '/' && input_name[0] == '/')
{
/* Make it so that relative names work. */
char *result;
i = strlen (input_name) - 1;
result = (char *)xmalloc (1 + strlen (input_name) + strlen (filename));
strcpy (result, input_name);
while (result[i] != '/' && i)
i--;
if (result[i] == '/')
i++;
strcpy (&result[i], filename);
free (filename);
return (result);
}
return (filename);
}
/* Return the full path to FILENAME. */
char *
full_pathname (filename)
char *filename;
{
int initial_character;
char *result;
/* No filename given? */
if (!filename || !(initial_character = *filename))
return (strdup (""));
/* Already absolute? */
if ((initial_character == '/') ||
((strncmp (filename, "./", 2) == 0) ||
(strncmp (filename, "../", 3) == 0)))
return (strdup (filename));
if (initial_character != '~')
{
char *localdir;
localdir = (char *)xmalloc (1025);
#if defined (HAVE_GETCWD)
if (!getcwd (localdir, 1024))
#else /* !HAVE_GETCWD */
if (!getwd (localdir))
#endif /* !HAVE_GETCWD */
{
fprintf (stderr, "%s: getwd: %s, %s\n",
progname, filename, localdir);
exit (1);
}
strcat (localdir, "/");
strcat (localdir, filename);
result = strdup (localdir);
free (localdir);
}
else
{
if (filename[1] == '/')
{
/* Return the concatenation of the environment variable HOME
and the rest of the string. */
char *temp_home;
temp_home = (char *) getenv ("HOME");
result = (char *)xmalloc (strlen (&filename[1])
+ 1
+ temp_home ? strlen (temp_home)
: 0);
*result = '\0';
if (temp_home)
strcpy (result, temp_home);
strcat (result, &filename[1]);
}
else
{
struct passwd *user_entry;
int i, c;
char *username = (char *)xmalloc (257);
for (i = 1; c = filename[i]; i++)
{
if (c == '/')
break;
else
username[i - 1] = c;
}
if (c)
username[i - 1] = '\0';
user_entry = getpwnam (username);
if (!user_entry)
return (strdup (filename));
result = (char *)xmalloc (1 + strlen (user_entry->pw_dir)
+ strlen (&filename[i]));
strcpy (result, user_entry->pw_dir);
strcat (result, &filename[i]);
}
}
return (result);
}
char *
output_name_from_input_name (name)
char *name;
{
return (expand_filename ((char *)NULL, name));
}
/* **************************************************************** */
/* */
/* Error Handling */
/* */
/* **************************************************************** */
/* Number of errors encountered. */
int errors_printed = 0;
/* Print the last error gotten from the file system. */
int
fs_error (filename)
char *filename;
{
remember_error ();
perror (filename);
return (0);
}
/* Print an error message, and return false. */
#if defined (HAVE_VARARGS_H) && defined (HAVE_VFPRINTF)
int
error (va_alist)
va_dcl
{
char *format;
va_list args;
remember_error ();
va_start (args);
format = va_arg (args, char *);
vfprintf (stderr, format, args);
va_end (args);
fprintf (stderr, "\n");
}
/* Just like error (), but print the line number as well. */
int
line_error (va_alist)
va_dcl
{
char *format;
va_list args;
remember_error ();
va_start (args);
format = va_arg (args, char *);
fprintf (stderr, "%s:%d: ", input_filename, line_number);
vfprintf (stderr, format, args);
fprintf (stderr, ".\n");
va_end (args);
return ((int) 0);
}
int
warning (va_alist)
va_dcl
{
char *format;
va_list args;
va_start (args);
format = va_arg (args, char *);
if (print_warnings)
{
fprintf (stderr, "%s:%d: Warning: ", input_filename, line_number);
vfprintf (stderr, format, args);
fprintf (stderr, ".\n");
}
va_end (args);
return ((int) 0);
}
#else /* !(HAVE_VARARGS_H && HAVE_VFPRINTF) */
int
error (format, arg1, arg2, arg3, arg4, arg5)
char *format;
{
remember_error ();
fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
fprintf (stderr, "\n");
return ((int) 0);
}
/* Just like error (), but print the line number as well. */
int
line_error (format, arg1, arg2, arg3, arg4, arg5)
char *format;
{
remember_error ();
fprintf (stderr, "%s:%d: ", input_filename, line_number);
fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
fprintf (stderr, ".\n");
return ((int) 0);
}
int
warning (format, arg1, arg2, arg3, arg4, arg5)
char *format;
{
if (print_warnings)
{
fprintf (stderr, "%s:%d: Warning: ", input_filename, line_number);
fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
fprintf (stderr, ".\n");
}
return ((int) 0);
}
#endif /* !(HAVE_VARARGS_H && HAVE_VFPRINTF) */
/* Remember that an error has been printed. If this is the first
error printed, then tell them which program is printing them.
If more than max_error_level have been printed, then exit the
program. */
void
remember_error ()
{
errors_printed++;
if (max_error_level && (errors_printed > max_error_level))
{
fprintf (stderr, "Too many errors! Gave up.\n");
flush_file_stack ();
cm_bye ();
exit (1);
}
}
/* **************************************************************** */
/* */
/* Hacking Tokens and Strings */
/* */
/* **************************************************************** */
/* Return the next token as a string pointer. We cons the
string. */
char *
read_token ()
{
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 = strdup (" ");
*result = character;
return (result);
}
for (i = 0; ((input_text_offset != size_of_input_text)
&& (character = curchar ())
&& command_char (character));
i++, input_text_offset++);
result = (char *)xmalloc (i + 1);
memcpy (result, &input_text[input_text_offset - i], i);
result[i] = '\0';
return (result);
}
/* Return non-zero if CHARACTER is self-delimiting. */
int
self_delimiting (character)
int character;
{
return (member (character, "{}:.@*'`,!?; \n\t"));
}
/* Clear whitespace from the front and end of string. */
void
canon_white (string)
char *string;
{
int len = strlen (string);
int x;
if (!len)
return;
for (x = 0; x < len; x++)
{
if (!cr_or_whitespace (string[x]))
{
strcpy (string, string + x);
break;
}
}
len = strlen (string);
if (len)
len--;
while (len > -1 && cr_or_whitespace (string[len]))
len--;
string[len + 1] = '\0';
}
/* Bash STRING, replacing all whitespace with just one space. */
void
fix_whitespace (string)
char *string;
{
char *temp = (char *)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 (string)
char *string;
{
int temp = search_forward (string, input_text_offset);
int tt = (temp < 0) ? size_of_input_text : 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)
{
input_text_offset = size_of_input_text - strlen (string);
if (strcmp (string, "\n") != 0)
{
line_error ("Expected `%s'", string);
return;
}
}
else
input_text_offset = temp;
input_text_offset += 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 (match, string)
char *match, **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 = size_of_input_text;
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 = (char *)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 > size_of_input_text)
input_text_offset = size_of_input_text;
return (new_point);
}
/* Read characters from the file until we are at MATCH or end of line.
Place the characters read into STRING. */
void
get_until_in_line (match, string)
char *match, **string;
{
int real_bottom, temp;
real_bottom = size_of_input_text;
temp = search_forward ("\n", input_text_offset);
if (temp < 0)
temp = size_of_input_text;
size_of_input_text = temp;
get_until (match, string);
size_of_input_text = real_bottom;
}
void
get_rest_of_line (string)
char **string;
{
get_until ("\n", string);
canon_white (*string);
if (curchar () == '\n') /* as opposed to the end of the file... */
{
line_number++;
input_text_offset++;
}
}
/* Backup the input pointer to the previous character, keeping track
of the current line number. */
void
backup_input_pointer ()
{
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 (match, string)
char *match, **string;
{
int i, brace = 0;
int match_len = strlen (match);
char *temp;
for (i = input_text_offset; i < size_of_input_text; i++)
{
if (input_text[i] == '{')
brace++;
else if (input_text[i] == '}')
brace--;
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 = (char *)xmalloc (2 + match_len);
strncpy (temp, input_text + input_text_offset, match_len);
temp[match_len] = '\0';
input_text_offset = i;
*string = temp;
}
/* **************************************************************** */
/* */
/* Converting the 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[] = {
"",
".texinfo",
".texi",
".txinfo",
(char *)NULL
};
void
initialize_conversion ()
{
init_tag_table ();
init_indices ();
init_internals ();
init_paragraph ();
}
/* 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. */
void
convert_from_stream (stream, name)
FILE *stream;
char *name;
{
char *buffer = (char *)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);
exit (FATAL);
}
buffer_offset += count;
if (count == 0)
break;
}
/* Set the globals to the new file. */
input_text = buffer;
size_of_input_text = buffer_offset;
input_filename = strdup (name);
node_filename = strdup (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 SIZE_OF_INPUT_TEXT is one past the actual end of the text. */
input_text[size_of_input_text] = '\n';
convert_from_loaded_file (name);
}
void
convert_from_file (name)
char *name;
{
register int i;
char *filename = (char *)xmalloc (strlen (name) + 50);
initialize_conversion ();
/* Try to load the file specified by NAME. If the file isn't found, and
there is no suffix in NAME, then try NAME.texinfo, and NAME.texi. */
for (i = 0; suffixes[i]; i++)
{
strcpy (filename, name);
strcat (filename, suffixes[i]);
if (find_and_load (filename))
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);
}
void
convert_from_loaded_file (name)
char *name;
{
char *expand_filename (), *filename_part ();
char *real_output_filename = (char *)NULL;
#if defined (HAVE_MACROS)
remember_itext (input_text, 0);
#endif /* HAVE_MACROS */
/* Search this file looking for the special string which starts conversion.
Once found, we may truly begin. */
input_text_offset = 0;
while (input_text_offset >= 0)
{
input_text_offset =
search_forward (setfilename_search, input_text_offset);
if ((input_text_offset == 0) ||
((input_text_offset > 0) &&
(input_text[input_text_offset -1] == '\n')))
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
register int i, end_of_first_line;
/* Find the end of the first line in the file. */
for (i = 0; i < size_of_input_text - 1; i++)
if (input_text[i] == '\n')
break;
end_of_first_line = i + 1;
input_text_offset = 0;
for (i = 0; i < end_of_first_line; i++)
{
if ((input_text[i] == '\\') &&
(strncmp (input_text + i + 1, "include", 7) == 0))
{
input_text_offset = end_of_first_line;
break;
}
}
command_output_filename = output_name_from_input_name (name);
#endif /* !REQUIRE_SETFILENAME */
}
}
else
input_text_offset += strlen (setfilename_search);
if (!command_output_filename)
get_until ("\n", &output_filename);
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 = (char *)NULL;
}
canon_white (output_filename);
if (real_output_filename &&
strcmp (real_output_filename, "-") == 0)
{
real_output_filename = strdup (real_output_filename);
output_stream = stdout;
splitting = 0; /* Cannot split when writing to stdout. */
}
else
{
if (!real_output_filename)
real_output_filename = expand_filename (output_filename, name);
else
real_output_filename = strdup (real_output_filename);
output_stream = fopen (real_output_filename, "w");
}
if (output_stream != stdout)
printf ("Making info file `%s' from `%s'.\n", output_filename, name);
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. */
if (output_stream != stdout)
pretty_output_filename = filename_part (output_filename);
else
pretty_output_filename = strdup ("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++;
}
if (!no_headers)
{
add_word_args ("This is Info file %s, produced by Makeinfo-%d.%d from ",
output_filename, major_version, minor_version);
add_word_args ("the input file %s.\n", input_filename);
}
close_paragraph ();
reader_loop ();
finished:
close_paragraph ();
flush_file_stack ();
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
fclose (macro_expansion_output_stream);
#endif /* HAVE_MACROS */
if (output_stream != NULL)
{
output_pending_notes ();
free_pending_notes ();
if (tag_table != NULL)
{
tag_table = (TAG_ENTRY *) reverse_list (tag_table);
if (!no_headers)
write_tag_table ();
}
if (output_stream != stdout)
fclose (output_stream);
/* If validating, then validate the entire file right now. */
if (validating)
validate_file (tag_table);
/* This used to test && !errors_printed.
But some files might have legit warnings. So split anyway. */
if (splitting)
split_file (real_output_filename, 0);
}
free (real_output_filename);
}
void
free_and_clear (pointer)
char **pointer;
{
if ((*pointer) != (char *) NULL)
{
free (*pointer);
*pointer = (char *) NULL;
}
}
/* Initialize some state. */
void
init_internals ()
{
free_and_clear (¤t_node);
free_and_clear (&output_filename);
free_and_clear (&command);
free_and_clear (&input_filename);
free_node_references ();
init_insertion_stack ();
init_brace_stack ();
command_index = 0;
in_menu = 0;
top_node_seen = 0;
non_top_node_seen = 0;
}
void
init_paragraph ()
{
free_and_clear (&output_paragraph);
output_paragraph = (unsigned char *)xmalloc (paragraph_buffer_len);
output_position = 0;
output_paragraph[0] = '\0';
output_paragraph_offset = 0;
output_column = 0;
paragraph_is_open = 0;
current_indent = 0;
}
/* Okay, we are ready to start the conversion. Call the reader on
some text, and fill the text as it is output. Handle commands by
remembering things like open braces and the current file position on a
stack, and when the corresponding close brace is found, you can call
the function with the proper arguments. */
void
reader_loop ()
{
int character;
int done = 0;
int dash_count = 0;
while (!done)
{
if (input_text_offset >= size_of_input_text)
break;
character = curchar ();
if (!in_fixed_width_font &&
(character == '\'' || character == '`') &&
input_text[input_text_offset + 1] == character)
{
input_text_offset++;
character = '"';
}
if (character == '-')
{
dash_count++;
if (dash_count == 2 && !in_fixed_width_font)
{
input_text_offset++;
continue;
}
}
else
{
dash_count = 0;
}
/* If this is a whitespace character, then check to see if the line
is blank. If so, advance to the carriage return. */
if (whitespace (character))
{
register int i = input_text_offset + 1;
while (i < size_of_input_text && whitespace (input_text[i]))
i++;
if (i == size_of_input_text || input_text[i] == '\n')
{
if (i == size_of_input_text)
i--;
input_text_offset = i;
character = curchar ();
}
}
if (character == '\n')
{
line_number++;
/* Check for a menu entry here, since the "escape sequence"
that begins menu entrys is "\n* ". */
if (in_menu && input_text_offset + 1 < size_of_input_text)
{
char *glean_node_from_menu (), *tem;
/* Note that the value of TEM is discarded, since it is
gauranteed to be NULL when glean_node_from_menu () is
called with a non-zero argument. */
tem = glean_node_from_menu (1);
}
}
switch (character)
{
case COMMAND_PREFIX:
read_command ();
break;
case '{':
/* Special case. I'm not supposed to see this character by itself.
If I do, it means there is a syntax error in the input text.
Report the error here, but remember this brace on the stack so
you can ignore its partner. */
line_error ("Misplaced `{'");
remember_brace (misplaced_brace);
/* Don't advance input_text_offset since this happens in
remember_brace ().
input_text_offset++;
*/
break;
case '}':
pop_and_call_brace ();
input_text_offset++;
break;
default:
add_char (character);
input_text_offset++;
}
}
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
maybe_write_itext (input_text, input_text_offset);
#endif /* HAVE_MACROS */
}
/* Find the command corresponding to STRING. If the command
is found, return a pointer to the data structure. Otherwise
return (-1). */
COMMAND *
get_command_entry (string)
char *string;
{
register int i;
for (i = 0; CommandTable[i].name; i++)
if (strcmp (CommandTable[i].name, string) == 0)
return (&CommandTable[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]);
/* Nope, 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. */
void
read_command ()
{
COMMAND *entry;
input_text_offset++;
free_and_clear (&command);
command = read_token ();
#if defined (HAVE_MACROS)
/* Check to see if this command is a macro. If so, execute it here. */
{
MACRO_DEF *def;
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;
execute_macro (def);
if (!(def->flags & ME_RECURSE))
def->inhibited = 0;
return;
}
}
#endif /* HAVE_MACROS */
entry = get_command_entry (command);
if (entry == (COMMAND *)-1)
{
line_error ("Unknown info command `%s'", command);
return;
}
if (entry->argument_in_braces)
remember_brace (entry->proc);
(*(entry->proc)) (START, output_paragraph_offset, 0);
}
/* Return the string which invokes PROC; a pointer to a function. */
char *
find_proc_name (proc)
COMMAND_FUNCTION *proc;
{
register int i;
for (i = 0; CommandTable[i].name; i++)
if (proc == CommandTable[i].proc)
return (CommandTable[i].name);
return ("NO_NAME!");
}
void
init_brace_stack ()
{
brace_stack = (BRACE_ELEMENT *) NULL;
}
void
remember_brace (proc)
COMMAND_FUNCTION *proc;
{
if (curchar () != '{')
line_error ("%c%s expected `{..}'", COMMAND_PREFIX, command);
else
input_text_offset++;
remember_brace_1 (proc, output_paragraph_offset);
}
/* Remember the current output position here. Save PROC
along with it so you can call it later. */
void
remember_brace_1 (proc, position)
COMMAND_FUNCTION *proc;
int position;
{
BRACE_ELEMENT *new = (BRACE_ELEMENT *) xmalloc (sizeof (BRACE_ELEMENT));
new->next = brace_stack;
new->proc = proc;
new->pos = position;
new->line = line_number;
brace_stack = new;
}
/* Pop the top of the brace stack, and call the associated function
with the args END and POS. */
void
pop_and_call_brace ()
{
BRACE_ELEMENT *temp;
COMMAND_FUNCTION *proc;
int pos;
if (brace_stack == (BRACE_ELEMENT *) NULL)
{
line_error ("Unmatched close brace");
return;
}
pos = brace_stack->pos;
proc = brace_stack->proc;
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. */
void
adjust_braces_following (here, amount)
int here, amount;
{
register BRACE_ELEMENT *stack = brace_stack;
while (stack)
{
if (stack->pos >= here)
stack->pos += amount;
stack = stack->next;
}
}
/* 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 ()
{
if (!brace_stack)
return;
while (brace_stack)
{
if (brace_stack->proc != misplaced_brace)
{
char *proc_name;
int temp_line_number = line_number;
line_number = brace_stack->line;
proc_name = find_proc_name (brace_stack->proc);
line_error ("%c%s missing close brace", COMMAND_PREFIX, proc_name);
line_number = temp_line_number;
pop_and_call_brace ();
}
else
{
BRACE_ELEMENT *temp;
temp = brace_stack->next;
free (brace_stack);
brace_stack = temp;
}
}
}
int
get_char_len (character)
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:
if (character < ' ')
len = 2;
else
len = 1;
}
return (len);
}
#if defined (HAVE_VARARGS_H) && defined (HAVE_VSPRINTF)
void
add_word_args (va_alist)
va_dcl
{
char buffer[1000];
char *format;
va_list args;
va_start (args);
format = va_arg (args, char *);
vsprintf (buffer, format, args);
va_end (args);
add_word (buffer);
}
#else /* !(HAVE_VARARGS_H && HAVE_VSPRINTF) */
void
add_word_args (format, arg1, arg2, arg3, arg4, arg5)
char *format;
{
char buffer[1000];
sprintf (buffer, format, arg1, arg2, arg3, arg4, arg5);
add_word (buffer);
}
#endif /* !(HAVE_VARARGS_H && HAVE_VSPRINTF) */
/* Add STRING to output_paragraph. */
void
add_word (string)
char *string;
{
while (*string)
add_char (*string++);
}
/* Non-zero if the last character inserted has the syntax class of NEWLINE. */
int last_char_was_newline = 1;
/* The actual last inserted character. Note that this may be something
other than NEWLINE even if last_char_was_newline is 1. */
int last_inserted_character = 0;
/* Non-zero means that a newline character has already been
inserted, so close_paragraph () should insert one less. */
int line_already_broken = 0;
/* When non-zero we have finished an insertion (see end_insertion ()) and we
want to ignore false continued paragraph closings. */
int insertion_paragraph_closed = 0;
/* Non-zero means attempt to make all of the lines have fill_column width. */
int do_justification = 0;
/* Add the character to the current paragraph. If filling_enabled is
non-zero, then do filling as well. */
void
add_char (character)
int character;
{
/* If we are avoiding outputting headers, and we are currently
in a menu, then simply return. */
if (no_headers && in_menu)
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 && member (character, " \t\n"))
character = ' ' | 0x80;
insertion_paragraph_closed = 0;
switch (character)
{
case '\n':
if (!filling_enabled)
{
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 /* CHARACTER is newline, and filling is enabled. */
{
if (sentence_ender (last_inserted_character))
{
insert (' ');
output_column++;
last_inserted_character = character;
}
}
if (last_char_was_newline)
{
close_paragraph ();
pending_indent = 0;
}
else
{
last_char_was_newline = 1;
insert (' ');
output_column++;
}
break;
default:
{
int len = get_char_len (character);
int suppress_insert = 0;
if ((character == ' ') && (last_char_was_newline))
{
if (!paragraph_is_open)
{
pending_indent++;
return;
}
}
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;
}
if ((output_column += len) > fill_column)
{
if (filling_enabled)
{
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--;
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)));
strncpy ((char *) &output_paragraph[temp],
(char *) &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)
{
int buffer_len = ((output_paragraph_offset - temp)
+ current_indent);
char *temp_buffer = (char *)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++] = ' ';
strncpy ((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;
}
strncpy ((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;
}
}
}
/* Insert CHARACTER into OUTPUT_PARAGRAPH. */
void
insert (character)
int character;
{
output_paragraph[output_paragraph_offset++] = character;
if (output_paragraph_offset == paragraph_buffer_len)
{
output_paragraph =
xrealloc (output_paragraph, (paragraph_buffer_len += 100));
}
}
/* 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 (count)
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;
}
}
/* Non-zero 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 ()
{
flushing_ignored++;
}
/* Allow calls to flush_output () to write the paragraph data. */
void
uninhibit_output_flushing ()
{
flushing_ignored--;
}
void
flush_output ()
{
register int i;
if (!output_paragraph_offset || flushing_ignored)
return;
for (i = 0; i < output_paragraph_offset; i++)
{
if (output_paragraph[i] == (unsigned char)(' ' | 0x80))
output_paragraph[i] &= 0x7f;
}
fwrite (output_paragraph, 1, output_paragraph_offset, output_stream);
output_position += output_paragraph_offset;
output_paragraph_offset = 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;
/* Close the current paragraph, leaving no blank lines between them. */
void
close_single_paragraph ()
{
close_paragraph_with_lines (0);
}
/* Close a paragraph after an insertion has ended. */
void
close_insertion_paragraph ()
{
if (!insertion_paragraph_closed)
{
/* Close the current paragraph, breaking the line. */
close_single_paragraph ();
/* Start a new paragraph here, inserting whatever indention is correct
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;
/* Let functions such as add_char () know that we have 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;
}
void
close_paragraph_with_lines (lines)
int lines;
{
int old_spacing = paragraph_spacing;
paragraph_spacing = lines;
close_paragraph ();
paragraph_spacing = old_spacing;
}
/* Close the currently open paragraph. */
void
close_paragraph ()
{
register int i;
/* The insertion paragraph is no longer closed. */
insertion_paragraph_closed = 0;
if (paragraph_is_open && !must_start_paragraph)
{
register int tindex, c;
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)
{
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');
}
/* 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 ()
{
last_inserted_character = '\n';
last_char_was_newline = 1;
}
/* Align the end of the text in output_paragraph with fill_column. */
void
do_flush_right_indentation ()
{
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)
{
register 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 = (char *)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;
}
}
}
/* Begin a new paragraph. */
void
start_paragraph ()
{
/* 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 (amount)
int amount;
{
register BRACE_ELEMENT *elt = brace_stack;
/* For every START_POS saved within the brace stack which will be affected
by this indentation, bump that start pos forward. */
while (elt)
{
if (elt->pos >= output_paragraph_offset)
elt->pos += amount;
elt = elt->next;
}
while (--amount >= 0)
insert (' ');
}
/* Search forward for STRING in input_text.
FROM says where where to start. */
int
search_forward (string, from)
char *string;
int from;
{
int len = strlen (string);
while (from < size_of_input_text)
{
if (strncmp (input_text + from, string, len) == 0)
return (from);
from++;
}
return (-1);
}
/* Whoops, Unix doesn't have strcasecmp. */
/* Case independent string compare. */
#if !defined (HAVE_STRCASECMP)
int
strcasecmp (string1, string2)
char *string1, *string2;
{
char ch1, ch2;
for (;;)
{
ch1 = *string1++;
ch2 = *string2++;
if (!(ch1 | ch2))
return (0);
ch1 = coerce_to_upper (ch1);
ch2 = coerce_to_upper (ch2);
if (ch1 != ch2)
return (ch1 - ch2);
}
}
#endif /* !HAVE_STRCASECMP */
enum insertion_type { menu, quotation, lisp, smalllisp, example,
smallexample, display, itemize, format, enumerate, cartouche, table,
ftable, vtable, group, ifinfo, flushleft, flushright, ifset, ifclear, deffn,
defun, defmac, defspec, defvr, defvar, defopt, deftypefn,
deftypefun, deftypevr, deftypevar, defcv, defivar, defop, defmethod,
deftypemethod, deftp, bad_type };
char *insertion_type_names[] = { "menu", "quotation", "lisp",
"smalllisp", "example", "smallexample", "display", "itemize",
"format", "enumerate", "cartouche", "table", "ftable", "vtable", "group",
"ifinfo", "flushleft", "flushright", "ifset", "ifclear", "deffn",
"defun", "defmac", "defspec", "defvr", "defvar", "defopt",
"deftypefn", "deftypefun", "deftypevr", "deftypevar", "defcv",
"defivar", "defop", "defmethod", "deftypemethod", "deftp",
"bad_type" };
int insertion_level = 0;
typedef struct istack_elt
{
struct istack_elt *next;
char *item_function;
char *filename;
int line_number;
int filling_enabled;
int indented_fill;
enum insertion_type insertion;
int inhibited;
} INSERTION_ELT;
INSERTION_ELT *insertion_stack = (INSERTION_ELT *) NULL;
void
init_insertion_stack ()
{
insertion_stack = (INSERTION_ELT *) NULL;
}
/* Return the type of the current insertion. */
enum insertion_type
current_insertion_type ()
{
if (!insertion_level)
return (bad_type);
else
return (insertion_stack->insertion);
}
/* Return a pointer to the string which is the function to wrap around
items. */
char *
current_item_function ()
{
register int level, done;
register INSERTION_ELT *elt;
level = insertion_level;
elt = insertion_stack;
done = 0;
/* Skip down through the stack until we find a non-conditional insertion. */
while (!done && (elt != NULL))
{
switch (elt->insertion)
{
case ifinfo:
case ifset:
case ifclear:
case cartouche:
elt = elt->next;
level--;
break;
default:
done = 1;
}
}
if (!level)
return ((char *) NULL);
else
return (elt->item_function);
}
char *
get_item_function ()
{
char *item_function;
get_rest_of_line (&item_function);
backup_input_pointer ();
canon_white (item_function);
return (item_function);
}
/* Push the state of the current insertion on the stack. */
void
push_insertion (type, item_function)
enum insertion_type type;
char *item_function;
{
INSERTION_ELT *new = (INSERTION_ELT *) xmalloc (sizeof (INSERTION_ELT));
new->item_function = item_function;
new->filling_enabled = filling_enabled;
new->indented_fill = indented_fill;
new->insertion = type;
new->line_number = line_number;
new->filename = strdup (input_filename);
new->inhibited = inhibit_paragraph_indentation;
new->next = insertion_stack;
insertion_stack = new;
insertion_level++;
}
/* Pop the value on top of the insertion stack into the
global variables. */
void
pop_insertion ()
{
INSERTION_ELT *temp = insertion_stack;
if (temp == (INSERTION_ELT *) NULL)
return;
inhibit_paragraph_indentation = temp->inhibited;
filling_enabled = temp->filling_enabled;
indented_fill = temp->indented_fill;
free_and_clear (&(temp->item_function));
free_and_clear (&(temp->filename));
insertion_stack = insertion_stack->next;
free (temp);
insertion_level--;
}
/* Return a pointer to the print name of this
enumerated type. */
char *
insertion_type_pname (type)
enum insertion_type type;
{
if ((int) type < (int) bad_type)
return (insertion_type_names[(int) type]);
else
return ("Broken-Type in insertion_type_pname");
}
/* Return the insertion_type associated with NAME.
If the type is not one of the known ones, return BAD_TYPE. */
enum insertion_type
find_type_from_name (name)
char *name;
{
int index = 0;
while (index < (int) bad_type)
{
if (strcmp (name, insertion_type_names[index]) == 0)
return (enum insertion_type) index;
index++;
}
return (bad_type);
}
void
do_nothing ()
{
}
int
defun_insertion (type)
enum insertion_type type;
{
return
((type == deffn)
|| (type == defun)
|| (type == defmac)
|| (type == defspec)
|| (type == defvr)
|| (type == defvar)
|| (type == defopt)
|| (type == deftypefn)
|| (type == deftypefun)
|| (type == deftypevr)
|| (type == deftypevar)
|| (type == defcv)
|| (type == defivar)
|| (type == defop)
|| (type == defmethod)
|| (type == deftypemethod)
|| (type == deftp));
}
/* MAX_NS is the maximum nesting level for enumerations. I picked 100
which seemed reasonable. This doesn't control the number of items,
just the number of nested lists. */
#define max_stack_depth 100
#define ENUM_DIGITS 1
#define ENUM_ALPHA 2
typedef struct {
int enumtype;
int enumval;
} DIGIT_ALPHA;
DIGIT_ALPHA enumstack[max_stack_depth];
int enumstack_offset = 0;
int current_enumval = 1;
int current_enumtype = ENUM_DIGITS;
char *enumeration_arg = (char *)NULL;
void
start_enumerating (at, type)
int at, type;
{
if ((enumstack_offset + 1) == max_stack_depth)
{
line_error ("Enumeration stack overflow");
return;
}
enumstack[enumstack_offset].enumtype = current_enumtype;
enumstack[enumstack_offset].enumval = current_enumval;
enumstack_offset++;
current_enumval = at;
current_enumtype = type;
}
void
stop_enumerating ()
{
--enumstack_offset;
if (enumstack_offset < 0)
enumstack_offset = 0;
current_enumval = enumstack[enumstack_offset].enumval;
current_enumtype = enumstack[enumstack_offset].enumtype;
}
/* Place a letter or digits into the output stream. */
void
enumerate_item ()
{
char temp[10];
if (current_enumtype == ENUM_ALPHA)
{
if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1))
{
current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A');
warning ("Lettering overflow, restarting at %c", current_enumval);
}
sprintf (temp, "%c. ", current_enumval);
}
else
sprintf (temp, "%d. ", current_enumval);
indent (output_column += (current_indent - strlen (temp)));
add_word (temp);
current_enumval++;
}
/* This is where the work for all the "insertion" style
commands is done. A huge switch statement handles the
various setups, and generic code is on both sides. */
void
begin_insertion (type)
enum insertion_type type;
{
int no_discard = 0;
if (defun_insertion (type))
{
push_insertion (type, strdup (""));
no_discard++;
}
else
push_insertion (type, get_item_function ());
switch (type)
{
case menu:
if (!no_headers)
close_paragraph ();
filling_enabled = no_indent = 0;
inhibit_paragraph_indentation = 1;
if (!no_headers)
add_word ("* Menu:\n");
in_menu++;
no_discard++;
break;
/* I think @quotation is meant to do filling.
If you don't want filling, then use @example. */
case quotation:
close_single_paragraph ();
last_char_was_newline = no_indent = 0;
indented_fill = filling_enabled = 1;
inhibit_paragraph_indentation = 1;
current_indent += default_indentation_increment;
break;
case display:
case example:
case smallexample:
case lisp:
case smalllisp:
/* Just like @example, but no indentation. */
case format:
close_single_paragraph ();
inhibit_paragraph_indentation = 1;
in_fixed_width_font++;
filling_enabled = 0;
last_char_was_newline = 0;
if (type != format)
current_indent += default_indentation_increment;
break;
case table:
case ftable:
case vtable:
case itemize:
close_single_paragraph ();
current_indent += default_indentation_increment;
filling_enabled = indented_fill = 1;
#if defined (INDENT_PARAGRAPHS_IN_TABLE)
inhibit_paragraph_indentation = 0;
#else
inhibit_paragraph_indentation = 1;
#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
/* Make things work for losers who forget the itemize syntax. */
if (allow_lax_format && (type == itemize))
{
if (!(*insertion_stack->item_function))
{
free (insertion_stack->item_function);
insertion_stack->item_function = strdup ("@bullet");
insertion_stack->item_function[0] = COMMAND_PREFIX;
}
}
if (!*insertion_stack->item_function)
{
line_error ("%s requires an argument: the formatter for %citem",
insertion_type_pname (type), COMMAND_PREFIX);
}
break;
case enumerate:
close_single_paragraph ();
no_indent = 0;
#if defined (INDENT_PARAGRAPHS_IN_TABLE)
inhibit_paragraph_indentation = 0;
#else
inhibit_paragraph_indentation = 1;
#endif /* !INDENT_PARAGRAPHS_IN_TABLE */
current_indent += default_indentation_increment;
filling_enabled = indented_fill = 1;
if (isdigit (*enumeration_arg))
start_enumerating (atoi (enumeration_arg), ENUM_DIGITS);
else
start_enumerating (*enumeration_arg, ENUM_ALPHA);
break;
/* Does nothing special in makeinfo. */
case group:
/* Only close the paragraph if we are not inside of an @example. */
if (!insertion_stack->next ||
insertion_stack->next->insertion != example)
close_single_paragraph ();
break;
/* Insertions that are no-ops in info, but do something in TeX. */
case ifinfo:
case ifset:
case ifclear:
case cartouche:
if (in_menu)
no_discard++;
break;
case deffn:
case defun:
case defmac:
case defspec:
case defvr:
case defvar:
case defopt:
case deftypefn:
case deftypefun:
case deftypevr:
case deftypevar:
case defcv:
case defivar:
case defop:
case defmethod:
case deftypemethod:
case deftp:
inhibit_paragraph_indentation = 1;
filling_enabled = indented_fill = 1;
current_indent += default_indentation_increment;
no_indent = 0;
break;
case flushleft:
close_single_paragraph ();
inhibit_paragraph_indentation = 1;
filling_enabled = indented_fill = no_indent = 0;
break;
case flushright:
close_single_paragraph ();
filling_enabled = indented_fill = no_indent = 0;
inhibit_paragraph_indentation = 1;
force_flush_right++;
break;
}
if (!no_discard)
discard_until ("\n");
}
/* Try to end the insertion with the specified TYPE.
TYPE, with a value of bad_type, gets translated to match
the value currently on top of the stack.
Otherwise, if TYPE doesn't match the top of the insertion stack,
give error. */
void
end_insertion (type)
enum insertion_type type;
{
enum insertion_type temp_type;
if (!insertion_level)
return;
temp_type = current_insertion_type ();
if (type == bad_type)
type = temp_type;
if (type != temp_type)
{
line_error
("`%cend' expected `%s', but saw `%s'", COMMAND_PREFIX,
insertion_type_pname (temp_type), insertion_type_pname (type));
return;
}
pop_insertion ();
switch (type)
{
/* Insertions which have no effect on paragraph formatting. */
case ifinfo:
case ifset:
case ifclear:
break;
case menu:
in_menu--; /* No longer hacking menus. */
if (!no_headers)
close_insertion_paragraph ();
break;
case enumerate:
stop_enumerating ();
close_insertion_paragraph ();
current_indent -= default_indentation_increment;
break;
case flushleft:
case group:
case cartouche:
close_insertion_paragraph ();
break;
case format:
case display:
case example:
case smallexample:
case lisp:
case smalllisp:
case quotation:
/* @quotation is the only one of the above without a fixed width
font. */
if (type != quotation)
in_fixed_width_font--;
/* @format is the only fixed_width insertion without a change
in indentation. */
if (type != format)
current_indent -= default_indentation_increment;
/* The ending of one of these insertions always marks the
start of a new paragraph. */
close_insertion_paragraph ();
break;
case table:
case ftable:
case vtable:
case itemize:
current_indent -= default_indentation_increment;
break;
case flushright:
force_flush_right--;
close_insertion_paragraph ();
break;
/* Handle the @defun style insertions with a default clause. */
default:
current_indent -= default_indentation_increment;
close_insertion_paragraph ();
break;
}
}
/* Insertions cannot cross certain boundaries, such as node beginnings. In
code that creates such boundaries, you should call discard_insertions ()
before doing anything else. It prints the errors for you, and cleans up
the insertion stack. */
void
discard_insertions ()
{
int real_line_number = line_number;
while (insertion_stack)
{
if (insertion_stack->insertion == ifinfo ||
insertion_stack->insertion == ifset ||
insertion_stack->insertion == ifclear)
break;
else
{
char *offender;
char *current_filename;
current_filename = input_filename;
offender = (char *)insertion_type_pname (insertion_stack->insertion);
input_filename = insertion_stack->filename;
line_number = insertion_stack->line_number;
line_error ("This `%s' doesn't have a matching `%cend %s'", offender,
COMMAND_PREFIX, offender);
input_filename = current_filename;
pop_insertion ();
}
}
line_number = real_line_number;
}
/* The actual commands themselves. */
/* Commands which insert themselves. */
void
insert_self ()
{
add_word (command);
}
/* Force a line break in the output. */
void
cm_asterisk ()
{
close_single_paragraph ();
#if !defined (ASTERISK_NEW_PARAGRAPH)
cm_noindent ();
#endif /* ASTERISK_NEW_PARAGRAPH */
}
/* Insert ellipsis. */
void
cm_dots (arg)
int arg;
{
if (arg == START)
add_word ("...");
}
void
cm_bullet (arg)
int arg;
{
if (arg == START)
add_char ('*');
}
void
cm_minus (arg)
int arg;
{
if (arg == START)
add_char ('-');
}
/* Insert "TeX". */
void
cm_TeX (arg)
int arg;
{
if (arg == START)
add_word ("TeX");
}
void
cm_copyright (arg)
int arg;
{
if (arg == START)
add_word ("(C)");
}
#if defined (__osf__)
#define LOCALTIME_CAST(x) (time_t *)(x)
#else
#define LOCALTIME_CAST(x) (x)
#endif
void
cm_today (arg)
int arg;
{
static char * months [12] =
{ "January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December" };
if (arg == START)
{
long timer = time (0);
struct tm *ts = localtime (LOCALTIME_CAST (&timer));
add_word_args
("%d %s %d",
(ts -> tm_mday),
(months [ts -> tm_mon]),
((ts -> tm_year) + 1900));
}
}
void
cm_code (arg)
int arg;
{
extern int printing_index;
if (printing_index)
return;
if (arg == START)
{
in_fixed_width_font++;
add_char ('`');
}
else
{
add_word ("'");
in_fixed_width_font--;
}
}
void
cm_samp (arg)
int arg;
{
cm_code (arg);
}
void
cm_file (arg)
int arg;
{
cm_code (arg);
}
void
cm_kbd (arg)
int arg;
{
cm_code (arg);
}
void
cm_key (arg)
int arg;
{
}
/* Convert the character at position into CTL. */
void
cm_ctrl (arg, start, end)
int arg, start, end;
{
/* Should we allow multiple character arguments? I think yes. */
if (arg == END)
{
register int i, character;
#if defined (NO_MULTIPLE_CTRL)
if ((end - start) != 1)
line_error ("%c%s expects a single character as an argument",
COMMAND_PREFIX, command);
else
#endif
for (i = start; i < end; i++)
{
character = output_paragraph[i];
if (isletter (character))
output_paragraph[i] = CTL (coerce_to_upper (character));
}
}
}
/* Small Caps in makeinfo just does all caps. */
void
cm_sc (arg, start_pos, end_pos)
int arg, start_pos, end_pos;
{
if (arg == END)
{
while (start_pos < end_pos)
{
output_paragraph[start_pos] =
coerce_to_upper (output_paragraph[start_pos]);
start_pos++;
}
}
}
/* @var in makeinfo just uppercases the text. */
void
cm_var (arg, start_pos, end_pos)
int arg, start_pos, end_pos;
{
if (arg == END)
{
while (start_pos < end_pos)
{
output_paragraph[start_pos] =
coerce_to_upper (output_paragraph[start_pos]);
start_pos++;
}
}
}
void
cm_dfn (arg, position)
int arg, position;
{
add_char ('"');
}
void
cm_emph (arg)
int arg;
{
add_char ('*');
}
void
cm_strong (arg, position)
int arg, position;
{
cm_emph (arg);
}
void
cm_cite (arg, position)
int arg, position;
{
if (arg == START)
add_word ("`");
else
add_word ("'");
}
/* Current text is italicized. */
void
cm_italic (arg, start, end)
int arg, start, end;
{
}
/* Current text is highlighted. */
void
cm_bold (arg, start, end)
int arg, start, end;
{
cm_italic (arg);
}
/* Current text is in roman font. */
void
cm_roman (arg, start, end)
int arg, start, end;
{
}
/* Current text is in roman font. */
void
cm_titlefont (arg, start, end)
int arg, start, end;
{
}
/* Italicize titles. */
void
cm_title (arg, start, end)
int arg, start, end;
{
cm_italic (arg);
}
/* @refill is a NOP. */
void
cm_refill ()
{
}
/* Prevent the argument from being split across two lines. */
void
cm_w (arg, start, end)
int arg, start, end;
{
if (arg == START)
non_splitting_words++;
else
non_splitting_words--;
}
/* Explain that this command is obsolete, thus the user shouldn't
do anything with it. */
void
cm_obsolete (arg, start, end)
int arg, start, end;
{
if (arg == START)
warning ("The command `%c%s' is obsolete", COMMAND_PREFIX, command);
}
/* Insert the text following input_text_offset up to the end of the line
in a new, separate paragraph. Directly underneath it, insert a
line of WITH_CHAR, the same length of the inserted text. */
void
insert_and_underscore (with_char)
int with_char;
{
register int i, len;
int old_no_indent, starting_pos, ending_pos;
char *temp;
close_paragraph ();
filling_enabled = indented_fill = 0;
old_no_indent = no_indent;
no_indent = 1;
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
append_to_expansion_output (input_text_offset + 1);
#endif /* HAVE_MACROS */
get_rest_of_line (&temp);
starting_pos = output_position + output_paragraph_offset;
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
{
char *temp1;
temp1 = (char *)xmalloc (2 + strlen (temp));
sprintf (temp1, "%s\n", temp);
remember_itext (input_text, input_text_offset);
me_execute_string (temp1);
free (temp1);
}
else
#endif /* HAVE_MACROS */
execute_string ("%s\n", temp);
ending_pos = output_position + output_paragraph_offset;
free (temp);
len = (ending_pos - starting_pos) - 1;
for (i = 0; i < len; i++)
add_char (with_char);
insert ('\n');
close_paragraph ();
filling_enabled = 1;
no_indent = old_no_indent;
}
/* Here is a structure which associates sectioning commands with
an integer, hopefully to reflect the `depth' of the current
section. */
struct {
char *name;
int level;
} section_alist[] = {
{ "unnumberedsubsubsec", 5 },
{ "unnumberedsubsec", 4 },
{ "unnumberedsec", 3 },
{ "unnumbered", 2 },
{ "appendixsubsubsec", 5 },
{ "appendixsubsec", 4 },
{ "appendixsec", 3 },
{ "appendixsection", 3 },
{ "appendix", 2 },
{ "subsubsec", 5 },
{ "subsubsection", 5 },
{ "subsection", 4 },
{ "section", 3 },
{ "chapter", 2 },
{ "top", 1 },
{ (char *)NULL, 0 }
};
/* Amount to offset the name of sectioning commands to levels by. */
int section_alist_offset = 0;
/* Shift the meaning of @section to @chapter. */
void
cm_raisesections ()
{
discard_until ("\n");
section_alist_offset--;
}
/* Shift the meaning of @chapter to @section. */
void
cm_lowersections ()
{
discard_until ("\n");
section_alist_offset++;
}
/* Return an integer which identifies the type section present in TEXT. */
int
what_section (text)
char *text;
{
register int i, j;
char *t;
find_section_command:
for (j = 0; text[j] && cr_or_whitespace (text[j]); j++);
if (text[j] != COMMAND_PREFIX)
return (-1);
text = text + j + 1;
/* We skip @c, @comment, and @?index commands. */
if ((strncmp (text, "comment", strlen ("comment")) == 0) ||
(text[0] == 'c' && cr_or_whitespace (text[1])) ||
(strcmp (text + 1, "index") == 0))
{
while (*text++ != '\n');
goto find_section_command;
}
/* Handle italicized sectioning commands. */
if (*text == 'i')
text++;
for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++);
for (i = 0; t = section_alist[i].name; i++)
{
if (j == strlen (t) && strncmp (t, text, j) == 0)
{
int return_val;
return_val = (section_alist[i].level + section_alist_offset);
if (return_val < 0)
return_val = 0;
else if (return_val > 5)
return_val = 5;
return (return_val);
}
}
return (-1);
}
/* Set the level of @top to LEVEL. Return the old level of @top. */
int
set_top_section_level (level)
int level;
{
register int i, result = -1;
for (i = 0; section_alist[i].name; i++)
if (strcmp (section_alist[i].name, "top") == 0)
{
result = section_alist[i].level;
section_alist[i].level = level;
break;
}
return (result);
}
/* Treat this just like @unnumbered. The only difference is
in node defaulting. */
void
cm_top ()
{
/* It is an error to have more than one @top. */
if (top_node_seen)
{
TAG_ENTRY *tag = tag_table;
line_error ("There already is a node having %ctop as a section",
COMMAND_PREFIX);
while (tag != (TAG_ENTRY *)NULL)
{
if ((tag->flags & IS_TOP))
{
int old_line_number = line_number;
char *old_input_filename = input_filename;
line_number = tag->line_no;
input_filename = tag->filename;
line_error ("Here is the %ctop node", COMMAND_PREFIX);
input_filename = old_input_filename;
line_number = old_line_number;
return;
}
tag = tag->next_ent;
}
}
else
{
top_node_seen = 1;
/* It is an error to use @top before you have used @node. */
if (!tag_table)
{
char *top_name;
get_rest_of_line (&top_name);
free (top_name);
line_error ("%ctop used before %cnode, defaulting to %s",
COMMAND_PREFIX, COMMAND_PREFIX, top_name);
execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name);
return;
}
cm_unnumbered ();
/* The most recently defined node is the top node. */
tag_table->flags |= IS_TOP;
/* Now set the logical hierarchical level of the Top node. */
{
int orig_offset = input_text_offset;
input_text_offset = search_forward (node_search_string, orig_offset);
if (input_text_offset > 0)
{
int this_section;
/* We have encountered a non-top node, so mark that one exists. */
non_top_node_seen = 1;
/* Move to the end of this line, and find out what the
sectioning command is here. */
while (input_text[input_text_offset] != '\n')
input_text_offset++;
if (input_text_offset < size_of_input_text)
input_text_offset++;
this_section = what_section (input_text + input_text_offset);
/* If we found a sectioning command, then give the top section
a level of this section - 1. */
if (this_section != -1)
set_top_section_level (this_section - 1);
}
input_text_offset = orig_offset;
}
}
}
/* Organized by level commands. That is, "*" == chapter, "=" == section. */
char *scoring_characters = "*=-.";
void
sectioning_underscore (command)
char *command;
{
char character;
char *temp;
int level;
temp = (char *)xmalloc (2 + strlen (command));
temp[0] = COMMAND_PREFIX;
strcpy (&temp[1], command);
level = what_section (temp);
free (temp);
level -= 2;
if (level < 0)
level = 0;
character = scoring_characters[level];
insert_and_underscore (character);
}
/* The remainder of the text on this line is a chapter heading. */
void
cm_chapter ()
{
sectioning_underscore ("chapter");
}
/* The remainder of the text on this line is a section heading. */
void
cm_section ()
{
sectioning_underscore ("section");
}
/* The remainder of the text on this line is a subsection heading. */
void
cm_subsection ()
{
sectioning_underscore ("subsection");
}
/* The remainder of the text on this line is a subsubsection heading. */
void
cm_subsubsection ()
{
sectioning_underscore ("subsubsection");
}
/* The remainder of the text on this line is an unnumbered heading. */
void
cm_unnumbered ()
{
cm_chapter ();
}
/* The remainder of the text on this line is an unnumbered section heading. */
void
cm_unnumberedsec ()
{
cm_section ();
}
/* The remainder of the text on this line is an unnumbered
subsection heading. */
void
cm_unnumberedsubsec ()
{
cm_subsection ();
}
/* The remainder of the text on this line is an unnumbered
subsubsection heading. */
void
cm_unnumberedsubsubsec ()
{
cm_subsubsection ();
}
/* The remainder of the text on this line is an appendix heading. */
void
cm_appendix ()
{
cm_chapter ();
}
/* The remainder of the text on this line is an appendix section heading. */
void
cm_appendixsec ()
{
cm_section ();
}
/* The remainder of the text on this line is an appendix subsection heading. */
void
cm_appendixsubsec ()
{
cm_subsection ();
}
/* The remainder of the text on this line is an appendix
subsubsection heading. */
void
cm_appendixsubsubsec ()
{
cm_subsubsection ();
}
/* Compatibility functions substitute for chapter, section, etc. */
void
cm_majorheading ()
{
cm_chapheading ();
}
void
cm_chapheading ()
{
cm_chapter ();
}
void
cm_heading ()
{
cm_section ();
}
void
cm_subheading ()
{
cm_subsection ();
}
void
cm_subsubheading ()
{
cm_subsubsection ();
}
/* **************************************************************** */
/* */
/* Adding nodes, and making tags */
/* */
/* **************************************************************** */
/* Start a new tag table. */
void
init_tag_table ()
{
while (tag_table != (TAG_ENTRY *) NULL)
{
TAG_ENTRY *temp = tag_table;
free (temp->node);
free (temp->prev);
free (temp->next);
free (temp->up);
tag_table = tag_table->next_ent;
free (temp);
}
}
void
write_tag_table ()
{
write_tag_table_internal (0); /* Not indirect. */
}
void
write_tag_table_indirect ()
{
write_tag_table_internal (1);
}
/* Write out the contents of the existing tag table.
INDIRECT_P says how to format the output. */
void
write_tag_table_internal (indirect_p)
int indirect_p;
{
TAG_ENTRY *node = tag_table;
int old_indent = no_indent;
no_indent = 1;
filling_enabled = 0;
must_start_paragraph = 0;
close_paragraph ();
if (!indirect_p)
{
no_indent = 1;
insert ('\n');
}
add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : "");
while (node != (TAG_ENTRY *) NULL)
{
execute_string ("Node: %s", node->node);
add_word_args ("\177%d\n", node->position);
node = node->next_ent;
}
add_word ("\037\nEnd Tag Table\n");
flush_output ();
no_indent = old_indent;
}
char *
get_node_token ()
{
char *string;
get_until_in_line (",", &string);
if (curchar () == ',')
input_text_offset++;
canon_white (string);
/* Force all versions of "top" to be "Top". */
normalize_node_name (string);
return (string);
}
/* Convert "top" and friends into "Top". */
void
normalize_node_name (string)
char *string;
{
if (strcasecmp (string, "Top") == 0)
strcpy (string, "Top");
}
/* Look up NAME in the tag table, and return the associated
tag_entry. If the node is not in the table return NULL. */
TAG_ENTRY *
find_node (name)
char *name;
{
TAG_ENTRY *tag = tag_table;
while (tag != (TAG_ENTRY *) NULL)
{
if (strcmp (tag->node, name) == 0)
return (tag);
tag = tag->next_ent;
}
return ((TAG_ENTRY *) NULL);
}
/* Remember NODE and associates. */
void
remember_node (node, prev, next, up, position, line_no, no_warn)
char *node, *prev, *next, *up;
int position, line_no, no_warn;
{
/* Check for existence of this tag already. */
if (validating)
{
register TAG_ENTRY *tag = find_node (node);
if (tag)
{
line_error ("Node `%s' multiply defined (%d is first definition)",
node, tag->line_no);
return;
}
}
/* First, make this the current node. */
current_node = node;
/* Now add it to the list. */
{
TAG_ENTRY *new = (TAG_ENTRY *) xmalloc (sizeof (TAG_ENTRY));
new->node = node;
new->prev = prev;
new->next = next;
new->up = up;
new->position = position;
new->line_no = line_no;
new->filename = node_filename;
new->touched = 0; /* not yet referenced. */
new->flags = 0;
if (no_warn)
new->flags |= NO_WARN;
new->next_ent = tag_table;
tag_table = new;
}
}
/* The order is: nodename, nextnode, prevnode, upnode.
If all of the NEXT, PREV, and UP fields are empty, they are defaulted.
You must follow a node command which has those fields defaulted
with a sectioning command (e.g. @chapter) giving the "level" of that node.
It is an error not to do so.
The defaults come from the menu in this node's parent. */
void
cm_node ()
{
char *node, *prev, *next, *up;
int new_node_pos, defaulting, this_section, no_warn = 0;
extern int already_outputting_pending_notes;
if (strcmp (command, "nwnode") == 0)
no_warn = 1;
/* Get rid of unmatched brace arguments from previous commands. */
discard_braces ();
/* There also might be insertions left lying around that haven't been
ended yet. Do that also. */
discard_insertions ();
if (!already_outputting_pending_notes)
{
close_paragraph ();
output_pending_notes ();
free_pending_notes ();
}
filling_enabled = indented_fill = 0;
new_node_pos = output_position;
current_footnote_number = 1;
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
append_to_expansion_output (input_text_offset + 1);
#endif /* HAVE_MACROS */
node = get_node_token ();
next = get_node_token ();
prev = get_node_token ();
up = get_node_token ();
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
remember_itext (input_text, input_text_offset);
#endif /* HAVE_MACROS */
no_indent = 1;
if (!no_headers)
{
add_word_args ("\037\nFile: %s, Node: ", pretty_output_filename);
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
me_execute_string (node);
else
#endif /* HAVE_MACROS */
execute_string ("%s", node);
filling_enabled = indented_fill = 0;
}
/* Check for defaulting of this node's next, prev, and up fields. */
defaulting = ((strlen (next) == 0) &&
(strlen (prev) == 0) &&
(strlen (up) == 0));
this_section = what_section (input_text + input_text_offset);
/* If we are defaulting, then look at the immediately following
sectioning command (error if none) to determine the node's
level. Find the node that contains the menu mentioning this node
that is one level up (error if not found). That node is the "Up"
of this node. Default the "Next" and "Prev" from the menu. */
if (defaulting)
{
NODE_REF *last_ref = (NODE_REF *)NULL;
NODE_REF *ref = node_references;
if ((this_section < 0) && (strcmp (node, "Top") != 0))
{
char *polite_section_name = "top";
int i;
for (i = 0; section_alist[i].name; i++)
if (section_alist[i].level == current_section + 1)
{
polite_section_name = section_alist[i].name;
break;
}
line_error
("Node `%s' requires a sectioning command (e.g. %c%s)",
node, COMMAND_PREFIX, polite_section_name);
}
else
{
if (strcmp (node, "Top") == 0)
{
/* Default the NEXT pointer to be the first menu item in
this node, if there is a menu in this node. We have to
try very hard to find the menu, as it may be obscured
by execution_strings which are on the filestack. For
every member of the filestack which has a FILENAME
member which is identical to the current INPUT_FILENAME,
search forward from that offset. */
int saved_input_text_offset = input_text_offset;
int saved_size_of_input_text = size_of_input_text;
char *saved_input_text = input_text;
FSTACK *next_file = filestack;
int orig_offset, orig_size;
char *glean_node_from_menu ();
/* No matter what, make this file point back at `(dir)'. */
free (up); up = strdup ("(dir)");
while (1)
{
orig_offset = input_text_offset;
orig_size =
search_forward (node_search_string, orig_offset);
if (orig_size < 0)
orig_size = size_of_input_text;
input_text_offset =
search_forward (menu_search_string, orig_offset);
if (input_text_offset > -1)
{
char *nodename_from_menu = (char *)NULL;
input_text_offset =
search_forward ("\n* ", input_text_offset);
if (input_text_offset != -1)
nodename_from_menu = glean_node_from_menu (0);
if (nodename_from_menu)
{
free (next); next = nodename_from_menu;
break;
}
}
/* We got here, so it hasn't been found yet. Try
the next file on the filestack if there is one. */
if (next_file &&
(strcmp (next_file->filename, input_filename) == 0))
{
input_text = next_file->text;
input_text_offset = next_file->offset;
size_of_input_text = next_file->size;
next_file = next_file->next;
}
else
{
/* No more input files to check. */
break;
}
}
input_text = saved_input_text;
input_text_offset = saved_input_text_offset;
size_of_input_text = saved_size_of_input_text;
}
}
/* Fix the level of the menu references in the Top node, iff it
was declared with @top, and no subsequent reference was found. */
if (top_node_seen && !non_top_node_seen)
{
/* Then this is the first non-@top node seen. */
int level;
level = set_top_section_level (this_section - 1);
non_top_node_seen = 1;
while (ref)
{
if (ref->section == level)
ref->section = this_section - 1;
ref = ref->next;
}
ref = node_references;
}
while (ref)
{
if (ref->section == (this_section - 1) &&
ref->type == menu_reference &&
strcmp (ref->node, node) == 0)
{
char *containing_node = ref->containing_node;
free (up);
up = strdup (containing_node);
if (last_ref &&
last_ref->type == menu_reference &&
(strcmp (last_ref->containing_node,
containing_node) == 0))
{
free (next);
next = strdup (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 = strdup (ref->next->node);
}
else if (!ref->next &&
strcasecmp (ref->containing_node, "Top") == 0)
{
free (prev);
prev = strdup (ref->containing_node);
}
break;
}
last_ref = ref;
ref = ref->next;
}
}
#if defined (HAVE_MACROS)
/* Insert the correct args if we are expanding macros, and the node's
pointers weren't defaulted. */
if (macro_expansion_output_stream && !defaulting)
{
char *temp;
int op_orig = output_paragraph_offset;
temp = (char *)xmalloc (3 + strlen (next));
sprintf (temp, ", %s", next);
me_execute_string (temp);
free (temp);
temp = (char *)xmalloc (3 + strlen (prev));
sprintf (temp, ", %s", prev);
me_execute_string (temp);
free (temp);
temp = (char *)xmalloc (4 + strlen (up));
sprintf (temp, ", %s", up);
me_execute_string (temp);
free (temp);
output_paragraph_offset = op_orig;
}
#endif /* HAVE_MACROS */
if (!no_headers)
{
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
me_inhibit_expansion++;
#endif /* HAVE_MACROS */
if (*next)
{
execute_string (", Next: %s", next);
filling_enabled = indented_fill = 0;
}
if (*prev)
{
execute_string (", Prev: %s", prev);
filling_enabled = indented_fill = 0;
}
if (*up)
{
execute_string (", Up: %s", up);
filling_enabled = indented_fill = 0;
}
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
me_inhibit_expansion--;
#endif /* HAVE_MACROS */
}
close_paragraph ();
no_indent = 0;
if (!*node)
{
line_error ("No node name specified for `%c%s' command",
COMMAND_PREFIX, command);
free (node);
free (next);
free (prev);
free (up);
}
else
{
if (!*next) { free (next); next = (char *)NULL; }
if (!*prev) { free (prev); prev = (char *)NULL; }
if (!*up) { free (up); up = (char *)NULL; }
remember_node (node, prev, next, up, new_node_pos, line_number, no_warn);
}
/* Change the section only if there was a sectioning command. */
if (this_section >= 0)
current_section = this_section;
filling_enabled = 1;
}
/* Validation of an info file.
Scan through the list of tag entrys touching the Prev, Next, and Up
elements of each. It is an error not to be able to touch one of them,
except in the case of external node references, such as "(DIR)".
If the Prev is different from the Up,
then the Prev node must have a Next pointing at this node.
Every node except Top must have an Up.
The Up node must contain some sort of reference, other than a Next,
to this node.
If the Next is different from the Next of the Up,
then the Next node must have a Prev pointing at this node. */
void
validate_file (tag_table)
TAG_ENTRY *tag_table;
{
char *old_input_filename = input_filename;
TAG_ENTRY *tags = tag_table;
while (tags != (TAG_ENTRY *) NULL)
{
register TAG_ENTRY *temp_tag;
input_filename = tags->filename;
line_number = tags->line_no;
/* If this is a "no warn" node, don't validate it in any way. */
if (tags->flags & NO_WARN)
{
tags = tags->next_ent;
continue;
}
/* If this node has a Next, then make sure that the Next exists. */
if (tags->next)
{
validate (tags->next, tags->line_no, "Next");
/* If the Next node exists, and there is no Up, then make
sure that the Prev of the Next points back. */
if (temp_tag = find_node (tags->next))
{
char *prev;
if (temp_tag->flags & NO_WARN)
{
/* Do nothing if we aren't supposed to issue warnings
about this node. */
}
else
{
prev = temp_tag->prev;
if (!prev || (strcmp (prev, tags->node) != 0))
{
line_error ("Node `%s''s Next field not pointed back to",
tags->node);
line_number = temp_tag->line_no;
input_filename = temp_tag->filename;
line_error
("This node (`%s') is the one with the bad `Prev'",
temp_tag->node);
input_filename = tags->filename;
line_number = tags->line_no;
temp_tag->flags |= PREV_ERROR;
}
}
}
}
/* Validate the Prev field if there is one, and we haven't already
complained about it in some way. You don't have to have a Prev
field at this stage. */
if (!(tags->flags & PREV_ERROR) && tags->prev)
{
int valid = validate (tags->prev, tags->line_no, "Prev");
if (!valid)
tags->flags |= PREV_ERROR;
else
{
/* If the Prev field is not the same as the Up field,
then the node pointed to by the Prev field must have
a Next field which points to this node. */
if (tags->up && (strcmp (tags->prev, tags->up) != 0))
{
temp_tag = find_node (tags->prev);
/* If we aren't supposed to issue warnings about the
target node, do nothing. */
if (!temp_tag || (temp_tag->flags & NO_WARN))
{
/* Do nothing. */
}
else
{
if (!temp_tag->next ||
(strcmp (temp_tag->next, tags->node) != 0))
{
line_error
("Node `%s''s Prev field not pointed back to",
tags->node);
line_number = temp_tag->line_no;
input_filename = temp_tag->filename;
line_error
("This node (`%s') is the one with the bad `Next'",
temp_tag->node);
input_filename = tags->filename;
line_number = tags->line_no;
temp_tag->flags |= NEXT_ERROR;
}
}
}
}
}
if (!tags->up && (strcasecmp (tags->node, "Top") != 0))
line_error ("Node `%s' is missing an \"Up\" field", tags->node);
else if (tags->up)
{
int valid = 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 && *tags->up != '(')
{
NODE_REF *nref, *tref, *list;
NODE_REF *find_node_reference ();
tref = (NODE_REF *) NULL;
list = node_references;
for (;;)
{
if (!(nref = find_node_reference (tags->node, list)))
break;
if (strcmp (nref->containing_node, tags->up) == 0)
{
if (nref->type != menu_reference)
{
tref = nref;
list = nref->next;
}
else
break;
}
list = nref->next;
}
if (!nref)
{
temp_tag = find_node (tags->up);
line_number = temp_tag->line_no;
input_filename = temp_tag->filename;
if (!tref)
line_error (
"`%s' has an Up field of `%s', but `%s' has no menu item for `%s'",
tags->node, tags->up, tags->up, tags->node);
line_number = tags->line_no;
input_filename = tags->filename;
}
}
}
tags = tags->next_ent;
}
validate_other_references (node_references);
/* We have told the user about the references which didn't exist.
Now tell him about the nodes which aren't referenced. */
tags = tag_table;
while (tags != (TAG_ENTRY *) NULL)
{
/* If this node is a "no warn" node, do nothing. */
if (tags->flags & NO_WARN)
{
tags = tags->next_ent;
continue;
}
/* Special hack. If the node in question appears to have
been referenced more than REFERENCE_WARNING_LIMIT times,
give a warning. */
if (tags->touched > reference_warning_limit)
{
input_filename = tags->filename;
line_number = tags->line_no;
warning ("Node `%s' has been referenced %d times",
tags->node, tags->touched);
}
if (tags->touched == 0)
{
input_filename = tags->filename;
line_number = tags->line_no;
/* Notice that the node "Top" is special, and doesn't have to
be referenced. */
if (strcasecmp (tags->node, "Top") != 0)
warning ("Unreferenced node `%s'", tags->node);
}
tags = tags->next_ent;
}
input_filename = old_input_filename;
}
/* Return 1 if tag correctly validated, or 0 if not. */
int
validate (tag, line, label)
char *tag;
int line;
char *label;
{
TAG_ENTRY *result;
/* If there isn't a tag to verify, or if the tag is in another file,
then it must be okay. */
if (!tag || !*tag || *tag == '(')
return (1);
/* Otherwise, the tag must exist. */
result = find_node (tag);
if (!result)
{
line_number = line;
line_error (
"Validation error. `%s' field points to node `%s', which doesn't exist",
label, tag);
return (0);
}
result->touched++;
return (1);
}
/* Split large output files into a series of smaller files. Each file
is pointed to in the tag table, which then gets written out as the
original file. The new files have the same name as the original file
with a "-num" attached. SIZE is the largest number of bytes to allow
in any single split file. */
void
split_file (filename, size)
char *filename;
int size;
{
char *root_filename, *root_pathname;
char *the_file, *filename_part ();
struct stat fileinfo;
long file_size;
char *the_header;
int header_size;
/* Can only do this to files with tag tables. */
if (!tag_table)
return;
if (size == 0)
size = DEFAULT_SPLIT_SIZE;
if ((stat (filename, &fileinfo) != 0) ||
(((long) fileinfo.st_size) < SPLIT_SIZE_THRESHOLD))
return;
file_size = (long) fileinfo.st_size;
the_file = find_and_load (filename);
if (!the_file)
return;
root_filename = filename_part (filename);
root_pathname = pathname_part (filename);
if (!root_pathname)
root_pathname = strdup ("");
/* Start splitting the file. Walk along the tag table
outputting sections of the file. When we have written
all of the nodes in the tag table, make the top-level
pointer file, which contains indirect pointers and
tags for the nodes. */
{
int which_file = 1;
TAG_ENTRY *tags = tag_table;
char *indirect_info = (char *)NULL;
/* Remember the `header' of this file. The first tag in the file is
the bottom of the header; the top of the file is the start. */
the_header = (char *)xmalloc (1 + (header_size = tags->position));
memcpy (the_header, the_file, header_size);
while (tags)
{
int file_top, file_bot, limit;
/* Have to include the Control-_. */
file_top = file_bot = tags->position;
limit = file_top + size;
/* If the rest of this file is only one node, then
that is the entire subfile. */
if (!tags->next_ent)
{
int i = tags->position + 1;
char last_char = the_file[i];
while (i < file_size)
{
if ((the_file[i] == '\037') &&
((last_char == '\n') ||
(last_char == '\014')))
break;
else
last_char = the_file[i];
i++;
}
file_bot = i;
tags = tags->next_ent;
goto write_region;
}
/* Otherwise, find the largest number of nodes that can fit in
this subfile. */
for (; tags; tags = tags->next_ent)
{
if (!tags->next_ent)
{
/* This entry is the last node. Search forward for the end
of this node, and that is the end of this file. */
int i = tags->position + 1;
char last_char = the_file[i];
while (i < file_size)
{
if ((the_file[i] == '\037') &&
((last_char == '\n') ||
(last_char == '\014')))
break;
else
last_char = the_file[i];
i++;
}
file_bot = i;
if (file_bot < limit)
{
tags = tags->next_ent;
goto write_region;
}
else
{
/* Here we want to write out everything before the last
node, and then write the last node out in a file
by itself. */
file_bot = tags->position;
goto write_region;
}
}
if (tags->next_ent->position > limit)
{
if (tags->position == file_top)
tags = tags->next_ent;
file_bot = tags->position;
write_region:
{
int fd;
char *split_filename;
split_filename = (char *) xmalloc
(10 + strlen (root_pathname) + strlen (root_filename));
sprintf
(split_filename,
"%s%s-%d", root_pathname, root_filename, which_file);
fd = open
(split_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
if ((fd < 0) ||
(write (fd, the_header, header_size) != header_size) ||
(write (fd, the_file + file_top, file_bot - file_top)
!= (file_bot - file_top)) ||
((close (fd)) < 0))
{
perror (split_filename);
if (fd != -1)
close (fd);
exit (FATAL);
}
if (!indirect_info)
{
indirect_info = the_file + file_top;
sprintf (indirect_info, "\037\nIndirect:\n");
indirect_info += strlen (indirect_info);
}
sprintf (indirect_info, "%s-%d: %d\n",
root_filename, which_file, file_top);
free (split_filename);
indirect_info += strlen (indirect_info);
which_file++;
break;
}
}
}
}
/* We have sucessfully created the subfiles. Now write out the
original again. We must use `output_stream', or
write_tag_table_indirect () won't know where to place the output. */
output_stream = fopen (filename, "w");
if (!output_stream)
{
perror (filename);
exit (FATAL);
}
{
int distance = indirect_info - the_file;
fwrite (the_file, 1, distance, output_stream);
/* Inhibit newlines. */
paragraph_is_open = 0;
write_tag_table_indirect ();
fclose (output_stream);
free (the_header);
free (the_file);
return;
}
}
}
/* Some menu hacking. 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. */
char *
reftype_type_string (type)
enum reftype type;
{
switch (type)
{
case menu_reference:
return ("Menu");
case followed_reference:
return ("Followed-Reference");
default:
return ("Internal-bad-reference-type");
}
}
/* Remember this node name for later validation use. */
void
remember_node_reference (node, line, type)
char *node;
int line;
enum reftype type;
{
NODE_REF *temp = (NODE_REF *) xmalloc (sizeof (NODE_REF));
temp->next = node_references;
temp->node = strdup (node);
temp->line_no = line;
temp->section = current_section;
temp->type = type;
temp->containing_node = strdup (current_node);
temp->filename = node_filename;
node_references = temp;
}
void
validate_other_references (ref_list)
register NODE_REF *ref_list;
{
char *old_input_filename = input_filename;
while (ref_list != (NODE_REF *) NULL)
{
input_filename = ref_list->filename;
validate (ref_list->node, ref_list->line_no,
reftype_type_string (ref_list->type));
ref_list = ref_list->next;
}
input_filename = old_input_filename;
}
/* Find NODE in REF_LIST. */
NODE_REF *
find_node_reference (node, ref_list)
char *node;
register NODE_REF *ref_list;
{
while (ref_list)
{
if (strcmp (node, ref_list->node) == 0)
break;
ref_list = ref_list->next;
}
return (ref_list);
}
void
free_node_references ()
{
register NODE_REF *list, *temp;
list = node_references;
while (list)
{
temp = list;
free (list->node);
free (list->containing_node);
list = list->next;
free (temp);
}
node_references = (NODE_REF *) NULL;
}
/* This function gets called at the start of every line while inside of
a menu. It checks to see if the line starts with "* ", and if so,
remembers the node reference that this menu refers to.
input_text_offset is at the \n just before the line start. */
#define menu_starter "* "
char *
glean_node_from_menu (remember_reference)
int remember_reference;
{
int i, orig_offset = input_text_offset;
char *nodename;
if (strncmp (&input_text[input_text_offset + 1],
menu_starter,
strlen (menu_starter)) != 0)
return ((char *)NULL);
else
input_text_offset += strlen (menu_starter) + 1;
get_until_in_line (":", &nodename);
if (curchar () == ':')
input_text_offset++;
canon_white (nodename);
if (curchar () == ':')
goto save_node;
free (nodename);
get_rest_of_line (&nodename);
/* Special hack: If the nodename follows the menu item name,
then we have to read the rest of the line in order to find
out what the nodename is. But we still have to read the
line later, in order to process any formatting commands that
might be present. So un-count the carriage return that has just
been counted. */
line_number--;
isolate_nodename (nodename);
save_node:
input_text_offset = orig_offset;
normalize_node_name (nodename);
i = strlen (nodename);
if (i && nodename[i - 1] == ':')
nodename[i - 1] = '\0';
if (remember_reference)
{
remember_node_reference (nodename, line_number, menu_reference);
free (nodename);
return ((char *)NULL);
}
else
return (nodename);
}
static void
isolate_nodename (nodename)
char *nodename;
{
register int i, c;
int paren_seen, paren;
if (!nodename)
return;
canon_white (nodename);
paren_seen = paren = i = 0;
if (*nodename == '.' || !*nodename)
{
*nodename = '\0';
return;
}
if (*nodename == '(')
{
paren++;
paren_seen++;
i++;
}
for (; c = nodename[i]; i++)
{
if (paren)
{
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';
}
void
cm_menu ()
{
if (current_node == (char *)NULL)
{
warning ("%cmenu seen before a node has been defined", COMMAND_PREFIX);
warning ("Creating `TOP' node.");
execute_string ("@node Top");
}
begin_insertion (menu);
}
/* **************************************************************** */
/* */
/* Cross Reference Hacking */
/* */
/* **************************************************************** */
char *
get_xref_token ()
{
char *string;
get_until_in_braces (",", &string);
if (curchar () == ',')
input_text_offset++;
fix_whitespace (string);
return (string);
}
int px_ref_flag = 0; /* Controls initial output string. */
/* Make a cross reference. */
void
cm_xref (arg)
{
if (arg == START)
{
char *arg1, *arg2, *arg3, *arg4, *arg5;
arg1 = get_xref_token ();
arg2 = get_xref_token ();
arg3 = get_xref_token ();
arg4 = get_xref_token ();
arg5 = get_xref_token ();
add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
if (*arg5 || *arg4)
{
char *node_name;
if (!*arg2)
{
if (*arg3)
node_name = arg3;
else
node_name = arg1;
}
else
node_name = arg2;
execute_string ("%s: (%s)%s", node_name, arg4, arg1);
/* 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 (!*arg2)
execute_string ("%s: %s", arg3, arg1);
else
execute_string ("%s: %s", arg2, arg1);
}
else
{
if (*arg2)
execute_string ("%s: %s", arg2, arg1);
else
execute_string ("%s::", arg1);
}
/* 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 to make sure that the next non-whitespace character is either
a period or a comma. input_text_offset is pointing at the "}" which
ended the xref or pxref command. */
int temp = input_text_offset + 1;
if (output_paragraph[output_paragraph_offset - 2] == ':' &&
output_paragraph[output_paragraph_offset - 1] == ':')
return;
while (temp < size_of_input_text)
{
if (cr_or_whitespace (input_text[temp]))
temp++;
else
{
if (input_text[temp] == '.' ||
input_text[temp] == ',' ||
input_text[temp] == '\t')
return;
else
{
line_error (
"Cross-reference must be terminated with a period or a comma");
return;
}
}
}
}
}
void
cm_pxref (arg)
int arg;
{
if (arg == START)
{
px_ref_flag++;
cm_xref (arg);
px_ref_flag--;
}
else
add_char ('.');
}
void
cm_inforef (arg)
int arg;
{
if (arg == START)
{
char *node, *pname, *file;
node = get_xref_token ();
pname = get_xref_token ();
file = get_xref_token ();
execute_string ("*note %s: (%s)%s", pname, file, node);
}
}
/* **************************************************************** */
/* */
/* Insertion Command Stubs */
/* */
/* **************************************************************** */
void
cm_quotation ()
{
begin_insertion (quotation);
}
void
cm_example ()
{
begin_insertion (example);
}
void
cm_smallexample ()
{
begin_insertion (smallexample);
}
void
cm_lisp ()
{
begin_insertion (lisp);
}
void
cm_smalllisp ()
{
begin_insertion (smalllisp);
}
/* @cartouche/@end cartouche draws box with rounded corners in
TeX output. Right now, just a NOP insertion. */
void
cm_cartouche ()
{
begin_insertion (cartouche);
}
void
cm_format ()
{
begin_insertion (format);
}
void
cm_display ()
{
begin_insertion (display);
}
void
cm_itemize ()
{
begin_insertion (itemize);
}
void
cm_enumerate ()
{
do_enumeration (enumerate, "1");
}
/* Start an enumeration insertion of type TYPE. If the user supplied
no argument on the line, then use DEFAULT_STRING as the initial string. */
void
do_enumeration (type, default_string)
int type;
char *default_string;
{
get_until_in_line (".", &enumeration_arg);
canon_white (enumeration_arg);
if (!*enumeration_arg)
{
free (enumeration_arg);
enumeration_arg = strdup (default_string);
}
if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg))
{
warning ("%s requires a letter or a digit", insertion_type_pname (type));
switch (type)
{
case enumerate:
default_string = "1";
break;
}
enumeration_arg = strdup (default_string);
}
begin_insertion (type);
}
void
cm_table ()
{
begin_insertion (table);
}
void
cm_ftable ()
{
begin_insertion (ftable);
}
void
cm_vtable ()
{
begin_insertion (vtable);
}
void
cm_group ()
{
begin_insertion (group);
}
void
cm_ifinfo ()
{
begin_insertion (ifinfo);
}
/* Begin an insertion where the lines are not filled or indented. */
void
cm_flushleft ()
{
begin_insertion (flushleft);
}
/* Begin an insertion where the lines are not filled, and each line is
forced to the right-hand side of the page. */
void
cm_flushright ()
{
begin_insertion (flushright);
}
/* **************************************************************** */
/* */
/* Conditional Handling */
/* */
/* **************************************************************** */
/* 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 = (DEFINE *)NULL;
/* Add NAME to the list of `set' defines. */
void
set (name, value)
char *name;
char *value;
{
DEFINE *temp;
for (temp = defines; temp; temp = temp->next)
if (strcmp (name, temp->name) == 0)
{
free (temp->value);
temp->value = strdup (value);
return;
}
temp = (DEFINE *)xmalloc (sizeof (DEFINE));
temp->next = defines;
temp->name = strdup (name);
temp->value = strdup (value);
defines = temp;
}
/* Remove NAME from the list of `set' defines. */
void
clear (name)
char *name;
{
register DEFINE *temp, *last;
last = (DEFINE *)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;
}
}
/* Return the value of NAME. The return value is NULL if NAME is unset. */
char *
set_p (name)
char *name;
{
register DEFINE *temp;
for (temp = defines; temp; temp = temp->next)
if (strcmp (temp->name, name) == 0)
return (temp->value);
return ((char *)NULL);
}
/* Conditionally parse based on the current command name. */
void
command_name_condition ()
{
char *discarder;
discarder = (char *)xmalloc (8 + strlen (command));
sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command);
discard_until (discarder);
discard_until ("\n");
free (discarder);
}
/* Create a variable whose name appears as the first word on this line. */
void
cm_set ()
{
handle_variable (SET);
}
/* Remove a variable whose name appears as the first word on this line. */
void
cm_clear ()
{
handle_variable (CLEAR);
}
void
cm_ifset ()
{
handle_variable (IFSET);
}
void
cm_ifclear ()
{
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 ()
{
register int i;
char **arglist;
arglist = get_brace_args (0);
if (arglist)
{
if (array_len (arglist) > 1)
{
if ((strcasecmp (arglist[0], arglist[1]) == 0) &&
(arglist[2] != (char *)NULL))
execute_string ("%s\n", arglist[2]);
}
free_array (arglist);
}
}
void
cm_value (arg, start_pos, end_pos)
int arg, start_pos, end_pos;
{
if (arg == END)
{
char *name, *value;
name = (char *)&output_paragraph[start_pos];
output_paragraph[end_pos] = '\0';
name = strdup (name);
value = set_p (name);
output_column -= end_pos - start_pos;
output_paragraph_offset = start_pos;
if (value)
execute_string ("%s", value);
else
add_word_args ("{No Value For \"%s\"}", name);
free (name);
}
}
/* Set, clear, or conditionalize based on ACTION. */
void
handle_variable (action)
int action;
{
char *name;
get_rest_of_line (&name);
backup_input_pointer ();
canon_white (name);
handle_variable_internal (action, name);
free (name);
}
void
handle_variable_internal (action, name)
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;
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)
{
char *freeable_line, *line;
get_rest_of_line (&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);
}
/* 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; /* Non-zero means string currently in use. */
} EXECUTION_STRING;
static EXECUTION_STRING **execution_strings = (EXECUTION_STRING **)NULL;
static int execution_strings_index = 0;
static int execution_strings_slots = 0;
EXECUTION_STRING *
get_execution_string (initial_size)
int initial_size;
{
register int i = 0;
EXECUTION_STRING *es = (EXECUTION_STRING *)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 = (EXECUTION_STRING **)xrealloc
(execution_strings,
(execution_strings_slots += 3) * sizeof (EXECUTION_STRING *));
for (; i < execution_strings_slots; i++)
execution_strings[i] = (EXECUTION_STRING *)NULL;
}
execution_strings[execution_strings_index] =
(EXECUTION_STRING *)xmalloc (sizeof (EXECUTION_STRING));
es = execution_strings[execution_strings_index];
execution_strings_index++;
es->size = 0;
es->string = (char *)NULL;
es->in_use = 0;
}
if (initial_size > es->size)
{
es->string = (char *) xrealloc (es->string, initial_size);
es->size = initial_size;
}
return (es);
}
/* Execute the string produced by formatting the ARGs with FORMAT. This
is like submitting a new file with @include. */
#if defined (HAVE_VARARGS_H) && defined (HAVE_VSPRINTF)
void
execute_string (va_alist)
va_dcl
{
EXECUTION_STRING *es;
char *temp_string;
char *format;
va_list args;
es = get_execution_string (4000);
temp_string = es->string;
es->in_use = 1;
va_start (args);
format = va_arg (args, char *);
vsprintf (temp_string, format, args);
va_end (args);
#else /* !(HAVE_VARARGS_H && HAVE_VSPRINTF) */
void
execute_string (format, arg1, arg2, arg3, arg4, arg5)
char *format;
{
EXECUTION_STRING *es;
char *temp_string;
es = get_execution_string (4000);
temp_string = es->string;
es->in_use = 1;
sprintf (temp_string, format, arg1, arg2, arg3, arg4, arg5);
#endif /* !(HAVE_VARARGS_H && HAVE_VSPRINTF) */
pushfile ();
input_text_offset = 0;
input_text = temp_string;
input_filename = strdup (input_filename);
size_of_input_text = strlen (temp_string);
executing_string++;
reader_loop ();
free (input_filename);
popfile ();
executing_string--;
es->in_use = 0;
}
/* **************************************************************** */
/* */
/* @itemx, @item */
/* */
/* **************************************************************** */
static int itemx_flag = 0;
void
cm_itemx ()
{
itemx_flag++;
cm_item ();
itemx_flag--;
}
void
cm_item ()
{
char *rest_of_line, *item_func;
/* Can only hack "@item" while inside of an insertion. */
if (insertion_level)
{
INSERTION_ELT *stack = insertion_stack;
int original_input_text_offset;
skip_whitespace ();
original_input_text_offset = input_text_offset;
get_rest_of_line (&rest_of_line);
canon_white (rest_of_line);
item_func = current_item_function ();
/* Okay, do the right thing depending on which insertion function
is active. */
switch_top:
switch (stack->insertion)
{
case ifinfo:
case ifset:
case ifclear:
case cartouche:
stack = stack->next;
if (!stack)
goto no_insertion;
else
goto switch_top;
break;
case menu:
case quotation:
case example:
case smallexample:
case lisp:
case format:
case display:
case group:
line_error ("The `%c%s' command is meaningless within a `@%s' block",
COMMAND_PREFIX, command,
insertion_type_pname (current_insertion_type ()));
break;
case itemize:
case enumerate:
if (itemx_flag)
{
line_error ("%citemx is not meaningful inside of a `%s' block",
COMMAND_PREFIX,
insertion_type_pname (current_insertion_type ()));
}
else
{
start_paragraph ();
kill_self_indent (-1);
filling_enabled = indented_fill = 1;
if (current_insertion_type () == itemize)
{
indent (output_column = current_indent - 2);
/* I need some way to determine whether this command
takes braces or not. I believe the user can type
either "@bullet" or "@bullet{}". Of course, they
can also type "o" or "#" or whatever else they want. */
if (item_func && *item_func)
{
if (*item_func == COMMAND_PREFIX)
if (item_func[strlen (item_func) - 1] != '}')
execute_string ("%s{}", item_func);
else
execute_string ("%s", item_func);
else
execute_string ("%s", item_func);
}
insert (' ');
output_column++;
}
else
enumerate_item ();
/* Special hack. This makes close paragraph ignore you until
the start_paragraph () function has been called. */
must_start_paragraph = 1;
/* Ultra special hack. It appears that some people incorrectly
place text directly after the @item, instead of on a new line
by itself. This happens to work in TeX, so I make it work
here. */
if (*rest_of_line)
{
line_number--;
input_text_offset = original_input_text_offset;
}
}
break;
case table:
case ftable:
case vtable:
{
/* Get rid of extra characters. */
kill_self_indent (-1);
/* 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 t;
t = 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 = t;
}
#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);
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;
}
}
free (rest_of_line);
}
else
{
no_insertion:
line_error ("%c%s found outside of an insertion block",
COMMAND_PREFIX, command);
}
}
/* **************************************************************** */
/* */
/* Defun and Friends */
/* */
/* **************************************************************** */
#define DEFUN_SELF_DELIMITING(c) \
(((c) == '(') \
|| ((c) == ')') \
|| ((c) == '[') \
|| ((c) == ']'))
struct token_accumulator
{
unsigned int length;
unsigned int index;
char **tokens;
};
void
initialize_token_accumulator (accumulator)
struct token_accumulator *accumulator;
{
(accumulator->length) = 0;
(accumulator->index) = 0;
(accumulator->tokens) = NULL;
}
void
accumulate_token (accumulator, token)
struct token_accumulator *accumulator;
char *token;
{
if ((accumulator->index) >= (accumulator->length))
{
(accumulator->length) += 10;
(accumulator->tokens) = (char **) xrealloc
(accumulator->tokens, (accumulator->length * sizeof (char *)));
}
accumulator->tokens[accumulator->index] = token;
accumulator->index += 1;
}
char *
copy_substring (start, end)
char *start;
char *end;
{
char *result, *scan, *scan_result;
result = (char *) xmalloc ((end - start) + 1);
scan_result = result;
scan = start;
while (scan < end)
*scan_result++ = *scan++;
*scan_result = '\0';
return (result);
}
/* Given `string' pointing at an open brace, skip forward and return a
pointer to just past the matching close brace. */
int
scan_group_in_string (string_pointer)
char **string_pointer;
{
register int c;
register char *scan_string;
register unsigned int level = 1;
scan_string = (*string_pointer) + 1;
while (1)
{
if (level == 0)
{
(*string_pointer) = scan_string;
return (1);
}
c = (*scan_string++);
if (c == '\0')
{
/* Tweak line_number to compensate for fact that
we gobbled the whole line before coming here. */
line_number -= 1;
line_error ("Missing `}' in %cdef arg", COMMAND_PREFIX);
line_number += 1;
(*string_pointer) = (scan_string - 1);
return (0);
}
if (c == '{')
level += 1;
if (c == '}')
level -= 1;
}
}
/* Return a list of tokens from the contents of `string'.
Commands and brace-delimited groups count as single tokens.
Contiguous whitespace characters are converted to a token
consisting of a single space. */
char **
args_from_string (string)
char *string;
{
struct token_accumulator accumulator;
register char *scan_string = string;
char *token_start, *token_end;
initialize_token_accumulator (&accumulator);
while ((*scan_string) != '\0')
{
/* Replace arbitrary whitespace by a single space. */
if (whitespace (*scan_string))
{
scan_string += 1;
while (whitespace (*scan_string))
scan_string += 1;
accumulate_token ((&accumulator), (strdup (" ")));
continue;
}
/* Commands count as single tokens. */
if ((*scan_string) == COMMAND_PREFIX)
{
token_start = scan_string;
scan_string += 1;
if (self_delimiting (*scan_string))
scan_string += 1;
else
{
register int c;
while (1)
{
c = *scan_string++;
if ((c == '\0') || (c == '{') || (whitespace (c)))
{
scan_string -= 1;
break;
}
}
if (*scan_string == '{')
{
char *s = scan_string;
(void) scan_group_in_string (&s);
scan_string = s;
}
}
token_end = scan_string;
}
/* Parentheses and brackets are self-delimiting. */
else if (DEFUN_SELF_DELIMITING (*scan_string))
{
token_start = scan_string;
scan_string += 1;
token_end = scan_string;
}
/* Open brace introduces a group that is a single token. */
else if (*scan_string == '{')
{
char *s = scan_string;
int balanced = scan_group_in_string (&s);
token_start = scan_string + 1;
scan_string = s;
token_end = balanced ? (scan_string - 1) : scan_string;
}
/* Otherwise a token is delimited by whitespace, parentheses,
brackets, or braces. A token is also ended by a command. */
else
{
token_start = scan_string;
while (1)
{
register int c;
c = *scan_string++;
if (!c ||
(whitespace (c) || DEFUN_SELF_DELIMITING (c) ||
c == '{' || c == '}'))
{
scan_string--;
break;
}
/* If we encounter a command imbedded within a token,
then end the token. */
if (c == COMMAND_PREFIX)
{
scan_string--;
break;
}
}
token_end = scan_string;
}
accumulate_token
(&accumulator, copy_substring (token_start, token_end));
}
accumulate_token (&accumulator, NULL);
return (accumulator.tokens);
}
void
process_defun_args (defun_args, auto_var_p)
char **defun_args;
int auto_var_p;
{
int pending_space = 0;
while (1)
{
char *defun_arg = *defun_args++;
if (defun_arg == NULL)
break;
if (defun_arg[0] == ' ')
{
pending_space = 1;
continue;
}
if (pending_space)
{
add_char (' ');
pending_space = 0;
}
if (DEFUN_SELF_DELIMITING (defun_arg[0]))
add_char (defun_arg[0]);
else if (defun_arg[0] == '&')
add_word (defun_arg);
else if (defun_arg[0] == COMMAND_PREFIX)
execute_string ("%s", defun_arg);
else if (auto_var_p)
execute_string ("%cvar{%s}", COMMAND_PREFIX, defun_arg);
else
add_word (defun_arg);
}
}
char *
next_nonwhite_defun_arg (arg_pointer)
char ***arg_pointer;
{
char **scan = (*arg_pointer);
char *arg = (*scan++);
if ((arg != 0) && (*arg == ' '))
arg = *scan++;
if (arg == 0)
scan -= 1;
*arg_pointer = scan;
return ((arg == 0) ? "" : arg);
}
/* Make the defun type insertion.
TYPE says which insertion this is.
X_P says not to start a new insertion if non-zero. */
void
defun_internal (type, x_p)
enum insertion_type type;
int x_p;
{
enum insertion_type base_type;
char **defun_args, **scan_args;
char *category, *defined_name, *type_name, *type_name2;
{
char *line;
get_rest_of_line (&line);
defun_args = (args_from_string (line));
free (line);
}
scan_args = defun_args;
switch (type)
{
case defun:
category = "Function";
base_type = deffn;
break;
case defmac:
category = "Macro";
base_type = deffn;
break;
case defspec:
category = "Special Form";
base_type = deffn;
break;
case defvar:
category = "Variable";
base_type = defvr;
break;
case defopt:
category = "User Option";
base_type = defvr;
break;
case deftypefun:
category = "Function";
base_type = deftypefn;
break;
case deftypevar:
category = "Variable";
base_type = deftypevr;
break;
case defivar:
category = "Instance Variable";
base_type = defcv;
break;
case defmethod:
category = "Method";
base_type = defop;
break;
case deftypemethod:
category = "Method";
base_type = deftypemethod;
break;
default:
category = next_nonwhite_defun_arg (&scan_args);
base_type = type;
break;
}
if ((base_type == deftypefn)
|| (base_type == deftypevr)
|| (base_type == defcv)
|| (base_type == defop)
|| (base_type == deftypemethod))
type_name = next_nonwhite_defun_arg (&scan_args);
if (base_type == deftypemethod)
type_name2 = next_nonwhite_defun_arg (&scan_args);
defined_name = next_nonwhite_defun_arg (&scan_args);
/* This hack exists solely for the purposes of formatting the texinfo
manual. I couldn't think of a better way. The token might be
a simple @@ followed immediately by more text. If this is the case,
then the next defun arg is part of this one, and we should concatenate
them. */
if (*scan_args && **scan_args && !whitespace (**scan_args) &&
(strcmp (defined_name, "@@") == 0))
{
char *tem = (char *)xmalloc (3 + strlen (scan_args[0]));
sprintf (tem, "@@%s", scan_args[0]);
free (scan_args[0]);
scan_args[0] = tem;
scan_args++;
defined_name = tem;
}
if (!x_p)
begin_insertion (type);
/* Write the definition header line.
This should start at the normal indentation. */
current_indent -= default_indentation_increment;
start_paragraph ();
switch (base_type)
{
case deffn:
case defvr:
case deftp:
execute_string (" -- %s: %s", category, defined_name);
break;
case deftypefn:
case deftypevr:
execute_string (" -- %s: %s %s", category, type_name, defined_name);
break;
case defcv:
execute_string (" -- %s of %s: %s", category, type_name, defined_name);
break;
case defop:
execute_string (" -- %s on %s: %s", category, type_name, defined_name);
break;
case deftypemethod:
execute_string (" -- %s on %s: %s %s", category, type_name, type_name2,
defined_name);
break;
}
current_indent += default_indentation_increment;
/* Now process the function arguments, if any.
If these carry onto the next line, they should be indented by two
increments to distinguish them from the body of the definition,
which is indented by one increment. */
current_indent += default_indentation_increment;
switch (base_type)
{
case deffn:
case defop:
process_defun_args (scan_args, 1);
break;
case deftp:
case deftypefn:
case deftypemethod:
process_defun_args (scan_args, 0);
break;
}
current_indent -= default_indentation_increment;
close_single_paragraph ();
/* Make an entry in the appropriate index. */
switch (base_type)
{
case deffn:
case deftypefn:
execute_string ("%cfindex %s\n", COMMAND_PREFIX, defined_name);
break;
case defvr:
case deftypevr:
case defcv:
execute_string ("%cvindex %s\n", COMMAND_PREFIX, defined_name);
break;
case defop:
case deftypemethod:
execute_string ("%cfindex %s on %s\n",
COMMAND_PREFIX, defined_name, type_name);
break;
case deftp:
execute_string ("%ctindex %s\n", COMMAND_PREFIX, defined_name);
break;
}
/* Deallocate the token list. */
scan_args = defun_args;
while (1)
{
char * arg = (*scan_args++);
if (arg == NULL)
break;
free (arg);
}
free (defun_args);
}
/* Add an entry for a function, macro, special form, variable, or option.
If the name of the calling command ends in `x', then this is an extra
entry included in the body of an insertion of the same type. */
void
cm_defun ()
{
int x_p;
enum insertion_type type;
char *temp = strdup (command);
x_p = (command[strlen (command) - 1] == 'x');
if (x_p)
temp[strlen (temp) - 1] = '\0';
type = find_type_from_name (temp);
free (temp);
/* If we are adding to an already existing insertion, then make sure
that we are already in an insertion of type TYPE. */
if (x_p &&
(!insertion_level || insertion_stack->insertion != type))
{
line_error ("Must be in a `%s' insertion in order to use `%s'x",
command, command);
discard_until ("\n");
return;
}
defun_internal (type, x_p);
}
/* End existing insertion block. */
void
cm_end ()
{
char *temp;
enum insertion_type type;
if (!insertion_level)
{
line_error ("Unmatched `%c%s'", COMMAND_PREFIX, command);
return;
}
get_rest_of_line (&temp);
canon_white (temp);
if (strlen (temp) == 0)
line_error ("`%c%s' needs something after it", COMMAND_PREFIX, command);
type = find_type_from_name (temp);
if (type == bad_type)
{
line_error ("Bad argument to `%s', `%s', using `%s'",
command, temp, insertion_type_pname (current_insertion_type ()));
}
end_insertion (type);
free (temp);
}
/* **************************************************************** */
/* */
/* Other Random Commands */
/* */
/* **************************************************************** */
/* This says to inhibit the indentation of the next paragraph, but
not of following paragraphs. */
void
cm_noindent ()
{
if (!inhibit_paragraph_indentation)
inhibit_paragraph_indentation = -1;
}
/* I don't know exactly what to do with this. Should I allow
someone to switch filenames in the middle of output? Since the
file could be partially written, this doesn't seem to make sense.
Another option: ignore it, since they don't *really* want to
switch files. Finally, complain, or at least warn. */
void
cm_setfilename ()
{
char *filename;
get_rest_of_line (&filename);
/* warning ("`@%s %s' encountered and ignored", command, filename); */
free (filename);
}
void
cm_ignore_line ()
{
discard_until ("\n");
}
/* @br can be immediately followed by `{}', so we have to read those here.
It should simply close the paragraph. */
void
cm_br ()
{
if (looking_at ("{}"))
input_text_offset += 2;
if (curchar () == '\n')
{
input_text_offset++;
line_number++;
}
close_paragraph ();
}
/* Insert the number of blank lines passed as argument. */
void
cm_sp ()
{
int lines;
char *line;
get_rest_of_line (&line);
if (sscanf (line, "%d", &lines) != 1)
{
line_error ("%csp requires a positive numeric argument", COMMAND_PREFIX);
}
else
{
if (lines < 0)
lines = 0;
while (lines--)
add_char ('\n');
}
free (line);
}
/* Start a new line with just this text on it.
Then center the line of text.
This always ends the current paragraph. */
void
cm_center ()
{
register int i, start, length;
int fudge_factor = 1;
unsigned char *line;
close_paragraph ();
filling_enabled = indented_fill = 0;
cm_noindent ();
start = output_paragraph_offset;
inhibit_output_flushing ();
get_rest_of_line ((char **)&line);
execute_string ("%s", (char *)line);
free (line);
uninhibit_output_flushing ();
i = output_paragraph_offset - 1;
while (i > (start - 1) && output_paragraph[i] == '\n')
i--;
output_paragraph_offset = ++i;
length = output_paragraph_offset - start;
if (length < (fill_column - fudge_factor))
{
line = (unsigned char *)xmalloc (1 + length);
memcpy (line, (char *)(output_paragraph + start), length);
i = (fill_column - fudge_factor - length) / 2;
output_paragraph_offset = start;
while (i--)
insert (' ');
for (i = 0; i < length; i++)
insert (line[i]);
free (line);
}
insert ('\n');
close_paragraph ();
filling_enabled = 1;
}
/* Show what an expression returns. */
void
cm_result (arg)
int arg;
{
if (arg == END)
add_word ("=>");
}
/* What an expression expands to. */
void
cm_expansion (arg)
int arg;
{
if (arg == END)
add_word ("==>");
}
/* Indicates two expressions are equivalent. */
void
cm_equiv (arg)
int arg;
{
if (arg == END)
add_word ("==");
}
/* What an expression may print. */
void
cm_print (arg)
int arg;
{
if (arg == END)
add_word ("-|");
}
/* An error signaled. */
void
cm_error (arg)
int arg;
{
if (arg == END)
add_word ("error-->");
}
/* The location of point in an example of a buffer. */
void
cm_point (arg)
int arg;
{
if (arg == END)
add_word ("-!-");
}
/* Start a new line with just this text on it.
The text is outdented one level if possible. */
void
cm_exdent ()
{
char *line;
int i = current_indent;
if (current_indent)
current_indent -= default_indentation_increment;
get_rest_of_line (&line);
close_single_paragraph ();
execute_string ("%s", line);
current_indent = i;
free (line);
close_single_paragraph ();
}
void
cm_include ()
{
cm_infoinclude ();
}
#if !defined (HAVE_STRERROR)
extern char *sys_errlist[];
extern int sys_nerr;
char *
strerror (num)
int num;
{
if (num >= sys_nerr)
return ("Unknown file system error");
else
return (sys_errlist[num]);
}
#endif /* !HAVE_STRERROR */
/* Remember this file, and move onto the next. */
void
cm_infoinclude ()
{
char *filename;
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
me_append_before_this_command ();
#endif /* HAVE_MACROS */
close_paragraph ();
get_rest_of_line (&filename);
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
remember_itext (input_text, input_text_offset);
#endif /* HAVE_MACROS */
pushfile ();
/* In verbose mode we print info about including another file. */
if (verbose_mode)
{
register int i = 0;
register FSTACK *stack = filestack;
for (i = 0, stack = filestack; stack; stack = stack->next, i++);
i *= 2;
printf ("%*s", i, "");
printf ("%c%s %s\n", COMMAND_PREFIX, command, filename);
fflush (stdout);
}
if (!find_and_load (filename))
{
extern int errno;
popfile ();
line_number--;
/* Cannot "@include foo", in line 5 of "/wh/bar". */
line_error ("`%c%s %s': %s", COMMAND_PREFIX, command, filename,
strerror (errno));
free (filename);
return;
}
else
{
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
remember_itext (input_text, input_text_offset);
#endif /* HAVE_MACROS */
reader_loop ();
}
free (filename);
popfile ();
}
/* The other side of a malformed expression. */
void
misplaced_brace ()
{
line_error ("Misplaced `}'");
}
/* Don't let the filling algorithm insert extra whitespace here. */
void
cm_force_abbreviated_whitespace ()
{
}
/* Do not let this character signify the end of a sentence, though
if it was seen without the command prefix it normally would. We
do this by turning on the 8th bit of the character. */
void
cm_ignore_sentence_ender ()
{
add_char (META ((*command)));
}
/* Signals end of processing. Easy to make this happen. */
void
cm_bye ()
{
input_text_offset = size_of_input_text;
}
void
cm_asis ()
{
}
void
cm_math ()
{
}
/* **************************************************************** */
/* */
/* Indexing Stuff */
/* */
/* **************************************************************** */
/* An index element... */
typedef struct index_elt
{
struct index_elt *next;
char *entry; /* The index entry itself. */
char *node; /* The node from whence it came. */
int code; /* Non-zero means add `@code{...}' when
printing this element. */
int defining_line; /* Line number where this entry was written. */
} INDEX_ELT;
/* A list of short-names for each index, and the index to that index in our
index array, the_indices. 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 index;
int code;
} INDEX_ALIST;
INDEX_ALIST **name_index_alist = (INDEX_ALIST **) NULL;
/* An array of pointers. Each one is for a different index. The
"synindex" command changes which array slot is pointed to by a
given "index". */
INDEX_ELT **the_indices = (INDEX_ELT **) NULL;
/* The number of defined indices. */
int defined_indices = 0;
/* We predefine these. */
#define program_index 0
#define function_index 1
#define concept_index 2
#define variable_index 3
#define datatype_index 4
#define key_index 5
void
init_indices ()
{
int i;
/* Create the default data structures. */
/* Initialize data space. */
if (!the_indices)
{
the_indices = (INDEX_ELT **) xmalloc ((1 + defined_indices) *
sizeof (INDEX_ELT *));
the_indices[defined_indices] = (INDEX_ELT *) NULL;
name_index_alist = (INDEX_ALIST **) xmalloc ((1 + defined_indices) *
sizeof (INDEX_ALIST *));
name_index_alist[defined_indices] = (INDEX_ALIST *) NULL;
}
/* If there were existing indices, get rid of them now. */
for (i = 0; i < defined_indices; i++)
undefindex (name_index_alist[i]->name);
/* Add the default indices. */
top_defindex ("pg", 0);
top_defindex ("fn", 1); /* "fn" is a code index. */
top_defindex ("cp", 0);
top_defindex ("vr", 0);
top_defindex ("tp", 0);
top_defindex ("ky", 0);
}
/* Find which element in the known list of indices has this name.
Returns -1 if NAME isn't found. */
int
find_index_offset (name)
char *name;
{
register int i;
for (i = 0; i < defined_indices; i++)
if (name_index_alist[i] &&
strcmp (name, name_index_alist[i]->name) == 0)
return (name_index_alist[i]->index);
return (-1);
}
/* Return a pointer to the entry of (name . index) for this name.
Return NULL if the index doesn't exist. */
INDEX_ALIST *
find_index (name)
char *name;
{
int offset = find_index_offset (name);
if (offset > -1)
return (name_index_alist[offset]);
else
return ((INDEX_ALIST *) NULL);
}
/* Given an index name, return the offset in the_indices of this index,
or -1 if there is no such index. */
int
translate_index (name)
char *name;
{
INDEX_ALIST *which = find_index (name);
if (which)
return (which->index);
else
return (-1);
}
/* Return the index list which belongs to NAME. */
INDEX_ELT *
index_list (name)
char *name;
{
int which = translate_index (name);
if (which < 0)
return ((INDEX_ELT *) -1);
else
return (the_indices[which]);
}
/* Please release me, let me go... */
void
free_index (index)
INDEX_ELT *index;
{
INDEX_ELT *temp;
while ((temp = index) != (INDEX_ELT *) NULL)
{
free (temp->entry);
free (temp->node);
index = index->next;
free (temp);
}
}
/* Flush an index by name. */
void
undefindex (name)
char *name;
{
int i;
int which = find_index_offset (name);
if (which < 0)
return;
i = name_index_alist[which]->index;
free_index (the_indices[i]);
the_indices[i] = (INDEX_ELT *) NULL;
free (name_index_alist[which]->name);
free (name_index_alist[which]);
name_index_alist[which] = (INDEX_ALIST *) NULL;
}
/* Define an index known as NAME. We assign the slot number.
CODE if non-zero says to make this a code index. */
void
defindex (name, code)
char *name;
int code;
{
register int i, slot;
/* If it already exists, flush it. */
undefindex (name);
/* Try to find an empty slot. */
slot = -1;
for (i = 0; i < defined_indices; i++)
if (!name_index_alist[i])
{
slot = i;
break;
}
if (slot < 0)
{
/* No such luck. Make space for another index. */
slot = defined_indices;
defined_indices++;
name_index_alist = (INDEX_ALIST **)
xrealloc ((char *)name_index_alist,
(1 + defined_indices) * sizeof (INDEX_ALIST *));
the_indices = (INDEX_ELT **)
xrealloc ((char *)the_indices,
(1 + defined_indices) * sizeof (INDEX_ELT *));
}
/* We have a slot. Start assigning. */
name_index_alist[slot] = (INDEX_ALIST *) xmalloc (sizeof (INDEX_ALIST));
name_index_alist[slot]->name = strdup (name);
name_index_alist[slot]->index = slot;
name_index_alist[slot]->code = code;
the_indices[slot] = (INDEX_ELT *) NULL;
}
/* Add the arguments to the current index command to the index NAME. */
void
index_add_arg (name)
char *name;
{
int which;
char *index_entry;
INDEX_ALIST *tem;
tem = find_index (name);
which = tem ? tem->index : -1;
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
append_to_expansion_output (input_text_offset + 1);
#endif /* HAVE_MACROS */
get_rest_of_line (&index_entry);
ignore_blank_line ();
#if defined (HAVE_MACROS)
if (macro_expansion_output_stream)
{
int op_orig;
remember_itext (input_text, input_text_offset);
op_orig = output_paragraph_offset;
me_execute_string (index_entry);
me_execute_string ("\n");
output_paragraph_offset = op_orig;
}
#endif /* HAVE_MACROS */
if (which < 0)
{
line_error ("Unknown index reference `%s'", name);
free (index_entry);
}
else
{
INDEX_ELT *new = (INDEX_ELT *) xmalloc (sizeof (INDEX_ELT));
new->next = the_indices[which];
new->entry = index_entry;
new->node = current_node;
new->code = tem->code;
new->defining_line = line_number - 1;
the_indices[which] = new;
}
}
#define INDEX_COMMAND_SUFFIX "index"
/* The function which user defined index commands call. */
void
gen_index ()
{
char *name = strdup (command);
if (strlen (name) >= strlen ("index"))
name[strlen (name) - strlen ("index")] = '\0';
index_add_arg (name);
free (name);
}
void
top_defindex (name, code)
char *name;
int code;
{
char *temp;
temp = (char *) xmalloc (1 + strlen (name) + strlen ("index"));
sprintf (temp, "%sindex", name);
define_user_command (temp, gen_index, 0);
defindex (name, code);
free (temp);
}
/* Define a new index command. Arg is name of index. */
void
cm_defindex ()
{
gen_defindex (0);
}
void
cm_defcodeindex ()
{
gen_defindex (1);
}
void
gen_defindex (code)
int code;
{
char *name;
get_rest_of_line (&name);
if (find_index (name))
{
line_error ("Index `%s' already exists", name);
free (name);
return;
}
else
{
char *temp = (char *) alloca (1 + strlen (name) + strlen ("index"));
sprintf (temp, "%sindex", name);
define_user_command (temp, gen_index, 0);
defindex (name, code);
free (name);
}
}
/* Append LIST2 to LIST1. Return the head of the list. */
INDEX_ELT *
index_append (head, tail)
INDEX_ELT *head, *tail;
{
register INDEX_ELT *t_head = head;
if (!t_head)
return (tail);
while (t_head->next)
t_head = t_head->next;
t_head->next = tail;
return (head);
}
/* Expects 2 args, on the same line. Both are index abbreviations.
Make the first one be a synonym for the second one, i.e. make the
first one have the same index as the second one. */
void
cm_synindex ()
{
int redirector, redirectee;
char *temp;
skip_whitespace ();
get_until_in_line (" ", &temp);
redirectee = find_index_offset (temp);
skip_whitespace ();
free_and_clear (&temp);
get_until_in_line (" ", &temp);
redirector = find_index_offset (temp);
free (temp);
if (redirector < 0 || redirectee < 0)
{
line_error ("Unknown index reference");
}
else
{
/* I think that we should let the user make indices synonymous to
each other without any lossage of info. This means that one can
say @synindex cp dt anywhere in the file, and things that used to
be in cp will go into dt. */
INDEX_ELT *i1 = the_indices[redirectee], *i2 = the_indices[redirector];
if (i1 || i2)
{
if (i1)
the_indices[redirectee] = index_append (i1, i2);
else
the_indices[redirectee] = index_append (i2, i1);
}
name_index_alist[redirectee]->index =
name_index_alist[redirector]->index;
}
}
void
cm_pindex () /* Pinhead index. */
{
index_add_arg ("pg");
}
void
cm_vindex () /* Variable index. */
{
index_add_arg ("vr");
}
void
cm_kindex () /* Key index. */
{
index_add_arg ("ky");
}
void
cm_cindex () /* Concept index. */
{
index_add_arg ("cp");
}
void
cm_findex () /* Function index. */
{
index_add_arg ("fn");
}
void
cm_tindex () /* Data Type index. */
{
index_add_arg ("tp");
}
/* Sorting the index. */
int
index_element_compare (element1, element2)
INDEX_ELT **element1, **element2;
{
/* This needs to ignore leading non-text characters. */
return (strcasecmp ((*element1)->entry, (*element2)->entry));
}
/* Force all index entries to be unique. */
void
make_index_entries_unique (array, count)
INDEX_ELT **array;
int count;
{
register int i, j;
INDEX_ELT **copy;
int counter = 1;
copy = (INDEX_ELT **)xmalloc ((1 + count) * sizeof (INDEX_ELT *));
for (i = 0, j = 0; i < count; i++)
{
if ((i == (count - 1)) ||
(array[i]->node != array[i + 1]->node) ||
(strcasecmp (array[i]->entry, array[i + 1]->entry) != 0))
copy[j++] = array[i];
else
{
free (array[i]->entry);
free (array[i]);
}
}
copy[j] = (INDEX_ELT *)NULL;
/* Now COPY contains only unique entries. Duplicated entries in the
original array have been freed. Replace the current array with
the copy, fixing the NEXT pointers. */
for (i = 0; copy[i] != (INDEX_ELT *)NULL; i++)
{
copy[i]->next = copy[i + 1];
/* Fix entry names which are the same. They point to different nodes,
so we make the entry name unique. */
if ((copy[i + 1] != (INDEX_ELT *)NULL) &&
(strcmp (copy[i]->entry, copy[i + 1]->entry) == 0))
{
char *new_entry_name;
new_entry_name = (char *)xmalloc (10 + strlen (copy[i]->entry));
sprintf (new_entry_name, "%s <%d>", copy[i]->entry, counter);
free (copy[i]->entry);
copy[i]->entry = new_entry_name;
counter++;
}
else
counter = 1;
array[i] = copy[i];
}
array[i] = (INDEX_ELT *)NULL;
/* Free the storage used only by COPY. */
free (copy);
}
/* Sort the index passed in INDEX, returning an array of
pointers to elements. The array is terminated with a NULL
pointer. We call qsort because it's supposed to be fast.
I think this looks bad. */
INDEX_ELT **
sort_index (index)
INDEX_ELT *index;
{
INDEX_ELT *temp = index;
INDEX_ELT **array;
int count = 0;
while (temp != (INDEX_ELT *) NULL)
{
count++;
temp = temp->next;
}
/* We have the length. Make an array. */
array = (INDEX_ELT **) xmalloc ((count + 1) * sizeof (INDEX_ELT *));
count = 0;
temp = index;
while (temp != (INDEX_ELT *) NULL)
{
array[count++] = temp;
temp = temp->next;
}
array[count] = (INDEX_ELT *) NULL; /* terminate the array. */
/* Sort the array. */
qsort (array, count, sizeof (INDEX_ELT *), index_element_compare);
make_index_entries_unique (array, count);
return (array);
}
/* Non-zero means that we are in the middle of printing an index. */
int printing_index = 0;
/* Takes one arg, a short name of an index to print.
Outputs a menu of the sorted elements of the index. */
void
cm_printindex ()
{
int item;
INDEX_ELT *index;
INDEX_ELT **array;
char *index_name;
int old_inhibitions = inhibit_paragraph_indentation;
int previous_filling_enabled_value = filling_enabled;
close_paragraph ();
get_rest_of_line (&index_name);
index = index_list (index_name);
if (index == (INDEX_ELT *)-1)
{
line_error ("Unknown index name `%s'", index_name);
free (index_name);
return;
}
else
free (index_name);
array = sort_index (index);
filling_enabled = 0;
inhibit_paragraph_indentation = 1;
close_paragraph ();
add_word ("* Menu:\n\n");
printing_index = 1;
#if defined (HAVE_MACROS)
me_inhibit_expansion++;
#endif /* HAVE_MACROS */
for (item = 0; (index = array[item]); item++)
{
int real_line_number = line_number;
/* Let errors generated while making the index entry point back
at the line which contains the entry. */
line_number = index->defining_line;
/* If this particular entry should be printed as a "code" index,
then wrap the entry with "@code{...}". */
if (index->code)
execute_string ("* %ccode{%s}: ", COMMAND_PREFIX, index->entry);
else
execute_string ("* %s: ", index->entry);
/* Pad the front of the destination nodename so that
the output looks nice. */
if (fill_column > 40 && output_column < 40)
indent (40 - output_column);
execute_string ("%s.\n", index->node);
line_number = real_line_number;
flush_output ();
}
#if defined (HAVE_MACROS)
me_inhibit_expansion--;
#endif /* HAVE_MACROS */
printing_index = 0;
free (array);
close_single_paragraph ();
filling_enabled = previous_filling_enabled_value;
inhibit_paragraph_indentation = old_inhibitions;
}
/* **************************************************************** */
/* */
/* Making User Defined Commands */
/* */
/* **************************************************************** */
void
define_user_command (name, proc, needs_braces_p)
char *name;
COMMAND_FUNCTION *proc;
int needs_braces_p;
{
int slot = user_command_array_len;
user_command_array_len++;
if (!user_command_array)
user_command_array = (COMMAND **) xmalloc (1 * sizeof (COMMAND *));
user_command_array = (COMMAND **) xrealloc (user_command_array,
(1 + user_command_array_len) *
sizeof (COMMAND *));
user_command_array[slot] = (COMMAND *) xmalloc (sizeof (COMMAND));
user_command_array[slot]->name = strdup (name);
user_command_array[slot]->proc = proc;
user_command_array[slot]->argument_in_braces = needs_braces_p;
}
/* Make ALIAS run the named FUNCTION. Copies properties from FUNCTION. */
void
define_alias (alias, function)
char *alias, *function;
{
}
/* 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.
Note that if NUM is zero, we assume `none'.
Returns 0 if successful, or non-zero if STRING isn't one of the above. */
int
set_paragraph_indent (string)
char *string;
{
if (strcmp (string, "asis") == 0)
paragraph_start_indent = 0;
else if (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);
}
void
cm_paragraphindent ()
{
char *arg;
get_rest_of_line (&arg);
if (set_paragraph_indent (arg) != 0)
line_error ("Bad argument to %c%s", COMMAND_PREFIX, command);
free (arg);
}
/* Some support for footnotes. */
/* Footnotes are a new construct in Info. We don't know the best method
of implementing them for sure, so we present two possiblities.
SeparateNode:
Make them look like followed references, with the reference
destinations in a makeinfo manufactured node or,
EndNode:
Make them appear at the bottom of the node that they originally
appeared in. */
#define SeparateNode 0
#define EndNode 1
int footnote_style = EndNode;
int first_footnote_this_node = 1;
int footnote_count = 0;
/* Set the footnote style based on he style identifier in STRING. */
int
set_footnote_style (string)
char *string;
{
if ((strcasecmp (string, "separate") == 0) ||
(strcasecmp (string, "MN") == 0))
footnote_style = SeparateNode;
else if ((strcasecmp (string, "end") == 0) ||
(strcasecmp (string, "EN") == 0))
footnote_style = EndNode;
else
return (-1);
return (0);
}
void
cm_footnotestyle ()
{
char *arg;
get_rest_of_line (&arg);
if (set_footnote_style (arg) != 0)
line_error ("Bad argument to %c%s", COMMAND_PREFIX, command);
free (arg);
}
typedef struct fn
{
struct fn *next;
char *marker;
char *note;
} FN;
FN *pending_notes = (FN *) NULL;
/* A method for remembering footnotes. Note that this list gets output
at the end of the current node. */
void
remember_note (marker, note)
char *marker, *note;
{
FN *temp = (FN *) xmalloc (sizeof (FN));
temp->marker = strdup (marker);
temp->note = strdup (note);
temp->next = pending_notes;
pending_notes = temp;
footnote_count++;
}
/* How to get rid of existing footnotes. */
void
free_pending_notes ()
{
FN *temp;
while ((temp = pending_notes) != (FN *) NULL)
{
free (temp->marker);
free (temp->note);
pending_notes = pending_notes->next;
free (temp);
}
first_footnote_this_node = 1;
footnote_count = 0;
}
/* What to do when you see a @footnote construct. */
/* Handle a "footnote".
footnote *{this is a footnote}
where "*" is the marker character for this note. */
void
cm_footnote ()
{
char *marker;
char *note;
get_until ("{", &marker);
canon_white (marker);
/* Read the argument in braces. */
if (curchar () != '{')
{
line_error ("`%c%s' expected more than just `%s'. It needs something in `{...}'",
COMMAND_PREFIX, command, marker);
free (marker);
return;
}
else
{
int braces = 1;
int temp = ++input_text_offset;
int len;
while (braces)
{
if (temp == size_of_input_text)
{
line_error ("No closing brace for footnote `%s'", marker);
return;
}
if (input_text[temp] == '{')
braces++;
else if (input_text[temp] == '}')
braces--;
else if (input_text[temp] == '\n')
line_number ++;
temp++;
}
len = (temp - input_text_offset) - 1;
note = (char *)xmalloc (len + 1);
strncpy (note, &input_text[input_text_offset], len);
note[len] = '\0';
input_text_offset = temp;
}
if (!current_node || !*current_node)
{
line_error ("Footnote defined without parent node");
free (marker);
free (note);
return;
}
if (!*marker)
{
free (marker);
if (number_footnotes)
{
marker = (char *)xmalloc (10);
sprintf (marker, "%d", current_footnote_number);
current_footnote_number++;
}
else
marker = strdup ("*");
}
remember_note (marker, note);
/* Your method should at least insert MARKER. */
switch (footnote_style)
{
case SeparateNode:
add_word_args ("(%s)", marker);
if (first_footnote_this_node)
{
char *temp_string;
temp_string = (char *)
xmalloc ((strlen (current_node)) + (strlen ("-Footnotes")) + 1);
add_word_args (" (*note %s-Footnotes::)", current_node);
strcpy (temp_string, current_node);
strcat (temp_string, "-Footnotes");
remember_node_reference (temp_string, line_number, followed_reference);
free (temp_string);
first_footnote_this_node = 0;
}
break;
case EndNode:
add_word_args ("(%s)", marker);
break;
default:
break;
}
free (marker);
free (note);
}
/* Non-zero means that we are currently in the process of outputting
footnotes. */
int already_outputting_pending_notes = 0;
/* Output the footnotes. We are at the end of the current node. */
void
output_pending_notes ()
{
FN *footnote = pending_notes;
if (!pending_notes)
return;
switch (footnote_style)
{
case SeparateNode:
{
char *old_current_node = current_node;
char *old_command = strdup (command);
already_outputting_pending_notes++;
execute_string ("%cnode %s-Footnotes,,,%s\n",
COMMAND_PREFIX, current_node, current_node);
already_outputting_pending_notes--;
current_node = old_current_node;
free (command);
command = old_command;
}
break;
case EndNode:
close_paragraph ();
in_fixed_width_font++;
execute_string ("---------- Footnotes ----------\n\n");
in_fixed_width_font--;
break;
}
/* Handle the footnotes in reverse order. */
{
FN **array = (FN **) xmalloc ((footnote_count + 1) * sizeof (FN *));
array[footnote_count] = (FN *) NULL;
while (--footnote_count > -1)
{
array[footnote_count] = footnote;
footnote = footnote->next;
}
filling_enabled = 1;
indented_fill = 1;
while (footnote = array[++footnote_count])
{
switch (footnote_style)
{
case SeparateNode:
case EndNode:
execute_string ("(%s) %s", footnote->marker, footnote->note);
close_paragraph ();
break;
}
}
close_paragraph ();
free (array);
}
}
/* **************************************************************** */
/* */
/* User definable Macros (text substitution) */
/* */
/* **************************************************************** */
#if defined (HAVE_MACROS)
/* Array of macros and definitions. */
MACRO_DEF **macro_list = (MACRO_DEF **)NULL;
int macro_list_len = 0; /* Number of elements. */
int macro_list_size = 0; /* Number of slots in total. */
/* Return the macro definition of NAME or NULL if NAME is not defined. */
MACRO_DEF *
find_macro (name)
char *name;
{
register int i;
register MACRO_DEF *def;
def = (MACRO_DEF *)NULL;
for (i = 0; macro_list && (def = macro_list[i]); i++)
{
if ((!def->inhibited) && (strcmp (def->name, name) == 0))
break;
}
return (def);
}
/* Add the macro NAME with ARGLIST and BODY to the list of defined macros.
SOURCE_FILE is the name of the file where this definition can be found,
and SOURCE_LINENO is the line number within that file. If a macro already
exists with NAME, then a warning is produced, and that previous
definition is overwritten. */
void
add_macro (name, arglist, body, source_file, source_lineno, flags)
char *name;
char **arglist;
char *body;
char *source_file;
int source_lineno, flags;
{
register MACRO_DEF *def;
def = find_macro (name);
if (!def)
{
if (macro_list_len + 2 >= macro_list_size)
macro_list = (MACRO_DEF **)xrealloc
(macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
macro_list[macro_list_len] = (MACRO_DEF *)xmalloc (sizeof (MACRO_DEF));
macro_list[macro_list_len + 1] = (MACRO_DEF *)NULL;
def = macro_list[macro_list_len];
macro_list_len += 1;
def->name = name;
}
else
{
char *temp_filename = input_filename;
int temp_line = line_number;
warning ("The macro `%s' is previously defined", name);
input_filename = def->source_file;
line_number = def->source_lineno;
warning ("Here is the previous definition of `%s'", name);
input_filename = temp_filename;
line_number = temp_line;
if (def->arglist)
{
register int i;
for (i = 0; def->arglist[i]; i++)
free (def->arglist[i]);
free (def->arglist);
}
free (def->source_file);
free (def->body);
}
def->source_file = strdup (source_file);
def->source_lineno = source_lineno;
def->body = body;
def->arglist = arglist;
def->inhibited = 0;
def->flags = flags;
}
/* Delete the macro with name NAME. The macro is deleted from the list,
but it is also returned. If there was no macro defined, NULL is
returned. */
MACRO_DEF *
delete_macro (name)
char *name;
{
register int i;
register MACRO_DEF *def;
def = (MACRO_DEF *)NULL;
for (i = 0; macro_list && (def = macro_list[i]); i++)
if (strcmp (def->name, name) == 0)
{
memmove (macro_list + i, macro_list + i + 1,
((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
break;
}
return (def);
}
/* Return the arglist on the current line. This can behave in two different
ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */
int braces_required_for_macro_args = 0;
char **
get_macro_args (def)
MACRO_DEF *def;
{
register int i;
char *word;
/* Quickly check to see if this macro has been invoked with any arguments.
If not, then don't skip any of the following whitespace. */
for (i = input_text_offset; i < size_of_input_text; i++)
if (!cr_or_whitespace (input_text[i]))
break;
if (input_text[i] != '{')
{
if (braces_required_for_macro_args)
{
return ((char **)NULL);
}
else
{
/* Braces are not required to fill out the macro arguments. If
this macro takes one argument, it is considered to be the
remainder of the line, sans whitespace. */
if (def->arglist && def->arglist[0] && !def->arglist[1])
{
char **arglist;
get_rest_of_line (&word);
if (input_text[input_text_offset - 1] == '\n')
input_text_offset--;
/* canon_white (word); */
arglist = (char **)xmalloc (2 * sizeof (char *));
arglist[0] = word;
arglist[1] = (char *)NULL;
return (arglist);
}
else
{
/* The macro either took no arguments, or took more than
one argument. In that case, it must be invoked with
arguments surrounded by braces. */
return ((char **)NULL);
}
}
}
return (get_brace_args (def->flags & ME_QUOTE_ARG));
}
/* Substitute actual parameters for named parameters in body.
The named parameters which appear in BODY must by surrounded
reverse slashes, as in \foo\. */
char *
apply (named, actuals, body)
char **named, **actuals, *body;
{
register int i;
int new_body_index, new_body_size;
char *new_body, *text;
int length_of_actuals;
length_of_actuals = array_len (actuals);
new_body_size = strlen (body);
new_body = (char *)xmalloc (1 + new_body_size);
/* Copy chars from BODY into NEW_BODY. */
i = 0; new_body_index = 0;
while (1)
{
if (!body[i])
break;
if (body[i] != '\\')
new_body[new_body_index++] = body[i++];
else
{
/* Snarf parameter name, check against named parameters. */
char *param;
int param_start, which, len;
param_start = ++i;
while ((body[i]) && (body[i] != '\\'))
i++;
len = i - param_start;
param = (char *)xmalloc (1 + len);
memcpy (param, body + param_start, len);
param[len] = '\0';
if (body[i])
i++;
/* Now check against named parameters. */
for (which = 0; named && named[which]; which++)
if (strcmp (named[which], param) == 0)
break;
if (named[which])
{
if (which < length_of_actuals)
text = actuals[which];
else
text = (char *)NULL;
if (!text)
text = "";
len = strlen (text);
}
else
{
len += 2;
text = (char *)xmalloc (1 + len);
sprintf (text, "\\%s\\", param);
}
if ((2 + strlen (param)) < len)
new_body = (char *)xrealloc
(new_body, new_body_size += (1 + len));
free (param);
strcpy (new_body + new_body_index, text);
new_body_index += len;
if (!named[which])
free (text);
}
}
new_body[new_body_index] = '\0';
return (new_body);
}
/* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */
void
execute_macro (def)
MACRO_DEF *def;
{
register int i;
char **arglist;
int num_args;
char *execution_string = (char *)NULL;
if (macro_expansion_output_stream && !me_inhibit_expansion)
me_append_before_this_command ();
/* Find out how many arguments this macro definition takes. */
num_args = array_len (def->arglist);
/* Gather the arguments present on the line if there are any. */
arglist = get_macro_args (def);
if (num_args < array_len (arglist))
{
free_array (arglist);
line_error ("Macro `%s' called with too many args", def->name);
return;
}
if (def->body)
execution_string = apply (def->arglist, arglist, def->body);
free_array (arglist);
if (def->body)
{
if (macro_expansion_output_stream && !me_inhibit_expansion)
{
remember_itext (input_text, input_text_offset);
me_execute_string (execution_string);
}
else
execute_string ("%s", execution_string);
free (execution_string);
}
}
/* Read and remember the definition of a macro. */
void
cm_macro ()
{
register int i;
char *name, **arglist, *body, *line;
int body_size, body_index;
int depth = 1;
int defining_line = line_number;
int flags = 0;
arglist = (char **)NULL;
body = (char *)NULL;
body_size = 0;
body_index = 0;
if (macro_expansion_output_stream)
me_append_before_this_command ();
skip_whitespace ();
/* Get the name of the macro. This is the set of characters which are
not whitespace and are not `{' immediately following the @macro. */
{
int start = input_text_offset;
int len;
for (i = start;
(i < size_of_input_text) &&
(input_text[i] != '{') &&
(!cr_or_whitespace (input_text[i]));
i++);
len = i - start;
name = (char *)xmalloc (1 + len);
strncpy (name, input_text + start, len);
name[len] = '\0';
input_text_offset = i;
}
skip_whitespace ();
/* It is not required that the definition of a macro includes an arglist.
If not, don't try to get the named parameters, just use a null list. */
if (curchar () == '{')
{
int arglist_index = 0, arglist_size = 0;
int gathering_words = 1;
char *word = (char *)NULL;
int character;
/* Read the words inside of the braces which determine the arglist.
These words will be replaced within the body of the macro at
execution time. */
input_text_offset++;
skip_whitespace_and_newlines ();
while (gathering_words)
{
int len;
for (i = input_text_offset;
character = input_text[i];
i++)
{
switch (character)
{
case '\n':
line_number++;
case ' ':
case '\t':
case ',':
case '}':
/* Found the end of the current arglist word. Save it. */
len = i - input_text_offset;
word = (char *)xmalloc (1 + len);
strncpy (word, input_text + input_text_offset, len);
word[len] = '\0';
input_text_offset = i;
/* Advance to the comma or close-brace that signified
the end of the argument. */
while ((character = curchar ())
&& character != ','
&& character != '}')
{
input_text_offset++;
if (character == '\n')
line_number++;
}
/* Add the word to our list of words. */
if ((arglist_index + 2) >= arglist_size)
arglist = (char **)xrealloc
(arglist, (arglist_size += 10) * sizeof (char *));
arglist[arglist_index++] = word;
arglist[arglist_index] = (char *)NULL;
break;
}
if (character == '}')
{
input_text_offset++;
gathering_words = 0;
break;
}
if (character == ',')
{
input_text_offset++;
skip_whitespace_and_newlines ();
i = input_text_offset - 1;
}
}
}
}
/* Read the text carefully until we find an "@end macro" which
matches this one. The text in between is the body of the macro. */
skip_whitespace_and_newlines ();
while (depth)
{
if ((input_text_offset + 9) > size_of_input_text)
{
int temp_line = line_number;
line_number = defining_line;
line_error ("%cend macro not found", COMMAND_PREFIX);
line_number = temp_line;
return;
}
get_rest_of_line (&line);
/* Handle commands only meaningful within a macro. */
if ((*line == COMMAND_PREFIX) && (depth == 1) &&
(strncmp (line + 1, "allow-recursion", 15) == 0) &&
(line[16] == '\0' || whitespace (line[16])))
{
for (i = 16; whitespace (line[i]); i++);
strcpy (line, line + i);
flags |= ME_RECURSE;
if (!*line)
{
free (line);
continue;
}
}
if ((*line == COMMAND_PREFIX) && (depth == 1) &&
(strncmp (line + 1, "quote-arg", 9) == 0) &&
(line[10] == '\0' || whitespace (line[10])))
{
for (i = 10; whitespace (line[i]); i++);
strcpy (line, line + i);
if (arglist && arglist[0] && !arglist[1])
{
flags |= ME_QUOTE_ARG;
if (!*line)
{
free (line);
continue;
}
}
else
{
line_error ("%cquote-arg only useful when the macro takes a single argument",
COMMAND_PREFIX);
}
}
if ((*line == COMMAND_PREFIX) &&
(strncmp (line + 1, "macro ", 6) == 0))
depth++;
if ((*line == COMMAND_PREFIX) &&
(strncmp (line + 1, "end macro", 9) == 0))
depth--;
if (depth)
{
if ((body_index + strlen (line) + 3) >= body_size)
body = (char *)xrealloc
(body, body_size += 3 + strlen (line));
strcpy (body + body_index, line);
body_index += strlen (line);
body[body_index++] = '\n';
body[body_index] = '\0';
}
free (line);
}
/* We now have the name, the arglist, and the body. However, BODY
includes the final newline which preceded the `@end macro' text.
Delete it. */
if (body && strlen (body))
body[strlen (body) - 1] = '\0';
add_macro (name, arglist, body, input_filename, defining_line, flags);
if (macro_expansion_output_stream)
remember_itext (input_text, input_text_offset);
}
void
cm_unmacro ()
{
register int i;
char *line, *name;
MACRO_DEF *def;
if (macro_expansion_output_stream)
me_append_before_this_command ();
get_rest_of_line (&line);
canon_white (line);
for (i = 0; line[i] && !whitespace (line[i]); i++);
name = (char *)xmalloc (i);
strncpy (name, line, i);
name[i] = '\0';
def = delete_macro (name);
if (def)
{
free (def->source_file);
free (def->name);
free (def->body);
if (def->arglist)
{
register int i;
for (i = 0; def->arglist[i]; i++)
free (def->arglist[i]);
free (def->arglist);
}
free (def);
}
free (line);
free (name);
if (macro_expansion_output_stream)
remember_itext (input_text, input_text_offset);
}
/* How to output sections of the input file verbatim. */
/* Set the value of POINTER's offset to OFFSET. */
ITEXT *
remember_itext (pointer, offset)
char *pointer;
int offset;
{
register int i;
ITEXT *itext = (ITEXT *)NULL;
/* If we have no info, initialize a blank list. */
if (!itext_info)
{
itext_info = (ITEXT **)xmalloc ((itext_size = 10) * sizeof (ITEXT *));
for (i = 0; i < itext_size; i++)
itext_info[i] = (ITEXT *)NULL;
}
/* If the pointer is already present in the list, then set the offset. */
for (i = 0; i < itext_size; i++)
if ((itext_info[i] != (ITEXT *)NULL) &&
(itext_info[i]->pointer == pointer))
{
itext = itext_info[i];
itext_info[i]->offset = offset;
break;
}
if (i == itext_size)
{
/* Find a blank slot, (or create a new one), and remember the
pointer and offset. */
for (i = 0; i < itext_size; i++)
if (itext_info[i] == (ITEXT *)NULL)
break;
/* If not found, then add some slots. */
if (i == itext_size)
{
register int j;
itext_info = (ITEXT **)xrealloc
(itext_info, (itext_size += 10) * sizeof (ITEXT *));
for (j = i; j < itext_size; j++)
itext_info[j] = (ITEXT *)NULL;
}
/* Now add the pointer and the offset. */
itext_info[i] = (ITEXT *)xmalloc (sizeof (ITEXT));
itext_info[i]->pointer = pointer;
itext_info[i]->offset = offset;
itext = itext_info[i];
}
return (itext);
}
/* Forget the input text associated with POINTER. */
void
forget_itext (pointer)
char *pointer;
{
register int i;
for (i = 0; i < itext_size; i++)
if (itext_info[i] && (itext_info[i]->pointer == pointer))
{
free (itext_info[i]);
itext_info[i] = (ITEXT *)NULL;
break;
}
}
/* Append the text which appeared in input_text from the last offset to
the character just before the command that we are currently executing. */
void
me_append_before_this_command ()
{
register int i;
for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--);
maybe_write_itext (input_text, i);
}
/* Similar to execute_string (), but only takes a single string argument,
and remembers the input text location, etc. */
void
me_execute_string (execution_string)
char *execution_string;
{
pushfile ();
input_text_offset = 0;
input_text = execution_string;
input_filename = strdup (input_filename);
size_of_input_text = strlen (execution_string);
remember_itext (execution_string, 0);
executing_string++;
reader_loop ();
popfile ();
executing_string--;
}
/* Append the text which appears in input_text from the last offset to
the current OFFSET. */
void
append_to_expansion_output (offset)
int offset;
{
register int i;
ITEXT *itext = (ITEXT *)NULL;
for (i = 0; i < itext_size; i++)
if (itext_info[i] && itext_info[i]->pointer == input_text)
{
itext = itext_info[i];
break;
}
if (!itext)
itext = remember_itext (input_text, 0);
if (offset > itext->offset)
{
write_region_to_macro_output
(input_text, itext->offset, offset);
remember_itext (input_text, offset);
}
}
/* Only write this input text iff it appears in our itext list. */
void
maybe_write_itext (pointer, offset)
char *pointer;
int offset;
{
register int i;
ITEXT *itext = (ITEXT *)NULL;
for (i = 0; i < itext_size; i++)
if (itext_info[i] && (itext_info[i]->pointer == pointer))
{
itext = itext_info[i];
break;
}
if (itext && (itext->offset < offset))
{
write_region_to_macro_output (itext->pointer, itext->offset, offset);
remember_itext (pointer, offset);
}
}
void
write_region_to_macro_output (string, start, end)
char *string;
int start, end;
{
if (macro_expansion_output_stream)
fwrite (string + start, 1, end - start, macro_expansion_output_stream);
}
#endif /* HAVE_MACROS */
/* Return the length of the array in ARRAY. */
int
array_len (array)
char **array;
{
register int i = 0;
if (array)
for (i = 0; array[i] != (char *)NULL; i++);
return (i);
}
void
free_array (array)
char **array;
{
if (array)
{
register int i;
for (i = 0; array[i] != (char *)NULL; i++)
free (array[i]);
free (array);
}
}
/* Function is used even when we don't have macros. Although, I have
to admit, it is unlikely that you would have a use for it if you
aren't using macros. */
char **
get_brace_args (quote_single)
int quote_single;
{
char **arglist, *word;
int arglist_index, arglist_size;
int character, escape_seen, start;
int depth = 1;
/* There is an arglist in braces here, so gather the args inside of it. */
skip_whitespace_and_newlines ();
input_text_offset++;
arglist = (char **)NULL;
arglist_index = arglist_size = 0;
get_arg:
skip_whitespace_and_newlines ();
start = input_text_offset;
escape_seen = 0;
while (character = curchar ())
{
if (character == '\\')
{
input_text_offset += 2;
escape_seen = 1;
}
else if (character == '{')
{
depth++;
input_text_offset++;
}
else if ((character == ',' && !quote_single) ||
((character == '}') && depth == 1))
{
int len = input_text_offset - start;
if (len || (character != '}'))
{
word = (char *)xmalloc (1 + len);
strncpy (word, input_text + start, len);
word[len] = '\0';
/* Clean up escaped characters. */
if (escape_seen)
{
register int i;
for (i = 0; word[i]; i++)
if (word[i] == '\\')
memmove (word + i, word + i + 1,
1 + strlen (word + i + 1));
}
if (arglist_index + 2 >= arglist_size)
arglist = (char **)xrealloc
(arglist, (arglist_size += 10) * sizeof (char *));
arglist[arglist_index++] = word;
arglist[arglist_index] = (char *)NULL;
}
input_text_offset++;
if (character == '}')
break;
else
goto get_arg;
}
else if (character == '}')
{
depth--;
input_text_offset++;
}
else
{
input_text_offset++;
if (character == '\n') line_number++;
}
}
return (arglist);
}
/* **************************************************************** */
/* */
/* Looking For Include Files */
/* */
/* **************************************************************** */
/* Given a string containing units of information separated by colons,
return the next one pointed to by INDEX, or NULL if there are no more.
Advance INDEX to the character after the colon. */
char *
extract_colon_unit (string, index)
char *string;
int *index;
{
int i, start;
i = *index;
if (!string || (i >= strlen (string)))
return ((char *)NULL);
/* Each call to this routine leaves the index pointing at a colon if
there is more to the path. If I is > 0, then increment past the
`:'. If I is 0, then the path has a leading colon. Trailing colons
are handled OK by the `else' part of the if statement; an empty
string is returned in that case. */
if (i && string[i] == ':')
i++;
start = i;
while (string[i] && string[i] != ':') i++;
*index = i;
if (i == start)
{
if (string[i])
(*index)++;
/* Return "" in the case of a trailing `:'. */
return (strdup (""));
}
else
{
char *value;
value = (char *)xmalloc (1 + (i - start));
strncpy (value, &string[start], (i - start));
value [i - start] = '\0';
return (value);
}
}
/* Return the full pathname for FILENAME by searching along PATH.
When found, return the stat () info for FILENAME in FINFO.
If PATH is NULL, only the current directory is searched.
If the file could not be found, return a NULL pointer. */
char *
get_file_info_in_path (filename, path, finfo)
char *filename, *path;
struct stat *finfo;
{
char *dir;
int result, index = 0;
if (path == (char *)NULL)
path = ".";
/* Handle absolute pathnames. "./foo", "/foo", "../foo". */
if (*filename == '/' ||
(*filename == '.' &&
(filename[1] == '/' ||
(filename[1] == '.' && filename[2] == '/'))))
{
if (stat (filename, finfo) == 0)
return (strdup (filename));
else
return ((char *)NULL);
}
while (dir = extract_colon_unit (path, &index))
{
char *fullpath;
if (!*dir)
{
free (dir);
dir = strdup (".");
}
fullpath = (char *)xmalloc (2 + strlen (dir) + strlen (filename));
sprintf (fullpath, "%s/%s", dir, filename);
free (dir);
result = stat (fullpath, finfo);
if (result == 0)
return (fullpath);
else
free (fullpath);
}
return ((char *)NULL);
}
texinfo-3.7/makeinfo/makeinfo.texi 100666 11732 13 24030 5764641161 15540 0 ustar bfox user \input texinfo @c -*-texinfo-*-
@comment %**start of header
@setfilename makeinfo.info
@set VERSION 1.61
@paragraphindent none
@comment %**start of header
@ifinfo
This file is an extract from the @cite{Texinfo} manual.@*
It documents @code{makeinfo}, a program that converts Texinfo
files into Info files.
Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@ignore
Permission is granted to process this file through TeX and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the Free Software Foundation.
@end ifinfo
@titlepage
@title GNU Makeinfo
@author Brian J. Fox and Robert J. Chassell
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the Free Software Foundation.
@end titlepage
@node Top, ,(dir), (dir)
@chapter What is @code{makeinfo}?
@iftex
This file documents the use of the @code{makeinfo} program, versions
@value{VERSION} and later. It is an extract from the @cite{TeXinfo} manual.
@end iftex
@code{makeinfo} is a program for converting @dfn{TeXinfo} files into @dfn{Info}
files. TeXinfo is a documentation system that uses a single source file to
produce both on-line information and printed output.
You can read the on-line information using Info; type @code{info} to
learn about Info.
@ifinfo
@xref{Top, Texinfo, Overview of Texinfo, texinfo, Texinfo},
@end ifinfo
@iftex
See the @cite{TeXinfo} manual,
@end iftex
to learn about the TeXinfo documentation system.
@menu
* Formatting Control:: Controlling the width of lines, paragraph
indentation, and other similar formatting.
* Options:: Command line options which control the
behaviour of Makeinfo.
* Pointer Validation:: How Makeinfo can help you to track node
references through complex Texinfo files.
* The Macro Facility:: Makeinfo allows the use of @dfn{macros}.
* Index:: Index of Concepts.
@end menu
@node Formatting Control
@section Controlling Paragraph Formats
Without any special options, @code{makeinfo} @dfn{fills} the paragraphs that
it outputs to an Info file. Filling is the process of breaking and connecting
lines so that lines are the same length as or shorter than the number
specified as the fill column. Lines are broken between words. With
@code{makeinfo}, you can control:
@itemize @bullet
@item
The width of each paragraph (the @dfn{fill-column}).
@item
The amount of indentation that the first line of
each paragraph receives (the @dfn{paragraph-indentation}).
@end itemize
@node Options
@section Command Line Options
The following command line options are available for @code{makeinfo}.
@need 100
@table @code
@item -D @var{var}
Cause @var{var} to be defined. This is equivalent to
@code{@@set @var{var}} in the Texinfo file.
@need 150
@item --error-limit @var{limit}
Set the maximum number of errors that @code{makeinfo} will report
before exiting (on the assumption that continuing would be useless).
The default number of errors that can be reported before
@code{makeinfo} gives up is 100.@refill
@need 150
@item --fill-column @var{width}
Specify the maximum number of columns in a line; this is the right-hand
edge of a line. Paragraphs that are filled will be filled to this
width. The default value for @code{fill-column} is 72.
@refill
@item --footnote-style @var{style}
Set the footnote style to @var{style}, either @samp{end} for the end
node style or @samp{separate} for the separate node style. The value
set by this option overrides the value set in a Texinfo file by an
@code{@@footnotestyle} command. When the footnote style is
@samp{separate}, @code{makeinfo} makes a new node containing the
footnotes found in the current node. When the footnote style is
@samp{end}, @code{makeinfo} places the footnote references at the end
of the current node.@refill
@need 150
@item -I @var{dir}
Add @code{dir} to the directory search list for finding files that are
included using the @code{@@include} command. By default,
@code{makeinfo} searches only the current directory.
@need 150
@item --no-headers
Do not include menus or node lines in the output. This results in an
@sc{ascii} file that you cannot read in Info since it does not contain
the requisite nodes or menus; but you can print such a file in a
single, typewriter-like font and produce acceptable output.
@need 150
@item --no-split
Suppress the splitting stage of @code{makeinfo}. Normally, large
output files (where the size is greater than 70k bytes) are split into
smaller subfiles, each one approximately 50k bytes. If you specify
@samp{--no-split}, @code{makeinfo} will not split up the output
file.@refill
@need 100
@item --no-pointer-validate
@item --no-validate
Suppress the pointer-validation phase of @code{makeinfo}. Normally,
after a Texinfo file is processed, some consistency checks are made to
ensure that cross references can be resolved, etc.
@xref{Pointer Validation}.@refill
@need 150
@item --no-warn
Suppress the output of warning messages. This does @emph{not}
suppress the output of error messages, only warnings. You might
want this if the file you are creating has examples of Texinfo cross
references within it, and the nodes that are referenced do not actually
exist.@refill
@item --no-number-footnotes
Supress automatic footnote numbering. By default, @code{makeinfo}
numbers each footnote sequentially in a single node, resetting the
current footnote number to 1 at the start of each node.
@need 150
@item --output @var{file}
@itemx -o @var{file}
Specify that the output should be directed to @var{file} and not to the
file name specified in the @code{@@setfilename} command found in the Texinfo
source. @var{file} can be the special token @samp{-}, which specifies
standard output.
@need 150
@item --paragraph-indent @var{indent}
Set the paragraph indentation style to @var{indent}. The value set by
this option overrides the value set in a Texinfo file by an
@code{@@paragraphindent} command. The value of @var{indent} is
interpreted as follows:@refill
@itemize @bullet
@item
If the value of @var{indent} is @samp{asis}, do not change the
existing indentation at the starts of paragraphs.@refill
@item
If the value of @var{indent} is zero, delete any existing
indentation.@refill
@item
If the value of @var{indent} is greater than zero, indent each
paragraph by that number of spaces.@refill
@end itemize
@need 100
@item --reference-limit @var{limit}
Set the value of the number of references to a node that
@code{makeinfo} will make without reporting a warning. If a node has more
than this number of references in it, @code{makeinfo} will make the
references but also report a warning.@refill
@need 150
@item -U @var{var}
Cause @var{var} to be undefined. This is equivalent to
@code{@@clear @var{var}} in the Texinfo file.
@need 100
@item --verbose
Cause @code{makeinfo} to display messages saying what it is doing.
Normally, @code{makeinfo} only outputs messages if there are errors or
warnings.@refill
@need 100
@item --version
Report the version number of this copy of @code{makeinfo}.@refill
@item --help
Show a summary of the commend line arguments to @code{makeinfo}.
@end table
@node Pointer Validation
@section Pointer Validation
@cindex Pointer validation with @code{makeinfo}
@cindex Validation of pointers
If you do not suppress pointer-validation (by using the
@samp{--no-pointer-validation} option), @code{makeinfo}
will check the validity of the final Info file. Mostly,
this means ensuring that nodes you have referenced
really exist. Here is a complete list of what is
checked:@refill
@enumerate
@item
If a `Next', `Previous', or `Up' node reference is a reference to a
node in the current file and is not an external reference such as to
@file{(dir)}, then the referenced node must exist.@refill
@item
In every node, if the `Previous' node is different from the `Up' node,
then the `Previous' node must also be pointed to by a `Next' node.@refill
@item
Every node except the `Top' node must have an `Up' pointer.@refill
@item
The node referenced by an `Up' pointer must contain a reference to the
current node in some manner other than through a `Next' reference.
This includes menu entries and cross references.@refill
@item
If the `Next' reference of a node is not the same as the `Next' reference
of the `Up' reference, then the node referenced by the `Next' pointer
must have a `Previous' pointer that points back to the current node.
This rule allows the last node in a section to point to the first node
of the next chapter.@refill
@end enumerate
@lowersections
@include macro.texi
@raisesections
@lowersections
@node Index
@appendix Index
@printindex cp
@raisesections
@contents
@bye
texinfo-3.7/makeinfo/multiformat.texi 100644 11732 13 2142 5764641162 16267 0 ustar bfox user @c multiformat.texi: -*- Texinfo -*- \input texinfo.tex
@c Copyright (c) 1995 Universal Access, Inc
@c Author: Brian J. Fox (bfox@ua.com) Sun Apr 2 07:56:23 1995.
@setfilename multiformat.info
@include html.texi
@ifset html
@html
@end ifset
@node First Node, First Section, (dir), (dir)
@chapter First Chapter
Here is some text that belongs in the first chapter. Nothing very
exciting happens here, but this is enough text to span a couple of
lines, and we feel that is important.
@paragraph
This is the second paragraph of the first chapter. Note that the
formatting commands in @code{HTML} seem to do the right thing, as do the
commands when invoked in @code{Texinfo} mode and in @TeX{}.
@node First Section, , First Node, First Node
@isection First Section
Here is some text in the first section of the first chapter. We are
trying very hard to examine the output here to see exactly how proper it
is. If I wasn't so tired, we could probably see it already.
@paragraph
Here is a list of items:
@paragraph
@itemize @bullet
@item Here is the first item.
@item Here is the second item.
@end itemize
@bye
texinfo-3.7/info/ 40777 11732 13 0 6067136360 12077 5 ustar bfox user texinfo-3.7/info/Makefile.in 100666 11732 13 14772 5771744311 14276 0 ustar bfox user # Makefile for texinfo/info. -*- Indented-Text -*-
# Copyright (C) 1993 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.
#### Start of system configuration section. ####
srcdir = @srcdir@
VPATH = $(srcdir):$(common)
common = $(srcdir)/../libtxi
util = $(srcdir)/../util
CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
LN = ln
RM = rm -f
TAR = tar
MKDIR = mkdir
MAKEINFO= PATH=../makeinfo:$$PATH makeinfo
COMPRESS= compress
DEFS = @DEFS@
LDEFS = -DHANDLE_MAN_PAGES -DNAMED_FUNCTIONS=1 -DDEFAULT_INFOPATH='"$(DEFAULT_INFOPATH)"'
TERMLIBS = @TERMLIBS@
LIBS = $(TERMLIBS) -L../libtxi -ltxi @LIBS@
LOADLIBES = $(LIBS)
SHELL = /bin/sh
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = $(exec_prefix)/bin
# Prefix for each installed program, normally empty or `g'.
binprefix =
libdir = $(prefix)/lib
# Prefix for each installed man page, normally empty or `g'.
manprefix =
mandir = $(prefix)/man/man1
manext = 1
infodir = $(prefix)/info
DEFAULT_INFOPATH= $(infodir):.
#### End of system configuration section. ####
SRCS = dir.c display.c echo_area.c filesys.c \
info-utils.c info.c infodoc.c infomap.c \
m-x.c nodes.c search.c session.c \
signals.c terminal.c tilde.c window.c \
xmalloc.c indices.c makedoc.c nodemenu.c \
footnotes.c dribble.c variables.c gc.c man.c \
clib.c
HDRS = display.h doc.h echo_area.h filesys.h \
general.h getopt.h info-utils.h info.h \
infomap.h nodes.h search.h session.h \
signals.h termdep.h terminal.h tilde.h \
indices.h window.h footnotes.h dribble.h \
variables.h gc.h clib.h
OBJS = dir.o display.o doc.o echo_area.o filesys.o info-utils.o info.o \
infodoc.o infomap.o m-x.o nodes.o search.o session.o signals.o \
terminal.o tilde.o window.o indices.o xmalloc.o nodemenu.o \
footnotes.o dribble.o variables.o gc.o man.o clib.o
# The names of files which declare info commands.
CMDFILES = $(srcdir)/session.c $(srcdir)/echo_area.c $(srcdir)/infodoc.c \
$(srcdir)/m-x.c $(srcdir)/indices.c $(srcdir)/nodemenu.c \
$(srcdir)/footnotes.c $(srcdir)/variables.c
# The name of the program which builds documentation structure from CMDFILES.
MAKEDOC_OBJECTS = makedoc.o clib.o xmalloc.o
MAKEDOC_SOURCE = makedoc.c clib.c xmalloc.c
.c.o:
$(CC) -c $(CPPFLAGS) $(LDEFS) $(DEFS) -I. -I$(srcdir) -I$(common) $(CFLAGS) $<
all: info info.info info-stnd.info
sub-all: all
install: all
$(INSTALL_PROGRAM) info $(bindir)/$(binprefix)info
-d=$(srcdir); test -f ./info.info && d=.; $(INSTALL_DATA) $$d/info.info $(infodir)/info.info
-d=$(srcdir); test -f ./info-stnd.info && d=.; $(INSTALL_DATA) $$d/info-stnd.info $(infodir)/info-stnd.info
-$(INSTALL_DATA) $(srcdir)/info.1 $(mandir)/info.$(manext)
uninstall:
$(RM) $(bindir)/info
$(RM) $(infodir)/info.info
$(RM) $(infodir)/info-stnd.info
$(RM) $(mandir)/info.$(manext)
info: $(OBJS) ../libtxi/libtxi.a
$(CC) $(LDFLAGS) -o info $(OBJS) $(LOADLIBES)
all-info: info.info info-stnd.info
info.info: info.texi
$(MAKEINFO) --no-split -I$(srcdir) info.texi
info-stnd.info: info-stnd.texi
$(MAKEINFO) --no-split -I$(srcdir) info-stnd.texi
all-dvi: info.dvi info-stnd.dvi
info.dvi: info.texi
PATH="$(util):$${PATH}" TEXINPUTS="$(srcdir):$(common):$${TEXINPUTS}" texi2dvi $(srcdir)/info.texi
info-stnd.dvi: info-stnd.texi
PATH="$(util):$${PATH}" TEXINPUTS="$(srcdir):$(common):$${TEXINPUTS}" texi2dvi $(srcdir)/info-stnd.texi
makedoc: $(MAKEDOC_OBJECTS) ../libtxi/libtxi.a
$(CC) $(LDFLAGS) -o makedoc $(MAKEDOC_OBJECTS) $(LOADLIBES)
Makefile: $(srcdir)/Makefile.in ../config.status
cd ..; sh config.status
clean:
$(RM) info funs.h doc.c makedoc $(OBJS) $(MAKEDOC_OBJECTS)
distclean: clean texclean
$(RM) Makefile config.status config.cache *~ core core.* *.core
$(RM) *.BAK makedoc-TAGS TAGS \#*
mostlyclean: clean
realclean: distclean
$(RM) info.info info-stnd.info
TAGS: $(SRCS) makedoc-TAGS
etags $(SRCS)
cat makedoc-TAGS >>TAGS && $(RM) makedoc-TAGS
makedoc-TAGS: $(CMDFILES)
./makedoc -tags $(CMDFILES) >makedoc-TAGS
texclean:
$(RM) *.toc *.aux *.log *.cp *.fn *.tp *.vr *.pg *.ky *.cps
$(RM) *.tps *.fns *.kys *.pgs *.vrs
check: info
# The files `doc.c' and `funs.h' are created by ./makedoc run over the source
# files which contain DECLARE_INFO_COMMAND. `funs.h' is a header file
# listing the functions found. `doc.c' is a structure containing pointers
# to those functions along with completable names and documentation strings.
funs.h: makedoc $(CMDFILES)
-@if test -f funs.h; then mv -f funs.h old-funs.h; fi; :
-@if test -f doc.c; then mv -f doc.c old-doc.c; fi; :
./makedoc $(CMDFILES)
-@if cmp -s old-funs.h funs.h; then mv old-funs.h funs.h; \
else $(RM) old-funs.h; fi; :
-@if cmp -s old-doc.c doc.c; then mv old-doc.c doc.c; \
else $(RM) old-doc.c; fi; :
doc.c: funs.h
dribble.o: dribble.c dribble.h
display.o: display.c
echo_area.o: echo_area.c
filesys.o: filesys.c
info-utils.o: info-utils.c
info.o: info.c filesys.h
infodoc.o: infodoc.c
infomap.o: infomap.c
m-x.o: m-x.c
nodes.o: nodes.c
search.o: search.c
session.o: session.c
signals.o: signals.c
terminal.o: terminal.c
tilde.o: tilde.c
window.o: window.c
xmalloc.o: xmalloc.c
indices.o: indices.c
makedoc.o: makedoc.c
dir.o: dir.c
display.o: nodes.h info-utils.h search.h
display.o: terminal.h window.h display.h
echo_area.o: info.h
filesys.o: general.h tilde.h filesys.h
footnotes.o: footnotes.h
info-utils.o: info-utils.h nodes.h search.h
info.o: info.h $(common)/getopt.h
infodoc.o: info.h doc.h
infomap.o: infomap.h funs.h
gc.o: info.h
m-x.o: info.h
nodes.o: search.h filesys.h
nodes.o: nodes.h info-utils.h
search.o: general.h search.h nodes.h
session.o: info.h
signals.o: info.h signals.h
terminal.o: terminal.h termdep.h
tilde.o: tilde.h
variables.c: variables.h
window.o: nodes.h window.h display.h
window.o: info-utils.h search.h infomap.h
# Prevent GNU make v3 from overflowing arg limit on SysV.
.NOEXPORT:
# eof
texinfo-3.7/info/NEWS 100666 11732 13 20053 5764640666 12727 0 ustar bfox user This release of Info is version 2.11. Please read the file README.
Version 2.11, Sat Apr 1 09:15:21 1995
Changes since 2.7 beta:
Although the basic code remains the same, there are numerous nits
fixed, including some display bugs, and a memory leak. Some changes
that have taken place with larger impact include the way in which the
(dir) node is built; I have added in support for "localdir"
directories among other things. Info files may be stored in
compressed formats, and in their own subdirectories; menu items which
do not explicitly name the node to which they are attached have the
menu item name looked up as an Info file if it is not found within the
current document. This means that the menu item:
* Info:: The Info documentation reader.
in (dir) refers to the info node "(info)Top".
Please see the ChangeLog and documentation for details on other
changes.
Version 2.7 beta, Wed Dec 30 02:02:38 1992
Version 2.6 beta, Tue Dec 22 03:58:07 1992
Version 2.5 beta, Tue Dec 8 14:50:35 1992
Version 2.4 beta, Sat Nov 28 14:34:02 1992
Version 2.3 beta, Fri Nov 27 01:04:13 1992
Version 2.2 beta, Tue Nov 24 09:36:08 1992
Version 2.1 beta, Tue Nov 17 23:29:36 1992
Changes since 2.5 beta:
Note that versions 2.6 and 2.7 Beta were only released to a select group.
* "info-" removed from the front of M-x commands.
* Automatic footnote display. When you enter a node which contains
footnotes, and the variable "automatic-footnotes" is "On", Info pops
up a window containing the footnotes. Likewise, when you leave that
node, the window containing the footnotes goes away.
* Cleaner built in documentation, and documentation functions.
Use:
o `M-x describe-variable' to read a variable's documenation
o `M-x describe-key' to find out what a particular keystroke does.
o `M-x describe-function' to read a function's documentation.
o `M-x where-is' to find out what keys invoke a particular function.
* Info can "tile" the displayed windows (via "M-x tile-windows"). If
the variable "automatic-tiling" is "On", then splitting a window or
deleting a window causes the remaining windows to be retiled.
* You can save every keystroke you type in a "dribble file" by using the
`--dribble FILENAME' option. You can initially read keystrokes from an
alternate input stream with `--restore FILENAME', or by redirecting
input on the command line `info < old-dribble'.
* New behaviour of menu items. If the label is the same as the
target node name, and the node couldn't be found in the current file,
treat the label as a file name. For example, a menu entry in "DIR"
might contain:
* Emacs:: Cool text-editor.
Info would not find the node "(dir)Emacs", so just plain "(emacs)"
would be tried.
* New variable "ISO-Latin" allows you to use European machines with
8-bit character sets.
* Cleanups in echo area reading, and redisplay. Cleanups in handling the
window which shows possible completions.
* Info can now read files that have been compressed. An array in filesys.c
maps extensions to programs that can decompress stdin, and write the results
to stdout. Currently, ".Z"/uncompress, ".z"/gunzip, and ".Y"/unyabba are
supported. The modeline for a compressed file shows "zz" in it.
* There is a new variable "gc-compressed-files" which, if non-zero, says
it is okay to reclaim the file buffer space allocated to a file which
was compressed, if, and only if, that file's contents do not appear in
any history node.
* New file `nodemenu.c' implements a few functions for manipulating
previously visited nodes. `C-x C-b' (list-visited-nodes) produces a
menu of the nodes that could be reached by info-history-node in some
window. `C-x b' (select-visited-node) is similar, but reads one of
the node names with completion.
* Keystroke `M-r' (move_to_screen_line) allows the user to place the cursor at
the start of a specific screen line. Without a numeric argument, place the
cursor on the center line; with an arg, place the cursor on that line.
* Interruptible display implemented. Basic display speedups and hacks.
* The message "*** Tags Out of Date ***" now means what it says.
* Index searching with `,' (info-index-next) has been improved.
* When scrolling with C-v, C-M-v, or M-v, only "Page Only" scrolling
will happen.
* Continous scrolling (along with `]' (info-global-next) and `['
(info-global-prev) works better. `]' and `[' accept numeric
arguments, moving that many nodes in that case.
* `C-x w' (info-toggle-wrap) controls how lines wider than the width
of the screen are displayed. If a line is too long, a `$' is
displayed in the rightmost column of the window.
* There are some new variables for controlling the behaviour of Info
interactively. The current list of variables is as follows:
Variable Name Default Value Description
------------- ------------- -----------
`automatic-footnotes' On When "On", footnotes appear and
disappear automatically.
`automatic-tiling' Off When "On", creating of deleting a
window resizes other windows.
`visible-bell' Off If non-zero, try to use a visible bell.
`errors-ring-bell' On If non-zero, errors cause a ring.
`show-index-match' On If non-zero, the portion of the string
matched is highlighted by changing its
case.
`scroll-behaviour' Continuous One of "Continuous", "Next Only", or
"Page Only". "Page Only" prevents you from
scrolling past the bottom or top of a node.
"Next Only" causes the Next or Prev node to
be selected when you scroll past the bottom
or top of a node. "Continous" moves
linearly through the files hierchichal
structure.
`scroll-step' 0 Controls how scrolling is done for you when
the cursor moves out of the current window.
Non-zero means it is the number of lines
you would like the screen to shift. A
value of 0 means to center the line
containing the cursor in the window.
`gc-compressed-files' Off If non-zero means it is okay to reclaim the
file buffer space allocated to a file which
was compressed, if, and only if, that
file's contents do not appear in the node
list of any window.
`ISO-Latin' Off Non-zero means that you are using an ISO
Latin character set. By default, standard
ASCII characters are assumed.
________________________________________
This release of Info is version 2.5 beta.
Changes since 2.4 beta:
* Index (i) and (,) commands fully implemented.
* "configure" script now shipped with Info.
* New function "set-variable" allows users to set various variables.
* User-settable behaviour on end or beginning of node scrolling. This
supercedes the SPC and DEL changes in 2.3 beta.
________________________________________
This release of Info is version 2.4 beta.
Changes since 2.3 beta:
* info-last-node now means move to the last node of this info file.
* info-history-node means move backwards through this window's node history.
* info-first-node moves to the first node in the Info file. This node is
not necessarily "Top"!
* SPC and DEL can select the Next or Prev node after printing an informative
message when pressed at the end/beg of a node.
----------------------------------------
This release of Info is version 2.3 beta.
Changes since 2.2 beta:
* M-x command lines if NAMED_COMMANDS is #defined. Variable in Makefile.
* Screen height changes made quite robust.
* Interactive function "set-screen-height" implements user height changes.
* Scrolling on some terminals is faster now.
* C-l with numeric arguement is fixed.
----------------------------------------
This release of Info is version 2.2 beta.
Changes since 2.0:
* C-g can now interrupt multi-file searches.
* Incremental search is fully implemented.
* Loading large tag tables is much faster now.
* makedoc.c replaces shell script, speeding incremental builds.
* Scrolling in redisplay is implemented.
* Recursive uses of the echo area made more robust.
* Garbage collection of unreferenced nodes.
texinfo-3.7/info/README 100666 11732 13 3075 5764640666 13075 0 ustar bfox user The file NEWS contains information about what has changed since the last
release.
The file ../INSTALL contains instructions on how to install Info.
Info 2.0 is a complete rewrite of the original standalone Info I wrote in
1987, the first program I wrote for rms. That program was something like
my second Unix program ever, and my die-hard machine language coding habits
tended to show through. I found the original Info hard to read and
maintain, and thus decided to write this one.
The rewrite consists of about 12,000 lines of code written in about 12
days. I believe this version of Info to be in much better shape than the
original Info, and the only reason it is in Beta test is because of its
short life span.
Info 2.0 is substantially different from its original standalone
predecessor. It appears almost identical to the GNU Emacs version, but has
the advantages of smaller size, ease of portability, and a built in library
which can be used in other programs (to get or display documentation from
Info files, for example).
I eagerly await responses to this newer version of Info; comments on its
portability, ease of use and user interface, code quality, and general
usefulness are all of interest to me, and I will appreciate any comments
that you would care to make.
A full listing of the commands available in Info can be gotten by typing
`?' while within an Info window. This produces a node in a window which
can be viewed just like any Info node.
Please send your comments, bug reports, and suggestions to
bug-texinfo@prep.ai.mit.edu
--Brian Fox
texinfo-3.7/info/clib.c 100666 11732 13 5016 5771507063 13256 0 ustar bfox user /* clib.c: Functions which we normally expect to find in the C library. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1995 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). */
#include
#if defined (HAVE_UNISTD_H)
#include
#endif
#if defined (HAVE_STDLIB_H)
#include
#endif
#if defined (HAVE_STRING_H)
#include
#endif
#include
extern void *xmalloc (), *xrealloc ();
#include "general.h"
#if !defined (errno)
extern int errno;
#endif
#if !defined (HAVE_STRDUP)
char *
strdup (string)
char *string;
{
char *result;
result = (char *)xmalloc (1 + strlen (string));
strcpy (result, string);
return (result);
}
#endif /* !HAVE_STRDUP */
#if !defined (HAVE_STRERROR)
extern char *sys_errlist[];
extern int sys_nerr;
char *
strerror (num)
int num;
{
if (num >= sys_nerr)
return ("");
else
return (sys_errlist[num]);
}
#endif /* !HAVE_STRERROR */
#if !defined (HAVE_STRCASECMP)
/* This Unix doesn't have the strcasecmp () function. */
int
strcasecmp (string1, string2)
char *string1, *string2;
{
char ch1, ch2;
for (;;)
{
ch1 = *string1++;
ch2 = *string2++;
if (!(ch1 | ch2))
return (0);
ch1 = info_toupper (ch1);
ch2 = info_toupper (ch2);
if (ch1 != ch2)
return (ch1 - ch2);
}
}
/* Compare at most COUNT characters from string1 to string2. Case
doesn't matter. */
int
strncasecmp (string1, string2, count)
char *string1, *string2;
int count;
{
register char ch1, ch2;
while (count)
{
ch1 = *string1++;
ch2 = *string2++;
ch1 = info_toupper (ch1);
ch2 = info_toupper (ch2);
if (ch1 == ch2)
count--;
else
break;
}
return (count);
}
#endif /* !STRCASECMP */
texinfo-3.7/info/clib.h 100666 11732 13 2353 5771506635 13270 0 ustar bfox user /* clib.h: Declarations of functions which appear in clib.c (or libc.a). */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1995 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). */
#if !defined (_CLIB_H_)
#define _CLIB_H_
#if !defined (HAVE_STRDUP)
extern char *strdup ();
#endif
#if !defined (HAVE_STRERROR)
extern char *strerror ();
#endif
#if !defined (HAVE_STRCASECMP)
extern int strcasecmp ();
extern int strncasecmp ();
#endif
#endif /* !_CLIB_H_ */
texinfo-3.7/info/dir.c 100666 11732 13 17734 5770343170 13151 0 ustar bfox user /* dir.c -- How to build a special "dir" node from "localdir" files. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include
#include
#include
#if defined (HAVE_SYS_FILE_H)
#include
#endif /* HAVE_SYS_FILE_H */
#include
#include "info-utils.h"
#include "filesys.h"
#include "tilde.h"
/* The "dir" node can be built from the contents of a file called "dir",
with the addition of the menus of every file named in the array
dirs_to_add which are found in INFOPATH. */
static void add_menu_to_file_buffer (), insert_text_into_fb_at_binding ();
static void build_dir_node_internal ();
static char *dirs_to_add[] = {
"dir", "localdir", (char *)NULL
};
void
maybe_build_dir_node (dirname)
char *dirname;
{
FILE_BUFFER *dir_buffer;
int path_index, update_tags;
char *this_dir;
/* Check to see if the file has already been built. If so, then
do not build it again. */
dir_buffer = info_find_file (dirname);
/* If there is no "dir" in the current info path, we cannot build one
from nothing. */
if (!dir_buffer)
return;
/* If this directory has already been built, return now. */
if (dir_buffer->flags & N_CannotGC)
return;
path_index = update_tags = 0;
/* Using each element of the path, check for one of the files in
DIRS_TO_ADD. Do not check for "localdir.info.Z" or anything else.
Only files explictly named are eligible. This is a design decision.
There can be an info file name "localdir.info" which contains
information on the setting up of "localdir" files. */
while (this_dir = extract_colon_unit (infopath, &path_index))
{
register int da_index;
char *from_file;
/* Expand a leading tilde if one is present. */
if (*this_dir == '~')
{
char *tilde_expanded_dirname;
tilde_expanded_dirname = tilde_expand_word (this_dir);
if (tilde_expanded_dirname != this_dir)
{
free (this_dir);
this_dir = tilde_expanded_dirname;
}
}
/* For every file named in DIRS_TO_ADD found in the search path,
add the contents of that file's menu to our "dir" node. */
for (da_index = 0; from_file = dirs_to_add[da_index]; da_index++)
{
struct stat finfo;
char *fullpath;
int namelen, statable;
namelen = strlen (from_file);
fullpath = (char *)xmalloc (3 + strlen (this_dir) + namelen);
strcpy (fullpath, this_dir);
if (fullpath[strlen (fullpath) - 1] != '/')
strcat (fullpath, "/");
strcat (fullpath, from_file);
statable = (stat (fullpath, &finfo) == 0);
/* Only add the contents of this file if it is not identical to the
file of the DIR buffer. */
if ((statable && S_ISREG (finfo.st_mode)) &&
(strcmp (dir_buffer->fullpath, fullpath) != 0))
{
long filesize;
char *contents;
contents = filesys_read_info_file (fullpath, &filesize, &finfo);
if (contents)
{
update_tags++;
add_menu_to_file_buffer (contents, filesize, dir_buffer);
free (contents);
}
}
free (fullpath);
}
free (this_dir);
}
if (update_tags)
build_tags_and_nodes (dir_buffer);
/* Flag that the dir buffer has been built. */
dir_buffer->flags |= N_CannotGC;
}
/* Given CONTENTS and FB (a file buffer), add the menu found in CONTENTS
to the menu found in FB->contents. Second argument SIZE is the total
size of CONTENTS. */
static void
add_menu_to_file_buffer (contents, size, fb)
char *contents;
long size;
FILE_BUFFER *fb;
{
SEARCH_BINDING contents_binding, fb_binding;
long contents_offset, fb_offset;
contents_binding.buffer = contents;
contents_binding.start = 0;
contents_binding.end = size;
contents_binding.flags = S_FoldCase | S_SkipDest;
fb_binding.buffer = fb->contents;
fb_binding.start = 0;
fb_binding.end = fb->filesize;
fb_binding.flags = S_FoldCase | S_SkipDest;
/* Move to the start of the menus in CONTENTS and FB. */
contents_offset = search_forward (INFO_MENU_LABEL, &contents_binding);
fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
/* If there is no menu in CONTENTS, quit now. */
if (contents_offset == -1)
return;
/* There is a menu in CONTENTS, and contents_offset points to the first
character following the menu starter string. Skip all whitespace
and newline characters. */
contents_offset += skip_whitespace_and_newlines (contents + contents_offset);
/* If there is no menu in FB, make one. */
if (fb_offset == -1)
{
/* Find the start of the second node in this file buffer. If there
is only one node, we will be adding the contents to the end of
this node. */
fb_offset = find_node_separator (&fb_binding);
/* If not even a single node separator, give up. */
if (fb_offset == -1)
return;
fb_binding.start = fb_offset;
fb_binding.start +=
skip_node_separator (fb_binding.buffer + fb_binding.start);
/* Try to find the next node separator. */
fb_offset = find_node_separator (&fb_binding);
/* If found one, consider that the start of the menu. Otherwise, the
start of this menu is the end of the file buffer (i.e., fb->size). */
if (fb_offset != -1)
fb_binding.start = fb_offset;
else
fb_binding.start = fb_binding.end;
insert_text_into_fb_at_binding
(fb, &fb_binding, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL));
fb_binding.buffer = fb->contents;
fb_binding.start = 0;
fb_binding.end = fb->filesize;
fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
if (fb_offset == -1)
abort ();
}
/* CONTENTS_OFFSET and FB_OFFSET point to the starts of the menus that
appear in their respective buffers. Add the remainder of CONTENTS
to the end of FB's menu. */
fb_binding.start = fb_offset;
fb_offset = find_node_separator (&fb_binding);
if (fb_offset != -1)
fb_binding.start = fb_offset;
else
fb_binding.start = fb_binding.end;
/* Leave exactly one blank line between directory entries. */
{
int num_found = 0;
while ((fb_binding.start > 0) &&
(whitespace_or_newline (fb_binding.buffer[fb_binding.start - 1])))
{
num_found++;
fb_binding.start--;
}
/* Optimize if possible. */
if (num_found >= 2)
{
fb_binding.buffer[fb_binding.start++] = '\n';
fb_binding.buffer[fb_binding.start++] = '\n';
}
else
{
/* Do it the hard way. */
insert_text_into_fb_at_binding (fb, &fb_binding, "\n\n", 2);
fb_binding.start += 2;
}
}
/* Insert the new menu. */
insert_text_into_fb_at_binding
(fb, &fb_binding, contents + contents_offset, size - contents_offset);
}
static void
insert_text_into_fb_at_binding (fb, binding, text, textlen)
FILE_BUFFER *fb;
SEARCH_BINDING *binding;
char *text;
int textlen;
{
char *contents;
long start, end;
start = binding->start;
end = fb->filesize;
contents = (char *)xmalloc (fb->filesize + textlen + 1);
memcpy (contents, fb->contents, start);
memcpy (contents + start, text, textlen);
memcpy (contents + start + textlen, fb->contents + start, end - start);
free (fb->contents);
fb->contents = contents;
fb->filesize += textlen;
fb->finfo.st_size = fb->filesize;
}
texinfo-3.7/info/display.c 100666 11732 13 40473 5770343174 14040 0 ustar bfox user /* display.c -- How to display Info windows. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include
#include
#include
#include
#include "display.h"
extern int info_any_buffered_input_p (); /* Found in session.c. */
static void free_display ();
static DISPLAY_LINE **make_display ();
/* An array of display lines which tell us what is currently visible on
the display. */
DISPLAY_LINE **the_display = (DISPLAY_LINE **)NULL;
/* Non-zero means do no output. */
int display_inhibited = 0;
/* Initialize THE_DISPLAY to WIDTH and HEIGHT, with nothing in it. */
void
display_initialize_display (width, height)
int width, height;
{
free_display (the_display);
the_display = make_display (width, height);
display_clear_display (the_display);
}
/* Clear all of the lines in DISPLAY making the screen blank. */
void
display_clear_display (display)
DISPLAY_LINE **display;
{
register int i;
register DISPLAY_LINE *display_line;
for (i = 0; display_line = display[i]; i++)
{
display[i]->text[0] = '\0';
display[i]->textlen = 0;
display[i]->inverse = 0;
}
}
/* Non-zero if we didn't completely redisplay a window. */
int display_was_interrupted_p = 0;
/* Update the windows pointed to by WINDOW in the_display. This actually
writes the text on the screen. */
void
display_update_display (window)
WINDOW *window;
{
register WINDOW *win;
display_was_interrupted_p = 0;
/* For every window in the list, check contents against the display. */
for (win = window; win; win = win->next)
{
/* Only re-display visible windows which need updating. */
if (((win->flags & W_WindowVisible) == 0) ||
((win->flags & W_UpdateWindow) == 0) ||
(win->height == 0))
continue;
display_update_one_window (win);
if (display_was_interrupted_p)
break;
}
/* Always update the echo area. */
display_update_one_window (the_echo_area);
}
/* Display WIN on the_display. Unlike display_update_display (), this
function only does one window. */
void
display_update_one_window (win)
WINDOW *win;
{
register char *nodetext; /* Current character to display. */
register char *last_node_char; /* Position of the last character in node. */
register int i; /* General use index. */
char *printed_line; /* Buffer for a printed line. */
int pl_index = 0; /* Index into PRINTED_LINE. */
int line_index = 0; /* Number of lines done so far. */
DISPLAY_LINE **display = the_display;
/* If display is inhibited, that counts as an interrupted display. */
if (display_inhibited)
display_was_interrupted_p = 1;
/* If the window has no height, or display is inhibited, quit now. */
if (!win->height || display_inhibited)
return;
/* If the window's first row doesn't appear in the_screen, then it
cannot be displayed. This can happen when the_echo_area is the
window to be displayed, and the screen has shrunk to less than one
line. */
if ((win->first_row < 0) || (win->first_row > the_screen->height))
return;
/* Print each line in the window into our local buffer, and then
check the contents of that buffer against the display. If they
differ, update the display. */
printed_line = (char *)xmalloc (1 + win->width);
if (!win->node || !win->line_starts)
goto done_with_node_display;
nodetext = win->line_starts[win->pagetop];
last_node_char = win->node->contents + win->node->nodelen;
for (; nodetext < last_node_char; nodetext++)
{
char *rep, *rep_carried_over, rep_temp[2];
int replen;
if (isprint (*nodetext))
{
rep_temp[0] = *nodetext;
replen = 1;
rep_temp[1] = '\0';
rep = rep_temp;
}
else
{
if (*nodetext == '\r' || *nodetext == '\n')
{
replen = win->width - pl_index;
}
else
{
rep = printed_representation (*nodetext, pl_index);
replen = strlen (rep);
}
}
/* If this character can be printed without passing the width of
the line, then stuff it into the line. */
if (replen + pl_index < win->width)
{
/* Optimize if possible. */
if (replen == 1)
{
printed_line[pl_index++] = *rep;
}
else
{
for (i = 0; i < replen; i++)
printed_line[pl_index++] = rep[i];
}
}
else
{
DISPLAY_LINE *entry;
/* If this character cannot be printed in this line, we have
found the end of this line as it would appear on the screen.
Carefully print the end of the line, and then compare. */
if (*nodetext == '\n' || *nodetext == '\r' || *nodetext == '\t')
{
printed_line[pl_index] = '\0';
rep_carried_over = (char *)NULL;
}
else
{
/* The printed representation of this character extends into
the next line. Remember the offset of the last character
printed out of REP so that we can carry the character over
to the next line. */
for (i = 0; pl_index < (win->width - 1);)
printed_line[pl_index++] = rep[i++];
rep_carried_over = rep + i;
/* If printing the last character in this window couldn't
possibly cause the screen to scroll, place a backslash
in the rightmost column. */
if (1 + line_index + win->first_row < the_screen->height)
{
if (win->flags & W_NoWrap)
printed_line[pl_index++] = '$';
else
printed_line[pl_index++] = '\\';
}
printed_line[pl_index] = '\0';
}
/* We have the exact line as it should appear on the screen.
Check to see if this line matches the one already appearing
on the screen. */
entry = display[line_index + win->first_row];
/* If the screen line is inversed, then we have to clear
the line from the screen first. Why, I don't know. */
if (entry->inverse)
{
terminal_goto_xy (0, line_index + win->first_row);
terminal_clear_to_eol ();
entry->inverse = 0;
entry->text[0] = '\0';
entry->textlen = 0;
}
/* Find the offset where these lines differ. */
for (i = 0; i < pl_index; i++)
if (printed_line[i] != entry->text[i])
break;
/* If the lines are not the same length, or if they differed
at all, we must do some redrawing. */
if ((i != pl_index) || (pl_index != entry->textlen))
{
/* Move to the proper point on the terminal. */
terminal_goto_xy (i, line_index + win->first_row);
/* If there is any text to print, print it. */
if (i != pl_index)
terminal_put_text (printed_line + i);
/* If the printed text didn't extend all the way to the edge
of the window, and text was appearing between here and the
edge of the window, clear from here to the end of the line. */
if ((pl_index < win->width && pl_index < entry->textlen) ||
(entry->inverse))
terminal_clear_to_eol ();
fflush (stdout);
/* Update the display text buffer. */
strcpy (entry->text + i, printed_line + i);
entry->textlen = pl_index;
/* Lines showing node text are not in inverse. Only modelines
have that distinction. */
entry->inverse = 0;
}
/* We have done at least one line. Increment our screen line
index, and check against the bottom of the window. */
if (++line_index == win->height)
break;
/* A line has been displayed, and the screen reflects that state.
If there is typeahead pending, then let that typeahead be read
now, instead of continuing with the display. */
if (info_any_buffered_input_p ())
{
free (printed_line);
display_was_interrupted_p = 1;
return;
}
/* Reset PL_INDEX to the start of the line. */
pl_index = 0;
/* If there are characters from REP left to print, stuff them
into the buffer now. */
if (rep_carried_over)
for (; rep[pl_index]; pl_index++)
printed_line[pl_index] = rep[pl_index];
/* If this window has chosen not to wrap lines, skip to the end
of the physical line in the buffer, and start a new line here. */
if (pl_index && (win->flags & W_NoWrap))
{
char *begin;
pl_index = 0;
printed_line[0] = '\0';
begin = nodetext;
while ((nodetext < last_node_char) && (*nodetext != '\n'))
nodetext++;
}
}
}
done_with_node_display:
/* We have reached the end of the node or the end of the window. If it
is the end of the node, then clear the lines of the window from here
to the end of the window. */
for (; line_index < win->height; line_index++)
{
DISPLAY_LINE *entry = display[line_index + win->first_row];
/* If this line has text on it then make it go away. */
if (entry && entry->textlen)
{
entry->textlen = 0;
entry->text[0] = '\0';
terminal_goto_xy (0, line_index + win->first_row);
terminal_clear_to_eol ();
}
}
/* Finally, if this window has a modeline it might need to be redisplayed.
Check the window's modeline against the one in the display, and update
if necessary. */
if ((win->flags & W_InhibitMode) == 0)
{
window_make_modeline (win);
line_index = win->first_row + win->height;
/* This display line must both be in inverse, and have the same
contents. */
if ((!display[line_index]->inverse) ||
(strcmp (display[line_index]->text, win->modeline) != 0))
{
terminal_goto_xy (0, line_index);
terminal_begin_inverse ();
terminal_put_text (win->modeline);
terminal_end_inverse ();
strcpy (display[line_index]->text, win->modeline);
display[line_index]->inverse = 1;
display[line_index]->textlen = strlen (win->modeline);
fflush (stdout);
}
}
/* Okay, this window doesn't need updating anymore. */
win->flags &= ~W_UpdateWindow;
free (printed_line);
fflush (stdout);
}
/* Scroll the region of the_display starting at START, ending at END, and
moving the lines AMOUNT lines. If AMOUNT is less than zero, the lines
are moved up in the screen, otherwise down. Actually, it is possible
for no scrolling to take place in the case that the terminal doesn't
support it. This doesn't matter to us. */
void
display_scroll_display (start, end, amount)
int start, end, amount;
{
register int i, last;
DISPLAY_LINE *temp;
/* If this terminal cannot do scrolling, give up now. */
if (!terminal_can_scroll)
return;
/* If there isn't anything displayed on the screen because it is too
small, quit now. */
if (!the_display[0])
return;
/* If there is typeahead pending, then don't actually do any scrolling. */
if (info_any_buffered_input_p ())
return;
/* Do it on the screen. */
terminal_scroll_terminal (start, end, amount);
/* Now do it in the display buffer so our contents match the screen. */
if (amount > 0)
{
last = end + amount;
/* Shift the lines to scroll right into place. */
for (i = 0; i < (end - start); i++)
{
temp = the_display[last - i];
the_display[last - i] = the_display[end - i];
the_display[end - i] = temp;
}
/* The lines have been shifted down in the buffer. Clear all of the
lines that were vacated. */
for (i = start; i != (start + amount); i++)
{
the_display[i]->text[0] = '\0';
the_display[i]->textlen = 0;
the_display[i]->inverse = 0;
}
}
if (amount < 0)
{
last = start + amount;
for (i = 0; i < (end - start); i++)
{
temp = the_display[last + i];
the_display[last + i] = the_display[start + i];
the_display[start + i] = temp;
}
/* The lines have been shifted up in the buffer. Clear all of the
lines that are left over. */
for (i = end + amount; i != end; i++)
{
the_display[i]->text[0] = '\0';
the_display[i]->textlen = 0;
the_display[i]->inverse = 0;
}
}
}
/* Try to scroll lines in WINDOW. OLD_PAGETOP is the pagetop of WINDOW before
having had its line starts recalculated. OLD_STARTS is the list of line
starts that used to appear in this window. OLD_COUNT is the number of lines
that appear in the OLD_STARTS array. */
void
display_scroll_line_starts (window, old_pagetop, old_starts, old_count)
WINDOW *window;
int old_pagetop, old_count;
char **old_starts;
{
register int i, old, new; /* Indices into the line starts arrays. */
int last_new, last_old; /* Index of the last visible line. */
int old_first, new_first; /* Index of the first changed line. */
int unchanged_at_top = 0;
int already_scrolled = 0;
/* Locate the first line which was displayed on the old window. */
old_first = old_pagetop;
new_first = window->pagetop;
/* Find the last line currently visible in this window. */
last_new = window->pagetop + (window->height - 1);
if (last_new > window->line_count)
last_new = window->line_count - 1;
/* Find the last line which used to be currently visible in this window. */
last_old = old_pagetop + (window->height - 1);
if (last_old > old_count)
last_old = old_count - 1;
for (old = old_first, new = new_first;
old < last_old && new < last_new;
old++, new++)
if (old_starts[old] != window->line_starts[new])
break;
else
unchanged_at_top++;
/* Loop through the old lines looking for a match in the new lines. */
for (old = old_first + unchanged_at_top; old < last_old; old++)
{
for (new = new_first; new < last_new; new++)
if (old_starts[old] == window->line_starts[new])
{
/* Find the extent of the matching lines. */
for (i = 0; (old + i) < last_old; i++)
if (old_starts[old + i] != window->line_starts[new + i])
break;
/* Scroll these lines if there are enough of them. */
{
int start, end, amount;
start = (window->first_row
+ ((old + already_scrolled) - old_pagetop));
amount = new - (old + already_scrolled);
end = window->first_row + window->height;
/* If we are shifting the block of lines down, then the last
AMOUNT lines will become invisible. Thus, don't bother
scrolling them. */
if (amount > 0)
end -= amount;
if ((end - start) > 0)
{
display_scroll_display (start, end, amount);
/* Some lines have been scrolled. Simulate the scrolling
by offsetting the value of the old index. */
old += i;
already_scrolled += amount;
}
}
}
}
}
/* Move the screen cursor to directly over the current character in WINDOW. */
void
display_cursor_at_point (window)
WINDOW *window;
{
int vpos, hpos;
vpos = window_line_of_point (window) - window->pagetop + window->first_row;
hpos = window_get_cursor_column (window);
terminal_goto_xy (hpos, vpos);
}
/* **************************************************************** */
/* */
/* Functions Static to this File */
/* */
/* **************************************************************** */
/* Make a DISPLAY_LINE ** with width and height. */
static DISPLAY_LINE **
make_display (width, height)
int width, height;
{
register int i;
DISPLAY_LINE **display;
display = (DISPLAY_LINE **)xmalloc ((1 + height) * sizeof (DISPLAY_LINE *));
for (i = 0; i < height; i++)
{
display[i] = (DISPLAY_LINE *)xmalloc (sizeof (DISPLAY_LINE));
display[i]->text = (char *)xmalloc (1 + width);
display[i]->textlen = 0;
display[i]->inverse = 0;
}
display[i] = (DISPLAY_LINE *)NULL;
return (display);
}
/* Free the storage allocated to DISPLAY. */
static void
free_display (display)
DISPLAY_LINE **display;
{
register int i;
register DISPLAY_LINE *display_line;
if (!display)
return;
for (i = 0; display_line = display[i]; i++)
{
free (display_line->text);
free (display_line);
}
free (display);
}
texinfo-3.7/info/display.h 100666 11732 13 5532 5770343364 14023 0 ustar bfox user /* display.h -- How the display in Info is done. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_DISPLAY_H_)
#define _DISPLAY_H_
#include "info-utils.h"
#include "terminal.h"
typedef struct {
char *text; /* Text of the line as it appears. */
int textlen; /* Printable Length of TEXT. */
int inverse; /* Non-zero means this line is inverse. */
} DISPLAY_LINE;
/* An array of display lines which tell us what is currently visible on
the display. */
extern DISPLAY_LINE **the_display;
/* Non-zero means do no output. */
extern int display_inhibited;
/* Non-zero if we didn't completely redisplay a window. */
extern int display_was_interrupted_p;
/* Initialize THE_DISPLAY to WIDTH and HEIGHT, with nothing in it. */
extern void display_initialize_display ();
/* Clear all of the lines in DISPLAY making the screen blank. */
extern void display_clear_display ();
/* Update the windows pointed to by WINDOWS in THE_DISPLAY. This actually
writes the text on the screen. */
extern void display_update_display ();
/* Display WIN on THE_DISPLAY. Unlike display_update_display (), this
function only does one window. */
extern void display_update_one_window ();
/* Move the screen cursor to directly over the current character in WINDOW. */
extern void display_cursor_at_point ();
/* Scroll the region of the_display starting at START, ending at END, and
moving the lines AMOUNT lines. If AMOUNT is less than zero, the lines
are moved up in the screen, otherwise down. Actually, it is possible
for no scrolling to take place in the case that the terminal doesn't
support it. This doesn't matter to us. */
extern void display_scroll_display ();
/* Try to scroll lines in WINDOW. OLD_PAGETOP is the pagetop of WINDOW before
having had its line starts recalculated. OLD_STARTS is the list of line
starts that used to appear in this window. OLD_COUNT is the number of lines
that appear in the OLD_STARTS array. */
extern void display_scroll_line_starts ();
#endif /* !_DISPLAY_H_ */
texinfo-3.7/info/doc.h 100666 11732 13 3356 5770343367 13130 0 ustar bfox user /* doc.h -- Structure associating function pointers with documentation. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_DOC_H_)
#define _DOC_H_
#if !defined (NULL)
# define NULL 0x0
#endif /* !NULL */
#if !defined (__FUNCTION_DEF)
# define __FUNCTION_DEF
typedef int Function ();
typedef void VFunction ();
#endif /* _FUNCTION_DEF */
typedef struct {
VFunction *func;
#if defined (NAMED_FUNCTIONS)
char *func_name;
#endif /* NAMED_FUNCTIONS */
char *doc;
} FUNCTION_DOC;
extern FUNCTION_DOC function_doc_array[];
extern char *function_documentation ();
extern char *key_documentation ();
extern char *pretty_keyname ();
extern char *replace_in_documentation ();
extern void info_document_key ();
extern void dump_map_to_message_buffer ();
#if defined (NAMED_FUNCTIONS)
extern char *function_name ();
extern VFunction *named_function ();
#endif /* NAMED_FUNCTIONS */
#endif /* !_DOC_H_ */
texinfo-3.7/info/dribble 100666 11732 13 63 5764640667 13476 0 ustar bfox user mfoo
em
buffers
ââ texinfo-3.7/info/dribble.c 100666 11732 13 4141 5770343202 13736 0 ustar bfox user /* dribble.c -- Dribble files for Info. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include
#include "dribble.h"
/* When non-zero, it is a stream to write all input characters to for the
duration of this info session. */
FILE *info_dribble_file = (FILE *)NULL;
/* Open a dribble file named NAME, perhaps closing an already open one.
This sets the global variable INFO_DRIBBLE_FILE to the open stream. */
void
open_dribble_file (name)
char *name;
{
/* Perhaps close existing dribble file. */
close_dribble_file ();
info_dribble_file = fopen (name, "w");
#if defined (HAVE_SETVBUF)
if (info_dribble_file)
# if defined (SETVBUF_REVERSED)
setvbuf (info_dribble_file, _IONBF, (char *)NULL, 1);
# else
setvbuf (info_dribble_file, (char *)NULL, _IONBF, 1);
# endif /* !SETVBUF_REVERSED */
#endif /* HAVE_SETVBUF */
}
/* If there is a dribble file already open, close it. */
void
close_dribble_file ()
{
if (info_dribble_file)
{
fflush (info_dribble_file);
fclose (info_dribble_file);
info_dribble_file = (FILE *)NULL;
}
}
/* Write some output to our existing dribble file. */
void
dribble (byte)
unsigned char byte;
{
if (info_dribble_file)
fwrite (&byte, sizeof (unsigned char), 1, info_dribble_file);
}
texinfo-3.7/info/dribble.h 100666 11732 13 2776 5770343372 13767 0 ustar bfox user /* dribble.h -- Functions and vars declared in dribble.c. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_DRIBBLE_H_)
#define _DRIBBLE_H_
/* When non-zero, it is a stream to write all input characters to for the
duration of this info session. */
extern FILE *info_dribble_file;
/* Open a dribble file named NAME, perhaps closing an already open one.
This sets the global variable INFO_DRIBBLE_FILE to the open stream. */
extern void open_dribble_file ();
/* If there is a dribble file already open, close it. */
extern void close_dribble_file ();
/* Write some output to our existing dribble file. */
extern void dribble ();
#endif /* !_DRIBBLE_H_ */
texinfo-3.7/info/echo_area.c 100666 11732 13 116266 5770343210 14314 0 ustar bfox user /* echo_area.c -- How to read a line in the echo area. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
#if defined (FD_SET)
# if defined (hpux)
# define fd_set_cast(x) (int *)(x)
# else
# define fd_set_cast(x) (fd_set *)(x)
# endif /* !hpux */
#endif /* FD_SET */
/* Non-zero means that C-g was used to quit reading input. */
int info_aborted_echo_area = 0;
/* Non-zero means that the echo area is being used to read input. */
int echo_area_is_active = 0;
/* The address of the last command executed in the echo area. */
VFunction *ea_last_executed_command = (VFunction *)NULL;
/* Non-zero means that the last command executed while reading input
killed some text. */
int echo_area_last_command_was_kill = 0;
/* Variables which hold on to the current state of the input line. */
static char input_line[1 + EA_MAX_INPUT];
static char *input_line_prompt;
static int input_line_point;
static int input_line_beg;
static int input_line_end;
static NODE input_line_node = {
(char *)NULL, (char *)NULL, (char *)NULL, input_line, EA_MAX_INPUT, 0
};
static void echo_area_initialize_node ();
static void push_echo_area (), pop_echo_area ();
static int echo_area_stack_depth (), echo_area_stack_contains_completions_p ();
static void ea_kill_text ();
/* Non-zero means we force the user to complete. */
static int echo_area_must_complete_p = 0;
static int completions_window_p ();
/* If non-null, this is a window which was specifically created to display
possible completions output. We remember it so we can delete it when
appropriate. */
static WINDOW *echo_area_completions_window = (WINDOW *)NULL;
/* Variables which keep track of the window which was active prior to
entering the echo area. */
static WINDOW *calling_window = (WINDOW *)NULL;
static NODE *calling_window_node = (NODE *)NULL;
static long calling_window_point = 0;
static long calling_window_pagetop = 0;
/* Remember the node and pertinent variables of the calling window. */
static void
remember_calling_window (window)
WINDOW *window;
{
/* Only do this if the calling window is not the completions window, or,
if it is the completions window and there is no other window. */
if (!completions_window_p (window) ||
((window == windows) && !(window->next)))
{
calling_window = window;
calling_window_node = window->node;
calling_window_point = window->point;
calling_window_pagetop = window->pagetop;
}
}
/* Restore the caller's window so that it shows the node that it was showing
on entry to info_read_xxx_echo_area (). */
static void
restore_calling_window ()
{
register WINDOW *win, *compwin = (WINDOW *)NULL;
/* If the calling window is still visible, and it is the window that
we used for completions output, then restore the calling window. */
for (win = windows; win; win = win->next)
{
if (completions_window_p (win))
compwin = win;
if (win == calling_window && win == compwin)
{
window_set_node_of_window (calling_window, calling_window_node);
calling_window->point = calling_window_point;
calling_window->pagetop = calling_window_pagetop;
compwin = (WINDOW *)NULL;
break;
}
}
/* Delete the completions window if it is still present, it isn't the
last window on the screen, and there aren't any prior echo area reads
pending which created a completions window. */
if (compwin)
{
if ((compwin != windows || windows->next) &&
!echo_area_stack_contains_completions_p ())
{
WINDOW *next;
int pagetop, start, end, amount;
next = compwin->next;
if (next)
{
start = next->first_row;
end = start + next->height;
amount = - (compwin->height + 1);
pagetop = next->pagetop;
}
info_delete_window_internal (compwin);
/* This is not necessary because info_delete_window_internal ()
calls echo_area_inform_of_deleted_window (), which does the
right thing. */
#if defined (UNNECESSARY)
echo_area_completions_window = (WINDOW *)NULL;
#endif /* UNNECESSARY */
if (next)
{
display_scroll_display (start, end, amount);
next->pagetop = pagetop;
display_update_display (windows);
}
}
}
}
/* Set up a new input line with PROMPT. */
static void
initialize_input_line (prompt)
char *prompt;
{
input_line_prompt = prompt;
if (prompt)
strcpy (input_line, prompt);
else
input_line[0] = '\0';
input_line_beg = input_line_end = input_line_point = strlen (prompt);
}
static char *
echo_area_after_read ()
{
char *return_value;
if (info_aborted_echo_area)
{
info_aborted_echo_area = 0;
return_value = (char *)NULL;
}
else
{
if (input_line_beg == input_line_end)
return_value = strdup ("");
else
{
int line_len = input_line_end - input_line_beg;
return_value = (char *) xmalloc (1 + line_len);
strncpy (return_value, &input_line[input_line_beg], line_len);
return_value[line_len] = '\0';
}
}
return (return_value);
}
/* Read a line of text in the echo area. Return a malloc ()'ed string,
or NULL if the user aborted out of this read. WINDOW is the currently
active window, so that we can restore it when we need to. PROMPT, if
non-null, is a prompt to print before reading the line. */
char *
info_read_in_echo_area (window, prompt)
WINDOW *window;
char *prompt;
{
char *line;
/* If the echo area is already active, remember the current state. */
if (echo_area_is_active)
push_echo_area ();
/* Initialize our local variables. */
initialize_input_line (prompt);
/* Initialize the echo area for the first (but maybe not the last) time. */
echo_area_initialize_node ();
/* Save away the original node of this window, and the window itself,
so echo area commands can temporarily use this window. */
remember_calling_window (window);
/* Let the rest of Info know that the echo area is active. */
echo_area_is_active++;
active_window = the_echo_area;
/* Read characters in the echo area. */
info_read_and_dispatch ();
echo_area_is_active--;
/* Restore the original active window and show point in it. */
active_window = calling_window;
restore_calling_window ();
display_cursor_at_point (active_window);
fflush (stdout);
/* Get the value of the line. */
line = echo_area_after_read ();
/* If there is a previous loop waiting for us, restore it now. */
if (echo_area_is_active)
pop_echo_area ();
/* Return the results to the caller. */
return (line);
}
/* (re) Initialize the echo area node. */
static void
echo_area_initialize_node ()
{
register int i;
for (i = input_line_end; i < sizeof (input_line); i++)
input_line[i] = ' ';
input_line[i - 1] = '\n';
window_set_node_of_window (the_echo_area, &input_line_node);
input_line[input_line_end] = '\n';
}
/* Prepare to read characters in the echo area. This can initialize the
echo area node, but its primary purpose is to side effect the input
line buffer contents. */
void
echo_area_prep_read ()
{
if (the_echo_area->node != &input_line_node)
echo_area_initialize_node ();
the_echo_area->point = input_line_point;
input_line[input_line_end] = '\n';
display_update_one_window (the_echo_area);
display_cursor_at_point (active_window);
}
/* **************************************************************** */
/* */
/* Echo Area Movement Commands */
/* */
/* **************************************************************** */
DECLARE_INFO_COMMAND (ea_forward, "Move forward a character")
{
if (count < 0)
ea_backward (window, -count, key);
else
{
input_line_point += count;
if (input_line_point > input_line_end)
input_line_point = input_line_end;
}
}
DECLARE_INFO_COMMAND (ea_backward, "Move backward a character")
{
if (count < 0)
ea_forward (window, -count, key);
else
{
input_line_point -= count;
if (input_line_point < input_line_beg)
input_line_point = input_line_beg;
}
}
DECLARE_INFO_COMMAND (ea_beg_of_line, "Move to the start of this line")
{
input_line_point = input_line_beg;
}
DECLARE_INFO_COMMAND (ea_end_of_line, "Move to the end of this line")
{
input_line_point = input_line_end;
}
#define alphabetic(c) (islower (c) || isupper (c) || isdigit (c))
/* Move forward a word in the input line. */
DECLARE_INFO_COMMAND (ea_forward_word, "Move forward a word")
{
int c;
if (count < 0)
ea_backward_word (window, -count, key);
else
{
while (count--)
{
if (input_line_point == input_line_end)
return;
/* If we are not in a word, move forward until we are in one.
Then, move forward until we hit a non-alphabetic character. */
c = input_line[input_line_point];
if (!alphabetic (c))
{
while (++input_line_point < input_line_end)
{
c = input_line[input_line_point];
if (alphabetic (c))
break;
}
}
if (input_line_point == input_line_end)
return;
while (++input_line_point < input_line_end)
{
c = input_line[input_line_point];
if (!alphabetic (c))
break;
}
}
}
}
DECLARE_INFO_COMMAND (ea_backward_word, "Move backward a word")
{
int c;
if (count < 0)
ea_forward_word (window, -count, key);
else
{
while (count--)
{
if (input_line_point == input_line_beg)
return;
/* Like ea_forward_word (), except that we look at the
characters just before point. */
c = input_line[input_line_point - 1];
if (!alphabetic (c))
{
while ((--input_line_point) != input_line_beg)
{
c = input_line[input_line_point - 1];
if (alphabetic (c))
break;
}
}
while (input_line_point != input_line_beg)
{
c = input_line[input_line_point - 1];
if (!alphabetic (c))
break;
else
--input_line_point;
}
}
}
}
DECLARE_INFO_COMMAND (ea_delete, "Delete the character under the cursor")
{
register int i;
if (count < 0)
ea_rubout (window, -count, key);
else
{
if (input_line_point == input_line_end)
return;
if (info_explicit_arg || count > 1)
{
int orig_point;
orig_point = input_line_point;
ea_forward (window, count, key);
ea_kill_text (orig_point, input_line_point);
input_line_point = orig_point;
}
else
{
for (i = input_line_point; i < input_line_end; i++)
input_line[i] = input_line[i + 1];
input_line_end--;
}
}
}
DECLARE_INFO_COMMAND (ea_rubout, "Delete the character behind the cursor")
{
if (count < 0)
ea_delete (window, -count, key);
else
{
int start;
if (input_line_point == input_line_beg)
return;
start = input_line_point;
ea_backward (window, count, key);
if (info_explicit_arg || count > 1)
ea_kill_text (start, input_line_point);
else
ea_delete (window, count, key);
}
}
DECLARE_INFO_COMMAND (ea_abort, "Cancel or quit operation")
{
/* If any text, just discard it, and restore the calling window's node.
If no text, quit. */
if (input_line_end != input_line_beg)
{
terminal_ring_bell ();
input_line_end = input_line_point = input_line_beg;
if (calling_window->node != calling_window_node)
restore_calling_window ();
}
else
info_aborted_echo_area = 1;
}
DECLARE_INFO_COMMAND (ea_newline, "Accept (or force completion of) this line")
{
/* Stub does nothing. Simply here to see if it has been executed. */
}
DECLARE_INFO_COMMAND (ea_quoted_insert, "Insert next character verbatim")
{
unsigned char character;
character = info_get_another_input_char ();
ea_insert (window, count, character);
}
DECLARE_INFO_COMMAND (ea_insert, "Insert this character")
{
register int i;
if ((input_line_end + 1) == EA_MAX_INPUT)
{
terminal_ring_bell ();
return;
}
for (i = input_line_end + 1; i != input_line_point; i--)
input_line[i] = input_line[i - 1];
input_line[input_line_point] = key;
input_line_point++;
input_line_end++;
}
DECLARE_INFO_COMMAND (ea_tab_insert, "Insert a TAB character")
{
ea_insert (window, count, '\t');
}
/* Transpose the characters at point. If point is at the end of the line,
then transpose the characters before point. */
DECLARE_INFO_COMMAND (ea_transpose_chars, "Transpose characters at point")
{
/* Handle conditions that would make it impossible to transpose
characters. */
if (!count || !input_line_point || (input_line_end - input_line_beg) < 2)
return;
while (count)
{
int t;
if (input_line_point == input_line_end)
{
t = input_line[input_line_point - 1];
input_line[input_line_point - 1] = input_line[input_line_point - 2];
input_line[input_line_point - 2] = t;
}
else
{
t = input_line[input_line_point];
input_line[input_line_point] = input_line[input_line_point - 1];
input_line[input_line_point - 1] = t;
if (count < 0 && input_line_point != input_line_beg)
input_line_point--;
else
input_line_point++;
}
if (count < 0)
count++;
else
count--;
}
}
/* **************************************************************** */
/* */
/* Echo Area Killing and Yanking */
/* */
/* **************************************************************** */
static char **kill_ring = (char **)NULL;
static int kill_ring_index = 0; /* Number of kills appearing in KILL_RING. */
static int kill_ring_slots = 0; /* Number of slots allocated to KILL_RING. */
static int kill_ring_loc = 0; /* Location of current yank pointer. */
/* The largest number of kills that we remember at one time. */
static int max_retained_kills = 15;
DECLARE_INFO_COMMAND (ea_yank, "Yank back the contents of the last kill")
{
register int i;
register char *text;
if (!kill_ring_index)
{
inform_in_echo_area ("Kill ring is empty");
return;
}
text = kill_ring[kill_ring_loc];
for (i = 0; text[i]; i++)
ea_insert (window, 1, text[i]);
}
/* If the last command was yank, or yank_pop, and the text just before
point is identical to the current kill item, then delete that text
from the line, rotate the index down, and yank back some other text. */
DECLARE_INFO_COMMAND (ea_yank_pop, "Yank back a previous kill")
{
register int len;
if (((ea_last_executed_command != ea_yank) &&
(ea_last_executed_command != ea_yank_pop)) ||
(kill_ring_index == 0))
return;
len = strlen (kill_ring[kill_ring_loc]);
/* Delete the last yanked item from the line. */
{
register int i, counter;
counter = input_line_end - input_line_point;
for (i = input_line_point - len; counter; i++, counter--)
input_line[i] = input_line[i + len];
input_line_end -= len;
input_line_point -= len;
}
/* Get a previous kill, and yank that. */
kill_ring_loc--;
if (kill_ring_loc < 0)
kill_ring_loc = kill_ring_index - 1;
ea_yank (window, count, key);
}
/* Delete the text from point to end of line. */
DECLARE_INFO_COMMAND (ea_kill_line, "Kill to the end of the line")
{
if (count < 0)
{
ea_kill_text (input_line_point, input_line_beg);
input_line_point = input_line_beg;
}
else
ea_kill_text (input_line_point, input_line_end);
}
/* Delete the text from point to beg of line. */
DECLARE_INFO_COMMAND (ea_backward_kill_line,
"Kill to the beginning of the line")
{
if (count < 0)
ea_kill_text (input_line_point, input_line_end);
else
{
ea_kill_text (input_line_point, input_line_beg);
input_line_point = input_line_beg;
}
}
/* Delete from point to the end of the current word. */
DECLARE_INFO_COMMAND (ea_kill_word, "Kill the word following the cursor")
{
int orig_point = input_line_point;
if (count < 0)
ea_backward_kill_word (window, -count, key);
else
{
ea_forward_word (window, count, key);
if (input_line_point != orig_point)
ea_kill_text (orig_point, input_line_point);
input_line_point = orig_point;
}
}
/* Delete from point to the start of the current word. */
DECLARE_INFO_COMMAND (ea_backward_kill_word,
"Kill the word preceding the cursor")
{
int orig_point = input_line_point;
if (count < 0)
ea_kill_word (window, -count, key);
else
{
ea_backward_word (window, count, key);
if (input_line_point != orig_point)
ea_kill_text (orig_point, input_line_point);
}
}
/* The way to kill something. This appends or prepends to the last
kill, if the last command was a kill command. If FROM is less
than TO, then the killed text is appended to the most recent kill,
otherwise it is prepended. If the last command was not a kill command,
then a new slot is made for this kill. */
static void
ea_kill_text (from, to)
int from, to;
{
register int i, counter, distance;
int killing_backwards, slot;
char *killed_text;
killing_backwards = (from > to);
/* If killing backwards, reverse the values of FROM and TO. */
if (killing_backwards)
{
int temp = from;
from = to;
to = temp;
}
/* Remember the text that we are about to delete. */
distance = to - from;
killed_text = (char *)xmalloc (1 + distance);
strncpy (killed_text, &input_line[from], distance);
killed_text[distance] = '\0';
/* Actually delete the text from the line. */
counter = input_line_end - to;
for (i = from; counter; i++, counter--)
input_line[i] = input_line[i + distance];
input_line_end -= distance;
/* If the last command was a kill, append or prepend the killed text to
the last command's killed text. */
if (echo_area_last_command_was_kill)
{
char *old, *new;
slot = kill_ring_loc;
old = kill_ring[slot];
new = (char *)xmalloc (1 + strlen (old) + strlen (killed_text));
if (killing_backwards)
{
/* Prepend TEXT to current kill. */
strcpy (new, killed_text);
strcat (new, old);
}
else
{
/* Append TEXT to current kill. */
strcpy (new, old);
strcat (new, killed_text);
}
free (old);
free (killed_text);
kill_ring[slot] = new;
}
else
{
/* Try to store the kill in a new slot, unless that would cause there
to be too many remembered kills. */
slot = kill_ring_index;
if (slot == max_retained_kills)
slot = 0;
if (slot + 1 > kill_ring_slots)
kill_ring = (char **) xrealloc
(kill_ring,
(kill_ring_slots += max_retained_kills) * sizeof (char *));
if (slot != kill_ring_index)
free (kill_ring[slot]);
else
kill_ring_index++;
kill_ring[slot] = killed_text;
kill_ring_loc = slot;
}
/* Notice that the last command was a kill. */
echo_area_last_command_was_kill++;
}
/* **************************************************************** */
/* */
/* Echo Area Completion */
/* */
/* **************************************************************** */
/* Pointer to an array of REFERENCE to complete over. */
static REFERENCE **echo_area_completion_items = (REFERENCE **)NULL;
/* Sorted array of REFERENCE * which is the possible completions found in
the variable echo_area_completion_items. If there is only one element,
it is the only possible completion. */
static REFERENCE **completions_found = (REFERENCE **)NULL;
static int completions_found_index = 0;
static int completions_found_slots = 0;
/* The lowest common denominator found while completing. */
static REFERENCE *LCD_completion;
/* Internal functions used by the user calls. */
static void build_completions (), completions_must_be_rebuilt ();
/* Variable which holds the output of completions. */
static NODE *possible_completions_output_node = (NODE *)NULL;
static char *compwin_name = "*Completions*";
/* Return non-zero if WINDOW is a window used for completions output. */
static int
completions_window_p (window)
WINDOW *window;
{
int result = 0;
if (internal_info_node_p (window->node) &&
(strcmp (window->node->nodename, compwin_name) == 0))
result = 1;
return (result);
}
/* Workhorse for completion readers. If FORCE is non-zero, the user cannot
exit unless the line read completes, or is empty. */
char *
info_read_completing_internal (window, prompt, completions, force)
WINDOW *window;
char *prompt;
REFERENCE **completions;
int force;
{
char *line;
/* If the echo area is already active, remember the current state. */
if (echo_area_is_active)
push_echo_area ();
echo_area_must_complete_p = force;
/* Initialize our local variables. */
initialize_input_line (prompt);
/* Initialize the echo area for the first (but maybe not the last) time. */
echo_area_initialize_node ();
/* Save away the original node of this window, and the window itself,
so echo area commands can temporarily use this window. */
remember_calling_window (window);
/* Save away the list of items to complete over. */
echo_area_completion_items = completions;
completions_must_be_rebuilt ();
active_window = the_echo_area;
echo_area_is_active++;
/* Read characters in the echo area. */
while (1)
{
info_read_and_dispatch ();
line = echo_area_after_read ();
/* Force the completion to take place if the user hasn't accepted
a default or aborted, and if FORCE is active. */
if (force && line && *line && completions)
{
register int i;
build_completions ();
/* If there is only one completion, then make the line be that
completion. */
if (completions_found_index == 1)
{
free (line);
line = strdup (completions_found[0]->label);
break;
}
/* If one of the completions matches exactly, then that is okay, so
return the current line. */
for (i = 0; i < completions_found_index; i++)
if (strcasecmp (completions_found[i]->label, line) == 0)
{
free (line);
line = strdup (completions_found[i]->label);
break;
}
/* If no match, go back and try again. */
if (i == completions_found_index)
{
inform_in_echo_area ("Not complete");
continue;
}
}
break;
}
echo_area_is_active--;
/* Restore the original active window and show point in it. */
active_window = calling_window;
restore_calling_window ();
display_cursor_at_point (active_window);
fflush (stdout);
echo_area_completion_items = (REFERENCE **)NULL;
completions_must_be_rebuilt ();
/* If there is a previous loop waiting for us, restore it now. */
if (echo_area_is_active)
pop_echo_area ();
return (line);
}
/* Read a line in the echo area with completion over COMPLETIONS. */
char *
info_read_completing_in_echo_area (window, prompt, completions)
WINDOW *window;
char *prompt;
REFERENCE **completions;
{
return (info_read_completing_internal (window, prompt, completions, 1));
}
/* Read a line in the echo area allowing completion over COMPLETIONS, but
not requiring it. */
char *
info_read_maybe_completing (window, prompt, completions)
WINDOW *window;
char *prompt;
REFERENCE **completions;
{
return (info_read_completing_internal (window, prompt, completions, 0));
}
DECLARE_INFO_COMMAND (ea_possible_completions, "List possible completions")
{
if (!echo_area_completion_items)
{
ea_insert (window, count, key);
return;
}
build_completions ();
if (!completions_found_index)
{
terminal_ring_bell ();
inform_in_echo_area ("No completions");
}
else if ((completions_found_index == 1) && (key != '?'))
{
inform_in_echo_area ("Sole completion");
}
else
{
register int i, l;
int limit, count, max_label = 0;
initialize_message_buffer ();
printf_to_message_buffer
("There %s %d ", completions_found_index == 1 ? "is" : "are",
completions_found_index);
printf_to_message_buffer
("completion%s:\n", completions_found_index == 1 ? "" : "s");
/* Find the maximum length of a label. */
for (i = 0; i < completions_found_index; i++)
{
int len = strlen (completions_found[i]->label);
if (len > max_label)
max_label = len;
}
max_label += 4;
/* Find out how many columns we should print in. */
limit = calling_window->width / max_label;
if (limit != 1 && (limit * max_label == calling_window->width))
limit--;
/* Avoid a possible floating exception. If max_label > width then
the limit will be 0 and a divide-by-zero fault will result. */
if (limit == 0)
limit = 1;
/* How many iterations of the printing loop? */
count = (completions_found_index + (limit - 1)) / limit;
/* Watch out for special case. If the number of completions is less
than LIMIT, then just do the inner printing loop. */
if (completions_found_index < limit)
count = 1;
/* Print the sorted items, up-and-down alphabetically. */
for (i = 0; i < count; i++)
{
register int j;
for (j = 0, l = i; j < limit; j++)
{
if (l >= completions_found_index)
break;
else
{
char *label;
int printed_length, k;
label = completions_found[l]->label;
printed_length = strlen (label);
printf_to_message_buffer ("%s", label);
if (j + 1 < limit)
{
for (k = 0; k < max_label - printed_length; k++)
printf_to_message_buffer (" ");
}
}
l += count;
}
printf_to_message_buffer ("\n");
}
/* Make a new node to hold onto possible completions. Don't destroy
dangling pointers. */
{
NODE *temp;
temp = message_buffer_to_node ();
add_gcable_pointer (temp->contents);
name_internal_node (temp, compwin_name);
possible_completions_output_node = temp;
}
/* Find a suitable window for displaying the completions output.
First choice is an existing window showing completions output.
If there is only one window, and it is large, make another
(smaller) window, and use that one. Otherwise, use the caller's
window. */
{
WINDOW *compwin;
compwin = get_internal_info_window (compwin_name);
if (!compwin)
{
/* If we can split the window to display most of the completion
items, then do so. */
if (calling_window->height > (count * 2))
{
int start, end, pagetop;
active_window = calling_window;
/* Perhaps we can scroll this window on redisplay. */
start = calling_window->first_row;
pagetop = calling_window->pagetop;
compwin =
window_make_window (possible_completions_output_node);
active_window = the_echo_area;
window_change_window_height
(compwin, -(compwin->height - (count + 2)));
window_adjust_pagetop (calling_window);
remember_calling_window (calling_window);
#if defined (SPLIT_BEFORE_ACTIVE)
/* If the pagetop hasn't changed, scrolling the calling
window is a reasonable thing to do. */
if (pagetop == calling_window->pagetop)
{
end = start + calling_window->height;
display_scroll_display
(start, end, calling_window->prev->height + 1);
}
#else /* !SPLIT_BEFORE_ACTIVE */
/* If the pagetop has changed, set the new pagetop here. */
if (pagetop != calling_window->pagetop)
{
int newtop = calling_window->pagetop;
calling_window->pagetop = pagetop;
set_window_pagetop (calling_window, newtop);
}
#endif /* !SPLIT_BEFORE_ACTIVE */
echo_area_completions_window = compwin;
remember_window_and_node (compwin, compwin->node);
}
else
compwin = calling_window;
}
if (compwin->node != possible_completions_output_node)
{
window_set_node_of_window
(compwin, possible_completions_output_node);
remember_window_and_node (compwin, compwin->node);
}
display_update_display (windows);
}
}
}
DECLARE_INFO_COMMAND (ea_complete, "Insert completion")
{
if (!echo_area_completion_items)
{
ea_insert (window, count, key);
return;
}
/* If KEY is SPC, and we are not forcing completion to take place, simply
insert the key. */
if (!echo_area_must_complete_p && key == SPC)
{
ea_insert (window, count, key);
return;
}
if (ea_last_executed_command == ea_complete)
{
/* If the keypress is a SPC character, and we have already tried
completing once, and there are several completions, then check
the batch of completions to see if any continue with a space.
If there are some, insert the space character and continue. */
if (key == SPC && completions_found_index > 1)
{
register int i, offset;
offset = input_line_end - input_line_beg;
for (i = 0; i < completions_found_index; i++)
if (completions_found[i]->label[offset] == ' ')
break;
if (completions_found[i])
ea_insert (window, 1, ' ');
else
{
ea_possible_completions (window, count, key);
return;
}
}
else
{
ea_possible_completions (window, count, key);
return;
}
}
input_line_point = input_line_end;
build_completions ();
if (!completions_found_index)
terminal_ring_bell ();
else if (LCD_completion->label[0] == '\0')
ea_possible_completions (window, count, key);
else
{
register int i;
input_line_point = input_line_end = input_line_beg;
for (i = 0; LCD_completion->label[i]; i++)
ea_insert (window, 1, LCD_completion->label[i]);
}
}
/* Utility REFERENCE used to store possible LCD. */
static REFERENCE LCD_reference = { (char *)NULL, (char *)NULL, (char *)NULL };
static void remove_completion_duplicates ();
/* Variables which remember the state of the most recent call
to build_completions (). */
static char *last_completion_request = (char *)NULL;
static REFERENCE **last_completion_items = (REFERENCE **)NULL;
/* How to tell the completion builder to reset internal state. */
static void
completions_must_be_rebuilt ()
{
maybe_free (last_completion_request);
last_completion_request = (char *)NULL;
last_completion_items = (REFERENCE **)NULL;
}
/* Build a list of possible completions from echo_area_completion_items,
and the contents of input_line. */
static void
build_completions ()
{
register int i, len;
register REFERENCE *entry;
char *request;
int informed_of_lengthy_job = 0;
/* If there are no items to complete over, exit immediately. */
if (!echo_area_completion_items)
{
completions_found_index = 0;
LCD_completion = (REFERENCE *)NULL;
return;
}
/* Check to see if this call to build completions is the same as the last
call to build completions. */
len = input_line_end - input_line_beg;
request = (char *)xmalloc (1 + len);
strncpy (request, &input_line[input_line_beg], len);
request[len] = '\0';
if (last_completion_request && last_completion_items &&
last_completion_items == echo_area_completion_items &&
(strcmp (last_completion_request, request) == 0))
{
free (request);
return;
}
maybe_free (last_completion_request);
last_completion_request = request;
last_completion_items = echo_area_completion_items;
/* Always start at the beginning of the list. */
completions_found_index = 0;
LCD_completion = (REFERENCE *)NULL;
for (i = 0; entry = echo_area_completion_items[i]; i++)
{
if (strncasecmp (request, entry->label, len) == 0)
add_pointer_to_array (entry, completions_found_index,
completions_found, completions_found_slots,
20, REFERENCE *);
if (!informed_of_lengthy_job && completions_found_index > 100)
{
informed_of_lengthy_job = 1;
window_message_in_echo_area ("Building completions...");
}
}
if (!completions_found_index)
return;
/* Sort and prune duplicate entries from the completions array. */
remove_completion_duplicates ();
/* If there is only one completion, just return that. */
if (completions_found_index == 1)
{
LCD_completion = completions_found[0];
return;
}
/* Find the least common denominator. */
{
long shortest = 100000;
for (i = 1; i < completions_found_index; i++)
{
register int j;
int c1, c2;
for (j = 0;
(c1 = info_tolower (completions_found[i - 1]->label[j])) &&
(c2 = info_tolower (completions_found[i]->label[j]));
j++)
if (c1 != c2)
break;
if (shortest > j)
shortest = j;
}
maybe_free (LCD_reference.label);
LCD_reference.label = (char *)xmalloc (1 + shortest);
strncpy (LCD_reference.label, completions_found[0]->label, shortest);
LCD_reference.label[shortest] = '\0';
LCD_completion = &LCD_reference;
}
if (informed_of_lengthy_job)
echo_area_initialize_node ();
}
/* Function called by qsort. */
static int
compare_references (entry1, entry2)
REFERENCE **entry1, **entry2;
{
return (strcasecmp ((*entry1)->label, (*entry2)->label));
}
/* Prune duplicate entries from COMPLETIONS_FOUND. */
static void
remove_completion_duplicates ()
{
register int i, j;
REFERENCE **temp;
int newlen;
if (!completions_found_index)
return;
/* Sort the items. */
qsort (completions_found, completions_found_index, sizeof (REFERENCE *),
compare_references);
for (i = 0, newlen = 1; i < completions_found_index - 1; i++)
{
if (strcmp (completions_found[i]->label,
completions_found[i + 1]->label) == 0)
completions_found[i] = (REFERENCE *)NULL;
else
newlen++;
}
/* We have marked all the dead slots. It is faster to copy the live slots
twice than to prune the dead slots one by one. */
temp = (REFERENCE **)xmalloc ((1 + newlen) * sizeof (REFERENCE *));
for (i = 0, j = 0; i < completions_found_index; i++)
if (completions_found[i])
temp[j++] = completions_found[i];
for (i = 0; i < newlen; i++)
completions_found[i] = temp[i];
completions_found[i] = (REFERENCE *)NULL;
completions_found_index = newlen;
free (temp);
}
/* Scroll the "other" window. If there is a window showing completions, scroll
that one, otherwise scroll the window which was active on entering the read
function. */
DECLARE_INFO_COMMAND (ea_scroll_completions_window, "Scroll the completions window")
{
WINDOW *compwin;
int old_pagetop;
compwin = get_internal_info_window (compwin_name);
if (!compwin)
compwin = calling_window;
old_pagetop = compwin->pagetop;
/* Let info_scroll_forward () do the work, and print any messages that
need to be displayed. */
info_scroll_forward (compwin, count, key);
}
/* Function which gets called when an Info window is deleted while the
echo area is active. WINDOW is the window which has just been deleted. */
void
echo_area_inform_of_deleted_window (window)
WINDOW *window;
{
/* If this is the calling_window, forget what we remembered about it. */
if (window == calling_window)
{
if (active_window != the_echo_area)
remember_calling_window (active_window);
else
remember_calling_window (windows);
}
/* If this window was the echo_area_completions_window, then notice that
the window has been deleted. */
if (window == echo_area_completions_window)
echo_area_completions_window = (WINDOW *)NULL;
}
/* **************************************************************** */
/* */
/* Pushing and Popping the Echo Area */
/* */
/* **************************************************************** */
/* Push and Pop the echo area. */
typedef struct {
char *line;
char *prompt;
REFERENCE **comp_items;
int point, beg, end;
int must_complete;
NODE node;
WINDOW *compwin;
} PUSHED_EA;
static PUSHED_EA **pushed_echo_areas = (PUSHED_EA **)NULL;
static int pushed_echo_areas_index = 0;
static int pushed_echo_areas_slots = 0;
/* Pushing the echo_area has a side effect of zeroing the completion_items. */
static void
push_echo_area ()
{
PUSHED_EA *pushed;
pushed = (PUSHED_EA *)xmalloc (sizeof (PUSHED_EA));
pushed->line = strdup (input_line);
pushed->prompt = input_line_prompt;
pushed->point = input_line_point;
pushed->beg = input_line_beg;
pushed->end = input_line_end;
pushed->node = input_line_node;
pushed->comp_items = echo_area_completion_items;
pushed->must_complete = echo_area_must_complete_p;
pushed->compwin = echo_area_completions_window;
add_pointer_to_array (pushed, pushed_echo_areas_index, pushed_echo_areas,
pushed_echo_areas_slots, 4, PUSHED_EA *);
echo_area_completion_items = (REFERENCE **)NULL;
}
static void
pop_echo_area ()
{
PUSHED_EA *popped;
popped = pushed_echo_areas[--pushed_echo_areas_index];
strcpy (input_line, popped->line);
free (popped->line);
input_line_prompt = popped->prompt;
input_line_point = popped->point;
input_line_beg = popped->beg;
input_line_end = popped->end;
input_line_node = popped->node;
echo_area_completion_items = popped->comp_items;
echo_area_must_complete_p = popped->must_complete;
echo_area_completions_window = popped->compwin;
completions_must_be_rebuilt ();
/* If the completion window no longer exists, forget about it. */
if (echo_area_completions_window)
{
register WINDOW *win;
for (win = windows; win; win = win->next)
if (echo_area_completions_window == win)
break;
/* If the window wasn't found, then it has already been deleted. */
if (!win)
echo_area_completions_window = (WINDOW *)NULL;
}
free (popped);
}
static int
echo_area_stack_depth ()
{
return (pushed_echo_areas_index);
}
/* Returns non-zero if any of the prior stacked calls to read in the echo
area produced a completions window. */
static int
echo_area_stack_contains_completions_p ()
{
register int i;
for (i = 0; i < pushed_echo_areas_index; i++)
if (pushed_echo_areas[i]->compwin)
return (1);
return (0);
}
/* **************************************************************** */
/* */
/* Error Messages While Reading in Echo Area */
/* */
/* **************************************************************** */
#if defined (HAVE_SYS_TIME_H)
# include
# define HAVE_STRUCT_TIMEVAL
#endif /* HAVE_SYS_TIME_H */
static void
pause_or_input ()
{
#if defined (FD_SET)
struct timeval timer;
fd_set readfds;
int ready;
FD_ZERO (&readfds);
FD_SET (fileno (stdin), &readfds);
timer.tv_sec = 2;
timer.tv_usec = 750;
ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
#endif /* FD_SET */
}
/* Print MESSAGE right after the end of the current line, and wait
for input or 2.75 seconds, whichever comes first. Then flush the
informational message that was printed. */
void
inform_in_echo_area (message)
char *message;
{
register int i;
char *text;
text = strdup (message);
for (i = 0; text[i] && text[i] != '\n'; i++);
text[i] = '\0';
echo_area_initialize_node ();
sprintf (&input_line[input_line_end], "%s[%s]\n",
echo_area_is_active ? " ": "", text);
free (text);
the_echo_area->point = input_line_point;
display_update_one_window (the_echo_area);
display_cursor_at_point (active_window);
fflush (stdout);
pause_or_input ();
echo_area_initialize_node ();
}
texinfo-3.7/info/echo_area.h 100666 11732 13 5147 5770343375 14270 0 ustar bfox user /* echo_area.h -- Functions used in reading information from the echo area. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_ECHO_AREA_H_)
#define _ECHO_AREA_H_
#define EA_MAX_INPUT 256
extern int echo_area_is_active, info_aborted_echo_area;
/* Non-zero means that the last command executed while reading input
killed some text. */
extern int echo_area_last_command_was_kill;
extern void inform_in_echo_area (), echo_area_inform_of_deleted_window ();
extern void echo_area_prep_read ();
extern VFunction *ea_last_executed_command;
/* Read a line of text in the echo area. Return a malloc ()'ed string,
or NULL if the user aborted out of this read. WINDOW is the currently
active window, so that we can restore it when we need to. PROMPT, if
non-null, is a prompt to print before reading the line. */
extern char *info_read_in_echo_area ();
/* Read a line in the echo area with completion over COMPLETIONS.
Takes arguments of WINDOW, PROMPT, and COMPLETIONS, a REFERENCE **. */
char *info_read_completing_in_echo_area ();
/* Read a line in the echo area allowing completion over COMPLETIONS, but
not requiring it. Takes arguments of WINDOW, PROMPT, and COMPLETIONS,
a REFERENCE **. */
extern char *info_read_maybe_completing ();
extern void ea_insert (), ea_quoted_insert ();
extern void ea_beg_of_line (), ea_backward (), ea_delete (), ea_end_of_line ();
extern void ea_forward (), ea_abort (), ea_rubout (), ea_complete ();
extern void ea_newline (), ea_kill_line (), ea_transpose_chars ();
extern void ea_yank (), ea_tab_insert (), ea_possible_completions ();
extern void ea_backward_word (), ea_kill_word (), ea_forward_word ();
extern void ea_yank_pop (), ea_backward_kill_word ();
extern void ea_scroll_completions_window ();
#endif /* _ECHO_AREA_H_ */
texinfo-3.7/info/filesys.c 100666 11732 13 36056 5770343214 14046 0 ustar bfox user /* filesys.c -- File system specific functions for hacking this system. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include
#include
#include
#if defined (HAVE_SYS_FILE_H)
#include
#endif /* HAVE_SYS_FILE_H */
#include
#include "general.h"
#include "tilde.h"
#include "filesys.h"
#if !defined (O_RDONLY)
#if defined (HAVE_SYS_FCNTL_H)
#include
#else /* !HAVE_SYS_FCNTL_H */
#include
#endif /* !HAVE_SYS_FCNTL_H */
#endif /* !O_RDONLY */
#if !defined (errno)
extern int errno;
#endif /* !errno */
/* Found in info-utils.c. */
extern char *filename_non_directory ();
#if !defined (BUILDING_LIBRARY)
/* Found in session.c */
extern int info_windows_initialized_p;
/* Found in window.c. */
extern void message_in_echo_area (), unmessage_in_echo_area ();
#endif /* !BUILDING_LIBRARY */
/* Local to this file. */
static char *info_file_in_path (), *lookup_info_filename ();
static void remember_info_filename (), maybe_initialize_infopath ();
#if !defined (NULL)
# define NULL 0x0
#endif /* !NULL */
typedef struct {
char *suffix;
char *decompressor;
} COMPRESSION_ALIST;
static char *info_suffixes[] = {
"",
".info",
"-info",
(char *)NULL
};
static COMPRESSION_ALIST compress_suffixes[] = {
{ ".Z", "uncompress" },
{ ".Y", "unyabba" },
{ ".z", "gunzip" },
{ ".gz", "gunzip" },
{ (char *)NULL, (char *)NULL }
};
/* The path on which we look for info files. You can initialize this
from the environment variable INFOPATH if there is one, or you can
call info_add_path () to add paths to the beginning or end of it.
You can call zap_infopath () to make the path go away. */
char *infopath = (char *)NULL;
static int infopath_size = 0;
/* Expand the filename in PARTIAL to make a real name for this operating
system. This looks in INFO_PATHS in order to find the correct file.
If it can't find the file, it returns NULL. */
static char *local_temp_filename = (char *)NULL;
static int local_temp_filename_size = 0;
char *
info_find_fullpath (partial)
char *partial;
{
int initial_character;
char *temp;
filesys_error_number = 0;
maybe_initialize_infopath ();
if (partial && (initial_character = *partial))
{
char *expansion;
expansion = lookup_info_filename (partial);
if (expansion)
return (expansion);
/* If we have the full path to this file, we still may have to add
various extensions to it. I guess we have to stat this file
after all. */
if (initial_character == '/')
temp = info_file_in_path (partial + 1, "/");
else if (initial_character == '~')
{
expansion = tilde_expand_word (partial);
if (*expansion == '/')
{
temp = info_file_in_path (expansion + 1, "/");
free (expansion);
}
else
temp = expansion;
}
else if (initial_character == '.' &&
(partial[1] == '/' || (partial[1] == '.' && partial[2] == '/')))
{
if (local_temp_filename_size < 1024)
local_temp_filename = (char *)xrealloc
(local_temp_filename, (local_temp_filename_size = 1024));
#if defined (HAVE_GETCWD)
if (!getcwd (local_temp_filename, local_temp_filename_size))
#else /* !HAVE_GETCWD */
if (!getwd (local_temp_filename))
#endif /* !HAVE_GETCWD */
{
filesys_error_number = errno;
return (partial);
}
strcat (local_temp_filename, "/");
strcat (local_temp_filename, partial);
return (local_temp_filename);
}
else
temp = info_file_in_path (partial, infopath);
if (temp)
{
remember_info_filename (partial, temp);
if (strlen (temp) > local_temp_filename_size)
local_temp_filename = (char *) xrealloc
(local_temp_filename,
(local_temp_filename_size = (50 + strlen (temp))));
strcpy (local_temp_filename, temp);
free (temp);
return (local_temp_filename);
}
}
return (partial);
}
/* Scan the list of directories in PATH looking for FILENAME. If we find
one that is a regular file, return it as a new string. Otherwise, return
a NULL pointer. */
static char *
info_file_in_path (filename, path)
char *filename, *path;
{
struct stat finfo;
char *temp_dirname;
int statable, dirname_index;
dirname_index = 0;
while (temp_dirname = extract_colon_unit (path, &dirname_index))
{
register int i, pre_suffix_length;
char *temp;
/* Expand a leading tilde if one is present. */
if (*temp_dirname == '~')
{
char *expanded_dirname;
expanded_dirname = tilde_expand_word (temp_dirname);
free (temp_dirname);
temp_dirname = expanded_dirname;
}
temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
strcpy (temp, temp_dirname);
if (temp[(strlen (temp)) - 1] != '/')
strcat (temp, "/");
strcat (temp, filename);
pre_suffix_length = strlen (temp);
free (temp_dirname);
for (i = 0; info_suffixes[i]; i++)
{
strcpy (temp + pre_suffix_length, info_suffixes[i]);
statable = (stat (temp, &finfo) == 0);
/* If we have found a regular file, then use that. Else, if we
have found a directory, look in that directory for this file. */
if (statable)
{
if (S_ISREG (finfo.st_mode))
{
return (temp);
}
else if (S_ISDIR (finfo.st_mode))
{
char *newpath, *filename_only, *newtemp;
newpath = strdup (temp);
filename_only = filename_non_directory (filename);
newtemp = info_file_in_path (filename_only, newpath);
free (newpath);
if (newtemp)
{
free (temp);
return (newtemp);
}
}
}
else
{
/* Add various compression suffixes to the name to see if
the file is present in compressed format. */
register int j, pre_compress_suffix_length;
pre_compress_suffix_length = strlen (temp);
for (j = 0; compress_suffixes[j].suffix; j++)
{
strcpy (temp + pre_compress_suffix_length,
compress_suffixes[j].suffix);
statable = (stat (temp, &finfo) == 0);
if (statable && (S_ISREG (finfo.st_mode)))
return (temp);
}
}
}
free (temp);
}
return ((char *)NULL);
}
/* Given a string containing units of information separated by colons,
return the next one pointed to by IDX, or NULL if there are no more.
Advance IDX to the character after the colon. */
char *
extract_colon_unit (string, idx)
char *string;
int *idx;
{
register int i, start;
i = start = *idx;
if ((i >= strlen (string)) || !string)
return ((char *) NULL);
while (string[i] && string[i] != ':')
i++;
if (i == start)
{
return ((char *) NULL);
}
else
{
char *value;
value = (char *) xmalloc (1 + (i - start));
strncpy (value, &string[start], (i - start));
value[i - start] = '\0';
if (string[i])
++i;
*idx = i;
return (value);
}
}
/* A structure which associates a filename with its expansion. */
typedef struct {
char *filename;
char *expansion;
} FILENAME_LIST;
/* An array of remembered arguments and results. */
static FILENAME_LIST **names_and_files = (FILENAME_LIST **)NULL;
static int names_and_files_index = 0;
static int names_and_files_slots = 0;
/* Find the result for having already called info_find_fullpath () with
FILENAME. */
static char *
lookup_info_filename (filename)
char *filename;
{
if (filename && names_and_files)
{
register int i;
for (i = 0; names_and_files[i]; i++)
{
if (strcmp (names_and_files[i]->filename, filename) == 0)
return (names_and_files[i]->expansion);
}
}
return (char *)NULL;;
}
/* Add a filename and its expansion to our list. */
static void
remember_info_filename (filename, expansion)
char *filename, *expansion;
{
FILENAME_LIST *new;
if (names_and_files_index + 2 > names_and_files_slots)
{
int alloc_size;
names_and_files_slots += 10;
alloc_size = names_and_files_slots * sizeof (FILENAME_LIST *);
names_and_files =
(FILENAME_LIST **) xrealloc (names_and_files, alloc_size);
}
new = (FILENAME_LIST *)xmalloc (sizeof (FILENAME_LIST));
new->filename = strdup (filename);
new->expansion = expansion ? strdup (expansion) : (char *)NULL;
names_and_files[names_and_files_index++] = new;
names_and_files[names_and_files_index] = (FILENAME_LIST *)NULL;
}
static void
maybe_initialize_infopath ()
{
if (!infopath_size)
{
infopath = (char *)
xmalloc (infopath_size = (1 + strlen (DEFAULT_INFOPATH)));
strcpy (infopath, DEFAULT_INFOPATH);
}
}
/* Add PATH to the list of paths found in INFOPATH. 2nd argument says
whether to put PATH at the front or end of INFOPATH. */
void
info_add_path (path, where)
char *path;
int where;
{
int len;
if (!infopath)
{
infopath = (char *)xmalloc (infopath_size = 200 + strlen (path));
infopath[0] = '\0';
}
len = strlen (path) + strlen (infopath);
if (len + 2 >= infopath_size)
infopath = (char *)xrealloc (infopath, (infopath_size += (2 * len) + 2));
if (!*infopath)
strcpy (infopath, path);
else if (where == INFOPATH_APPEND)
{
strcat (infopath, ":");
strcat (infopath, path);
}
else if (where == INFOPATH_PREPEND)
{
char *temp = strdup (infopath);
strcpy (infopath, path);
strcat (infopath, ":");
strcat (infopath, temp);
free (temp);
}
}
/* Make INFOPATH have absolutely nothing in it. */
void
zap_infopath ()
{
if (infopath)
free (infopath);
infopath = (char *)NULL;
infopath_size = 0;
}
/* Read the contents of PATHNAME, returning a buffer with the contents of
that file in it, and returning the size of that buffer in FILESIZE.
FINFO is a stat struct which has already been filled in by the caller.
If the file cannot be read, return a NULL pointer. */
char *
filesys_read_info_file (pathname, filesize, finfo)
char *pathname;
long *filesize;
struct stat *finfo;
{
long st_size;
*filesize = filesys_error_number = 0;
if (compressed_filename_p (pathname))
return (filesys_read_compressed (pathname, filesize, finfo));
else
{
int descriptor;
char *contents;
descriptor = open (pathname, O_RDONLY, 0666);
/* If the file couldn't be opened, give up. */
if (descriptor < 0)
{
filesys_error_number = errno;
return ((char *)NULL);
}
/* Try to read the contents of this file. */
st_size = (long) finfo->st_size;
contents = (char *)xmalloc (1 + st_size);
if ((read (descriptor, contents, st_size)) != st_size)
{
filesys_error_number = errno;
close (descriptor);
free (contents);
return ((char *)NULL);
}
close (descriptor);
*filesize = st_size;
return (contents);
}
}
/* Typically, pipe buffers are 4k. */
#define BASIC_PIPE_BUFFER (4 * 1024)
/* We use some large multiple of that. */
#define FILESYS_PIPE_BUFFER_SIZE (16 * BASIC_PIPE_BUFFER)
char *
filesys_read_compressed (pathname, filesize, finfo)
char *pathname;
long *filesize;
struct stat *finfo;
{
FILE *stream;
char *command, *decompressor;
char *contents = (char *)NULL;
*filesize = filesys_error_number = 0;
decompressor = filesys_decompressor_for_file (pathname);
if (!decompressor)
return ((char *)NULL);
command = (char *)xmalloc (10 + strlen (pathname) + strlen (decompressor));
sprintf (command, "%s < %s", decompressor, pathname);
#if !defined (BUILDING_LIBRARY)
if (info_windows_initialized_p)
{
char *temp;
temp = (char *)xmalloc (5 + strlen (command));
sprintf (temp, "%s...", command);
message_in_echo_area ("%s", temp);
free (temp);
}
#endif /* !BUILDING_LIBRARY */
stream = popen (command, "r");
free (command);
/* Read chunks from this file until there are none left to read. */
if (stream)
{
int offset, size;
char *chunk;
offset = size = 0;
chunk = (char *)xmalloc (FILESYS_PIPE_BUFFER_SIZE);
while (1)
{
int bytes_read;
bytes_read = fread (chunk, 1, FILESYS_PIPE_BUFFER_SIZE, stream);
if (bytes_read + offset >= size)
contents = (char *)xrealloc
(contents, size += (2 * FILESYS_PIPE_BUFFER_SIZE));
memcpy (contents + offset, chunk, bytes_read);
offset += bytes_read;
if (bytes_read != FILESYS_PIPE_BUFFER_SIZE)
break;
}
free (chunk);
pclose (stream);
contents = (char *)xrealloc (contents, offset + 1);
*filesize = offset;
}
else
{
filesys_error_number = errno;
}
#if !defined (BUILDING_LIBARARY)
if (info_windows_initialized_p)
unmessage_in_echo_area ();
#endif /* !BUILDING_LIBRARY */
return (contents);
}
/* Return non-zero if FILENAME belongs to a compressed file. */
int
compressed_filename_p (filename)
char *filename;
{
char *decompressor;
/* Find the final extension of this filename, and see if it matches one
of our known ones. */
decompressor = filesys_decompressor_for_file (filename);
if (decompressor)
return (1);
else
return (0);
}
/* Return the command string that would be used to decompress FILENAME. */
char *
filesys_decompressor_for_file (filename)
char *filename;
{
register int i;
char *extension = (char *)NULL;
/* Find the final extension of FILENAME, and see if it appears in our
list of known compression extensions. */
for (i = strlen (filename) - 1; i > 0; i--)
if (filename[i] == '.')
{
extension = filename + i;
break;
}
if (!extension)
return ((char *)NULL);
for (i = 0; compress_suffixes[i].suffix; i++)
if (strcmp (extension, compress_suffixes[i].suffix) == 0)
return (compress_suffixes[i].decompressor);
return ((char *)NULL);
}
/* The number of the most recent file system error. */
int filesys_error_number = 0;
/* A function which returns a pointer to a static buffer containing
an error message for FILENAME and ERROR_NUM. */
static char *errmsg_buf = (char *)NULL;
static int errmsg_buf_size = 0;
char *
filesys_error_string (filename, error_num)
char *filename;
int error_num;
{
int len;
char *result;
if (error_num == 0)
return ((char *)NULL);
result = strerror (error_num);
len = 4 + strlen (filename) + strlen (result);
if (len >= errmsg_buf_size)
errmsg_buf = (char *)xrealloc (errmsg_buf, (errmsg_buf_size = 2 + len));
sprintf (errmsg_buf, "%s: %s", filename, result);
return (errmsg_buf);
}
texinfo-3.7/info/filesys.h 100666 11732 13 7036 5770343400 14024 0 ustar bfox user /* filesys.h -- External declarations of functions and vars in filesys.c. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_FILESYS_H_)
#define _FILESYS_H_
/* The path on which we look for info files. You can initialize this
from the environment variable INFOPATH if there is one, or you can
call info_add_path () to add paths to the beginning or end of it. */
extern char *infopath;
/* Make INFOPATH have absolutely nothing in it. */
extern void zap_infopath ();
/* Add PATH to the list of paths found in INFOPATH. 2nd argument says
whether to put PATH at the front or end of INFOPATH. */
extern void info_add_path ();
/* Defines that are passed along with the pathname to info_add_path (). */
#define INFOPATH_PREPEND 0
#define INFOPATH_APPEND 1
/* Expand the filename in PARTIAL to make a real name for this operating
system. This looks in INFO_PATHS in order to find the correct file.
If it can't find the file, it returns NULL. */
extern char *info_find_fullpath ();
/* Read the contents of PATHNAME, returning a buffer with the contents of
that file in it, and returning the size of that buffer in FILESIZE.
FINFO is a stat struct which has already been filled in by the caller.
If the file cannot be read, return a NULL pointer. */
extern char *filesys_read_info_file ();
extern char *filesys_read_compressed ();
/* Return the command string that would be used to decompress FILENAME. */
extern char *filesys_decompressor_for_file ();
extern int compressed_filename_p ();
/* A function which returns a pointer to a static buffer containing
an error message for FILENAME and ERROR_NUM. */
extern char *filesys_error_string ();
/* The number of the most recent file system error. */
extern int filesys_error_number;
/* Given a string containing units of information separated by colons,
return the next one pointed to by IDX, or NULL if there are no more.
Advance IDX to the character after the colon. */
extern char *extract_colon_unit ();
/* The default value of INFOPATH. */
#if !defined (DEFAULT_INFOPATH)
! # define DEFAULT_INFOPATH "/usr/local/info:/usr/info:/usr/local/lib/info:/usr/lib/info:/usr/local/gnu/info:/usr/local/gnu/lib/info:/usr/gnu/info:/usr/gnu/lib/info:/opt/gnu/info:/usr/share/info:/usr/share/lib/info:/usr/local/share/info:/usr/local/share/lib/info:/usr/gnu/lib/emacs/info:/usr/local/gnu/lib/emacs/info:/usr/local/lib/emacs/info:/usr/local/emacs/info:."
#endif /* !DEFAULT_INFOPATH */
#if !defined (S_ISREG) && defined (S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif /* !S_ISREG && S_IFREG */
#if !defined (S_ISDIR) && defined (S_IFDIR)
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif /* !S_ISDIR && S_IFDIR */
#endif /* !_FILESYS_H_ */
texinfo-3.7/info/footnotes.c 100666 11732 13 16532 5770343220 14402 0 ustar bfox user /* footnotes.c -- Some functions for manipulating footnotes. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
/* Non-zero means attempt to show footnotes when displaying a new window. */
int auto_footnotes_p = 1;
static char *footnote_nodename = "*Footnotes*";
#define FOOTNOTE_HEADER_FORMAT \
"*** Footnotes appearing in the node \"%s\" ***\n"
/* Find the window currently showing footnotes. */
static WINDOW *
find_footnotes_window ()
{
WINDOW *win;
/* Try to find an existing window first. */
for (win = windows; win; win = win->next)
if (internal_info_node_p (win->node) &&
(strcmp (win->node->nodename, footnote_nodename) == 0))
break;
return (win);
}
/* Manufacture a node containing the footnotes of this node, and
return the manufactured node. If NODE has no footnotes, return a
NULL pointer. */
NODE *
make_footnotes_node (node)
NODE *node;
{
NODE *fn_node, *result = (NODE *)NULL;
long fn_start;
/* Make the initial assumption that the footnotes appear as simple
text within this windows node. */
fn_node = node;
/* See if this node contains the magic footnote label. */
fn_start =
info_search_in_node (FOOTNOTE_LABEL, node, 0, (WINDOW *)NULL, 1);
/* If it doesn't, check to see if it has an associated footnotes node. */
if (fn_start == -1)
{
REFERENCE **refs;
refs = info_xrefs_of_node (node);
if (refs)
{
register int i;
char *refname;
refname = (char *)xmalloc
(1 + strlen ("-Footnotes") + strlen (node->nodename));
strcpy (refname, node->nodename);
strcat (refname, "-Footnotes");
for (i = 0; refs[i]; i++)
if ((refs[i]->nodename != (char *)NULL) &&
(strcmp (refs[i]->nodename, refname) == 0))
{
char *filename;
filename = node->parent;
if (!filename)
filename = node->filename;
fn_node = info_get_node (filename, refname);
if (fn_node)
fn_start = 0;
break;
}
free (refname);
info_free_references (refs);
}
}
/* If we never found the start of a footnotes area, quit now. */
if (fn_start == -1)
return ((NODE *)NULL);
/* Make the new node. */
result = (NODE *)xmalloc (sizeof (NODE));
result->flags = 0;
/* Get the size of the footnotes appearing within this node. */
{
char *header;
long text_start = fn_start;
header = (char *)xmalloc
(1 + strlen (node->nodename) + strlen (FOOTNOTE_HEADER_FORMAT));
sprintf (header, FOOTNOTE_HEADER_FORMAT, node->nodename);
/* Move the start of the displayed text to right after the first line.
This effectively skips either "---- footno...", or "File: foo...". */
while (text_start < fn_node->nodelen)
if (fn_node->contents[text_start++] == '\n')
break;
result->nodelen = strlen (header) + fn_node->nodelen - text_start;
/* Set the contents of this node. */
result->contents = (char *)xmalloc (1 + result->nodelen);
sprintf (result->contents, "%s", header);
memcpy (result->contents + strlen (header),
fn_node->contents + text_start, fn_node->nodelen - text_start);
name_internal_node (result, footnote_nodename);
free (header);
}
#if defined (NOTDEF)
/* If the footnotes were gleaned from the node that we were called with,
shorten the calling node's display length. */
if (fn_node == node)
narrow_node (node, 0, fn_start);
#endif /* NOTDEF */
return (result);
}
/* Create or delete the footnotes window depending on whether footnotes
exist in WINDOW's node or not. Returns FN_FOUND if footnotes were found
and displayed. Returns FN_UNFOUND if there were no footnotes found
in WINDOW's node. Returns FN_UNABLE if there were footnotes, but the
window to show them couldn't be made. */
int
info_get_or_remove_footnotes (window)
WINDOW *window;
{
WINDOW *fn_win;
NODE *new_footnotes;
fn_win = find_footnotes_window ();
/* If we are in the footnotes window, change nothing. */
if (fn_win == window)
return (FN_FOUND);
/* Try to find footnotes for this window's node. */
new_footnotes = make_footnotes_node (window->node);
/* If there was a window showing footnotes, and there are no footnotes
for the current window, delete the old footnote window. */
if (fn_win && !new_footnotes)
{
if (windows->next)
info_delete_window_internal (fn_win);
}
/* If there are footnotes for this window's node, but no window around
showing footnotes, try to make a new window. */
if (new_footnotes && !fn_win)
{
WINDOW *old_active;
WINDOW *last, *win;
/* Always make this window be the last one appearing in the list. Find
the last window in the chain. */
for (win = windows, last = windows; win; last = win, win = win->next);
/* Try to split this window, and make the split window the one to
contain the footnotes. */
old_active = active_window;
active_window = last;
fn_win = window_make_window (new_footnotes);
active_window = old_active;
if (!fn_win)
{
free (new_footnotes->contents);
free (new_footnotes);
/* If we are hacking automatic footnotes, and there are footnotes
but we couldn't display them, print a message to that effect. */
if (auto_footnotes_p)
inform_in_echo_area ("Footnotes could not be displayed");
return (FN_UNABLE);
}
}
/* If there are footnotes, and there is a window to display them,
make that window be the number of lines appearing in the footnotes. */
if (new_footnotes && fn_win)
{
window_set_node_of_window (fn_win, new_footnotes);
window_change_window_height
(fn_win, fn_win->line_count - fn_win->height);
remember_window_and_node (fn_win, new_footnotes);
add_gcable_pointer (new_footnotes->contents);
}
if (!new_footnotes)
return (FN_UNFOUND);
else
return (FN_FOUND);
}
/* Show the footnotes associated with this node in another window. */
DECLARE_INFO_COMMAND (info_show_footnotes,
"Show the footnotes associated with this node in another window")
{
int result;
/* A negative argument means just make the window go away. */
if (count < 0)
{
WINDOW *fn_win = find_footnotes_window ();
/* If there is an old footnotes window, and it isn't the only window
on the screen, delete it. */
if (fn_win && windows->next)
info_delete_window_internal (fn_win);
}
else
{
int result;
result = info_get_or_remove_footnotes (window);
switch (result)
{
case FN_UNFOUND:
info_error (NO_FOOT_NODE);
break;
case FN_UNABLE:
info_error (WIN_TOO_SMALL);
break;
}
}
}
texinfo-3.7/info/footnotes.h 100666 11732 13 3272 5770343406 14372 0 ustar bfox user /* footnotes.h -- Some functions for manipulating footnotes. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_FOOTNOTES_H_)
#define _FOOTNOTES_H_
/* Magic string which indicates following text is footnotes. */
#define FOOTNOTE_LABEL "---------- Footnotes ----------"
#define FN_FOUND 0
#define FN_UNFOUND 1
#define FN_UNABLE 2
/* Create or delete the footnotes window depending on whether footnotes
exist in WINDOW's node or not. Returns FN_FOUND if footnotes were found
and displayed. Returns FN_UNFOUND if there were no footnotes found
in WINDOW's node. Returns FN_UNABLE if there were footnotes, but the
window to show them couldn't be made. */
extern int info_get_or_remove_footnotes ();
/* Non-zero means attempt to show footnotes when displaying a new window. */
extern int auto_footnotes_p;
#endif /* !_FOOTNOTES_H_ */
texinfo-3.7/info/gc.c 100666 11732 13 5753 5770343223 12741 0 ustar bfox user /* gc.c -- Functions to remember and garbage collect unused node contents. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
/* Array of pointers to the contents of gc-able nodes. A pointer on this
list can be garbage collected when no info window contains a node whose
contents member match the pointer. */
static char **gcable_pointers = (char **)NULL;
static int gcable_pointers_index = 0;
static int gcable_pointers_slots = 0;
/* Add POINTER to the list of garbage collectible pointers. A pointer
is not actually garbage collected until no info window contains a node
whose contents member is equal to the pointer. */
void
add_gcable_pointer (pointer)
char *pointer;
{
gc_pointers ();
add_pointer_to_array (pointer, gcable_pointers_index, gcable_pointers,
gcable_pointers_slots, 10, char *);
}
/* Grovel the list of info windows and gc-able pointers finding those
node->contents which are collectible, and free them. */
void
gc_pointers ()
{
register int i, j, k;
INFO_WINDOW *iw;
char **new = (char **)NULL;
int new_index = 0;
int new_slots = 0;
if (!info_windows || !gcable_pointers_index)
return;
for (i = 0; iw = info_windows[i]; i++)
{
for (j = 0; j < iw->nodes_index; j++)
{
NODE *node = iw->nodes[j];
/* If this node->contents appears in our list of gcable_pointers,
it is not gc-able, so save it. */
for (k = 0; k < gcable_pointers_index; k++)
if (gcable_pointers[k] == node->contents)
{
add_pointer_to_array
(node->contents, new_index, new, new_slots, 10, char *);
break;
}
}
}
/* We have gathered all of the pointers which need to be saved. Free any
of the original pointers which do not appear in the new list. */
for (i = 0; i < gcable_pointers_index; i++)
{
for (j = 0; j < new_index; j++)
if (gcable_pointers[i] == new[j])
break;
/* If we got all the way through the new list, then the old pointer
can be garbage collected. */
if (new && !new[j])
free (gcable_pointers[i]);
}
free (gcable_pointers);
gcable_pointers = new;
gcable_pointers_slots = new_slots;
gcable_pointers_index = new_index;
}
texinfo-3.7/info/gc.h 100666 11732 13 2616 5770343414 12743 0 ustar bfox user /* gc.h -- Functions for garbage collecting unused node contents. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_GC_H_)
#define _GC_H_
/* Add POINTER to the list of garbage collectible pointers. A pointer
is not actually garbage collected until no info window contains a node
whose contents member is equal to the pointer. */
extern void add_gcable_pointer ();
/* Grovel the list of info windows and gc-able pointers finding those
node->contents which are collectible, and free them. */
extern void gc_pointers ();
#endif /* !_GC_H_ */
texinfo-3.7/info/general.h 100666 11732 13 5713 5770343417 13773 0 ustar bfox user /* general.h -- Some generally useful defines. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_GENERAL_H_)
#define _GENERAL_H_
extern void *xmalloc (), *xrealloc ();
#if defined (HAVE_UNISTD_H)
# include
#endif /* HAVE_UNISTD_H */
#if defined (HAVE_STRING_H)
# include
#else
# include
#endif /* !HAVE_STRING_H */
#include "clib.h"
#define info_toupper(x) (islower (x) ? toupper (x) : x)
#define info_tolower(x) (isupper (x) ? tolower (x) : x)
#if !defined (whitespace)
# define whitespace(c) ((c == ' ') || (c == '\t'))
#endif /* !whitespace */
#if !defined (whitespace_or_newline)
# define whitespace_or_newline(c) (whitespace (c) || (c == '\n'))
#endif /* !whitespace_or_newline */
#if !defined (__FUNCTION_DEF)
# define __FUNCTION_DEF
typedef int Function ();
typedef void VFunction ();
typedef char *CFunction ();
#endif /* _FUNCTION_DEF */
/* Add POINTER to the list of pointers found in ARRAY. SLOTS is the number
of slots that have already been allocated. INDEX is the index into the
array where POINTER should be added. GROW is the number of slots to grow
ARRAY by, in the case that it needs growing. TYPE is a cast of the type
of object stored in ARRAY (e.g., NODE_ENTRY *. */
#define add_pointer_to_array(pointer, idx, array, slots, grow, type) \
do { \
if (idx + 2 >= slots) \
array = (type *)(xrealloc (array, (slots += grow) * sizeof (type))); \
array[idx++] = (type)pointer; \
array[idx] = (type)NULL; \
} while (0)
#define maybe_free(x) do { if (x) free (x); } while (0)
#if !defined (zero_mem) && defined (HAVE_MEMSET)
# define zero_mem(mem, length) memset (mem, 0, length)
#endif /* !zero_mem && HAVE_MEMSET */
#if !defined (zero_mem) && defined (HAVE_BZERO)
# define zero_mem(mem, length) bzero (mem, length)
#endif /* !zero_mem && HAVE_BZERO */
#if !defined (zero_mem)
# define zero_mem(mem, length) \
do { \
register int zi; \
register unsigned char *place; \
\
place = (unsigned char *)mem; \
for (zi = 0; zi < length; zi++) \
place[zi] = 0; \
} while (0)
#endif /* !zero_mem */
#endif /* !_GENERAL_H_ */
texinfo-3.7/info/indices.c 100666 11732 13 42366 5770343233 14010 0 ustar bfox user /* indices.c -- Commands for dealing with an Info file Index. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
#include "indices.h"
/* User-visible variable controls the output of info-index-next. */
int show_index_match = 1;
/* In the Info sense, an index is a menu. This variable holds the last
parsed index. */
static REFERENCE **index_index = (REFERENCE **)NULL;
/* The offset of the most recently selected index element. */
static int index_offset = 0;
/* Variable which holds the last string searched for. */
static char *index_search = (char *)NULL;
/* A couple of "globals" describing where the initial index was found. */
static char *initial_index_filename = (char *)NULL;
static char *initial_index_nodename = (char *)NULL;
/* A structure associating index names with index offset ranges. */
typedef struct {
char *name; /* The nodename of this index. */
int first; /* The index in our list of the first entry. */
int last; /* The index in our list of the last entry. */
} INDEX_NAME_ASSOC;
/* An array associating index nodenames with index offset ranges. */
static INDEX_NAME_ASSOC **index_nodenames = (INDEX_NAME_ASSOC **)NULL;
static int index_nodenames_index = 0;
static int index_nodenames_slots = 0;
/* Add the name of NODE, and the range of the associated index elements
(passed in ARRAY) to index_nodenames. */
static void
add_index_to_index_nodenames (array, node)
REFERENCE **array;
NODE *node;
{
register int i, last;
INDEX_NAME_ASSOC *assoc;
for (last = 0; array[last]; last++);
assoc = (INDEX_NAME_ASSOC *)xmalloc (sizeof (INDEX_NAME_ASSOC));
assoc->name = strdup (node->nodename);
if (!index_nodenames_index)
{
assoc->first = 0;
assoc->last = last;
}
else
{
for (i = 0; index_nodenames[i + 1]; i++);
assoc->first = 1 + index_nodenames[i]->last;
assoc->last = assoc->first + last;
}
add_pointer_to_array
(assoc, index_nodenames_index, index_nodenames, index_nodenames_slots,
10, INDEX_NAME_ASSOC *);
}
/* Find and return the indices of WINDOW's file. The indices are defined
as the first node in the file containing the word "Index" and any
immediately following nodes whose names also contain "Index". All such
indices are concatenated and the result returned. If WINDOW's info file
doesn't have any indices, a NULL pointer is returned. */
REFERENCE **
info_indices_of_window (window)
WINDOW *window;
{
FILE_BUFFER *fb;
fb = file_buffer_of_window (window);
return (info_indices_of_file_buffer (fb));
}
REFERENCE **
info_indices_of_file_buffer (file_buffer)
FILE_BUFFER *file_buffer;
{
register int i;
REFERENCE **result = (REFERENCE **)NULL;
/* No file buffer, no indices. */
if (!file_buffer)
return ((REFERENCE **)NULL);
/* Reset globals describing where the index was found. */
maybe_free (initial_index_filename);
maybe_free (initial_index_nodename);
initial_index_filename = (char *)NULL;
initial_index_nodename = (char *)NULL;
if (index_nodenames)
{
for (i = 0; index_nodenames[i]; i++)
{
free (index_nodenames[i]->name);
free (index_nodenames[i]);
}
index_nodenames_index = 0;
index_nodenames[0] = (INDEX_NAME_ASSOC *)NULL;
}
/* Grovel the names of the nodes found in this file. */
if (file_buffer->tags)
{
TAG *tag;
for (i = 0; tag = file_buffer->tags[i]; i++)
{
if (string_in_line ("Index", tag->nodename) != -1)
{
NODE *node;
REFERENCE **menu;
/* Found one. Get its menu. */
node = info_get_node (tag->filename, tag->nodename);
if (!node)
continue;
/* Remember the filename and nodename of this index. */
initial_index_filename = strdup (file_buffer->filename);
initial_index_nodename = strdup (tag->nodename);
menu = info_menu_of_node (node);
/* If we have a menu, add this index's nodename and range
to our list of index_nodenames. */
if (menu)
{
add_index_to_index_nodenames (menu, node);
/* Concatenate the references found so far. */
result = info_concatenate_references (result, menu);
}
free (node);
}
}
}
/* If there is a result, clean it up so that every entry has a filename. */
for (i = 0; result && result[i]; i++)
if (!result[i]->filename)
result[i]->filename = strdup (file_buffer->filename);
return (result);
}
DECLARE_INFO_COMMAND (info_index_search,
"Look up a string in the index for this file")
{
FILE_BUFFER *fb;
char *line;
/* Reset the index offset, since this is not the info-index-next command. */
index_offset = 0;
/* The user is selecting a new search string, so flush the old one. */
maybe_free (index_search);
index_search = (char *)NULL;
/* If this window's file is not the same as the one that we last built an
index for, build and remember an index now. */
fb = file_buffer_of_window (window);
if (!initial_index_filename ||
(strcmp (initial_index_filename, fb->filename) != 0))
{
info_free_references (index_index);
window_message_in_echo_area ("Finding index entries...");
index_index = info_indices_of_file_buffer (fb);
}
/* If there is no index, quit now. */
if (!index_index)
{
info_error ("No indices found.");
return;
}
/* Okay, there is an index. Let the user select one of the members of it. */
line =
info_read_maybe_completing (window, "Index entry: ", index_index);
window = active_window;
/* User aborted? */
if (!line)
{
info_abort_key (active_window, 1, 0);
return;
}
/* Empty line means move to the Index node. */
if (!*line)
{
free (line);
if (initial_index_filename && initial_index_nodename)
{
NODE *node;
node =
info_get_node (initial_index_filename, initial_index_nodename);
set_remembered_pagetop_and_point (window);
window_set_node_of_window (window, node);
remember_window_and_node (window, node);
window_clear_echo_area ();
return;
}
}
/* The user typed either a completed index label, or a partial string.
Find an exact match, or, failing that, the first index entry containing
the partial string. So, we just call info_next_index_match () with minor
manipulation of INDEX_OFFSET. */
{
int old_offset;
/* Start the search right after/before this index. */
if (count < 0)
{
register int i;
for (i = 0; index_index[i]; i++);
index_offset = i;
}
else
index_offset = -1;
old_offset = index_offset;
/* The "last" string searched for is this one. */
index_search = line;
/* Find it, or error. */
info_next_index_match (window, count, 0);
/* If the search failed, return the index offset to where it belongs. */
if (index_offset == old_offset)
index_offset = 0;
}
}
DECLARE_INFO_COMMAND (info_next_index_match,
"Go to the next matching index item from the last `\\[index-search]' command")
{
register int i;
int partial, dir;
NODE *node;
/* If there is no previous search string, the user hasn't built an index
yet. */
if (!index_search)
{
info_error ("No previous index search string.");
return;
}
/* If there is no index, that is an error. */
if (!index_index)
{
info_error ("No index entries.");
return;
}
/* The direction of this search is controlled by the value of the
numeric argument. */
if (count < 0)
dir = -1;
else
dir = 1;
/* Search for the next occurence of index_search. First try to find
an exact match. */
partial = 0;
for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
if (strcmp (index_search, index_index[i]->label) == 0)
break;
/* If that failed, look for the next substring match. */
if ((i < 0) || (!index_index[i]))
{
for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
if (string_in_line (index_search, index_index[i]->label) != -1)
break;
if ((i > -1) && (index_index[i]))
partial = string_in_line (index_search, index_index[i]->label);
}
/* If that failed, print an error. */
if ((i < 0) || (!index_index[i]))
{
info_error ("No %sindex entries containing \"%s\".",
index_offset > 0 ? "more " : "", index_search);
return;
}
/* Okay, we found the next one. Move the offset to the current entry. */
index_offset = i;
/* Report to the user on what we have found. */
{
register int j;
char *name = "CAN'T SEE THIS";
char *match;
for (j = 0; index_nodenames[j]; j++)
{
if ((i >= index_nodenames[j]->first) &&
(i <= index_nodenames[j]->last))
{
name = index_nodenames[j]->name;
break;
}
}
/* If we had a partial match, indicate to the user which part of the
string matched. */
match = strdup (index_index[i]->label);
if (partial && show_index_match)
{
int j, ls, start, upper;
ls = strlen (index_search);
start = partial - ls;
upper = isupper (match[start]) ? 1 : 0;
for (j = 0; j < ls; j++)
if (upper)
match[j + start] = info_tolower (match[j + start]);
else
match[j + start] = info_toupper (match[j + start]);
}
{
char *format;
format = replace_in_documentation
("Found \"%s\" in %s. (`\\[next-index-match]' tries to find next.)");
window_message_in_echo_area (format, match, name);
}
free (match);
}
/* Select the node corresponding to this index entry. */
node = info_get_node (index_index[i]->filename, index_index[i]->nodename);
if (!node)
{
info_error (CANT_FILE_NODE,
index_index[i]->filename, index_index[i]->nodename);
return;
}
set_remembered_pagetop_and_point (window);
window_set_node_of_window (window, node);
remember_window_and_node (window, node);
/* Try to find an occurence of LABEL in this node. */
{
long start, loc;
start = window->line_starts[1] - window->node->contents;
loc = info_target_search_node (node, index_index[i]->label, start);
if (loc != -1)
{
window->point = loc;
window_adjust_pagetop (window);
}
}
}
/* **************************************************************** */
/* */
/* Info APROPOS: Search every known index. */
/* */
/* **************************************************************** */
/* For every menu item in DIR, search the indices of that file for
SEARCH_STRING. */
REFERENCE **
apropos_in_all_indices (search_string, inform)
char *search_string;
int inform;
{
register int i, dir_index;
REFERENCE **all_indices = (REFERENCE **)NULL;
REFERENCE **dir_menu = (REFERENCE **)NULL;
NODE *dir_node;
int printed = 0;
dir_node = info_get_node ("dir", "Top");
if (dir_node)
dir_menu = info_menu_of_node (dir_node);
if (!dir_menu)
return;
/* For every menu item in DIR, get the associated node's file buffer and
read the indices of that file buffer. Gather all of the indices into
one large one. */
for (dir_index = 0; dir_menu[dir_index]; dir_index++)
{
REFERENCE **this_index, *this_item;
NODE *this_node;
FILE_BUFFER *this_fb;
this_item = dir_menu[dir_index];
if (!this_item->filename)
{
if (dir_node->parent)
this_item->filename = strdup (dir_node->parent);
else
this_item->filename = strdup (dir_node->filename);
}
/* Find this node. If we cannot find it, try using the label of the
entry as a file (i.e., "(LABEL)Top"). */
this_node = info_get_node (this_item->filename, this_item->nodename);
if (!this_node && this_item->nodename &&
(strcmp (this_item->label, this_item->nodename) == 0))
this_node = info_get_node (this_item->label, "Top");
if (!this_node)
continue;
/* Get the file buffer associated with this node. */
{
char *files_name;
files_name = this_node->parent;
if (!files_name)
files_name = this_node->filename;
this_fb = info_find_file (files_name);
if (this_fb && inform)
message_in_echo_area ("Scanning indices of \"%s\"...", files_name);
this_index = info_indices_of_file_buffer (this_fb);
free (this_node);
if (this_fb && inform)
unmessage_in_echo_area ();
}
if (this_index)
{
/* Remember the filename which contains this set of references. */
for (i = 0; this_index && this_index[i]; i++)
if (!this_index[i]->filename)
this_index[i]->filename = strdup (this_fb->filename);
/* Concatenate with the other indices. */
all_indices = info_concatenate_references (all_indices, this_index);
}
}
info_free_references (dir_menu);
/* Build a list of the references which contain SEARCH_STRING. */
if (all_indices)
{
REFERENCE *entry, **apropos_list = (REFERENCE **)NULL;
int apropos_list_index = 0;
int apropos_list_slots = 0;
for (i = 0; (entry = all_indices[i]); i++)
{
if (string_in_line (search_string, entry->label) != -1)
{
add_pointer_to_array
(entry, apropos_list_index, apropos_list, apropos_list_slots,
100, REFERENCE *);
}
else
{
maybe_free (entry->label);
maybe_free (entry->filename);
maybe_free (entry->nodename);
free (entry);
}
}
free (all_indices);
all_indices = apropos_list;
}
return (all_indices);
}
#define APROPOS_NONE \
"No available info files reference \"%s\" in their indices."
void
info_apropos (string)
char *string;
{
REFERENCE **apropos_list;
apropos_list = apropos_in_all_indices (string, 0);
if (!apropos_list)
{
info_error (APROPOS_NONE, string);
}
else
{
register int i;
REFERENCE *entry;
for (i = 0; (entry = apropos_list[i]); i++)
fprintf (stderr, "\"(%s)%s\" -- %s\n",
entry->filename, entry->nodename, entry->label);
}
info_free_references (apropos_list);
}
static char *apropos_list_nodename = "*Apropos*";
DECLARE_INFO_COMMAND (info_index_apropos,
"Grovel all known info file's indices for a string and build a menu")
{
char *line;
line = info_read_in_echo_area (window, "Index apropos: ");
window = active_window;
/* User aborted? */
if (!line)
{
info_abort_key (window, 1, 1);
return;
}
/* User typed something? */
if (*line)
{
REFERENCE **apropos_list;
NODE *apropos_node;
apropos_list = apropos_in_all_indices (line, 1);
if (!apropos_list)
{
info_error (APROPOS_NONE, line);
}
else
{
register int i;
char *line_buffer;
initialize_message_buffer ();
printf_to_message_buffer
("\n* Menu: Nodes whoses indices contain \"%s\":\n", line);
line_buffer = (char *)xmalloc (500);
for (i = 0; apropos_list[i]; i++)
{
int len;
sprintf (line_buffer, "* (%s)%s::",
apropos_list[i]->filename, apropos_list[i]->nodename);
len = pad_to (36, line_buffer);
sprintf (line_buffer + len, "%s", apropos_list[i]->label);
printf_to_message_buffer ("%s\n", line_buffer);
}
free (line_buffer);
}
apropos_node = message_buffer_to_node ();
add_gcable_pointer (apropos_node->contents);
name_internal_node (apropos_node, apropos_list_nodename);
/* Even though this is an internal node, we don't want the window
system to treat it specially. So we turn off the internalness
of it here. */
apropos_node->flags &= ~N_IsInternal;
/* Find/Create a window to contain this node. */
{
WINDOW *new;
NODE *node;
set_remembered_pagetop_and_point (window);
/* If a window is visible and showing an apropos list already,
re-use it. */
for (new = windows; new; new = new->next)
{
node = new->node;
if (internal_info_node_p (node) &&
(strcmp (node->nodename, apropos_list_nodename) == 0))
break;
}
/* If we couldn't find an existing window, try to use the next window
in the chain. */
if (!new && window->next)
new = window->next;
/* If we still don't have a window, make a new one to contain
the list. */
if (!new)
{
WINDOW *old_active;
old_active = active_window;
active_window = window;
new = window_make_window ((NODE *)NULL);
active_window = old_active;
}
/* If we couldn't make a new window, use this one. */
if (!new)
new = window;
/* Lines do not wrap in this window. */
new->flags |= W_NoWrap;
window_set_node_of_window (new, apropos_node);
remember_window_and_node (new, apropos_node);
active_window = new;
}
info_free_references (apropos_list);
}
free (line);
if (!info_error_was_printed)
window_clear_echo_area ();
}
texinfo-3.7/info/indices.h 100666 11732 13 2672 5770343422 13771 0 ustar bfox user /* indices.h -- Functions defined in indices.c. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_INDICES_H_)
#define _INDICES_H_
/* User-visible variable controls the output of info-index-next. */
extern int show_index_match;
extern REFERENCE **info_indices_of_window (), **info_indices_of_file_buffer ();
extern void info_apropos ();
/* For every menu item in DIR, search the indices of that file for STRING. */
REFERENCE **apropos_in_all_indices ();
/* User visible functions declared in indices.c. */
extern void info_index_search (), info_next_index_match ();
#endif /* !_INDICES_H_ */
texinfo-3.7/info/info-stnd.texi 100666 11732 13 141064 5764640672 15047 0 ustar bfox user \input texinfo @c -*-texinfo-*-
@comment %**start of header
@setfilename info-stnd.info
@settitle GNU Info
@set InfoProgVer 2.11
@paragraphindent none
@footnotestyle end
@synindex vr cp
@synindex fn cp
@synindex ky cp
@comment %**end of header
@ifinfo
This file documents GNU Info, a program for viewing the on-line formatted
versions of Texinfo files. This documentation is different from the
documentation for the Info reader that is part of GNU Emacs. If you do
not know how to use Info, but have a working Info reader, you should
read that documentation first.
Copyright @copyright{} 1992, 1993 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.
@ignore
Permission is granted to process this file through TeX and print the
results, provided the printed document carries a copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided also that the
sections entitled ``Copying'' and ``GNU General Public License'' are
included exactly as in the original, and provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation
approved by the Free Software Foundation.
@end ifinfo
@titlepage
@title GNU Info User's Guide
@subtitle For GNU Info version @value{InfoProgVer}
@author Brian J. Fox (bfox@@ai.mit.edu)
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1992, 1993 Free Software Foundation
Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided also that the
sections entitled ``Copying'' and ``GNU General Public License'' are
included exactly as in the original, and provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation
approved by the Free Software Foundation.
@end titlepage
@ifinfo
@node Top, What is Info, (dir), (dir)
@top The GNU Info Program
This file documents GNU Info, a program for viewing the on-line
formatted versions of Texinfo files, version @value{InfoProgVer}. This
documentation is different from the documentation for the Info reader
that is part of GNU Emacs.
@end ifinfo
@menu
* What is Info::
* Options:: Options you can pass on the command line.
* Cursor Commands:: Commands which move the cursor within a node.
* Scrolling Commands:: Commands for moving the node around
in a window.
* Node Commands:: Commands for selecting a new node.
* Searching Commands:: Commands for searching an Info file.
* Xref Commands:: Commands for selecting cross references.
* Window Commands:: Commands which manipulate multiple windows.
* Printing Nodes:: How to print out the contents of a node.
* Miscellaneous Commands:: A few commands that defy categories.
* Variables:: How to change the default behavior of Info.
* GNU Info Global Index:: Global index containing keystrokes,
command names, variable names,
and general concepts.
@end menu
@node What is Info, Options, Top, Top
@chapter What is Info?
@iftex
This file documents GNU Info, a program for viewing the on-line formatted
versions of Texinfo files, version @value{InfoProgVer}.
@end iftex
@dfn{Info} is a program which is used to view Info files on an ASCII
terminal. @dfn{Info files} are the result of processing Texinfo files
with the program @code{makeinfo} or with one of the Emacs commands, such
as @code{M-x texinfo-format-buffer}. Texinfo itself is a documentation
system that uses a single source file to produce both on-line
information and printed output. You can typeset and print the
files that you read in Info.@refill
@node Options, Cursor Commands, What is Info, Top
@chapter Command Line Options
@cindex command line options
@cindex arguments, command line
GNU Info accepts several options to control the initial node being
viewed, and to specify which directories to search for Info files. Here
is a template showing an invocation of GNU Info from the shell:
@example
info [--@var{option-name} @var{option-value}] @var{menu-item}@dots{}
@end example
The following @var{option-names} are available when invoking Info from
the shell:
@table @code
@cindex directory path
@item --directory @var{directory-path}
@itemx -d @var{directory-path}
Add @var{directory-path} to the list of directory paths searched when
Info needs to find a file. You may issue @code{--directory} multiple
times; once for each directory which contains Info files.
Alternatively, you may specify a value for the environment variable
@code{INFOPATH}; if @code{--directory} is not given, the value of
@code{INFOPATH} is used. The value of @code{INFOPATH} is a colon
separated list of directory names. If you do not supply @code{INFOPATH}
or @code{--directory-path}, Info uses a default path.
@item --file @var{filename}
@itemx -f @var{filename}
@cindex Info file, selecting
Specify a particular Info file to visit. By default, Info visits
the file @code{dir}; if you use this option, Info will start with
@code{(@var{filename})Top} as the first file and node.
@item --node @var{nodename}
@itemx -n @var{nodename}
@cindex node, selecting
Specify a particular node to visit in the initial file that Info
loads. This is especially useful in conjunction with
@code{--file}@footnote{Of course, you can specify both the file and node
in a @code{--node} command; but don't forget to escape the open and
close parentheses from the shell as in: @code{info --node
"(emacs)Buffers"}}. You may specify @code{--node} multiple times; for
an interactive Info, each @var{nodename} is visited in its own window,
for a non-interactive Info (such as when @code{--output} is given) each
@var{nodename} is processed sequentially.
@item --output @var{filename}
@itemx -o @var{filename}
@cindex file, outputting to
@cindex outputting to a file
Specify @var{filename} as the name of a file to which to direct output.
Each node that Info visits will be output to @var{filename} instead of
interactively viewed. A value of @code{-} for @var{filename} specifies
the standard output.
@item --subnodes
@cindex @code{--subnodes}, command line option
This option only has meaning when given in conjunction with
@code{--output}. It means to recursively output the nodes appearing in
the menus of each node being output. Menu items which resolve to
external Info files are not output, and neither are menu items which are
members of an index. Each node is only output once.
@item --help
@itemx -h
Produces a relatively brief description of the available Info options.
@item --version
@cindex version information
Prints the version information of Info and exits.
@item @var{menu-item}
@cindex menu, following
Info treats its remaining arguments as the names of menu items. The
first argument is a menu item in the initial node visited, while
the second argument is a menu item in the first argument's node.
You can easily move to the node of your choice by specifying the menu
names which describe the path to that node. For example,
@example
info emacs buffers
@end example
@noindent
first selects the menu item @samp{Emacs} in the node @samp{(dir)Top},
and then selects the menu item @samp{Buffers} in the node
@samp{(emacs)Top}.
@end table
@node Cursor Commands, Scrolling Commands, Options, Top
@chapter Moving the Cursor
@cindex cursor, moving
Many people find that reading screens of text page by page is made
easier when one is able to indicate particular pieces of text with some
kind of pointing device. Since this is the case, GNU Info (both the
Emacs and standalone versions) have several commands which allow you to
move the cursor about the screen. The notation used in this manual to
describe keystrokes is identical to the notation used within the Emacs
manual, and the GNU Readline manual. @xref{Characters, , Character
Conventions, emacs, the GNU Emacs Manual}, if you are unfamiliar with the
notation.
The following table lists the basic cursor movement commands in Info.
Each entry consists of the key sequence you should type to execute the
cursor movement, the @code{M-x}@footnote{@code{M-x} is also a command; it
invokes @code{execute-extended-command}. @xref{M-x, , Executing an
extended command, emacs, the GNU Emacs Manual}, for more detailed
information.} command name (displayed in parentheses), and a short
description of what the command does. All of the cursor motion commands
can take an @dfn{numeric} argument (@pxref{Miscellaneous Commands,
@code{universal-argument}}), to find out how to supply them. With a
numeric argument, the motion commands are simply executed that
many times; for example, a numeric argument of 4 given to
@code{next-line} causes the cursor to move down 4 lines. With a
negative numeric argument, the motion is reversed; an argument of -4
given to the @code{next-line} command would cause the cursor to move
@emph{up} 4 lines.
@table @asis
@item @code{C-n} (@code{next-line})
@kindex C-n
@findex next-line
Move the cursor down to the next line.
@item @code{C-p} (@code{prev-line})
@kindex C-p
@findex prev-line
Move the cursor up to the previous line.
@item @code{C-a} (@code{beginning-of-line})
@kindex C-a, in Info windows
@findex beginning-of-line
Move the cursor to the start of the current line.
@item @code{C-e} (@code{end-of-line})
@kindex C-e, in Info windows
@findex end-of-line
Move the cursor to the end of the current line.
@item @code{C-f} (@code{forward-char})
@kindex C-f, in Info windows
@findex forward-char
Move the cursor forward a character.
@item @code{C-b} (@code{backward-char})
@kindex C-b, in Info windows
@findex backward-char
Move the cursor backward a character.
@item @code{M-f} (@code{forward-word})
@kindex M-f, in Info windows
@findex forward-word
Move the cursor forward a word.
@item @code{M-b} (@code{backward-word})
@kindex M-b, in Info windows
@findex backward-word
Move the cursor backward a word.
@item @code{M-<} (@code{beginning-of-node})
@itemx @code{b}
@kindex b, in Info windows
@kindex M-<
@findex beginning-of-node
Move the cursor to the start of the current node.
@item @code{M->} (@code{end-of-node})
@kindex M->
@findex end-of-node
Move the cursor to the end of the current node.
@item @code{M-r} (@code{move-to-window-line})
@kindex M-r
@findex move-to-window-line
Move the cursor to a specific line of the window. Without a numeric
argument, @code{M-r} moves the cursor to the start of the line in the
center of the window. With a numeric argument of @var{n}, @code{M-r}
moves the cursor to the start of the @var{n}th line in the window.
@end table
@node Scrolling Commands, Node Commands, Cursor Commands, Top
@chapter Moving Text Within a Window
@cindex scrolling
Sometimes you are looking at a screenful of text, and only part of the
current paragraph you are reading is visible on the screen. The
commands detailed in this section are used to shift which part of the
current node is visible on the screen.
@table @asis
@item @code{SPC} (@code{scroll-forward})
@itemx @code{C-v}
@kindex SPC, in Info windows
@kindex C-v
@findex scroll-forward
Shift the text in this window up. That is, show more of the node which
is currently below the bottom of the window. With a numeric argument,
show that many more lines at the bottom of the window; a numeric
argument of 4 would shift all of the text in the window up 4 lines
(discarding the top 4 lines), and show you four new lines at the bottom
of the window. Without a numeric argument, @key{SPC} takes the bottom
two lines of the window and places them at the top of the window,
redisplaying almost a completely new screenful of lines.
@item @code{DEL} (@code{scroll-backward})
@itemx @code{M-v}
@kindex DEL, in Info windows
@kindex M-v
@findex scroll-backward
Shift the text in this window down. The inverse of
@code{scroll-forward}.
@end table
@cindex scrolling through node structure
The @code{scroll-forward} and @code{scroll-backward} commands can also
move forward and backward through the node structure of the file. If
you press @key{SPC} while viewing the end of a node, or @key{DEL} while
viewing the beginning of a node, what happens is controlled by the
variable @code{scroll-behavior}. @xref{Variables,
@code{scroll-behavior}}, for more information.
@table @asis
@item @code{C-l} (@code{redraw-display})
@kindex C-l
@findex redraw-display
Redraw the display from scratch, or shift the line containing the cursor
to a specified location. With no numeric argument, @samp{C-l} clears
the screen, and then redraws its entire contents. Given a numeric
argument of @var{n}, the line containing the cursor is shifted so that
it is on the @var{n}th line of the window.
@item @code{C-x w} (@code{toggle-wrap})
@kindex C-w
@findex toggle-wrap
Toggles the state of line wrapping in the current window. Normally,
lines which are longer than the screen width @dfn{wrap}, i.e., they are
continued on the next line. Lines which wrap have a @samp{\} appearing
in the rightmost column of the screen. You can cause such lines to be
terminated at the rightmost column by changing the state of line
wrapping in the window with @code{C-x w}. When a line which needs more
space than one screen width to display is displayed, a @samp{$} appears
in the rightmost column of the screen, and the remainder of the line is
invisible.
@end table
@node Node Commands, Searching Commands, Scrolling Commands, Top
@chapter Selecting a New Node
@cindex nodes, selection of
This section details the numerous Info commands which select a new node
to view in the current window.
The most basic node commands are @samp{n}, @samp{p}, @samp{u}, and
@samp{l}.
When you are viewing a node, the top line of the node contains some Info
@dfn{pointers} which describe where the next, previous, and up nodes
are. Info uses this line to move about the node structure of the file
when you use the following commands:
@table @asis
@item @code{n} (@code{next-node})
@kindex n
@findex next-node
Select the `Next' node.
@item @code{p} (@code{prev-node})
@kindex p
@findex prev-node
Select the `Prev' node.
@item @code{u} (@code{up-node})
@kindex u
@findex up-node
Select the `Up' node.
@end table
You can easily select a node that you have already viewed in this window
by using the @samp{l} command -- this name stands for "last", and
actually moves through the list of already visited nodes for this
window. @samp{l} with a negative numeric argument moves forward through
the history of nodes for this window, so you can quickly step between
two adjacent (in viewing history) nodes.
@table @asis
@item @code{l} (@code{history-node})
@kindex l
@findex history-node
Select the most recently selected node in this window.
@end table
Two additional commands make it easy to select the most commonly
selected nodes; they are @samp{t} and @samp{d}.
@table @asis
@item @code{t} (@code{top-node})
@kindex t
@findex top-node
Select the node @samp{Top} in the current Info file.
@item @code{d} (@code{dir-node})
@kindex d
@findex dir-node
Select the directory node (i.e., the node @samp{(dir)}).
@end table
Here are some other commands which immediately result in the selection
of a different node in the current window:
@table @asis
@item @code{<} (@code{first-node})
@kindex <
@findex first-node
Selects the first node which appears in this file. This node is most
often @samp{Top}, but it does not have to be.
@item @code{>} (@code{last-node})
@kindex >
@findex last-node
Select the last node which appears in this file.
@item @code{]} (@code{global-next-node})
@kindex ]
@findex global-next-node
Move forward or down through node structure. If the node that you are
currently viewing has a @samp{Next} pointer, that node is selected.
Otherwise, if this node has a menu, the first menu item is selected. If
there is no @samp{Next} and no menu, the same process is tried with the
@samp{Up} node of this node.
@item @code{[} (@code{global-prev-node})
@kindex [
@findex global-prev-node
Move backward or up through node structure. If the node that you are
currently viewing has a @samp{Prev} pointer, that node is selected.
Otherwise, if the node has an @samp{Up} pointer, that node is selected,
and if it has a menu, the last item in the menu is selected.
@end table
You can get the same behavior as @code{global-next-node} and
@code{global-prev-node} while simply scrolling through the file with
@key{SPC} and @key{DEL}; @xref{Variables, @code{scroll-behavior}}, for
more information.
@table @asis
@item @code{g} (@code{goto-node})
@kindex g
@findex goto-node
Read the name of a node and select it. No completion is done while
reading the node name, since the desired node may reside in a separate
file. The node must be typed exactly as it appears in the Info file. A
file name may be included as with any node specification, for example
@example
@code{g(emacs)Buffers}
@end example
finds the node @samp{Buffers} in the Info file @file{emacs}.
@item @code{C-x k} (@code{kill-node})
@kindex C-x k
@findex kill-node
Kill a node. The node name is prompted for in the echo area, with a
default of the current node. @dfn{Killing} a node means that Info tries
hard to forget about it, removing it from the list of history nodes kept
for the window where that node is found. Another node is selected in
the window which contained the killed node.
@item @code{C-x C-f} (@code{view-file})
@kindex C-x C-f
@findex view-file
Read the name of a file and selects the entire file. The command
@example
@code{C-x C-f @var{filename}}
@end example
is equivalent to typing
@example
@code{g(@var{filename})*}
@end example
@item @code{C-x C-b} (@code{list-visited-nodes})
@kindex C-x C-b
@findex list-visited-nodes
Make a window containing a menu of all of the currently visited nodes.
This window becomes the selected window, and you may use the standard
Info commands within it.
@item @code{C-x b} (@code{select-visited-node})
@kindex C-x b
@findex select-visited-node
Select a node which has been previously visited in a visible window.
This is similar to @samp{C-x C-b} followed by @samp{m}, but no window is
created.
@end table
@node Searching Commands, Xref Commands, Node Commands, Top
@chapter Searching an Info File
@cindex searching
GNU Info allows you to search for a sequence of characters throughout an
entire Info file, search through the indices of an Info file, or find
areas within an Info file which discuss a particular topic.
@table @asis
@item @code{s} (@code{search})
@kindex s
@findex search
Read a string in the echo area and search for it.
@item @code{C-s} (@code{isearch-forward})
@kindex C-s
@findex isearch-forward
Interactively search forward through the Info file for a string as you
type it.
@item @code{C-r} (@code{isearch-backward})
@kindex C-r
@findex isearch-backward
Interactively search backward through the Info file for a string as
you type it.
@item @code{i} (@code{index-search})
@kindex i
@findex index-search
Look up a string in the indices for this Info file, and select a node
where the found index entry points to.
@item @code{,} (@code{next-index-match})
@kindex ,
@findex next-index-match
Move to the node containing the next matching index item from the last
@samp{i} command.
@end table
The most basic searching command is @samp{s} (@code{search}). The
@samp{s} command prompts you for a string in the echo area, and then
searches the remainder of the Info file for an occurrence of that string.
If the string is found, the node containing it is selected, and the
cursor is left positioned at the start of the found string. Subsequent
@samp{s} commands show you the default search string within @samp{[} and
@samp{]}; pressing @key{RET} instead of typing a new string will use the
default search string.
@dfn{Incremental searching} is similar to basic searching, but the
string is looked up while you are typing it, instead of waiting until
the entire search string has been specified.
@node Xref Commands, Window Commands, Searching Commands, Top
@chapter Selecting Cross References
We have already discussed the @samp{Next}, @samp{Prev}, and @samp{Up}
pointers which appear at the top of a node. In addition to these
pointers, a node may contain other pointers which refer you to a
different node, perhaps in another Info file. Such pointers are called
@dfn{cross references}, or @dfn{xrefs} for short.
@menu
* Parts of an Xref:: What a cross reference is made of.
* Selecting Xrefs:: Commands for selecting menu or note items.
@end menu
@node Parts of an Xref, Selecting Xrefs, , Xref Commands
@section Parts of an Xref
Cross references have two major parts: the first part is called the
@dfn{label}; it is the name that you can use to refer to the cross
reference, and the second is the @dfn{target}; it is the full name of
the node that the cross reference points to.
The target is separated from the label by a colon @samp{:}; first the
label appears, and then the target. For example, in the sample menu
cross reference below, the single colon separates the label from the
target.
@example
* Foo Label: Foo Target. More information about Foo.
@end example
Note the @samp{.} which ends the name of the target. The @samp{.} is
not part of the target; it serves only to let Info know where the target
name ends.
A shorthand way of specifying references allows two adjacent colons to
stand for a target name which is the same as the label name:
@example
* Foo Commands:: Commands pertaining to Foo.
@end example
In the above example, the name of the target is the same as the name of
the label, in this case @code{Foo Commands}.
You will normally see two types of cross reference while viewing nodes:
@dfn{menu} references, and @dfn{note} references. Menu references
appear within a node's menu; they begin with a @samp{*} at the beginning
of a line, and continue with a label, a target, and a comment which
describes what the contents of the node pointed to contains.
Note references appear within the body of the node text; they begin with
@code{*Note}, and continue with a label and a target.
Like @samp{Next}, @samp{Prev}, and @samp{Up} pointers, cross references
can point to any valid node. They are used to refer you to a place
where more detailed information can be found on a particular subject.
Here is a cross reference which points to a node within the Texinfo
documentation: @xref{xref, , Writing an Xref, texinfo, the Texinfo
Manual}, for more information on creating your own texinfo cross
references.
@node Selecting Xrefs, , Parts of an Xref, Xref Commands
@section Selecting Xrefs
The following table lists the Info commands which operate on menu items.
@table @asis
@item @code{1} (@code{menu-digit})
@itemx @code{2} @dots{} @code{9}
@cindex 1 @dots{} 9, in Info windows
@kindex 1 @dots{} 9, in Info windows
@findex menu-digit
Within an Info window, pressing a single digit, (such as @samp{1}),
selects that menu item, and places its node in the current window.
For convenience, there is one exception; pressing @samp{0} selects the
@emph{last} item in the node's menu.
@item @code{0} (@code{last-menu-item})
@kindex 0, in Info windows
@findex last-menu-item
Select the last item in the current node's menu.
@item @code{m} (@code{menu-item})
@kindex m
@findex menu-item
Reads the name of a menu item in the echo area and selects its node.
Completion is available while reading the menu label.
@item @code{M-x find-menu}
@findex find-menu
Move the cursor to the start of this node's menu.
@end table
This table lists the Info commands which operate on note cross references.
@table @asis
@item @code{f} (@code{xref-item})
@itemx @code{r}
@kindex f
@kindex r
@findex xref-item
Reads the name of a note cross reference in the echo area and selects
its node. Completion is available while reading the cross reference
label.
@end table
Finally, the next few commands operate on menu or note references alike:
@table @asis
@item @code{TAB} (@code{move-to-next-xref})
@kindex TAB, in Info windows
@findex move-to-next-xref
Move the cursor to the start of the next nearest menu item or note
reference in this node. You can then use @key{RET}
(@code{select-reference-this-line}) to select the menu or note reference.
@item @code{M-TAB} (@code{move-to-prev-xref})
@kindex M-TAB, in Info windows
@findex move-to-prev-xref
Move the cursor the start of the nearest previous menu item or note
reference in this node.
@item @code{RET} (@code{select-reference-this-line})
@kindex RET, in Info windows
@findex select-reference-this-line
Select the menu item or note reference appearing on this line.
@end table
@node Window Commands, Printing Nodes, Xref Commands, Top
@chapter Manipulating Multiple Windows
@cindex windows, manipulating
A @dfn{window} is a place to show the text of a node. Windows have a
view area where the text of the node is displayed, and an associated
@dfn{mode line}, which briefly describes the node being viewed.
GNU Info supports multiple windows appearing in a single screen; each
window is separated from the next by its modeline. At any time, there
is only one @dfn{active} window, that is, the window in which the cursor
appears. There are commands available for creating windows, changing
the size of windows, selecting which window is active, and for deleting
windows.
@menu
* The Mode Line:: What appears in the mode line?
* Basic Windows:: Manipulating windows in Info.
* The Echo Area:: Used for displaying errors and reading input.
@end menu
@node The Mode Line, Basic Windows, , Window Commands
@section The Mode Line
A @dfn{mode line} is a line of inverse video which appears at the bottom
of an Info window. It describes the contents of the window just above
it; this information includes the name of the file and node appearing in
that window, the number of screen lines it takes to display the node,
and the percentage of text that is above the top of the window. It can
also tell you if the indirect tags table for this Info file needs to be
updated, and whether or not the Info file was compressed when stored on
disk.
Here is a sample mode line for a window containing an uncompressed file
named @file{dir}, showing the node @samp{Top}.
@example
@group
-----Info: (dir)Top, 40 lines --Top---------------------------------------
^^ ^ ^^^ ^^
(file)Node #lines where
@end group
@end example
When a node comes from a file which is compressed on disk, this is
indicated in the mode line with two small @samp{z}'s. In addition, if
the Info file containing the node has been split into subfiles, the name
of the subfile containing the node appears in the modeline as well:
@example
--zz-Info: (emacs)Top, 291 lines --Top-- Subfile: emacs-1.Z---------------
@end example
When Info makes a node internally, such that there is no corresponding
info file on disk, the name of the node is surrounded by asterisks
(@samp{*}). The name itself tells you what the contents of the window
are; the sample mode line below shows an internally constructed node
showing possible completions:
@example
-----Info: *Completions*, 7 lines --All-----------------------------------
@end example
@node Basic Windows, The Echo Area, The Mode Line, Window Commands
@section Window Commands
It can be convenient to view more than one node at a time. To allow
this, Info can display more than one @dfn{window}. Each window has its
own mode line (@pxref{The Mode Line}) and history of nodes viewed in that
window (@pxref{Node Commands, , @code{history-node}}).
@table @asis
@item @code{C-x o} (@code{next-window})
@cindex windows, selecting
@kindex C-x o
@findex next-window
Select the next window on the screen. Note that the echo area can only be
selected if it is already in use, and you have left it temporarily.
Normally, @samp{C-x o} simply moves the cursor into the next window on
the screen, or if you are already within the last window, into the first
window on the screen. Given a numeric argument, @samp{C-x o} moves over
that many windows. A negative argument causes @samp{C-x o} to select
the previous window on the screen.
@item @code{M-x prev-window}
@findex prev-window
Select the previous window on the screen. This is identical to
@samp{C-x o} with a negative argument.
@item @code{C-x 2} (@code{split-window})
@cindex windows, creating
@kindex C-x 2
@findex split-window
Split the current window into two windows, both showing the same node.
Each window is one half the size of the original window, and the cursor
remains in the original window. The variable @code{automatic-tiling}
can cause all of the windows on the screen to be resized for you
automatically, please @pxref{Variables, , automatic-tiling} for more
information.
@item @code{C-x 0} (@code{delete-window})
@cindex windows, deleting
@kindex C-x 0
@findex delete-window
Delete the current window from the screen. If you have made too many
windows and your screen appears cluttered, this is the way to get rid of
some of them.
@item @code{C-x 1} (@code{keep-one-window})
@kindex C-x 1
@findex keep-one-window
Delete all of the windows excepting the current one.
@item @code{ESC C-v} (@code{scroll-other-window})
@kindex ESC C-v, in Info windows
@findex scroll-other-window
Scroll the other window, in the same fashion that @samp{C-v} might
scroll the current window. Given a negative argument, scroll the
"other" window backward.
@item @code{C-x ^} (@code{grow-window})
@kindex C-x ^
@findex grow-window
Grow (or shrink) the current window. Given a numeric argument, grow
the current window that many lines; with a negative numeric argument,
shrink the window instead.
@item @code{C-x t} (@code{tile-windows})
@cindex tiling
@kindex C-x t
@findex tile-windows
Divide the available screen space among all of the visible windows.
Each window is given an equal portion of the screen in which to display
its contents. The variable @code{automatic-tiling} can cause
@code{tile-windows} to be called when a window is created or deleted.
@xref{Variables, , @code{automatic-tiling}}.
@end table
@node The Echo Area, , Basic Windows, Window Commands
@section The Echo Area
@cindex echo area
The @dfn{echo area} is a one line window which appears at the bottom of
the screen. It is used to display informative or error messages, and to
read lines of input from you when that is necessary. Almost all of the
commands available in the echo area are identical to their Emacs
counterparts, so please refer to that documentation for greater depth of
discussion on the concepts of editing a line of text. The following
table briefly lists the commands that are available while input is being
read in the echo area:
@table @asis
@item @code{C-f} (@code{echo-area-forward})
@kindex C-f, in the echo area
@findex echo-area-forward
Move forward a character.
@item @code{C-b} (@code{echo-area-backward})
@kindex C-b, in the echo area
@findex echo-area-backward
Move backward a character.
@item @code{C-a} (@code{echo-area-beg-of-line})
@kindex C-a, in the echo area
@findex echo-area-beg-of-line
Move to the start of the input line.
@item @code{C-e} (@code{echo-area-end-of-line})
@kindex C-e, in the echo area
@findex echo-area-end-of-line
Move to the end of the input line.
@item @code{M-f} (@code{echo-area-forward-word})
@kindex M-f, in the echo area
@findex echo-area-forward-word
Move forward a word.
@item @code{M-b} (@code{echo-area-backward-word})
@kindex M-b, in the echo area
@findex echo-area-backward-word
Move backward a word.
@item @code{C-d} (@code{echo-area-delete})
@kindex C-d, in the echo area
@findex echo-area-delete
Delete the character under the cursor.
@item @code{DEL} (@code{echo-area-rubout})
@kindex DEL, in the echo area
@findex echo-area-rubout
Delete the character behind the cursor.
@item @code{C-g} (@code{echo-area-abort})
@kindex C-g, in the echo area
@findex echo-area-abort
Cancel or quit the current operation. If completion is being read,
@samp{C-g} discards the text of the input line which does not match any
completion. If the input line is empty, @samp{C-g} aborts the calling
function.
@item @code{RET} (@code{echo-area-newline})
@kindex RET, in the echo area
@findex echo-area-newline
Accept (or forces completion of) the current input line.
@item @code{C-q} (@code{echo-area-quoted-insert})
@kindex C-q, in the echo area
@findex echo-area-quoted-insert
Insert the next character verbatim. This is how you can insert control
characters into a search string, for example.
@item @var{printing character} (@code{echo-area-insert})
@kindex printing characters, in the echo area
@findex echo-area-insert
Insert the character.
@item @code{M-TAB} (@code{echo-area-tab-insert})
@kindex M-TAB, in the echo area
@findex echo-area-tab-insert
Insert a TAB character.
@item @code{C-t} (@code{echo-area-transpose-chars})
@kindex C-t, in the echo area
@findex echo-area-transpose-chars
Transpose the characters at the cursor.
@end table
The next group of commands deal with @dfn{killing}, and @dfn{yanking}
text. For an in depth discussion of killing and yanking,
@pxref{Killing, , Killing and Deleting, emacs, the GNU Emacs Manual}
@table @asis
@item @code{M-d} (@code{echo-area-kill-word})
@kindex M-d, in the echo area
@findex echo-area-kill-word
Kill the word following the cursor.
@item @code{M-DEL} (@code{echo-area-backward-kill-word})
@kindex M-DEL, in the echo area
@findex echo-area-backward-kill-word
Kill the word preceding the cursor.
@item @code{C-k} (@code{echo-area-kill-line})
@kindex C-k, in the echo area
@findex echo-area-kill-line
Kill the text from the cursor to the end of the line.
@item @code{C-x DEL} (@code{echo-area-backward-kill-line})
@kindex C-x DEL, in the echo area
@findex echo-area-backward-kill-line
Kill the text from the cursor to the beginning of the line.
@item @code{C-y} (@code{echo-area-yank})
@kindex C-y, in the echo area
@findex echo-area-yank
Yank back the contents of the last kill.
@item @code{M-y} (@code{echo-area-yank-pop})
@kindex M-y, in the echo area
@findex echo-area-yank-pop
Yank back a previous kill, removing the last yanked text first.
@end table
Sometimes when reading input in the echo area, the command that needed
input will only accept one of a list of several choices. The choices
represent the @dfn{possible completions}, and you must respond with one
of them. Since there are a limited number of responses you can make,
Info allows you to abbreviate what you type, only typing as much of the
response as is necessary to uniquely identify it. In addition, you can
request Info to fill in as much of the response as is possible; this
is called @dfn{completion}.
The following commands are available when completing in the echo area:
@table @asis
@item @code{TAB} (@code{echo-area-complete})
@itemx @code{SPC}
@kindex TAB, in the echo area
@kindex SPC, in the echo area
@findex echo-area-complete
Insert as much of a completion as is possible.
@item @code{?} (@code{echo-area-possible-completions})
@kindex ?, in the echo area
@findex echo-area-possible-completions
Display a window containing a list of the possible completions of what
you have typed so far. For example, if the available choices are:
@example
@group
bar
foliate
food
forget
@end group
@end example
@noindent
and you have typed an @samp{f}, followed by @samp{?}, the possible
completions would contain:
@example
@group
foliate
food
forget
@end group
@end example
@noindent
i.e., all of the choices which begin with @samp{f}. Pressing @key{SPC}
or @key{TAB} would result in @samp{fo} appearing in the echo area, since
all of the choices which begin with @samp{f} continue with @samp{o}.
Now, typing @samp{l} followed by @samp{TAB} results in @samp{foliate}
appearing in the echo area, since that is the only choice which begins
with @samp{fol}.
@item @code{ESC C-v} (@code{echo-area-scroll-completions-window})
@kindex ESC C-v, in the echo area
@findex echo-area-scroll-completions-window
Scroll the completions window, if that is visible, or the "other"
window if not.
@end table
@node Printing Nodes, Miscellaneous Commands, Window Commands, Top
@chapter Printing Out Nodes
@cindex printing
You may wish to print out the contents of a node as a quick reference
document for later use. Info provides you with a command for doing
this. In general, we recommend that you use @TeX{} to format the
document and print sections of it, by running @code{tex} on the Texinfo
source file.
@table @asis
@item @code{M-x print-node}
@findex print-node
@cindex INFO_PRINT_COMMAND, environment variable
Pipe the contents of the current node through the command in the
environment variable @code{INFO_PRINT_COMMAND}. If the variable does not
exist, the node is simply piped to @code{lpr}.
@end table
@node Miscellaneous Commands, Variables, Printing Nodes, Top
@chapter Miscellaneous Commands
GNU Info contains several commands which self-document GNU Info:
@table @asis
@item @code{M-x describe-command}
@cindex functions, describing
@cindex commands, describing
@findex describe-command
Read the name of an Info command in the echo area and then display a
brief description of what that command does.
@item @code{M-x describe-key}
@cindex keys, describing
@findex describe-key
Read a key sequence in the echo area, and then display the name and
documentation of the Info command that the key sequence invokes.
@item @code{M-x describe-variable}
Read the name of a variable in the echo area and then display a brief
description of what the variable affects.
@item @code{M-x where-is}
@findex where-is
Read the name of an Info command in the echo area, and then display
a key sequence which can be typed in order to invoke that command.
@item @code{C-h} (@code{get-help-window})
@itemx @code{?}
@kindex C-h
@kindex ?, in Info windows
@findex get-help-window
Create (or Move into) the window displaying @code{*Help*}, and place
a node containing a quick reference card into it. This window displays
the most concise information about GNU Info available.
@item @code{h} (@code{get-info-help-node})
@kindex h
@findex get-info-help-node
Try hard to visit the node @code{(info)Help}. The Info file
@file{info.texi} distributed with GNU Info contains this node. Of
course, the file must first be processed with @code{makeinfo}, and then
placed into the location of your Info directory.
@end table
Here are the commands for creating a numeric argument:
@table @asis
@item @code{C-u} (@code{universal-argument})
@cindex numeric arguments
@kindex C-u
@findex universal-argument
Start (or multiply by 4) the current numeric argument. @samp{C-u} is
a good way to give a small numeric argument to cursor movement or
scrolling commands; @samp{C-u C-v} scrolls the screen 4 lines, while
@samp{C-u C-u C-n} moves the cursor down 16 lines.
@item @code{M-1} (@code{add-digit-to-numeric-arg})
@itemx @code{M-2} @dots{} @code{M-9}
@kindex M-1 @dots{} M-9
@findex add-digit-to-numeric-arg
Add the digit value of the invoking key to the current numeric
argument. Once Info is reading a numeric argument, you may just type
the digits of the argument, without the Meta prefix. For example, you
might give @samp{C-l} a numeric argument of 32 by typing:
@example
@kbd{C-u 3 2 C-l}
@end example
@noindent
or
@example
@kbd{M-3 2 C-l}
@end example
@end table
@samp{C-g} is used to abort the reading of a multi-character key
sequence, to cancel lengthy operations (such as multi-file searches) and
to cancel reading input in the echo area.
@table @asis
@item @code{C-g} (@code{abort-key})
@cindex cancelling typeahead
@cindex cancelling the current operation
@kindex C-g, in Info windows
@findex abort-key
Cancel current operation.
@end table
The @samp{q} command of Info simply quits running Info.
@table @asis
@item @code{q} (@code{quit})
@cindex quitting
@kindex q
@findex quit
Exit GNU Info.
@end table
If the operating system tells GNU Info that the screen is 60 lines tall,
and it is actually only 40 lines tall, here is a way to tell Info that
the operating system is correct.
@table @asis
@item @code{M-x set-screen-height}
@findex set-screen-height
@cindex screen, changing the height of
Read a height value in the echo area and set the height of the
displayed screen to that value.
@end table
Finally, Info provides a convenient way to display footnotes which might
be associated with the current node that you are viewing:
@table @asis
@item @code{ESC C-f} (@code{show-footnotes})
@kindex ESC C-f
@findex show-footnotes
@cindex footnotes, displaying
Show the footnotes (if any) associated with the current node in another
window. You can have Info automatically display the footnotes
associated with a node when the node is selected by setting the variable
@code{automatic-footnotes}. @xref{Variables, , @code{automatic-footnotes}}.
@end table
@node Variables, GNU Info Global Index, Miscellaneous Commands, Top
@chapter Manipulating Variables
GNU Info contains several @dfn{variables} whose values are looked at by
various Info commands. You can change the values of these variables,
and thus change the behavior of Info to more closely match your
environment and Info file reading manner.
@table @asis
@item @code{M-x set-variable}
@cindex variables, setting
@findex set-variable
Read the name of a variable, and the value for it, in the echo area and
then set the variable to that value. Completion is available when
reading the variable name; often, completion is available when reading
the value to give to the variable, but that depends on the variable
itself. If a variable does @emph{not} supply multiple choices to
complete over, it expects a numeric value.
@item @code{M-x describe-variable}
@cindex variables, describing
@findex describe-variable
Read the name of a variable in the echo area and then display a brief
description of what the variable affects.
@end table
Here is a list of the variables that you can set in Info.
@table @code
@item automatic-footnotes
@vindex automatic-footnotes
When set to @code{On}, footnotes appear and disappear automatically.
This variable is @code{On} by default. When a node is selected, a
window containing the footnotes which appear in that node is created,
and the footnotes are displayed within the new window. The window that
Info creates to contain the footnotes is called @samp{*Footnotes*}. If
a node is selected which contains no footnotes, and a @samp{*Footnotes*}
window is on the screen, the @samp{*Footnotes*} window is deleted.
Footnote windows created in this fashion are not automatically tiled so
that they can use as little of the display as is possible.
@item automatic-tiling
@vindex automatic-tiling
When set to @code{On}, creating or deleting a window resizes other
windows. This variable is @code{Off} by default. Normally, typing
@samp{C-x 2} divides the current window into two equal parts. When
@code{automatic-tiling} is set to @code{On}, all of the windows are
resized automatically, keeping an equal number of lines visible in each
window. There are exceptions to the automatic tiling; specifically, the
windows @samp{*Completions*} and @samp{*Footnotes*} are @emph{not}
resized through automatic tiling; they remain their original size.
@item visible-bell
@vindex visible-bell
When set to @code{On}, GNU Info attempts to flash the screen instead of
ringing the bell. This variable is @code{Off} by default. Of course,
Info can only flash the screen if the terminal allows it; in the case
that the terminal does not allow it, the setting of this variable has no
effect. However, you can make Info perform quietly by setting the
@code{errors-ring-bell} variable to @code{Off}.
@item errors-ring-bell
@vindex errors-ring-bell
When set to @code{On}, errors cause the bell to ring. The default
setting of this variable is @code{On}.
@item gc-compressed-files
@vindex gc-compressed-files
When set to @code{On}, Info garbage collects files which had to be
uncompressed. The default value of this variable is @code{Off}.
Whenever a node is visited in Info, the Info file containing that node
is read into core, and Info reads information about the tags and nodes
contained in that file. Once the tags information is read by Info, it
is never forgotten. However, the actual text of the nodes does not need
to remain in core unless a particular Info window needs it. For
non-compressed files, the text of the nodes does not remain in core when
it is no longer in use. But de-compressing a file can be a time
consuming operation, and so Info tries hard not to do it twice.
@code{gc-compressed-files} tells Info it is okay to garbage collect the
text of the nodes of a file which was compressed on disk.
@item show-index-match
@vindex show-index-match
When set to @code{On}, the portion of the matched search string is
highlighted in the message which explains where the matched search
string was found. The default value of this variable is @code{On}.
When Info displays the location where an index match was found,
(@pxref{Searching Commands, , @code{next-index-match}}), the portion of the
string that you had typed is highlighted by displaying it in the inverse
case from its surrounding characters.
@item scroll-behavior
@vindex scroll-behavior
Control what happens when forward scrolling is requested at the end of
a node, or when backward scrolling is requested at the beginning of a
node. The default value for this variable is @code{Continuous}. There
are three possible values for this variable:
@table @code
@item Continuous
Try to get the first item in this node's menu, or failing that, the
@samp{Next} node, or failing that, the @samp{Next} of the @samp{Up}.
This behavior is identical to using the @samp{]}
(@code{global-next-node}) and @samp{[} (@code{global-prev-node})
commands.
@item Next Only
Only try to get the @samp{Next} node.
@item Page Only
Simply give up, changing nothing. If @code{scroll-behavior} is
@code{Page Only}, no scrolling command can change the node that is being
viewed.
@end table
@item scroll-step
@vindex scroll-step
The number of lines to scroll when the cursor moves out of the window.
Scrolling happens automatically if the cursor has moved out of the
visible portion of the node text when it is time to display. Usually
the scrolling is done so as to put the cursor on the center line of the
current window. However, if the variable @code{scroll-step} has a
nonzero value, Info attempts to scroll the node text by that many lines;
if that is enough to bring the cursor back into the window, that is what
is done. The default value of this variable is 0, thus placing the
cursor (and the text it is attached to) in the center of the window.
Setting this variable to 1 causes a kind of "smooth scrolling" which
some people prefer.
@item ISO-Latin
@cindex ISO Latin characters
@vindex ISO-Latin
When set to @code{On}, Info accepts and displays ISO Latin characters.
By default, Info assumes an ASCII character set. @code{ISO-Latin} tells
Info that it is running in an environment where the European standard
character set is in use, and allows you to input such characters to
Info, as well as display them.
@end table
@c the following is incomplete
@ignore
@c node Info for Sys Admins
@c chapter Info for System Administrators
This text describes some common ways of setting up an Info hierarchy
from scratch, and details the various options that are available when
installing Info. This text is designed for the person who is installing
GNU Info on the system; although users may find the information present
in this section interesting, none of it is vital to understanding how to
use GNU Info.
@menu
* Setting the INFOPATH:: Where are my Info files kept?
* Editing the DIR node:: What goes in `DIR', and why?
* Storing Info files:: Alternate formats allow flexibility in setups.
* Using `localdir':: Building DIR on the fly.
* Example setups:: Some common ways to organize Info files.
@end menu
@c node Setting the INFOPATH
@c section Setting the INFOPATH
Where are my Info files kept?
@c node Editing the DIR node
@c section Editing the DIR node
What goes in `DIR', and why?
@c node Storing Info files
@c section Storing Info files
Alternate formats allow flexibility in setups.
@c node Using `localdir'
@c section Using `localdir'
Building DIR on the fly.
@c node Example setups
@c section Example setups
Some common ways to organize Info files.
@end ignore
@node GNU Info Global Index, , Variables, Top
@appendix Global Index
@printindex cp
@contents
@bye
texinfo-3.7/info/info-utils.c 100666 11732 13 40500 5770343237 14453 0 ustar bfox user /* info-utils.c -- Useful functions for manipulating Info file quirks. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include /* For "NULL". Yechhh! */
#include
#include
#include
#if defined (HAVE_STRING_H)
# include
#endif /* HAVE_STRING_H */
#include "info-utils.h"
#if defined (HANDLE_MAN_PAGES)
# include "man.h"
#endif /* HANDLE_MAN_PAGES */
/* When non-zero, various display and input functions handle ISO Latin
character sets correctly. */
int ISO_Latin_p = 0;
/* Variable which holds the most recent filename parsed as a result of
calling info_parse_xxx (). */
char *info_parsed_filename = (char *)NULL;
/* Variable which holds the most recent nodename parsed as a result of
calling info_parse_xxx (). */
char *info_parsed_nodename = (char *)NULL;
/* Functions to remember a filename or nodename for later return. */
static void save_filename (), saven_filename ();
static void save_nodename (), saven_nodename ();
/* How to get a reference (either menu or cross). */
static REFERENCE **info_references_internal ();
/* Parse the filename and nodename out of STRING. If STRING doesn't
contain a filename (i.e., it is NOT (FILENAME)NODENAME) then set
INFO_PARSED_FILENAME to NULL. If second argument NEWLINES_OKAY is
non-zero, it says to allow the nodename specification to cross a
newline boundary (i.e., only `,', `.', or `TAB' can end the spec). */
void
info_parse_node (string, newlines_okay)
char *string;
int newlines_okay;
{
register int i = 0;
/* Default the answer. */
save_filename ((char *)NULL);
save_nodename ((char *)NULL);
/* Special case of nothing passed. Return nothing. */
if (!string || !*string)
return;
string += skip_whitespace (string);
/* Check for (FILENAME)NODENAME. */
if (*string == '(')
{
i = 0;
/* Advance past the opening paren. */
string++;
/* Find the closing paren. */
while (string[i] && string[i] != ')')
i++;
/* Remember parsed filename. */
saven_filename (string, i);
/* Point directly at the nodename. */
string += i;
if (*string)
string++;
}
/* Parse out nodename. */
i = skip_node_characters (string, newlines_okay);
saven_nodename (string, i);
canonicalize_whitespace (info_parsed_nodename);
if (info_parsed_nodename && !*info_parsed_nodename)
{
free (info_parsed_nodename);
info_parsed_nodename = (char *)NULL;
}
}
/* Return the node addressed by LABEL in NODE (usually one of "Prev:",
"Next:", "Up:", "File:", or "Node:". After a call to this function,
the global INFO_PARSED_NODENAME and INFO_PARSED_FILENAME contain
the information. */
void
info_parse_label (label, node)
char *label;
NODE *node;
{
register int i;
char *nodeline;
/* Default answer to failure. */
save_nodename ((char *)NULL);
save_filename ((char *)NULL);
/* Find the label in the first line of this node. */
nodeline = node->contents;
i = string_in_line (label, nodeline);
if (i == -1)
return;
nodeline += i;
nodeline += skip_whitespace (nodeline);
info_parse_node (nodeline, DONT_SKIP_NEWLINES);
}
/* **************************************************************** */
/* */
/* Finding and Building Menus */
/* */
/* **************************************************************** */
/* Return a NULL terminated array of REFERENCE * which represents the menu
found in NODE. If there is no menu in NODE, just return a NULL pointer. */
REFERENCE **
info_menu_of_node (node)
NODE *node;
{
long position;
SEARCH_BINDING search;
REFERENCE **menu = (REFERENCE **)NULL;
search.buffer = node->contents;
search.start = 0;
search.end = node->nodelen;
search.flags = S_FoldCase;
/* Find the start of the menu. */
position = search_forward (INFO_MENU_LABEL, &search);
if (position == -1)
return ((REFERENCE **) NULL);
/* We have the start of the menu now. Glean menu items from the rest
of the node. */
search.start = position + strlen (INFO_MENU_LABEL);
search.start += skip_line (search.buffer + search.start);
search.start--;
menu = info_menu_items (&search);
return (menu);
}
/* Return a NULL terminated array of REFERENCE * which represents the cross
refrences found in NODE. If there are no cross references in NODE, just
return a NULL pointer. */
REFERENCE **
info_xrefs_of_node (node)
NODE *node;
{
SEARCH_BINDING search;
#if defined (HANDLE_MAN_PAGES)
if (node->flags & N_IsManPage)
return (xrefs_of_manpage (node));
#endif
search.buffer = node->contents;
search.start = 0;
search.end = node->nodelen;
search.flags = S_FoldCase;
return (info_xrefs (&search));
}
/* Glean menu entries from BINDING->buffer + BINDING->start until we
have looked at the entire contents of BINDING. Return an array
of REFERENCE * that represents each menu item in this range. */
REFERENCE **
info_menu_items (binding)
SEARCH_BINDING *binding;
{
return (info_references_internal (INFO_MENU_ENTRY_LABEL, binding));
}
/* Glean cross references from BINDING->buffer + BINDING->start until
BINDING->end. Return an array of REFERENCE * that represents each
cross reference in this range. */
REFERENCE **
info_xrefs (binding)
SEARCH_BINDING *binding;
{
return (info_references_internal (INFO_XREF_LABEL, binding));
}
/* Glean cross references or menu items from BINDING. Return an array
of REFERENCE * that represents the items found. */
static REFERENCE **
info_references_internal (label, binding)
char *label;
SEARCH_BINDING *binding;
{
SEARCH_BINDING search;
REFERENCE **refs = (REFERENCE **)NULL;
int refs_index = 0, refs_slots = 0;
int searching_for_menu_items = 0;
long position;
search.buffer = binding->buffer;
search.start = binding->start;
search.end = binding->end;
search.flags = S_FoldCase | S_SkipDest;
searching_for_menu_items = (strcasecmp (label, INFO_MENU_ENTRY_LABEL) == 0);
while ((position = search_forward (label, &search)) != -1)
{
int offset, start;
char *refdef;
REFERENCE *entry;
search.start = position;
search.start += skip_whitespace (search.buffer + search.start);
start = search.start - binding->start;
refdef = search.buffer + search.start;
offset = string_in_line (":", refdef);
/* When searching for menu items, if no colon, there is no
menu item on this line. */
if (offset == -1)
{
if (searching_for_menu_items)
continue;
else
{
int temp;
temp = skip_line (refdef);
offset = string_in_line (":", refdef + temp);
if (offset == -1)
continue; /* Give up? */
else
offset += temp;
}
}
entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
entry->filename = (char *)NULL;
entry->nodename = (char *)NULL;
entry->label = (char *)xmalloc (offset);
strncpy (entry->label, refdef, offset - 1);
entry->label[offset - 1] = '\0';
canonicalize_whitespace (entry->label);
refdef += offset;
entry->start = start;
entry->end = refdef - binding->buffer;
/* If this reference entry continues with another ':' then the
nodename is the same as the label. */
if (*refdef == ':')
{
entry->nodename = strdup (entry->label);
}
else
{
/* This entry continues with a specific nodename. Parse the
nodename from the specification. */
refdef += skip_whitespace_and_newlines (refdef);
if (searching_for_menu_items)
info_parse_node (refdef, DONT_SKIP_NEWLINES);
else
info_parse_node (refdef, SKIP_NEWLINES);
if (info_parsed_filename)
entry->filename = strdup (info_parsed_filename);
if (info_parsed_nodename)
entry->nodename = strdup (info_parsed_nodename);
}
add_pointer_to_array
(entry, refs_index, refs, refs_slots, 50, REFERENCE *);
}
return (refs);
}
/* Get the entry associated with LABEL in MENU. Return a pointer to the
REFERENCE if found, or NULL. */
REFERENCE *
info_get_labeled_reference (label, references)
char *label;
REFERENCE **references;
{
register int i;
REFERENCE *entry;
for (i = 0; references && (entry = references[i]); i++)
{
if (strcmp (label, entry->label) == 0)
return (entry);
}
return ((REFERENCE *)NULL);
}
/* A utility function for concatenating REFERENCE **. Returns a new
REFERENCE ** which is the concatenation of REF1 and REF2. The REF1
and REF2 arrays are freed, but their contents are not. */
REFERENCE **
info_concatenate_references (ref1, ref2)
REFERENCE **ref1, **ref2;
{
register int i, j;
REFERENCE **result;
int size;
/* With one argument passed as NULL, simply return the other arg. */
if (!ref1)
return (ref2);
else if (!ref2)
return (ref1);
/* Get the total size of the slots that we will need. */
for (i = 0; ref1[i]; i++);
size = i;
for (i = 0; ref2[i]; i++);
size += i;
result = (REFERENCE **)xmalloc ((1 + size) * sizeof (REFERENCE *));
/* Copy the contents over. */
for (i = 0; ref1[i]; i++)
result[i] = ref1[i];
j = i;
for (i = 0; ref2[i]; i++)
result[j++] = ref2[i];
result[j] = (REFERENCE *)NULL;
free (ref1);
free (ref2);
return (result);
}
/* Free the data associated with REFERENCES. */
void
info_free_references (references)
REFERENCE **references;
{
register int i;
REFERENCE *entry;
if (references)
{
for (i = 0; references && (entry = references[i]); i++)
{
maybe_free (entry->label);
maybe_free (entry->filename);
maybe_free (entry->nodename);
free (entry);
}
free (references);
}
}
/* Search for sequences of whitespace or newlines in STRING, replacing
all such sequences with just a single space. Remove whitespace from
start and end of string. */
void
canonicalize_whitespace (string)
char *string;
{
register int i, j;
int len, whitespace_found, whitespace_loc;
char *temp;
if (!string)
return;
len = strlen (string);
temp = (char *)xmalloc (1 + len);
/* Search for sequences of whitespace or newlines. Replace all such
sequences in the string with just a single space. */
whitespace_found = 0;
for (i = 0, j = 0; string[i]; i++)
{
if (whitespace_or_newline (string[i]))
{
whitespace_found++;
whitespace_loc = i;
continue;
}
else
{
if (whitespace_found && whitespace_loc)
{
whitespace_found = 0;
/* Suppress whitespace at start of string. */
if (j)
temp[j++] = ' ';
}
temp[j++] = string[i];
}
}
/* Kill trailing whitespace. */
if (j && whitespace (temp[j - 1]))
j--;
temp[j] = '\0';
strcpy (string, temp);
free (temp);
}
/* String representation of a char returned by printed_representation (). */
static char the_rep[10];
/* Return a pointer to a string which is the printed representation
of CHARACTER if it were printed at HPOS. */
char *
printed_representation (character, hpos)
unsigned char character;
int hpos;
{
register int i = 0;
int printable_limit;
if (ISO_Latin_p)
printable_limit = 160;
else
printable_limit = 127;
if (character == '\177')
{
the_rep[i++] = '^';
the_rep[i++] = '?';
}
else if (iscntrl (character))
{
switch (character)
{
case '\r':
case '\n':
the_rep[i++] = character;
break;
case '\t':
{
int tw;
tw = ((hpos + 8) & 0xf8) - hpos;
while (i < tw)
the_rep[i++] = ' ';
}
break;
default:
the_rep[i++] = '^';
the_rep[i++] = (character | 0x40);
}
}
else if (character > printable_limit)
{
sprintf (the_rep + i, "\\%0o", character);
i = strlen (the_rep);
}
else
the_rep[i++] = character;
the_rep[i] = '\0';
return (the_rep);
}
/* **************************************************************** */
/* */
/* Functions Static To This File */
/* */
/* **************************************************************** */
/* Amount of space allocated to INFO_PARSED_FILENAME via xmalloc (). */
static int parsed_filename_size = 0;
/* Amount of space allocated to INFO_PARSED_NODENAME via xmalloc (). */
static int parsed_nodename_size = 0;
static void save_string (), saven_string ();
/* Remember FILENAME in PARSED_FILENAME. An empty FILENAME is translated
to a NULL pointer in PARSED_FILENAME. */
static void
save_filename (filename)
char *filename;
{
save_string (filename, &info_parsed_filename, &parsed_filename_size);
}
/* Just like save_filename (), but you pass the length of the string. */
static void
saven_filename (filename, len)
char *filename;
int len;
{
saven_string (filename, len,
&info_parsed_filename, &parsed_filename_size);
}
/* Remember NODENAME in PARSED_NODENAME. An empty NODENAME is translated
to a NULL pointer in PARSED_NODENAME. */
static void
save_nodename (nodename)
char *nodename;
{
save_string (nodename, &info_parsed_nodename, &parsed_nodename_size);
}
/* Just like save_nodename (), but you pass the length of the string. */
static void
saven_nodename (nodename, len)
char *nodename;
int len;
{
saven_string (nodename, len,
&info_parsed_nodename, &parsed_nodename_size);
}
/* Remember STRING in STRING_P. STRING_P should currently have STRING_SIZE_P
bytes allocated to it. An empty STRING is translated to a NULL pointer
in STRING_P. */
static void
save_string (string, string_p, string_size_p)
char *string;
char **string_p;
int *string_size_p;
{
if (!string || !*string)
{
if (*string_p)
free (*string_p);
*string_p = (char *)NULL;
*string_size_p = 0;
}
else
{
if (strlen (string) >= *string_size_p)
*string_p = (char *)xrealloc
(*string_p, (*string_size_p = 1 + strlen (string)));
strcpy (*string_p, string);
}
}
/* Just like save_string (), but you also pass the length of STRING. */
static void
saven_string (string, len, string_p, string_size_p)
char *string;
int len;
char **string_p;
int *string_size_p;
{
if (!string)
{
if (*string_p)
free (*string_p);
*string_p = (char *)NULL;
*string_size_p = 0;
}
else
{
if (len >= *string_size_p)
*string_p = (char *)xrealloc (*string_p, (*string_size_p = 1 + len));
strncpy (*string_p, string, len);
(*string_p)[len] = '\0';
}
}
/* Return a pointer to the part of PATHNAME that simply defines the file. */
char *
filename_non_directory (pathname)
char *pathname;
{
char *filename;
filename = (char *) strrchr (pathname, '/');
if (filename)
filename++;
else
filename = pathname;
return (filename);
}
/* Return non-zero if NODE is one especially created by Info. */
int
internal_info_node_p (node)
NODE *node;
{
#if defined (NEVER)
if (node &&
(node->filename && !*node->filename) &&
!node->parent && node->nodename)
return (1);
else
return (0);
#else
return ((node != (NODE *)NULL) && ((node->flags & N_IsInternal) != 0));
#endif /* !NEVER */
}
/* Make NODE appear to be one especially created by Info. */
void
name_internal_node (node, name)
NODE *node;
char *name;
{
if (!node)
return;
node->filename = "";
node->parent = (char *)NULL;
node->nodename = name;
node->flags |= N_IsInternal;
}
/* Return the window displaying NAME, the name of an internally created
Info window. */
WINDOW *
get_internal_info_window (name)
char *name;
{
WINDOW *win;
for (win = windows; win; win = win->next)
if (internal_info_node_p (win->node) &&
(strcmp (win->node->nodename, name) == 0))
break;
return (win);
}
texinfo-3.7/info/info-utils.h 100666 11732 13 12734 5770343426 14470 0 ustar bfox user /* info-utils.h -- Exported functions and variables from info-util.c. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_INFO_UTILS_H_)
#define _INFO_UTILS_H_
#if !defined (HAVE_STRCHR)
# undef strchr
# undef strrchr
# define strchr index
# define strrchr rindex
#endif /* !HAVE_STRCHR */
#if !defined (HAVE_MEMCPY)
# undef memcpy
# define memcpy(dest, source, count) bcopy(source, dest, count)
#endif /* !HAVE_MEMCPY */
#include "nodes.h"
#include "window.h"
#include "search.h"
/* Structure which describes a node reference, such as a menu entry or
cross reference. Arrays of such references can be built by calling
info_menus_of_node () or info_xrefs_of_node (). */
typedef struct {
char *label; /* User Label. */
char *filename; /* File where this node can be found. */
char *nodename; /* Name of the node. */
int start, end; /* Offsets within the containing node of LABEL. */
} REFERENCE;
/* When non-zero, various display and input functions handle ISO Latin
character sets correctly. */
extern int ISO_Latin_p;
/* Variable which holds the most recent filename parsed as a result of
calling info_parse_xxx (). */
extern char *info_parsed_filename;
/* Variable which holds the most recent nodename parsed as a result of
calling info_parse_xxx (). */
extern char *info_parsed_nodename;
/* Parse the filename and nodename out of STRING. If STRING doesn't
contain a filename (i.e., it is NOT (FILENAME)NODENAME) then set
INFO_PARSED_FILENAME to NULL. If second argument NEWLINES_OKAY is
non-zero, it says to allow the nodename specification to cross a
newline boundary (i.e., only `,', `.', or `TAB' can end the spec). */
void info_parse_node ();
/* Return a NULL terminated array of REFERENCE * which represents the menu
found in NODE. If there is no menu in NODE, just return a NULL pointer. */
extern REFERENCE **info_menu_of_node ();
/* Return a NULL terminated array of REFERENCE * which represents the cross
refrences found in NODE. If there are no cross references in NODE, just
return a NULL pointer. */
extern REFERENCE **info_xrefs_of_node ();
/* Glean cross references from BINDING->buffer + BINDING->start until
BINDING->end. Return an array of REFERENCE * that represents each
cross reference in this range. */
extern REFERENCE **info_xrefs ();
/* Get the entry associated with LABEL in REFERENCES. Return a pointer to
the reference if found, or NULL. */
extern REFERENCE *info_get_labeled_reference ();
/* Glean menu entries from BINDING->buffer + BINDING->start until we
have looked at the entire contents of BINDING. Return an array
of REFERENCE * that represents each menu item in this range. */
extern REFERENCE **info_menu_items ();
/* A utility function for concatenating REFERENCE **. Returns a new
REFERENCE ** which is the concatenation of REF1 and REF2. The REF1
and REF2 arrays are freed, but their contents are not. */
REFERENCE **info_concatenate_references ();
/* Free the data associated with REFERENCES. */
extern void info_free_references ();
/* Search for sequences of whitespace or newlines in STRING, replacing
all such sequences with just a single space. Remove whitespace from
start and end of string. */
void canonicalize_whitespace ();
/* Return a pointer to a string which is the printed representation
of CHARACTER if it were printed at HPOS. */
extern char *printed_representation ();
/* Return a pointer to the part of PATHNAME that simply defines the file. */
extern char *filename_non_directory ();
/* Return non-zero if NODE is one especially created by Info. */
extern int internal_info_node_p ();
/* Make NODE appear to be one especially created by Info, and give it NAME. */
extern void name_internal_node ();
/* Return the window displaying NAME, the name of an internally created
Info window. */
extern WINDOW *get_internal_info_window ();
/* Return the node addressed by LABEL in NODE (usually one of "Prev:",
"Next:", "Up:", "File:", or "Node:". After a call to this function,
the global INFO_PARSED_NODENAME and INFO_PARSED_FILENAME contain
the information. */
extern void info_parse_label (/* label, node */);
#define info_label_was_found \
(info_parsed_nodename != NULL || info_parsed_filename != NULL)
#define info_file_label_of_node(n) info_parse_label (INFO_FILE_LABEL, n)
#define info_next_label_of_node(n) info_parse_label (INFO_NEXT_LABEL, n)
#define info_up_label_of_node(n) info_parse_label (INFO_UP_LABEL, n)
#define info_prev_label_of_node(n) \
do { \
info_parse_label (INFO_PREV_LABEL, n); \
if (!info_label_was_found) \
info_parse_label (INFO_ALTPREV_LABEL, n); \
} while (0)
#endif /* !_INFO_UTILS_H_ */
texinfo-3.7/info/info.1 100666 11732 13 11051 5764640672 13240 0 ustar bfox user .TH info 1 "7th December 1990"
.SH NAME
info \- GNU's hypertext system
.SH SYNOPSIS
.B info
[
.B \-\-option-name option-value
]
.B \menu-item...
.SH COPYRIGHT
.if n Copyright (C) 1989, 1993 Free Software Foundation, Inc.
.if t Copyright \(co 1989, 1993 Free Software Foundation, Inc.
.SH DESCRIPTION
.LP
The GNU project has a hypertext system called
.I Info
which allows the same source file to be either printed as a
paper manual, or viewed using
.B info.
It is possible to use the
.B info
program from inside Emacs, or to use the stand-alone version described here.
This manual page gives a brief summary of its capabilities.
.SH OPTIONS
.TP
.B \-\-directory directory-path
Add
.B directory-path
to the list of directory paths searched when
.B info
needs to find a file. You may issue
.B \-\-directory
multiple times.
Alternatively, you may specify a value for the environment variable
.B INFOPATH;
if
.B \-\-directory
is not given, the value of
.B INFOPATH
is used. The value of
.B INFOPATH
is a colon separated list of directory names. If you do not supply either
.B INFOPATH
or
.B \-\-directory-path,
.B info
uses a default path.
.TP
.B \-f filename
Specify a particular
.B info
file to visit. By default,
.B info
visits
the file
.B dir;
if you use this option,
.B info
will start with
.B (FILENAME)Top
as the first file and node.
.TP
.B \-n nodename
Specify a particular node to visit in the initial file that
.B info
loads. This is especially useful in conjunction with
.B \-\-file.
You may specify
.B \-\-node
multiple times.
.TP
.B -o file
Direct output to
.B file
instead of starting an interactive
.B info
session.
.TP
.B \-h
Produce a relatively brief description of the available
.B info
options.
.TP
.B \-\-version
Print the version information of
.B info
and exit.
.TP
.B menu-item
.B info
treats its remaining arguments as the names of menu items.
The first argument is a menu item in the initial node visited,
while the second argument is a menu item in the first argument's
node. You can easily move to the node of your choice by
specifying the menu names which describe the path to that node.
For example,
.B info emacs buffers
first selects the menu item
.B emacs
in the node
.B (dir)Top,
and then selects the menu item
.B buffers
in the node
.B (emacs)Top.
.SH COMMANDS
When in
.B info
the following commands are available:
.TP
.B h
Invoke the Info tutorial.
.TP
.B ?
Get a short summary of
.B info
commands.
.TP
.B h
Select the
.B info
node from the main directory; this is much more complete than just
using
.B ?.
.TP
.B Ctrl-g
Abort whatever you are doing.
.TP
.B Ctrl-l
Redraw the screen.
.PP
Selecting other nodes:
.TP
.B n
Move to the "next" node of this node.
.TP
.B p
Move to the "previous" node of this node.
.TP
.B u
Move to this node's "up" node.
.TP
.B m
Pick a menu item specified by name. Picking a menu item causes another
node to be selected. You do not need to type a complete nodename; if
you type a few letters and then a space or tab
.B info
will will try to fill in the rest of the nodename. If you ask for further
completion without typing any more characters you'll be given a list
of possibilities; you can also get the list with
.B ?.
If you type a few characters and then hit return
.B info
will try to do a completion, and if it is ambigous use the first possibility.
.TP
.B f
Follow a cross reference. You are asked for the name of the reference,
using command completion as for
.B m.
.TP
.B l
Move to the last node you were at.
.PP
Moving within a node:
.TP
.B Space
Scroll forward a page.
.TP
.B DEL
Scroll backward a page.
.TP
.B b
Go to the beginning of this node.
.PP
Advanced commands:
.TP
.B q
Quit
.B info.
.TP
.B 1
Pick first item in node's menu.
.TP
.B 2 \-\- 5
Pick second ... fifth item in node's menu.
.TP
.B g
Move to node specified by name. You may include a filename as well,
as
.B (FILENAME)NODENAME.
.TP
.B s
Search through this
.B info
file for a specified string, and select the node in which
the next occurrence is found.
.TP
.B M-x print-node
Pipe the contents of the current node through the command in the
environment variable
.B INFO_PRINT_COMMAND.
If the variable does not exist, the node is simply piped to
.B lpr.
.SH ENVIRONMENT
.TP
.B INFOPATH
A colon-separated list of directories to search for
.B info
files. Used if
.B \-\-directory
is not given.
.TP
.B INFO_PRINT_COMMAND
The command used for printing.
.SH SEE ALSO
.BR emacs (1)
.SH AUTHOR
.RS
Brian Fox, Free Software Foundation
.br
bfox@ai.mit.edu
.SH MANUAL AUTHOR
.RS
Robert Lupton; updated by Robert J. Chassell.
.br
rhl@astro.princeton.edu; bob@gnu.ai.mit.edu
texinfo-3.7/info/info.c 100666 11732 13 37605 6067065663 13335 0 ustar bfox user /* info.c -- Display nodes of Info files in multiple windows. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
#include "dribble.h"
#include "getopt.h"
#if defined (HANDLE_MAN_PAGES)
# include "man.h"
#endif /* HANDLE_MAN_PAGES */
/* The version numbers of this version of Info. */
int info_major_version = 2;
int info_minor_version = 14;
int info_patch_level = 1;
/* Non-zero means search all indices for APROPOS_SEARCH_STRING. */
static int apropos_p = 0;
/* Variable containing the string to search for when apropos_p is non-zero. */
static char *apropos_search_string = (char *)NULL;
/* Non-zero means print version info only. */
static int print_version_p = 0;
/* Non-zero means print a short description of the options. */
static int print_help_p = 0;
/* Array of the names of nodes that the user specified with "--node" on the
command line. */
static char **user_nodenames = (char **)NULL;
static int user_nodenames_index = 0;
static int user_nodenames_slots = 0;
/* String specifying the first file to load. This string can only be set
by the user specifying "--file" on the command line. */
static char *user_filename = (char *)NULL;
/* String specifying the name of the file to dump nodes to. This value is
filled if the user speficies "--output" on the command line. */
static char *user_output_filename = (char *)NULL;
/* Non-zero indicates that when "--output" is specified, all of the menu
items of the specified nodes (and their subnodes as well) should be
dumped in the order encountered. This basically can print a book. */
int dump_subnodes = 0;
/* Structure describing the options that Info accepts. We pass this structure
to getopt_long (). If you add or otherwise change this structure, you must
also change the string which follows it. */
#define APROPOS_OPTION 1
#define DRIBBLE_OPTION 2
#define RESTORE_OPTION 3
static struct option long_options[] = {
{ "apropos", 1, 0, APROPOS_OPTION },
{ "directory", 1, 0, 'd' },
{ "node", 1, 0, 'n' },
{ "file", 1, 0, 'f' },
{ "subnodes", 0, &dump_subnodes, 1 },
{ "output", 1, 0, 'o' },
{ "help", 0, &print_help_p, 1 },
{ "version", 0, &print_version_p, 1 },
{ "dribble", 1, 0, DRIBBLE_OPTION },
{ "restore", 1, 0, RESTORE_OPTION },
{NULL, 0, NULL, 0}
};
/* String describing the shorthand versions of the long options found above. */
static char *short_options = "d:n:f:o:s";
/* When non-zero, the Info window system has been initialized. */
int info_windows_initialized_p = 0;
/* Some "forward" declarations. */
static void usage (), info_short_help (), remember_info_program_name ();
/* **************************************************************** */
/* */
/* Main Entry Point to the Info Program */
/* */
/* **************************************************************** */
int
main (argc, argv)
int argc;
char **argv;
{
int getopt_long_index; /* Index returned by getopt_long (). */
NODE *initial_node; /* First node loaded by Info. */
remember_info_program_name (argv[0]);
while (1)
{
int option_character;
option_character = getopt_long
(argc, argv, short_options, long_options, &getopt_long_index);
/* getopt_long () returns EOF when there are no more long options. */
if (option_character == EOF)
break;
/* If this is a long option, then get the short version of it. */
if (option_character == 0 && long_options[getopt_long_index].flag == 0)
option_character = long_options[getopt_long_index].val;
/* Case on the option that we have received. */
switch (option_character)
{
case 0:
break;
/* User wants to add a directory. */
case 'd':
info_add_path (optarg, INFOPATH_PREPEND);
break;
/* User is specifying a particular node. */
case 'n':
add_pointer_to_array (optarg, user_nodenames_index, user_nodenames,
user_nodenames_slots, 10, char *);
break;
/* User is specifying a particular Info file. */
case 'f':
if (user_filename)
free (user_filename);
user_filename = strdup (optarg);
break;
/* User is specifying the name of a file to output to. */
case 'o':
if (user_output_filename)
free (user_output_filename);
user_output_filename = strdup (optarg);
break;
/* User is specifying that she wishes to dump the subnodes of
the node that she is dumping. */
case 's':
dump_subnodes = 1;
break;
/* User has specified a string to search all indices for. */
case APROPOS_OPTION:
apropos_p = 1;
maybe_free (apropos_search_string);
apropos_search_string = strdup (optarg);
break;
/* User has specified a dribble file to receive keystrokes. */
case DRIBBLE_OPTION:
close_dribble_file ();
open_dribble_file (optarg);
break;
/* User has specified an alternate input stream. */
case RESTORE_OPTION:
info_set_input_from_file (optarg);
break;
default:
usage ();
}
}
/* If the output device is not a terminal, and no output filename has been
specified, make user_output_filename be "-", so that the info is written
to stdout, and turn on the dumping of subnodes. */
if ((!isatty (fileno (stdout))) && (user_output_filename == (char *)NULL))
{
user_output_filename = strdup ("-");
dump_subnodes = 1;
}
/* If the user specified --version, then show the version and exit. */
if (print_version_p)
{
printf ("GNU Info, Version %s, from texinfo-3.7.\n", version_string ());
exit (0);
}
/* If the `--help' option was present, show the help and exit. */
if (print_help_p)
{
info_short_help ();
exit (0);
}
/* If the user hasn't specified a path for Info files, default that path
now. */
if (!infopath)
{
char *path_from_env, *getenv ();
path_from_env = getenv ("INFOPATH");
if (path_from_env)
info_add_path (path_from_env, INFOPATH_PREPEND);
else
info_add_path (DEFAULT_INFOPATH, INFOPATH_PREPEND);
}
/* If the user specified a particular filename, add the path of that
file to the contents of INFOPATH. */
if (user_filename)
{
char *directory_name, *temp;
directory_name = strdup (user_filename);
temp = filename_non_directory (directory_name);
if (temp != directory_name)
{
*temp = 0;
info_add_path (directory_name, INFOPATH_PREPEND);
}
free (directory_name);
}
/* If the user wants to search every known index for a given string,
do that now, and report the results. */
if (apropos_p)
{
info_apropos (apropos_search_string);
exit (0);
}
/* Get the initial Info node. It is either "(dir)Top", or what the user
specifed with values in user_filename and user_nodenames. */
if (user_nodenames)
initial_node = info_get_node (user_filename, user_nodenames[0]);
else
initial_node = info_get_node (user_filename, (char *)NULL);
/* If we couldn't get the initial node, this user is in trouble. */
if (!initial_node)
{
if (info_recent_file_error)
info_error (info_recent_file_error);
else
info_error
(CANT_FIND_NODE, user_nodenames ? user_nodenames[0] : "Top");
exit (1);
}
/* Special cases for when the user specifies multiple nodes. If we are
dumping to an output file, dump all of the nodes specified. Otherwise,
attempt to create enough windows to handle the nodes that this user wants
displayed. */
if (user_nodenames_index > 1)
{
free (initial_node);
if (user_output_filename)
dump_nodes_to_file
(user_filename, user_nodenames, user_output_filename, dump_subnodes);
else
begin_multiple_window_info_session (user_filename, user_nodenames);
exit (0);
}
/* If there are arguments remaining, they are the names of menu items
in sequential info files starting from the first one loaded. That
file name is either "dir", or the contents of user_filename if one
was specified. */
while (optind != argc)
{
REFERENCE **menu;
REFERENCE *entry;
NODE *node;
char *arg;
static char *first_arg = (char *)NULL;
/* Remember the name of the menu entry we want. */
arg = argv[optind++];
if (first_arg == (char *)NULL)
first_arg = arg;
/* Build and return a list of the menu items in this node. */
menu = info_menu_of_node (initial_node);
/* If there wasn't a menu item in this node, stop here, but let
the user continue to use Info. Perhaps they wanted this node
and didn't realize it. */
if (!menu)
{
#if defined (HANDLE_MAN_PAGES)
if (first_arg == arg)
{
node = make_manpage_node (first_arg);
if (node)
goto maybe_got_node;
}
#endif /* HANDLE_MAN_PAGES */
begin_info_session_with_error
(initial_node, "There is no menu in this node.");
exit (0);
}
/* Find the specified menu item. */
entry = info_get_labeled_reference (arg, menu);
/* If the item wasn't found, search the list sloppily. Perhaps this
user typed "buffer" when they really meant "Buffers". */
if (!entry)
{
register int i;
int best_guess = -1;
for (i = 0; entry = menu[i]; i++)
{
if (strcasecmp (entry->label, arg) == 0)
break;
else
if (strncasecmp (entry->label, arg, strlen (arg)) == 0)
best_guess = i;
}
if (!entry && best_guess != -1)
entry = menu[best_guess];
}
/* If we failed to find the reference, start Info with the current
node anyway. It is probably a misspelling. */
if (!entry)
{
char *error_message = "There is no menu item \"%s\" in this node.";
#if defined (HANDLE_MAN_PAGES)
if (first_arg == arg)
{
node = make_manpage_node (first_arg);
if (node)
goto maybe_got_node;
}
#endif /* HANDLE_MAN_PAGES */
info_free_references (menu);
/* If we were supposed to dump this node, complain. */
if (user_output_filename)
info_error (error_message, arg);
else
begin_info_session_with_error (initial_node, error_message, arg);
exit (0);
}
/* We have found the reference that the user specified. Clean it
up a little bit. */
if (!entry->filename)
{
if (initial_node->parent)
entry->filename = strdup (initial_node->parent);
else
entry->filename = strdup (initial_node->filename);
}
/* Find this node. If we can find it, then turn the initial_node
into this one. If we cannot find it, try using the label of the
entry as a file (i.e., "(LABEL)Top"). Otherwise the Info file is
malformed in some way, and we will just use the current value of
initial node. */
node = info_get_node (entry->filename, entry->nodename);
#if defined (HANDLE_MAN_PAGES)
if ((first_arg == arg) && !node)
{
node = make_manpage_node (first_arg);
if (node)
goto maybe_got_node;
}
#endif /* HANDLE_MAN_PAGES */
if (!node && entry->nodename &&
(strcmp (entry->label, entry->nodename) == 0))
node = info_get_node (entry->label, "Top");
maybe_got_node:
if (node)
{
free (initial_node);
initial_node = node;
info_free_references (menu);
}
else
{
char *temp = strdup (entry->label);
char *error_message;
error_message = "Unable to find the node referenced by \"%s\".";
info_free_references (menu);
/* If we were trying to dump the node, then give up. Otherwise,
start the session with an error message. */
if (user_output_filename)
info_error (error_message, temp);
else
begin_info_session_with_error (initial_node, error_message, temp);
exit (0);
}
}
/* If the user specified that this node should be output, then do that
now. Otherwise, start the Info session with this node. */
if (user_output_filename)
dump_node_to_file (initial_node, user_output_filename, dump_subnodes);
else
begin_info_session (initial_node);
exit (0);
}
/* Return a string describing the current version of Info. */
char *
version_string ()
{
static char *vstring = (char *)NULL;
if (!vstring)
{
vstring = (char *)xmalloc (50);
sprintf (vstring, "%d.%d", info_major_version, info_minor_version);
if (info_patch_level)
sprintf (vstring + strlen (vstring), "-p%d", info_patch_level);
}
return (vstring);
}
/* **************************************************************** */
/* */
/* Error Handling for Info */
/* */
/* **************************************************************** */
static char *program_name = (char *)NULL;
static void
remember_info_program_name (fullpath)
char *fullpath;
{
char *filename;
filename = filename_non_directory (fullpath);
program_name = strdup (filename);
}
/* Non-zero if an error has been signalled. */
int info_error_was_printed = 0;
/* Non-zero means ring terminal bell on errors. */
int info_error_rings_bell_p = 1;
/* Print FORMAT with ARG1 and ARG2. If the window system was initialized,
then the message is printed in the echo area. Otherwise, a message is
output to stderr. */
void
info_error (format, arg1, arg2)
char *format;
void *arg1, *arg2;
{
info_error_was_printed = 1;
if (!info_windows_initialized_p || display_inhibited)
{
fprintf (stderr, "%s: ", program_name);
fprintf (stderr, format, arg1, arg2);
fprintf (stderr, "\n");
fflush (stderr);
}
else
{
if (!echo_area_is_active)
{
if (info_error_rings_bell_p)
terminal_ring_bell ();
window_message_in_echo_area (format, arg1, arg2);
}
else
{
NODE *temp;
temp = build_message_node (format, arg1, arg2);
if (info_error_rings_bell_p)
terminal_ring_bell ();
inform_in_echo_area (temp->contents);
free (temp->contents);
free (temp);
}
}
}
/* Produce a very brief descripton of the available options and exit with
an error. */
static void
usage ()
{
fprintf (stderr,"%s\n%s\n%s\n%s\n%s\n",
"Usage: info [-d dir-path] [-f info-file] [-o output-file] [-n node-name]...",
" [--directory dir-path] [--file info-file] [--node node-name]...",
" [--help] [--output output-file] [--subnodes] [--version]",
" [--dribble dribble-file] [--restore from-file]",
" [menu-selection ...]");
exit (1);
}
/* Produce a scaled down description of the available options to Info. */
static void
info_short_help ()
{
printf ("%s", "\
Here is a quick description of Info's options. For a more complete\n\
description of how to use Info, type `info info options'.\n\
\n\
--directory DIR Add DIR to INFOPATH.\n\
--file FILENAME Specify Info file to visit.\n\
--node NODENAME Specify nodes in first visited Info file.\n\
--output FILENAME Output selected nodes to FILENAME.\n\
--dribble FILENAME Remember user keystrokes in FILENAME.\n\
--restore FILENAME Read initial keystrokes from FILENAME.\n\
--subnodes Recursively output menu items.\n\
--help Get this help message.\n\
--version Display Info's version information.\n\
\n\
Remaining arguments to Info are treated as the names of menu\n\
items in the initial node visited. You can easily move to the\n\
node of your choice by specifying the menu names which describe\n\
the path to that node. For example, `info emacs buffers'.\n");
exit (0);
}
texinfo-3.7/info/info.h 100666 11732 13 7475 5770343431 13314 0 ustar bfox user /* info.h -- Header file which includes all of the other headers. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_INFO_H_)
#define _INFO_H_
#include
#include
#include
#include
#if defined (HAVE_STRING_H)
#include
#endif /* HAVE_STRING_H */
#include "filesys.h"
#include "display.h"
#include "session.h"
#include "echo_area.h"
#include "doc.h"
#include "footnotes.h"
#include "gc.h"
/* A structure associating the nodes visited in a particular window. */
typedef struct {
WINDOW *window; /* The window that this list is attached to. */
NODE **nodes; /* Array of nodes visited in this window. */
int *pagetops; /* For each node in NODES, the pagetop. */
long *points; /* For each node in NODES, the point. */
int current; /* Index in NODES of the current node. */
int nodes_index; /* Index where to add the next node. */
int nodes_slots; /* Number of slots allocated to NODES. */
} INFO_WINDOW;
/* Array of structures describing for each window which nodes have been
visited in that window. */
extern INFO_WINDOW **info_windows;
/* For handling errors. If you initialize the window system, you should
also set info_windows_initialized_p to non-zero. It is used by the
info_error () function to determine how to format and output errors. */
extern int info_windows_initialized_p;
/* Non-zero if an error message has been printed. */
extern int info_error_was_printed;
/* Non-zero means ring terminal bell on errors. */
extern int info_error_rings_bell_p;
/* Print FORMAT with ARG1 and ARG2. If the window system was initialized,
then the message is printed in the echo area. Otherwise, a message is
output to stderr. */
extern void info_error ();
/* The version numbers of Info. */
extern int info_major_version, info_minor_version, info_patch_level;
/* How to get the version string for this version of Info. Returns
something similar to "2.11". */
extern char *version_string ();
/* Error message defines. */
#define CANT_FIND_NODE "Cannot find the node \"%s\"."
#define CANT_FILE_NODE "Cannot find the node \"(%s)%s\"."
#define CANT_FIND_WIND "Cannot find a window!"
#define CANT_FIND_POINT "Point doesn't appear within this window's node!"
#define CANT_KILL_LAST "Cannot delete the last window."
#define NO_MENU_NODE "No menu in this node."
#define NO_FOOT_NODE "No footnotes in this node."
#define NO_XREF_NODE "No cross references in this node."
#define NO_POINTER "No \"%s\" pointer for this node."
#define UNKNOWN_COMMAND "Unknown Info command `%c'. `?' for help."
#define TERM_TOO_DUMB "Terminal type \"%s\" is not smart enough to run Info."
#define AT_NODE_BOTTOM "You are already at the last page of this node."
#define AT_NODE_TOP "You are already at the first page of this node."
#define ONE_WINDOW "Only one window."
#define WIN_TOO_SMALL "Resulting window would be too small."
#define CANT_MAKE_HELP \
"There isn't enough room to make a help window. Please delete a window."
#endif /* !_INFO_H_ */
texinfo-3.7/info/info.texi 100666 11732 13 113223 5764640673 14076 0 ustar bfox user \input texinfo @c -*-texinfo-*-
@comment %**start of header
@setfilename info.info
@settitle Info 1.0
@comment %**end of header
@iftex
@finalout
@end iftex
@ifinfo
This file describes how to use Info,
the on-line, menu-driven GNU documentation system.
Copyright (C) 1989, 1992 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@ignore
Permission is granted to process this file through TeX and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the Free Software Foundation.
@end ifinfo
@setchapternewpage odd
@titlepage
@sp 11
@center @titlefont{Info}
@sp 2
@center The
@sp 2
@center On-line, Menu-driven
@sp 2
@center GNU Documentation System
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1989, 1992, 1993 Free Software Foundation, Inc.
@sp 2
Published by the Free Software Foundation @*
675 Massachusetts Avenue, @*
Cambridge, MA 02139 USA @*
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the Free Software Foundation.
@end titlepage
@ifinfo
@node Top, Getting Started, (dir), (dir)
@top Info: An Introduction
Info is a program for reading documentation, which you are using now.
To learn how to use Info, type the command @kbd{h}. It brings you
to a programmed instruction sequence.
@c Need to make sure that `Info-help' goes to the right node,
@c which is the first node of the first chapter. (It should.)
@c (Info-find-node "info"
@c (if (< (window-height) 23)
@c "Help-Small-Screen"
@c "Help")))
To learn advanced Info commands, type @kbd{n} twice. This brings you to
@cite{Info for Experts}, skipping over the `Getting Started' chapter.
@end ifinfo
@menu
* Getting Started:: Getting started using an Info reader.
* Advanced Info:: Advanced commands within Info.
* Create an Info File:: How to make your own Info file.
* The Standalone Info Program: (info-stnd.info).
@end menu
@node Getting Started, Advanced Info, Top, Top
@comment node-name, next, previous, up
@chapter Getting Started
This first part of the Info manual describes how to get around inside
of Info. The second part of the manual describes various advanced
Info commands, and how to write an Info as distinct from a Texinfo
file. The third part is about how to generate Info files from
Texinfo files.
@iftex
This manual is primarily designed for use on a computer, so that you can
try Info commands while reading about them. Reading it on paper is less
effective, since you must take it on faith that the commands described
really do what the manual says. By all means go through this manual now
that you have it; but please try going through the on-line version as
well.
There are two ways of looking at the online version of this manual:
@enumerate
@item
Type @code{info} at your shell's command line. This approach uses a
small stand-alone program designed just to read Info files.
@item
Type @code{emacs} at the command line; then type @kbd{C-h i} (Control
@kbd{h}, followed by @kbd{i}). This approach uses the Info mode of the
Emacs program, an editor with many other capabilities.
@end enumerate
In either case, then type @kbd{mInfo} (just the letters), followed by
@key{RET}---the ``Return'' or ``Enter'' key. At this point, you should
be ready to follow the instructions in this manual as you read them on
the screen.
@c FIXME! (pesch@cygnus.com, 14 dec 1992)
@c Is it worth worrying about what-if the beginner goes to somebody
@c else's Emacs session, which already has an Info running in the middle
@c of something---in which case these simple instructions won't work?
@end iftex
@menu
* Help-Small-Screen:: Starting Info on a Small Screen
* Help:: How to use Info
* Help-P:: Returning to the Previous node
* Help-^L:: The Space, Rubout, B and ^L commands.
* Help-M:: Menus
* Help-Adv:: Some advanced Info commands
* Help-Q:: Quitting Info
@end menu
@node Help-Small-Screen, Help, , Getting Started
@comment node-name, next, previous, up
@section Starting Info on a Small Screen
@iftex
(In Info, you only see this section if your terminal has a small
number of lines; most readers pass by it without seeing it.)
@end iftex
Since your terminal has an unusually small number of lines on its
screen, it is necessary to give you special advice at the beginning.
If you see the text @samp{--All----} at near the bottom right corner
of the screen, it means the entire text you are looking at fits on the
screen. If you see @samp{--Top----} instead, it means that there is
more text below that does not fit. To move forward through the text
and see another screen full, press the Space bar, @key{SPC}. To move
back up, press the key labeled @samp{Backspace} or @key{Delete}.
@ifinfo
Here are 40 lines of junk, so you can try Spaces and Deletes and
see what they do. At the end are instructions of what you should do
next.
This is line 17 @*
This is line 18 @*
This is line 19 @*
This is line 20 @*
This is line 21 @*
This is line 22 @*
This is line 23 @*
This is line 24 @*
This is line 25 @*
This is line 26 @*
This is line 27 @*
This is line 28 @*
This is line 29 @*
This is line 30 @*
This is line 31 @*
This is line 32 @*
This is line 33 @*
This is line 34 @*
This is line 35 @*
This is line 36 @*
This is line 37 @*
This is line 38 @*
This is line 39 @*
This is line 40 @*
This is line 41 @*
This is line 42 @*
This is line 43 @*
This is line 44 @*
This is line 45 @*
This is line 46 @*
This is line 47 @*
This is line 48 @*
This is line 49 @*
This is line 50 @*
This is line 51 @*
This is line 52 @*
This is line 53 @*
This is line 54 @*
This is line 55 @*
This is line 56 @*
If you have managed to get here, go back to the beginning with
Delete, and come back here again, then you understand Space and
Delete. So now type an @kbd{n} ---just one character; don't type
the quotes and don't type the Return key afterward--- to
get to the normal start of the course.
@end ifinfo
@node Help, Help-P, Help-Small-Screen, Getting Started
@comment node-name, next, previous, up
@section How to use Info
You are talking to the program Info, for reading documentation.
Right now you are looking at one @dfn{Node} of Information.
A node contains text describing a specific topic at a specific
level of detail. This node's topic is ``how to use Info''.
The top line of a node is its @dfn{header}. This node's header (look at
it now) says that it is the node named @samp{Help} in the file
@file{info}. It says that the @samp{Next} node after this one is the node
called @samp{Help-P}. An advanced Info command lets you go to any node
whose name you know.
Besides a @samp{Next}, a node can have a @samp{Previous} or an @samp{Up}.
This node has a @samp{Previous} but no @samp{Up}, as you can see.
Now it is time to move on to the @samp{Next} node, named @samp{Help-P}.
>> Type @samp{n} to move there. Type just one character;
do not type the quotes and do not type a @key{RET} afterward.
@samp{>>} in the margin means it is really time to try a command.
@node Help-P, Help-^L, Help, Getting Started
@comment node-name, next, previous, up
@section Returning to the Previous node
This node is called @samp{Help-P}. The @samp{Previous} node, as you see,
is @samp{Help}, which is the one you just came from using the @kbd{n}
command. Another @kbd{n} command now would take you to the next
node, @samp{Help-^L}.
>> But do not do that yet. First, try the @kbd{p} command, which takes
you to the @samp{Previous} node. When you get there, you can do an
@kbd{n} again to return here.
This all probably seems insultingly simple so far, but @emph{do not} be
led into skimming. Things will get more complicated soon. Also,
do not try a new command until you are told it is time to. Otherwise,
you may make Info skip past an important warning that was coming up.
>> Now do an @kbd{n} to get to the node @samp{Help-^L} and learn more.
@node Help-^L, Help-M, Help-P, Getting Started
@comment node-name, next, previous, up
@section The Space, Delete, B and ^L commands.
This node's header tells you that you are now at node @samp{Help-^L}, and
that @kbd{p} would get you back to @samp{Help-P}. The node's title is
underlined; it says what the node is about (most nodes have titles).
This is a big node and it does not all fit on your display screen.
You can tell that there is more that is not visible because you
can see the string @samp{--Top-----} rather than @samp{--All----} near
the bottom right corner of the screen.
The Space, Delete and @kbd{B} commands exist to allow you to ``move
around'' in a node that does not all fit on the screen at once.
Space moves forward, to show what was below the bottom of the screen.
Delete moves backward, to show what was above the top of the screen
(there is not anything above the top until you have typed some spaces).
>> Now try typing a Space (afterward, type a Delete to return here).
When you type the space, the two lines that were at the bottom of
the screen appear at the top, followed by more lines. Delete takes
the two lines from the top and moves them to the bottom,
@emph{usually}, but if there are not a full screen's worth of lines
above them they may not make it all the way to the bottom.
If you type Space when there is no more to see, it rings the
bell and otherwise does nothing. The same goes for Delete when
the header of the node is visible.
If your screen is ever garbaged, you can tell Info to print it out
again by typing @kbd{C-l} (@kbd{Control-L}, that is---hold down ``Control'' and
type an @key{L} or @kbd{l}).
>> Type @kbd{C-l} now.
To move back to the beginning of the node you are on, you can type
a lot of Deletes. You can also type simply @kbd{b} for beginning.
>> Try that now. (We have put in enough verbiage to push this past
the first screenful, but screens are so big nowadays that perhaps it
isn't enough. You may need to shrink your Emacs or Info window.)
Then come back, with Spaces.
If your screen is very tall, all of this node might fit at once.
In that case, "b" won't do anything. Sorry; what can we do?
You have just learned a considerable number of commands. If you
want to use one but have trouble remembering which, you should type
a @key{?} which prints out a brief list of commands. When you are
finished looking at the list, make it go away by typing a @key{SPC}.
>> Type a @key{?} now. After it finishes, type a @key{SPC}.
(If you are using the standalone Info reader, type `l' to return here.)
From now on, you will encounter large nodes without warning, and
will be expected to know how to use Space and Delete to move
around in them without being told. Since not all terminals have
the same size screen, it would be impossible to warn you anyway.
>> Now type @kbd{n} to see the description of the @kbd{m} command.
@node Help-M, Help-Adv, Help-^L, Getting Started
@comment node-name, next, previous, up
@section Menus
Menus and the @kbd{m} command
With only the @kbd{n} and @kbd{p} commands for moving between nodes, nodes
are restricted to a linear sequence. Menus allow a branching
structure. A menu is a list of other nodes you can move to. It is
actually just part of the text of the node formatted specially so that
Info can interpret it. The beginning of a menu is always identified
by a line which starts with @samp{* Menu:}. A node contains a menu if and
only if it has a line in it which starts that way. The only menu you
can use at any moment is the one in the node you are in. To use a
menu in any other node, you must move to that node first.
After the start of the menu, each line that starts with a @samp{*}
identifies one subtopic. The line usually contains a brief name
for the subtopic (followed by a @samp{:}), the name of the node that talks
about that subtopic, and optionally some further description of the
subtopic. Lines in the menu that do not start with a @samp{*} have no
special meaning---they are only for the human reader's benefit and do
not define additional subtopics. Here is an example:
@example
* Foo: FOO's Node This tells about FOO
@end example
The subtopic name is Foo, and the node describing it is @samp{FOO's Node}.
The rest of the line is just for the reader's Information.
[[ But this line is not a real menu item, simply because there is
no line above it which starts with @samp{* Menu:}.]]
When you use a menu to go to another node (in a way that will be
described soon), what you specify is the subtopic name, the first
thing in the menu line. Info uses it to find the menu line, extracts
the node name from it, and goes to that node. The reason that there
is both a subtopic name and a node name is that the node name must be
meaningful to the computer and may therefore have to be ugly looking.
The subtopic name can be chosen just to be convenient for the user to
specify. Often the node name is convenient for the user to specify
and so both it and the subtopic name are the same. There is an
abbreviation for this:
@example
* Foo:: This tells about FOO
@end example
@noindent
This means that the subtopic name and node name are the same; they are
both @samp{Foo}.
>> Now use Spaces to find the menu in this node, then come back to
the front with a @kbd{b} and some Spaces. As you see, a menu is
actually visible in its node. If you cannot find a menu in a node
by looking at it, then the node does not have a menu and the
@kbd{m} command is not available.
The command to go to one of the subnodes is @kbd{m}---but @emph{do
not do it yet!} Before you use @kbd{m}, you must understand the
difference between commands and arguments. So far, you have learned
several commands that do not need arguments. When you type one, Info
processes it and is instantly ready for another command. The @kbd{m}
command is different: it is incomplete without the @dfn{name of the
subtopic}. Once you have typed @kbd{m}, Info tries to read the
subtopic name.
Now look for the line containing many dashes near the bottom of the
screen. There is one more line beneath that one, but usually it is
blank. If it is empty, Info is ready for a command, such as @kbd{n}
or @kbd{b} or Space or @kbd{m}. If that line contains text ending
in a colon, it mean Info is trying to read the @dfn{argument} to a
command. At such times, commands do not work, because Info tries to
use them as the argument. You must either type the argument and
finish the command you started, or type @kbd{Control-g} to cancel the
command. When you have done one of those things, the line becomes
blank again.
The command to go to a subnode via a menu is @kbd{m}. After you type
the @kbd{m}, the line at the bottom of the screen says @samp{Menu item: }.
You must then type the name of the subtopic you want, and end it with
a @key{RET}.
You can abbreviate the subtopic name. If the abbreviation is not
unique, the first matching subtopic is chosen. Some menus put
the shortest possible abbreviation for each subtopic name in capital
letters, so you can see how much you need to type. It does not
matter whether you use upper case or lower case when you type the
subtopic. You should not put any spaces at the end, or inside of the
item name, except for one space where a space appears in the item in
the menu.
You can also use the @dfn{completion} feature to help enter the subtopic
name. If you type the Tab key after entering part of a name, it will
magically fill in more of the name---as much as follows uniquely from
what you have entered.
If you move the cursor to one of the menu subtopic lines, then you do
not need to type the argument: you just type a Return, and it stands for
the subtopic of the line you are on.
Here is a menu to give you a chance to practice.
* Menu: The menu starts here.
This menu gives you three ways of going to one place, Help-FOO.
* Foo: Help-FOO. A node you can visit for fun.@*
* Bar: Help-FOO. Strange! two ways to get to the same place.@*
* Help-FOO:: And yet another!@*
>> Now type just an @kbd{m} and see what happens:
Now you are ``inside'' an @kbd{m} command. Commands cannot be used
now; the next thing you will type must be the name of a subtopic.
You can change your mind about doing the @kbd{m} by typing Control-g.
>> Try that now; notice the bottom line clear.
>> Then type another @kbd{m}.
>> Now type @samp{BAR} item name. Do not type Return yet.
While you are typing the item name, you can use the Delete key to
cancel one character at a time if you make a mistake.
>> Type one to cancel the @samp{R}. You could type another @samp{R} to
replace it. You do not have to, since @samp{BA} is a valid abbreviation.
>> Now you are ready to go. Type a @key{RET}.
After visiting Help-FOO, you should return here.
>> Type @kbd{n} to see more commands.
@c If a menu appears at the end of this node, remove it.
@c It is an accident of the menu updating command.
Here is another way to get to Help-FOO, a menu. You can ignore this
if you want, or else try it (but then please come back to here).
@menu
* Help-FOO::
@end menu
@node Help-FOO, , , Help-M
@comment node-name, next, previous, up
@subsection The @kbd{u} command
Congratulations! This is the node @samp{Help-FOO}. Unlike the other
nodes you have seen, this one has an @samp{Up}: @samp{Help-M}, the node you
just came from via the @kbd{m} command. This is the usual
convention---the nodes you reach from a menu have @samp{Up} nodes that lead
back to the menu. Menus move Down in the tree, and @samp{Up} moves Up.
@samp{Previous}, on the other hand, is usually used to ``stay on the same
level but go backwards''
You can go back to the node @samp{Help-M} by typing the command
@kbd{u} for ``Up''. That puts you at the @emph{front} of the
node---to get back to where you were reading you have to type
some @key{SPC}s.
>> Now type @kbd{u} to move back up to @samp{Help-M}.
@node Help-Adv, Help-Q, Help-M, Getting Started
@comment node-name, next, previous, up
@section Some advanced Info commands
The course is almost over, so please stick with it to the end.
If you have been moving around to different nodes and wish to
retrace your steps, the @kbd{l} command (@kbd{l} for @dfn{last}) will
do that, one node-step at a time. As you move from node to node, Info
records the nodes where you have been in a special history list. The
@kbd{l} command revisits nodes in the history list; each successive
@kbd{l} command moves one step back through the history.
If you have been following directions, ad @kbd{l} command now will get
you back to @samp{Help-M}. Another @kbd{l} command would undo the
@kbd{u} and get you back to @samp{Help-FOO}. Another @kbd{l} would undo
the @kbd{m} and get you back to @samp{Help-M}.
>> Try typing three @kbd{l}'s, pausing in between to see what each
@kbd{l} does.
Then follow directions again and you will end up back here.
Note the difference between @kbd{l} and @kbd{p}: @kbd{l} moves to
where @emph{you} last were, whereas @kbd{p} always moves to the node
which the header says is the @samp{Previous} node (from this node, to
@samp{Help-M}).
The @samp{d} command gets you instantly to the Directory node.
This node, which is the first one you saw when you entered Info,
has a menu which leads (directly, or indirectly through other menus),
to all the nodes that exist.
>> Try doing a @samp{d}, then do an @kbd{l} to return here (yes,
@emph{do} return).
Sometimes, in Info documentation, you will see a cross reference.
Cross references look like this: @xref{Help-Cross, Cross}. That is a
real, live cross reference which is named @samp{Cross} and points at
the node named @samp{Help-Cross}.
If you wish to follow a cross reference, you must use the @samp{f}
command. The @samp{f} must be followed by the cross reference name
(in this case, @samp{Cross}). While you enter the name, you can use the
Delete key to edit your input. If you change your mind about following
any reference, you can use @kbd{Control-g} to cancel the command.
Completion is available in the @samp{f} command; you can complete among
all the cross reference names in the current node by typing a Tab.
>> Type @samp{f}, followed by @samp{Cross}, and a @key{RET}.
To get a list of all the cross references in the current node, you can
type @kbd{?} after an @samp{f}. The @samp{f} continues to await a
cross reference name even after printing the list, so if you don't
actually want to follow a reference, you should type a @kbd{Control-g}
to cancel the @samp{f}.
>> Type "f?" to get a list of the cross references in this node. Then
type a @kbd{Control-g} and see how the @samp{f} gives up.
>> Now type @kbd{n} to see the last node of the course.
@c If a menu appears at the end of this node, remove it.
@c It is an accident of the menu updating command.
@node Help-Cross, , , Help-Adv
@comment node-name, next, previous, up
@unnumberedsubsec The node reached by the cross reference in Info
This is the node reached by the cross reference named @samp{Cross}.
While this node is specifically intended to be reached by a cross
reference, most cross references lead to nodes that ``belong''
someplace else far away in the structure of Info. So you cannot expect
the footnote to have a @samp{Next}, @samp{Previous} or @samp{Up} pointing back to
where you came from. In general, the @kbd{l} (el) command is the only
way to get back there.
>> Type @kbd{l} to return to the node where the cross reference was.
@node Help-Q, , Help-Adv, Getting Started
@comment node-name, next, previous, up
@section Quitting Info
To get out of Info, back to what you were doing before, type @kbd{q}
for @dfn{Quit}.
This is the end of the course on using Info. There are some other
commands that are meant for experienced users; they are useful, and you
can find them by looking in the directory node for documentation on
Info. Finding them will be a good exercise in using Info in the usual
manner.
>> Type @samp{d} to go to the Info directory node; then type
@samp{mInfo} and Return, to get to the node about Info and
see what other help is available.
@node Advanced Info, Create an Info File, Getting Started, Top
@comment node-name, next, previous, up
@chapter Info for Experts
This chapter describes various advanced Info commands, and how to write
an Info as distinct from a Texinfo file. (However, in most cases, writing a
Texinfo file is better, since you can use it @emph{both} to generate an
Info file and to make a printed manual. @xref{Top,, Overview of
Texinfo, texinfo, Texinfo: The GNU Documentation Format}.)
@menu
* Expert:: Advanced Info commands: g, s, e, and 1 - 5.
* Add:: Describes how to add new nodes to the hierarchy.
Also tells what nodes look like.
* Menus:: How to add to or create menus in Info nodes.
* Cross-refs:: How to add cross-references to Info nodes.
* Tags:: How to make tag tables for Info files.
* Checking:: Checking an Info File
* Emacs Info Variables:: Variables modifying the behavior of Emacs Info.
@end menu
@node Expert, Add, , Advanced Info
@comment node-name, next, previous, up
@section Advanced Info Commands
@kbd{g}, @kbd{s}, @kbd{1}, -- @kbd{9}, and @kbd{e}
If you know a node's name, you can go there by typing @kbd{g}, the
name, and @key{RET}. Thus, @kbd{gTop@key{RET}} would go to the node
called @samp{Top} in this file (its directory node).
@kbd{gExpert@key{RET}} would come back here.
Unlike @kbd{m}, @kbd{g} does not allow the use of abbreviations.
To go to a node in another file, you can include the filename in the
node name by putting it at the front, in parentheses. Thus,
@kbd{g(dir)Top@key{RET}} would go to the Info Directory node, which is
node @samp{Top} in the file @file{dir}.
The node name @samp{*} specifies the whole file. So you can look at
all of the current file by typing @kbd{g*@key{RET}} or all of any
other file with @kbd{g(FILENAME)@key{RET}}.
The @kbd{s} command allows you to search a whole file for a string.
It switches to the next node if and when that is necessary. You
type @kbd{s} followed by the string to search for, terminated by
@key{RET}. To search for the same string again, just @kbd{s} followed
by @key{RET} will do. The file's nodes are scanned in the order
they are in in the file, which has no necessary relationship to the
order that they may be in in the tree structure of menus and @samp{next} pointers.
But normally the two orders are not very different. In any case,
you can always do a @kbd{b} to find out what node you have reached, if
the header is not visible (this can happen, because @kbd{s} puts your
cursor at the occurrence of the string, not at the beginning of the
node).
If you grudge the system each character of type-in it requires, you
might like to use the commands @kbd{1}, @kbd{2}, @kbd{3}, @kbd{4}, ...
@kbd{9}. They are short for the @kbd{m} command together with an
argument. @kbd{1} goes through the first item in the current node's
menu; @kbd{2} goes through the second item, etc.
If you display supports multiple fonts, and you are using Emacs' Info
mode to read Info files, the @samp{*} for the fifth menu item is
underlines, and so is the @samp{*} for the ninth item; these underlines
make it easy to see at a glance which number to use for an item.
On ordinary terminals, you won't have underlining. If you need to
actually count items, it is better to use @kbd{m} instead, and specify
the name.
The Info command @kbd{e} changes from Info mode to an ordinary
Emacs editing mode, so that you can edit the text of the current node.
Type @kbd{C-c C-c} to switch back to Info. The @kbd{e} command is allowed
only if the variable @code{Info-enable-edit} is non-@code{nil}.
@node Add, Menus, Expert, Advanced Info
@comment node-name, next, previous, up
@section Adding a new node to Info
To add a new topic to the list in the Info directory, you must:
@enumerate
@item
Create some nodes, in some file, to document that topic.
@item
Put that topic in the menu in the directory. @xref{Menus, Menu}.
@end enumerate
Usually, the way to create the nodes is with Texinfo @pxref{Top,, Overview of
Texinfo, texinfo, Texinfo: The GNU Documentation Format}); this has the
advantage that you can also make a printed manual from them. However,
if hyou want to edit an Info file, here is how.
The new node can live in an existing documentation file, or in a new
one. It must have a @key{^_} character before it (invisible to the
user; this node has one but you cannot see it), and it ends with either
a @key{^_}, a @key{^L}, or the end of file. Note: If you put in a
@key{^L} to end a new node, be sure that there is a @key{^_} after it
to start the next one, since @key{^L} cannot @emph{start} a node.
Also, a nicer way to make a node boundary be a page boundary as well
is to put a @key{^L} @emph{right after} the @key{^_}.
The @key{^_} starting a node must be followed by a newline or a
@key{^L} newline, after which comes the node's header line. The
header line must give the node's name (by which Info finds it),
and state the names of the @samp{Next}, @samp{Previous}, and @samp{Up} nodes (if
there are any). As you can see, this node's @samp{Up} node is the node
@samp{Top}, which points at all the documentation for Info. The @samp{Next}
node is @samp{Menus}.
The keywords @dfn{Node}, @dfn{Previous}, @dfn{Up}, and @dfn{Next},
may appear in any order, anywhere in the header line, but the
recommended order is the one in this sentence. Each keyword must be
followed by a colon, spaces and tabs, and then the appropriate name.
The name may be terminated with a tab, a comma, or a newline. A space
does not end it; node names may contain spaces. The case of letters
in the names is insignificant.
A node name has two forms. A node in the current file is named by
what appears after the @samp{Node: } in that node's first line. For
example, this node's name is @samp{Add}. A node in another file is
named by @samp{(@var{filename})@var{node-within-file}}, as in
@samp{(info)Add} for this node. If the file name starts with ``./'',
then it is relative to the current directory; otherwise, it is relative
starting from the standard Info file directory of your site.
The name @samp{(@var{filename})Top} can be abbreviated to just
@samp{(@var{filename})}. By convention, the name @samp{Top} is used for
the ``highest'' node in any single file---the node whose @samp{Up} points
out of the file. The Directory node is @file{(dir)}. The @samp{Top} node
of a document file listed in the Directory should have an @samp{Up:
(dir)} in it.
The node name @kbd{*} is special: it refers to the entire file.
Thus, @kbd{g*} shows you the whole current file. The use of the
node @kbd{*} is to make it possible to make old-fashioned,
unstructured files into nodes of the tree.
The @samp{Node:} name, in which a node states its own name, must not
contain a filename, since Info when searching for a node does not
expect one to be there. The @samp{Next}, @samp{Previous} and @samp{Up} names may
contain them. In this node, since the @samp{Up} node is in the same file,
it was not necessary to use one.
Note that the nodes in this file have a file name in the header
line. The file names are ignored by Info, but they serve as comments
to help identify the node for the user.
@node Menus, Cross-refs, Add, Advanced Info
@comment node-name, next, previous, up
@section How to Create Menus
Any node in the Info hierarchy may have a @dfn{menu}---a list of subnodes.
The @kbd{m} command searches the current node's menu for the topic which it
reads from the terminal.
A menu begins with a line starting with @samp{* Menu:}. The rest of the
line is a comment. After the starting line, every line that begins
with a @samp{* } lists a single topic. The name of the topic--the
argument that the user must give to the @kbd{m} command to select this
topic---comes right after the star and space, and is followed by a
colon, spaces and tabs, and the name of the node which discusses that
topic. The node name, like node names following @samp{Next}, @samp{Previous}
and @samp{Up}, may be terminated with a tab, comma, or newline; it may also
be terminated with a period.
If the node name and topic name are the same, then rather than
giving the name twice, the abbreviation @samp{* NAME::} may be used
(and should be used, whenever possible, as it reduces the visual
clutter in the menu).
It is considerate to choose the topic names so that they differ
from each other very near the beginning---this allows the user to type
short abbreviations. In a long menu, it is a good idea to capitalize
the beginning of each item name which is the minimum acceptable
abbreviation for it (a long menu is more than 5 or so entries).
The nodes listed in a node's menu are called its ``subnodes'', and
it is their ``superior''. They should each have an @samp{Up:} pointing at
the superior. It is often useful to arrange all or most of the
subnodes in a sequence of @samp{Next} and @samp{Previous} pointers so that someone who
wants to see them all need not keep revisiting the Menu.
The Info Directory is simply the menu of the node @samp{(dir)Top}---that
is, node @samp{Top} in file @file{.../info/dir}. You can put new entries
in that menu just like any other menu. The Info Directory is @emph{not} the
same as the file directory called @file{info}. It happens that many of
Info's files live on that file directory, but they do not have to; and
files on that directory are not automatically listed in the Info
Directory node.
Also, although the Info node graph is claimed to be a ``hierarchy'',
in fact it can be @emph{any} directed graph. Shared structures and
pointer cycles are perfectly possible, and can be used if they are
appropriate to the meaning to be expressed. There is no need for all
the nodes in a file to form a connected structure. In fact, this file
has two connected components. You are in one of them, which is under
the node @samp{Top}; the other contains the node @samp{Help} which the
@kbd{h} command goes to. In fact, since there is no garbage
collector, nothing terrible happens if a substructure is not pointed
to, but such a substructure is rather useless since nobody can
ever find out that it exists.
@node Cross-refs, Tags, Menus, Advanced Info
@comment node-name, next, previous, up
@section Creating Cross References
A cross reference can be placed anywhere in the text, unlike a menu
item which must go at the front of a line. A cross reference looks
like a menu item except that it has @samp{*note} instead of @kbd{*}.
It @emph{cannot} be terminated by a @samp{)}, because @samp{)}'s are
so often part of node names. If you wish to enclose a cross reference
in parentheses, terminate it with a period first. Here are two
examples of cross references pointers:
@example
*Note details: commands. (See *note 3: Full Proof.)
@end example
They are just examples. The places they ``lead to'' do not really exist!
@node Tags, Checking, Cross-refs, Advanced Info
@comment node-name, next, previous, up
@section Tag Tables for Info Files
You can speed up the access to nodes of a large Info file by giving
it a tag table. Unlike the tag table for a program, the tag table for
an Info file lives inside the file itself and is used
automatically whenever Info reads in the file.
To make a tag table, go to a node in the file using Emacs Info mode and type
@kbd{M-x Info-tagify}. Then you must use @kbd{C-x C-s} to save the
file.
Once the Info file has a tag table, you must make certain it is up
to date. If, as a result of deletion of text, any node moves back
more than a thousand characters in the file from the position
recorded in the tag table, Info will no longer be able to find that
node. To update the tag table, use the @code{Info-tagify} command again.
An Info file tag table appears at the end of the file and looks like
this:
@example
^_
Tag Table:
File: info, Node: Cross-refs^?21419
File: info, Node: Tags^?22145
^_
End Tag Table
@end example
@noindent
Note that it contains one line per node, and this line contains
the beginning of the node's header (ending just after the node name),
a Delete character, and the character position in the file of the
beginning of the node.
@node Checking, Emacs Info Variables, Tags, Advanced Info
@comment node-name, next, previous, up
@section Checking an Info File
When creating an Info file, it is easy to forget the name of a node
when you are making a pointer to it from another node. If you put in
the wrong name for a node, this is not detected until someone
tries to go through the pointer using Info. Verification of the Info
file is an automatic process which checks all pointers to nodes and
reports any pointers which are invalid. Every @samp{Next}, @samp{Previous}, and
@samp{Up} is checked, as is every menu item and every cross reference. In
addition, any @samp{Next} which does not have a @samp{Previous} pointing back is
reported. Only pointers within the file are checked, because checking
pointers to other files would be terribly slow. But those are usually
few.
To check an Info file, do @kbd{M-x Info-validate} while looking at
any node of the file with Emacs Info mode.
@node Emacs Info Variables, , Checking, Advanced Info
@section Emacs Info-mode Variables
The following variables may modify the behaviour of Info-mode in Emacs;
you may wish to set one or several of these variables interactively, or
in your @file{~/.emacs} init file. @xref{Examining, Examining and Setting
Variables, Examining and Setting Variables, emacs, The GNU Emacs
Manual}.
@table @code
@item Info-enable-edit
Set to @code{nil}, disables the @samp{e} (@code{Info-edit}) command. A
non-@code{nil} value enables it. @xref{Add, Edit}.
@item Info-enable-active-nodes
When set to a non-@code{nil} value, allows Info to execute Lisp code
associated with nodes. The Lisp code is executed when the node is
selected.
@item Info-directory-list
The list of directories to search for Info files. Each element is a
string (directory name) or @code{nil} (try default directory).
@item Info-directory
The standard directory for Info documentation files. Only used when the
function @code{Info-directory} is called.
@end table
@node Create an Info File, , Advanced Info, Top
@comment node-name, next, previous, up
@chapter Creating an Info File from a Makeinfo file
@code{makeinfo} is a utility that converts a Texinfo file into an Info
file; @code{texinfo-format-region} and @code{texinfo-format-buffer} are
GNU Emacs functions that do the same.
@xref{Create an Info File, , Creating an Info File, texinfo, the Texinfo
Manual}, to learn how to create an Info file from a Texinfo file.
@xref{Top,, Overview of Texinfo, texinfo, Texinfo: The GNU Documentation
Format}, to learn how to write a Texinfo file.
@bye
texinfo-3.7/info/infodoc.c 100666 11732 13 50354 5770343255 14013 0 ustar bfox user /* infodoc.c -- Functions which build documentation nodes. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
/* Normally we do not define HELP_NODE_GETS_REGENERATED because the
contents of the help node currently can never change once an info
session has been started. You should consider defining this in
the case that you place information about dynamic variables in the
help text. When that happens, the contents of the help node will
change dependent on the value of those variables, and the user will
expect to see those changes. */
/* #define HELP_NODE_GETS_REGENERATED 1 */
/* **************************************************************** */
/* */
/* Info Help Windows */
/* */
/* **************************************************************** */
/* The name of the node used in the help window. */
static char *info_help_nodename = "*Info Help*";
/* A node containing printed key bindings and their documentation. */
static NODE *internal_info_help_node = (NODE *)NULL;
/* A pointer to the contents of the help node. */
static char *internal_info_help_node_contents = (char *)NULL;
/* The static text which appears in the internal info help node. */
static char *info_internal_help_text[] = {
"Basic Commands in Info Windows",
"******************************",
"",
" h Invoke the Info tutorial.",
"",
"Selecting other nodes:",
"----------------------",
" n Move to the \"next\" node of this node.",
" p Move to the \"previous\" node of this node.",
" u Move \"up\" from this node.",
" m Pick menu item specified by name.",
" Picking a menu item causes another node to be selected.",
" f Follow a cross reference. Reads name of reference.",
" l Move to the last node seen in this window.",
" d Move to the `directory' node. Equivalent to `g(DIR)'.",
"",
"Moving within a node:",
"---------------------",
" SPC Scroll forward a page.",
" DEL Scroll backward a page.",
" b Go to the beginning of this node.",
" e Go to the end of this node.",
"",
"\"Advanced\" commands:",
"--------------------",
" q Quit Info.",
" 1 Pick first item in node's menu.",
" 2-9 Pick second ... ninth item in node's menu.",
" 0 Pick last item in node's menu.",
" g Move to node specified by name.",
" You may include a filename as well, as in (FILENAME)NODENAME.",
" s Search through this Info file for a specified string,",
" and select the node in which the next occurrence is found.",
(char *)NULL
};
static char *where_is (), *where_is_internal ();
void
dump_map_to_message_buffer (prefix, map)
char *prefix;
Keymap map;
{
register int i;
for (i = 0; i < 256; i++)
{
if (map[i].type == ISKMAP)
{
char *new_prefix, *keyname;
keyname = pretty_keyname (i);
new_prefix = (char *)
xmalloc (3 + strlen (prefix) + strlen (keyname));
sprintf (new_prefix, "%s%s%s ", prefix, *prefix ? " " : "", keyname);
dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
free (new_prefix);
}
else if (map[i].function)
{
register int last;
char *doc, *name;
doc = function_documentation (map[i].function);
name = function_name (map[i].function);
if (!*doc)
continue;
/* Find out if there is a series of identical functions, as in
ea_insert (). */
for (last = i + 1; last < 256; last++)
if ((map[last].type != ISFUNC) ||
(map[last].function != map[i].function))
break;
if (last - 1 != i)
{
printf_to_message_buffer
("%s%s .. ", prefix, pretty_keyname (i));
printf_to_message_buffer
("%s%s\t", prefix, pretty_keyname (last - 1));
i = last - 1;
}
else
printf_to_message_buffer ("%s%s\t", prefix, pretty_keyname (i));
#if defined (NAMED_FUNCTIONS)
/* Print the name of the function, and some padding before the
documentation string is printed. */
{
int length_so_far;
int desired_doc_start = 40; /* Must be multiple of 8. */
printf_to_message_buffer ("(%s)", name);
length_so_far = message_buffer_length_this_line ();
if ((desired_doc_start + strlen (doc)) >= the_screen->width)
printf_to_message_buffer ("\n ");
else
{
while (length_so_far < desired_doc_start)
{
printf_to_message_buffer ("\t");
length_so_far += character_width ('\t', length_so_far);
}
}
}
#endif /* NAMED_FUNCTIONS */
printf_to_message_buffer ("%s\n", doc);
}
}
}
/* How to create internal_info_help_node. */
static void
create_internal_info_help_node ()
{
register int i;
char *contents = (char *)NULL;
NODE *node;
#if !defined (HELP_NODE_GETS_REGENERATED)
if (internal_info_help_node_contents)
contents = internal_info_help_node_contents;
#endif /* !HELP_NODE_GETS_REGENERATED */
if (!contents)
{
int printed_one_mx = 0;
initialize_message_buffer ();
for (i = 0; info_internal_help_text[i]; i++)
printf_to_message_buffer ("%s\n", info_internal_help_text[i]);
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer ("The current search path is:\n");
printf_to_message_buffer (" \"%s\"\n", infopath);
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer ("Commands available in Info windows:\n\n");
dump_map_to_message_buffer ("", info_keymap);
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer ("Commands available in the echo area:\n\n");
dump_map_to_message_buffer ("", echo_area_keymap);
#if defined (NAMED_FUNCTIONS)
/* Get a list of the M-x commands which have no keystroke equivs. */
for (i = 0; function_doc_array[i].func; i++)
{
VFunction *func = function_doc_array[i].func;
if ((!where_is_internal (info_keymap, func)) &&
(!where_is_internal (echo_area_keymap, func)))
{
if (!printed_one_mx)
{
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer
("The following commands can only be invoked via M-x:\n\n");
printed_one_mx = 1;
}
printf_to_message_buffer
("M-x %s\n %s\n",
function_doc_array[i].func_name,
replace_in_documentation (function_doc_array[i].doc));
}
}
if (printed_one_mx)
printf_to_message_buffer ("\n");
#endif /* NAMED_FUNCTIONS */
printf_to_message_buffer
("%s", replace_in_documentation
("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n"));
node = message_buffer_to_node ();
internal_info_help_node_contents = node->contents;
}
else
{
/* We already had the right contents, so simply use them. */
node = build_message_node ("", 0, 0);
free (node->contents);
node->contents = contents;
node->nodelen = 1 + strlen (contents);
}
internal_info_help_node = node;
/* Do not GC this node's contents. It never changes, and we never need
to delete it once it is made. If you change some things (such as
placing information about dynamic variables in the help text) then
you will need to allow the contents to be gc'd, and you will have to
arrange to always regenerate the help node. */
#if defined (HELP_NODE_GETS_REGENERATED)
add_gcable_pointer (internal_info_help_node->contents);
#endif
name_internal_node (internal_info_help_node, info_help_nodename);
/* Even though this is an internal node, we don't want the window
system to treat it specially. So we turn off the internalness
of it here. */
internal_info_help_node->flags &= ~N_IsInternal;
}
/* Return a window which is the window showing help in this Info. */
static WINDOW *
info_find_or_create_help_window ()
{
WINDOW *help_window, *eligible, *window;
eligible = (WINDOW *)NULL;
help_window = get_internal_info_window (info_help_nodename);
/* If we couldn't find the help window, then make it. */
if (!help_window)
{
int max = 0;
for (window = windows; window; window = window->next)
{
if (window->height > max)
{
max = window->height;
eligible = window;
}
}
if (!eligible)
return ((WINDOW *)NULL);
}
#if !defined (HELP_NODE_GETS_REGENERATED)
else
return (help_window);
#endif /* !HELP_NODE_GETS_REGENERATED */
/* Make sure that we have a node containing the help text. */
create_internal_info_help_node ();
/* Either use the existing window to display the help node, or create
a new window if there was no existing help window. */
if (!help_window)
{
/* Split the largest window into 2 windows, and show the help text
in that window. */
if (eligible->height > 30)
{
active_window = eligible;
help_window = window_make_window (internal_info_help_node);
}
else
{
set_remembered_pagetop_and_point (active_window);
window_set_node_of_window (active_window, internal_info_help_node);
help_window = active_window;
}
}
else
{
/* Case where help node always gets regenerated, and we have an
existing window in which to place the node. */
if (active_window != help_window)
{
set_remembered_pagetop_and_point (active_window);
active_window = help_window;
}
window_set_node_of_window (active_window, internal_info_help_node);
}
remember_window_and_node (help_window, help_window->node);
return (help_window);
}
/* Create or move to the help window. */
DECLARE_INFO_COMMAND (info_get_help_window, "Display help message")
{
WINDOW *help_window;
help_window = info_find_or_create_help_window ();
if (help_window)
{
active_window = help_window;
active_window->flags |= W_UpdateWindow;
}
else
{
info_error (CANT_MAKE_HELP);
}
}
/* Show the Info help node. This means that the "info" file is installed
where it can easily be found on your system. */
DECLARE_INFO_COMMAND (info_get_info_help_node, "Visit Info node `(info)Help'")
{
NODE *node;
char *nodename;
/* If there is a window on the screen showing the node "(info)Help" or
the node "(info)Help-Small-Screen", simply select that window. */
{
WINDOW *win;
for (win = windows; win; win = win->next)
{
if (win->node && win->node->filename &&
(strcasecmp
(filename_non_directory (win->node->filename), "info") == 0) &&
((strcmp (win->node->nodename, "Help") == 0) ||
(strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
{
active_window = win;
return;
}
}
}
/* If the current window is small, show the small screen help. */
if (active_window->height < 24)
nodename = "Help-Small-Screen";
else
nodename = "Help";
/* Try to get the info file for Info. */
node = info_get_node ("Info", nodename);
if (!node)
{
if (info_recent_file_error)
info_error (info_recent_file_error);
else
info_error (CANT_FILE_NODE, "Info", nodename);
}
else
{
/* If the current window is very large (greater than 45 lines),
then split it and show the help node in another window.
Otherwise, use the current window. */
if (active_window->height > 45)
active_window = window_make_window (node);
else
{
set_remembered_pagetop_and_point (active_window);
window_set_node_of_window (active_window, node);
}
remember_window_and_node (active_window, node);
}
}
/* **************************************************************** */
/* */
/* Groveling Info Keymaps and Docs */
/* */
/* **************************************************************** */
/* Return the documentation associated with the Info command FUNCTION. */
char *
function_documentation (function)
VFunction *function;
{
register int i;
for (i = 0; function_doc_array[i].func; i++)
if (function == function_doc_array[i].func)
break;
return (replace_in_documentation (function_doc_array[i].doc));
}
#if defined (NAMED_FUNCTIONS)
/* Return the user-visible name of the function associated with the
Info command FUNCTION. */
char *
function_name (function)
VFunction *function;
{
register int i;
for (i = 0; function_doc_array[i].func; i++)
if (function == function_doc_array[i].func)
break;
return (function_doc_array[i].func_name);
}
/* Return a pointer to the function named NAME. */
VFunction *
named_function (name)
char *name;
{
register int i;
for (i = 0; function_doc_array[i].func; i++)
if (strcmp (function_doc_array[i].func_name, name) == 0)
break;
return (function_doc_array[i].func);
}
#endif /* NAMED_FUNCTIONS */
/* Return the documentation associated with KEY in MAP. */
char *
key_documentation (key, map)
char key;
Keymap map;
{
VFunction *function = map[key].function;
if (function)
return (function_documentation (function));
else
return ((char *)NULL);
}
DECLARE_INFO_COMMAND (describe_key, "Print documentation for KEY")
{
char keyname[50];
int keyname_index = 0;
unsigned char keystroke;
char *rep;
Keymap map;
keyname[0] = '\0';
map = window->keymap;
while (1)
{
message_in_echo_area ("Describe key: %s", keyname);
keystroke = info_get_input_char ();
unmessage_in_echo_area ();
if (Meta_p (keystroke) && (!ISO_Latin_p || key < 160))
{
if (map[ESC].type != ISKMAP)
{
window_message_in_echo_area
("ESC %s is undefined.", pretty_keyname (UnMeta (keystroke)));
return;
}
strcpy (keyname + keyname_index, "ESC ");
keyname_index = strlen (keyname);
keystroke = UnMeta (keystroke);
map = (Keymap)map[ESC].function;
}
/* Add the printed representation of KEYSTROKE to our keyname. */
rep = pretty_keyname (keystroke);
strcpy (keyname + keyname_index, rep);
keyname_index = strlen (keyname);
if (map[keystroke].function == (VFunction *)NULL)
{
message_in_echo_area ("%s is undefined.", keyname);
return;
}
else if (map[keystroke].type == ISKMAP)
{
map = (Keymap)map[keystroke].function;
strcat (keyname, " ");
keyname_index = strlen (keyname);
continue;
}
else
{
char *message, *fundoc, *funname = "";
#if defined (NAMED_FUNCTIONS)
funname = function_name (map[keystroke].function);
#endif /* NAMED_FUNCTIONS */
fundoc = function_documentation (map[keystroke].function);
message = (char *)xmalloc
(10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
#if defined (NAMED_FUNCTIONS)
sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
#else
sprintf (message, "%s is defined to %s.", keyname, fundoc);
#endif /* !NAMED_FUNCTIONS */
window_message_in_echo_area ("%s", message);
free (message);
break;
}
}
}
/* How to get the pretty printable name of a character. */
static char rep_buffer[30];
char *
pretty_keyname (key)
unsigned char key;
{
char *rep;
if (Meta_p (key))
{
char temp[20];
rep = pretty_keyname (UnMeta (key));
sprintf (temp, "ESC %s", rep);
strcpy (rep_buffer, temp);
rep = rep_buffer;
}
else if (Control_p (key))
{
switch (key)
{
case '\n': rep = "LFD"; break;
case '\t': rep = "TAB"; break;
case '\r': rep = "RET"; break;
case ESC: rep = "ESC"; break;
default:
sprintf (rep_buffer, "C-%c", UnControl (key));
rep = rep_buffer;
}
}
else
{
switch (key)
{
case ' ': rep = "SPC"; break;
case DEL: rep = "DEL"; break;
default:
rep_buffer[0] = key;
rep_buffer[1] = '\0';
rep = rep_buffer;
}
}
return (rep);
}
/* Replace the names of functions with the key that invokes them. */
char *
replace_in_documentation (string)
char *string;
{
register int i, start, next;
static char *result = (char *)NULL;
maybe_free (result);
result = (char *)xmalloc (1 + strlen (string));
i = next = start = 0;
/* Skip to the beginning of a replaceable function. */
for (i = start; string[i]; i++)
{
/* Is this the start of a replaceable function name? */
if (string[i] == '\\' && string[i + 1] == '[')
{
char *fun_name, *rep;
VFunction *function;
/* Copy in the old text. */
strncpy (result + next, string + start, i - start);
next += (i - start);
start = i + 2;
/* Move to the end of the function name. */
for (i = start; string[i] && (string[i] != ']'); i++);
fun_name = (char *)xmalloc (1 + i - start);
strncpy (fun_name, string + start, i - start);
fun_name[i - start] = '\0';
/* Find a key which invokes this function in the info_keymap. */
function = named_function (fun_name);
/* If the internal documentation string fails, there is a
serious problem with the associated command's documentation.
We croak so that it can be fixed immediately. */
if (!function)
abort ();
rep = where_is (info_keymap, function);
strcpy (result + next, rep);
next = strlen (result);
start = i;
if (string[i])
start++;
}
}
strcpy (result + next, string + start);
return (result);
}
/* Return a string of characters which could be typed from the keymap
MAP to invoke FUNCTION. */
static char *where_is_rep = (char *)NULL;
static int where_is_rep_index = 0;
static int where_is_rep_size = 0;
static char *
where_is (map, function)
Keymap map;
VFunction *function;
{
char *rep;
if (!where_is_rep_size)
where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
where_is_rep_index = 0;
rep = where_is_internal (map, function);
/* If it couldn't be found, return "M-x Foo". */
if (!rep)
{
char *name;
name = function_name (function);
if (name)
sprintf (where_is_rep, "M-x %s", name);
rep = where_is_rep;
}
return (rep);
}
/* Return the printed rep of FUNCTION as found in MAP, or NULL. */
static char *
where_is_internal (map, function)
Keymap map;
VFunction *function;
{
register int i;
/* If the function is directly invokable in MAP, return the representation
of that keystroke. */
for (i = 0; i < 256; i++)
if ((map[i].type == ISFUNC) && map[i].function == function)
{
sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
return (where_is_rep);
}
/* Okay, search subsequent maps for this function. */
for (i = 0; i < 256; i++)
{
if (map[i].type == ISKMAP)
{
int saved_index = where_is_rep_index;
char *rep;
sprintf (where_is_rep + where_is_rep_index, "%s ",
pretty_keyname (i));
where_is_rep_index = strlen (where_is_rep);
rep = where_is_internal ((Keymap)map[i].function, function);
if (rep)
return (where_is_rep);
where_is_rep_index = saved_index;
}
}
return ((char *)NULL);
}
extern char *read_function_name ();
DECLARE_INFO_COMMAND (info_where_is,
"Show what to type to execute a given command")
{
char *command_name;
command_name = read_function_name ("Where is command: ", window);
if (!command_name)
{
info_abort_key (active_window, count, key);
return;
}
if (*command_name)
{
VFunction *function;
function = named_function (command_name);
if (function)
{
char *location;
location = where_is (active_window->keymap, function);
if (!location)
{
info_error ("`%s' is not on any keys", command_name);
}
else
{
if (strncmp (location, "M-x ", 4) == 0)
window_message_in_echo_area
("%s can only be invoked via %s.", command_name, location);
else
window_message_in_echo_area
("%s can be invoked via %s.", command_name, location);
}
}
else
info_error ("There is no function named `%s'", command_name);
}
free (command_name);
}
texinfo-3.7/info/infomap.c 100666 11732 13 20573 5770343263 14022 0 ustar bfox user /* infomap.c -- Keymaps for Info. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "stdio.h"
#include "ctype.h"
#include "infomap.h"
#include "funs.h"
/* Return a new keymap which has all the uppercase letters mapped to run
the function info_do_lowercase_version (). */
Keymap
keymap_make_keymap ()
{
register int i;
Keymap keymap;
keymap = (Keymap)xmalloc (256 * sizeof (KEYMAP_ENTRY));
for (i = 0; i < 256; i++)
{
keymap[i].type = ISFUNC;
keymap[i].function = (VFunction *)NULL;
}
for (i = 'A'; i < ('Z' + 1); i++)
{
keymap[i].type = ISFUNC;
keymap[i].function = info_do_lowercase_version;
}
return (keymap);
}
/* Return a new keymap which is a copy of MAP. */
Keymap
keymap_copy_keymap (map)
Keymap map;
{
register int i;
Keymap keymap;
keymap = keymap_make_keymap ();
for (i = 0; i < 256; i++)
{
keymap[i].type = map[i].type;
keymap[i].function = map[i].function;
}
return (keymap);
}
/* Free the keymap and it's descendents. */
void
keymap_discard_keymap (map)
Keymap (map);
{
register int i;
if (!map)
return;
for (i = 0; i < 256; i++)
{
switch (map[i].type)
{
case ISFUNC:
break;
case ISKMAP:
keymap_discard_keymap ((Keymap)map[i].function);
break;
}
}
}
/* Initialize the standard info keymaps. */
Keymap info_keymap = (Keymap)NULL;
Keymap echo_area_keymap = (Keymap)NULL;
void
initialize_info_keymaps ()
{
register int i;
Keymap map;
if (!info_keymap)
{
info_keymap = keymap_make_keymap ();
info_keymap[ESC].type = ISKMAP;
info_keymap[ESC].function = (VFunction *)keymap_make_keymap ();
info_keymap[Control ('x')].type = ISKMAP;
info_keymap[Control ('x')].function = (VFunction *)keymap_make_keymap ();
echo_area_keymap = keymap_make_keymap ();
echo_area_keymap[ESC].type = ISKMAP;
echo_area_keymap[ESC].function = (VFunction *)keymap_make_keymap ();
echo_area_keymap[Control ('x')].type = ISKMAP;
echo_area_keymap[Control ('x')].function =
(VFunction *)keymap_make_keymap ();
}
/* Bind numeric arg functions for both echo area and info window maps. */
for (i = '0'; i < '9' + 1; i++)
{
((Keymap) info_keymap[ESC].function)[i].function =
((Keymap) echo_area_keymap[ESC].function)[i].function =
info_add_digit_to_numeric_arg;
}
((Keymap) info_keymap[ESC].function)['-'].function =
((Keymap) echo_area_keymap[ESC].function)['-'].function =
info_add_digit_to_numeric_arg;
/* Bind the echo area routines. */
map = echo_area_keymap;
/* Bind the echo area insert routines. */
for (i = 0; i < 160; i++)
if (isprint (i))
map[i].function = ea_insert;
map[Control ('a')].function = ea_beg_of_line;
map[Control ('b')].function = ea_backward;
map[Control ('d')].function = ea_delete;
map[Control ('e')].function = ea_end_of_line;
map[Control ('f')].function = ea_forward;
map[Control ('g')].function = ea_abort;
map[Control ('h')].function = ea_rubout;
map[Control ('k')].function = ea_kill_line;
map[Control ('l')].function = info_redraw_display;
map[Control ('q')].function = ea_quoted_insert;
map[Control ('t')].function = ea_transpose_chars;
map[Control ('u')].function = info_universal_argument;
map[Control ('y')].function = ea_yank;
map[LFD].function = ea_newline;
map[RET].function = ea_newline;
map[SPC].function = ea_complete;
map[TAB].function = ea_complete;
map['?'].function = ea_possible_completions;
map[DEL].function = ea_rubout;
/* Bind the echo area ESC keymap. */
map = (Keymap)echo_area_keymap[ESC].function;
map[Control ('g')].function = ea_abort;
map[Control ('v')].function = ea_scroll_completions_window;
map['b'].function = ea_backward_word;
map['d'].function = ea_kill_word;
map['f'].function = ea_forward_word;
#if defined (NAMED_FUNCTIONS)
/* map['x'].function = info_execute_command; */
#endif /* NAMED_FUNCTIONS */
map['y'].function = ea_yank_pop;
map['?'].function = ea_possible_completions;
map[TAB].function = ea_tab_insert;
map[DEL].function = ea_backward_kill_word;
/* Bind the echo area Control-x keymap. */
map = (Keymap)echo_area_keymap[Control ('x')].function;
map['o'].function = info_next_window;
map[DEL].function = ea_backward_kill_line;
/* Bind commands for Info window keymaps. */
map = info_keymap;
map[TAB].function = info_move_to_next_xref;
map[LFD].function = info_select_reference_this_line;
map[RET].function = info_select_reference_this_line;
map[SPC].function = info_scroll_forward;
map[Control ('a')].function = info_beginning_of_line;
map[Control ('b')].function = info_backward_char;
map[Control ('e')].function = info_end_of_line;
map[Control ('f')].function = info_forward_char;
map[Control ('g')].function = info_abort_key;
map[Control ('h')].function = info_get_help_window;
map[Control ('l')].function = info_redraw_display;
map[Control ('n')].function = info_next_line;
map[Control ('p')].function = info_prev_line;
map[Control ('r')].function = isearch_backward;
map[Control ('s')].function = isearch_forward;
map[Control ('u')].function = info_universal_argument;
map[Control ('v')].function = info_scroll_forward;
map[','].function = info_next_index_match;
for (i = '1'; i < '9' + 1; i++)
map[i].function = info_menu_digit;
map['0'].function = info_last_menu_item;
map['<'].function = info_first_node;
map['>'].function = info_last_node;
map['?'].function = info_get_help_window;
map['['].function = info_global_prev_node;
map[']'].function = info_global_next_node;
map['b'].function = info_beginning_of_node;
map['d'].function = info_dir_node;
map['e'].function = info_end_of_node;
map['f'].function = info_xref_item;
map['g'].function = info_goto_node;
map['h'].function = info_get_info_help_node;
map['i'].function = info_index_search;
map['l'].function = info_history_node;
map['m'].function = info_menu_item;
map['n'].function = info_next_node;
map['p'].function = info_prev_node;
map['q'].function = info_quit;
map['r'].function = info_xref_item;
map['s'].function = info_search;
map['t'].function = info_top_node;
map['u'].function = info_up_node;
map[DEL].function = info_scroll_backward;
/* Bind members in the ESC map for Info windows. */
map = (Keymap)info_keymap[ESC].function;
map[Control ('f')].function = info_show_footnotes;
map[Control ('g')].function = info_abort_key;
map[TAB].function = info_move_to_prev_xref;
map[Control ('v')].function = info_scroll_other_window;
map['<'].function = info_beginning_of_node;
map['>'].function = info_end_of_node;
map['b'].function = info_backward_word;
map['f'].function = info_forward_word;
map['r'].function = info_move_to_window_line;
map['v'].function = info_scroll_backward;
#if defined (NAMED_FUNCTIONS)
map['x'].function = info_execute_command;
#endif /* NAMED_FUNCTIONS */
/* Bind members in the Control-X map for Info windows. */
map = (Keymap)info_keymap[Control ('x')].function;
map[Control ('b')].function = list_visited_nodes;
map[Control ('c')].function = info_quit;
map[Control ('f')].function = info_view_file;
map[Control ('g')].function = info_abort_key;
map[Control ('v')].function = info_view_file;
map['0'].function = info_delete_window;
map['1'].function = info_keep_one_window;
map['2'].function = info_split_window;
map['^'].function = info_grow_window;
map['b'].function = select_visited_node;
map['k'].function = info_kill_node;
map['o'].function = info_next_window;
map['t'].function = info_tile_windows;
map['w'].function = info_toggle_wrap;
}
texinfo-3.7/info/infomap.h 100666 11732 13 5015 5770343441 13777 0 ustar bfox user /* infomap.h -- Description of a keymap in Info and related functions. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_INFOMAP_H_)
#define _INFOMAP_H_
#include "general.h"
#define ESC '\033'
#define DEL '\177'
#define TAB '\011'
#define RET '\r'
#define LFD '\n'
#define SPC ' '
#define meta_character_threshold (DEL + 1)
#define control_character_threshold (SPC)
#define meta_character_bit 0x80
#define control_character_bit 0x40
#define Meta_p(c) (((c) > meta_character_threshold))
#define Control_p(c) ((c) < control_character_threshold)
#define Meta(c) ((c) | (meta_character_bit))
#define UnMeta(c) ((c) & (~meta_character_bit))
#define Control(c) ((toupper (c)) & (~control_character_bit))
#define UnControl(c) (tolower ((c) | control_character_bit))
/* A keymap contains one entry for each key in the ASCII set.
Each entry consists of a type and a pointer.
FUNCTION is the address of a function to run, or the
address of a keymap to indirect through.
TYPE says which kind of thing FUNCTION is. */
typedef struct {
char type;
VFunction *function;
} KEYMAP_ENTRY;
typedef KEYMAP_ENTRY *Keymap;
/* The values that TYPE can have in a keymap entry. */
#define ISFUNC 0
#define ISKMAP 1
extern Keymap info_keymap;
extern Keymap echo_area_keymap;
/* Return a new keymap which has all the uppercase letters mapped to run
the function info_do_lowercase_version (). */
extern Keymap keymap_make_keymap ();
/* Return a new keymap which is a copy of MAP. */
extern Keymap keymap_copy_keymap ();
/* Free MAP and it's descendents. */
extern void keymap_discard_keymap ();
/* Initialize the info keymaps. */
extern void initialize_info_keymaps ();
#endif /* !_INFOMAP_H_ */
texinfo-3.7/info/m-x.c 100666 11732 13 11353 5770343267 13072 0 ustar bfox user /* m-x.c -- Meta-X minibuffer reader. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
/* **************************************************************** */
/* */
/* Reading Named Commands */
/* */
/* **************************************************************** */
/* Read the name of an Info function in the echo area and return the
name. A return value of NULL indicates that no function name could
be read. */
char *
read_function_name (prompt, window)
char *prompt;
WINDOW *window;
{
register int i;
char *line;
REFERENCE **array = (REFERENCE **)NULL;
int array_index = 0, array_slots = 0;
/* Make an array of REFERENCE which actually contains the names of
the functions available in Info. */
for (i = 0; function_doc_array[i].func; i++)
{
REFERENCE *entry;
entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
entry->label = strdup (function_doc_array[i].func_name);
entry->nodename = (char *)NULL;
entry->filename = (char *)NULL;
add_pointer_to_array
(entry, array_index, array, array_slots, 200, REFERENCE *);
}
line = info_read_completing_in_echo_area (window, prompt, array);
info_free_references (array);
if (!echo_area_is_active)
window_clear_echo_area ();
return (line);
}
DECLARE_INFO_COMMAND (describe_command,
"Read the name of an Info command and describe it")
{
char *line;
line = read_function_name ("Describe command: ", window);
if (!line)
{
info_abort_key (active_window, count, key);
return;
}
/* Describe the function named in "LINE". */
if (*line)
{
char *fundoc;
VFunction *fun;
fun = named_function (line);
if (!fun)
return;
window_message_in_echo_area ("%s: %s.",
line, function_documentation (fun));
}
free (line);
}
DECLARE_INFO_COMMAND (info_execute_command,
"Read a command name in the echo area and execute it")
{
char *line;
/* Ask the completer to read a reference for us. */
if (info_explicit_arg || count != 1)
{
char *prompt;
prompt = (char *)xmalloc (20);
sprintf (prompt, "%d M-x ", count);
line = read_function_name (prompt, window);
}
else
line = read_function_name ("M-x ", window);
/* User aborted? */
if (!line)
{
info_abort_key (active_window, count, key);
return;
}
/* User accepted "default"? (There is none.) */
if (!*line)
{
free (line);
return;
}
/* User wants to execute a named command. Do it. */
{
VFunction *function;
if ((active_window != the_echo_area) &&
(strncmp (line, "echo-area-", 10) == 0))
{
free (line);
info_error ("Cannot execute an `echo-area' command here.");
return;
}
function = named_function (line);
free (line);
if (!function)
return;
(*function) (active_window, count, 0);
}
}
/* Okay, now that we have M-x, let the user set the screen height. */
DECLARE_INFO_COMMAND (set_screen_height,
"Set the height of the displayed window")
{
int new_height;
if (info_explicit_arg || count != 1)
new_height = count;
else
{
char prompt[80];
char *line;
new_height = screenheight;
sprintf (prompt, "Set screen height to (%d): ", new_height);
line = info_read_in_echo_area (window, prompt);
/* If the user aborted, do that now. */
if (!line)
{
info_abort_key (active_window, count, 0);
return;
}
/* Find out what the new height is supposed to be. */
if (*line)
new_height = atoi (line);
/* Clear the echo area if it isn't active. */
if (!echo_area_is_active)
window_clear_echo_area ();
free (line);
}
terminal_clear_screen ();
display_clear_display (the_display);
screenheight = new_height;
display_initialize_display (screenwidth, screenheight);
window_new_screen_size (screenwidth, screenheight);
}
texinfo-3.7/info/makedoc.c 100666 11732 13 27117 5770343273 13776 0 ustar bfox user /* makedoc.c -- Make DOC.C and FUNS.H from input files. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
/* This program grovels the contents of the source files passed as arguments
and writes out a file of function pointers and documentation strings, and
a header file which describes the contents. This only does the functions
declared with DECLARE_INFO_COMMAND. */
#include
#include
#include
#if defined (HAVE_SYS_FILE_H)
#include
#endif /* HAVE_SYS_FILE_H */
#include
#include "general.h"
#if !defined (O_RDONLY)
#if defined (HAVE_SYS_FCNTL_H)
#include
#else /* !HAVE_SYS_FCNTL_H */
#include
#endif /* !HAVE_SYS_FCNTL_H */
#endif /* !O_RDONLY */
extern void *xmalloc (), *xrealloc ();
static void fatal_file_error ();
/* Name of the header file which receives the declarations of functions. */
static char *funs_filename = "funs.h";
/* Name of the documentation to function pointer file. */
static char *doc_filename = "doc.c";
static char *doc_header[] = {
"/* doc.c -- Generated structure containing function names and doc strings.",
"",
" This file was automatically made from various source files with the",
" command \"%s\". DO NOT EDIT THIS FILE, only \"%s.c\".",
(char *)NULL
};
static char *doc_header_1[] = {
" An entry in the array FUNCTION_DOC_ARRAY is made for each command",
" found in the above files; each entry consists of a function pointer,",
#if defined (NAMED_FUNCTIONS)
" a string which is the user-visible name of the function,",
#endif /* NAMED_FUNCTIONS */
" and a string which documents its purpose. */",
"",
"#include \"doc.h\"",
"#include \"funs.h\"",
"",
"FUNCTION_DOC function_doc_array[] = {",
"",
(char *)NULL
};
/* How to remember the locations of the functions found so that Emacs
can use the information in a tag table. */
typedef struct {
char *name; /* Name of the tag. */
int line; /* Line number at which it appears. */
long char_offset; /* Character offset at which it appears. */
} EMACS_TAG;
typedef struct {
char *filename; /* Name of the file containing entries. */
long entrylen; /* Total number of characters in tag block. */
EMACS_TAG **entries; /* Entries found in FILENAME. */
int entries_index;
int entries_slots;
} EMACS_TAG_BLOCK;
EMACS_TAG_BLOCK **emacs_tags = (EMACS_TAG_BLOCK **)NULL;
int emacs_tags_index = 0;
int emacs_tags_slots = 0;
#define DECLARATION_STRING "\nDECLARE_INFO_COMMAND"
static void process_one_file ();
static void maybe_dump_tags ();
static FILE *must_fopen ();
int
main (argc, argv)
int argc;
char **argv;
{
register int i;
int tags_only = 0;
FILE *funs_stream, *doc_stream;
for (i = 1; i < argc; i++)
if (strcmp (argv[i], "-tags") == 0)
{
tags_only++;
break;
}
if (tags_only)
{
funs_filename = "/dev/null";
doc_filename = "/dev/null";
}
funs_stream = must_fopen (funs_filename, "w");
doc_stream = must_fopen (doc_filename, "w");
fprintf (funs_stream,
"/* %s -- Generated declarations for Info commands. */\n",
funs_filename);
for (i = 0; doc_header[i]; i++)
{
fprintf (doc_stream, doc_header[i], argv[0], argv[0]);
fprintf (doc_stream, "\n");
}
fprintf (doc_stream,
" Source files groveled to make this file include:\n\n");
for (i = 1; i < argc; i++)
fprintf (doc_stream, "\t%s\n", argv[i]);
fprintf (doc_stream, "\n");
for (i = 0; doc_header_1[i]; i++)
fprintf (doc_stream, "%s\n", doc_header_1[i]);
for (i = 1; i < argc; i++)
{
char *curfile;
curfile = argv[i];
if (*curfile == '-')
continue;
fprintf (doc_stream, "/* Commands found in \"%s\". */\n", curfile);
fprintf (funs_stream, "\n/* Functions declared in \"%s\". */\n",
curfile);
process_one_file (curfile, doc_stream, funs_stream);
}
fprintf (doc_stream,
" { (VFunction *)NULL, (char *)NULL, (char *)NULL }\n};\n");
fclose (funs_stream);
fclose (doc_stream);
if (tags_only)
maybe_dump_tags (stdout);
exit (0);
}
/* Dumping out the contents of an Emacs tags table. */
static void
maybe_dump_tags (stream)
FILE *stream;
{
register int i;
/* Print out the information for each block. */
for (i = 0; i < emacs_tags_index; i++)
{
register int j;
register EMACS_TAG_BLOCK *block;
register EMACS_TAG *etag;
long block_len;
block_len = 0;
block = emacs_tags[i];
/* Calculate the length of the dumped block first. */
for (j = 0; j < block->entries_index; j++)
{
char digits[30];
etag = block->entries[j];
block_len += 3 + strlen (etag->name);
sprintf (digits, "%d,%d", etag->line, etag->char_offset);
block_len += strlen (digits);
}
/* Print out the defining line. */
fprintf (stream, "\f\n%s,%d\n", block->filename, block_len);
/* Print out the individual tags. */
for (j = 0; j < block->entries_index; j++)
{
etag = block->entries[j];
fprintf (stream, "%s,\177%d,%d\n",
etag->name, etag->line, etag->char_offset);
}
}
}
/* Keeping track of names, line numbers and character offsets of functions
found in source files. */
static EMACS_TAG_BLOCK *
make_emacs_tag_block (filename)
char *filename;
{
EMACS_TAG_BLOCK *block;
block = (EMACS_TAG_BLOCK *)xmalloc (sizeof (EMACS_TAG_BLOCK));
block->filename = strdup (filename);
block->entrylen = 0;
block->entries = (EMACS_TAG **)NULL;
block->entries_index = 0;
block->entries_slots = 0;
return (block);
}
static void
add_tag_to_block (block, name, line, char_offset)
EMACS_TAG_BLOCK *block;
char *name;
int line;
long char_offset;
{
EMACS_TAG *tag;
tag = (EMACS_TAG *)xmalloc (sizeof (EMACS_TAG));
tag->name = name;
tag->line = line;
tag->char_offset = char_offset;
add_pointer_to_array (tag, block->entries_index, block->entries,
block->entries_slots, 50, EMACS_TAG *);
}
/* Read the file represented by FILENAME into core, and search it for Info
function declarations. Output the declarations in various forms to the
DOC_STREAM and FUNS_STREAM. */
static void
process_one_file (filename, doc_stream, funs_stream)
char *filename;
FILE *doc_stream, *funs_stream;
{
int descriptor, decl_len;
char *buffer, *decl_str;
struct stat finfo;
long offset;
long file_size;
EMACS_TAG_BLOCK *block;
if (stat (filename, &finfo) == -1)
fatal_file_error (filename);
descriptor = open (filename, O_RDONLY, 0666);
if (descriptor == -1)
fatal_file_error (filename);
file_size = (long) finfo.st_size;
buffer = (char *)xmalloc (1 + file_size);
read (descriptor, buffer, file_size);
close (descriptor);
offset = 0;
decl_str = DECLARATION_STRING;
decl_len = strlen (decl_str);
block = make_emacs_tag_block (filename);
while (1)
{
long point = 0;
long line_start = 0;
int line_number = 0;
char *func, *doc;
#if defined (NAMED_FUNCTIONS)
char *func_name;
#endif /* NAMED_FUNCTIONS */
for (; offset < (file_size - decl_len); offset++)
{
if (buffer[offset] == '\n')
{
line_number++;
line_start = offset + 1;
}
if (strncmp (buffer + offset, decl_str, decl_len) == 0)
{
offset += decl_len;
point = offset;
break;
}
}
if (!point)
break;
/* Skip forward until we find the open paren. */
while (point < file_size)
{
if (buffer[point] == '\n')
{
line_number++;
line_start = point + 1;
}
else if (buffer[point] == '(')
break;
point++;
}
while (point++ < file_size)
{
if (!whitespace_or_newline (buffer[point]))
break;
else if (buffer[point] == '\n')
{
line_number++;
line_start = point + 1;
}
}
if (point >= file_size)
break;
/* Now looking at name of function. Get it. */
for (offset = point; buffer[offset] != ','; offset++);
func = (char *)xmalloc (1 + (offset - point));
strncpy (func, buffer + point, offset - point);
func[offset - point] = '\0';
/* Remember this tag in the current block. */
{
char *tag_name;
tag_name = (char *)xmalloc (1 + (offset - line_start));
strncpy (tag_name, buffer + line_start, offset - line_start);
tag_name[offset - line_start] = '\0';
add_tag_to_block (block, tag_name, line_number, point);
}
#if defined (NAMED_FUNCTIONS)
/* Generate the user-visible function name from the function's name. */
{
register int i;
char *name_start;
name_start = func;
if (strncmp (name_start, "info_", 5) == 0)
name_start += 5;
func_name = strdup (name_start);
/* Fix up "ea" commands. */
if (strncmp (func_name, "ea_", 3) == 0)
{
char *temp_func_name;
temp_func_name = (char *)xmalloc (10 + strlen (func_name));
strcpy (temp_func_name, "echo_area_");
strcat (temp_func_name, func_name + 3);
free (func_name);
func_name = temp_func_name;
}
for (i = 0; func_name[i]; i++)
if (func_name[i] == '_')
func_name[i] = '-';
}
#endif /* NAMED_FUNCTIONS */
/* Find doc string. */
point = offset + 1;
while (point < file_size)
{
if (buffer[point] == '\n')
{
line_number++;
line_start = point + 1;
}
if (buffer[point] == '"')
break;
else
point++;
}
offset = point + 1;
while (offset < file_size)
{
if (buffer[offset] == '\n')
{
line_number++;
line_start = offset + 1;
}
if (buffer[offset] == '\\')
offset += 2;
else if (buffer[offset] == '"')
break;
else
offset++;
}
offset++;
if (offset >= file_size)
break;
doc = (char *)xmalloc (1 + (offset - point));
strncpy (doc, buffer + point, offset - point);
doc[offset - point] = '\0';
#if defined (NAMED_FUNCTIONS)
fprintf (doc_stream, " { %s, \"%s\", %s },\n", func, func_name, doc);
free (func_name);
#else /* !NAMED_FUNCTIONS */
fprintf (doc_stream, " { %s, %s },\n", func, doc);
#endif /* !NAMED_FUNCTIONS */
fprintf (funs_stream, "extern void %s ();\n", func);
free (func);
free (doc);
}
free (buffer);
/* If we created any tags, remember this file on our global list. Otherwise,
free the memory already allocated to it. */
if (block->entries)
add_pointer_to_array (block, emacs_tags_index, emacs_tags,
emacs_tags_slots, 10, EMACS_TAG_BLOCK *);
else
{
free (block->filename);
free (block);
}
}
static void
fatal_file_error (filename)
char *filename;
{
fprintf (stderr, "Couldn't manipulate the file %s.\n", filename);
exit (2);
}
static FILE *
must_fopen (filename, mode)
char *filename, *mode;
{
FILE *stream;
stream = fopen (filename, mode);
if (!stream)
fatal_file_error (filename);
return (stream);
}
texinfo-3.7/info/man.c 100666 11732 13 34516 6067071535 13146 0 ustar bfox user /* man.c: How to read and format man files. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1995 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 Thu May 4 09:17:52 1995 (bfox@ai.mit.edu). */
#include "info.h"
#include
#include
#include "signals.h"
#if defined (HAVE_SYS_TIME_H)
#include
#endif
#if defined (HAVE_SYS_WAIT_H)
#include
#endif
#include "tilde.h"
#include "man.h"
#if !defined (_POSIX_VERSION)
#define pid_t int
#endif
#if defined (FD_SET)
# if defined (hpux)
# define fd_set_cast(x) (int *)(x)
# else
# define fd_set_cast(x) (fd_set *)(x)
# endif /* !hpux */
#endif /* FD_SET */
static char *read_from_fd ();
static void clean_manpage ();
static NODE *manpage_node_of_file_buffer ();
static char *get_manpage_contents ();
NODE *
make_manpage_node (pagename)
char *pagename;
{
return (info_get_node (MANPAGE_FILE_BUFFER_NAME, pagename));
}
NODE *
get_manpage_node (file_buffer, pagename)
FILE_BUFFER *file_buffer;
char *pagename;
{
NODE *node;
node = manpage_node_of_file_buffer (file_buffer, pagename);
if (!node)
{
char *page;
page = get_manpage_contents (pagename);
if (page)
{
char header[1024];
long oldsize, newsize;
int hlen, plen;
sprintf (header, "\n\n%c\n%s %s, %s %s, %s (dir)\n\n",
INFO_COOKIE,
INFO_FILE_LABEL, file_buffer->filename,
INFO_NODE_LABEL, pagename,
INFO_UP_LABEL);
oldsize = file_buffer->filesize;
hlen = strlen (header);
plen = strlen (page);
newsize = (oldsize + hlen + plen);
file_buffer->contents =
(char *)xrealloc (file_buffer->contents, 1 + newsize);
memcpy (file_buffer->contents + oldsize, header, hlen);
oldsize += hlen;
memcpy (file_buffer->contents + oldsize, page, plen);
file_buffer->contents[newsize] = '\0';
file_buffer->filesize = newsize;
file_buffer->finfo.st_size = newsize;
build_tags_and_nodes (file_buffer);
free (page);
}
node = manpage_node_of_file_buffer (file_buffer, pagename);
}
return (node);
}
FILE_BUFFER *
create_manpage_file_buffer ()
{
FILE_BUFFER *file_buffer;
struct stat *finfo;
file_buffer = make_file_buffer ();
file_buffer->filename = strdup (MANPAGE_FILE_BUFFER_NAME);
file_buffer->fullpath = strdup (MANPAGE_FILE_BUFFER_NAME);
file_buffer->finfo.st_size = 0;
file_buffer->filesize = 0;
file_buffer->contents = (char *)NULL;
file_buffer->flags = (N_IsInternal | N_CannotGC | N_IsManPage);
return (file_buffer);
}
/* Scan the list of directories in PATH looking for FILENAME. If we find
one that is an executable file, return it as a new string. Otherwise,
return a NULL pointer. */
static char *
executable_file_in_path (filename, path)
char *filename, *path;
{
struct stat finfo;
char *temp_dirname;
int statable, dirname_index;
dirname_index = 0;
while (temp_dirname = extract_colon_unit (path, &dirname_index))
{
register int i;
char *temp;
/* Expand a leading tilde if one is present. */
if (*temp_dirname == '~')
{
char *expanded_dirname;
expanded_dirname = tilde_expand_word (temp_dirname);
free (temp_dirname);
temp_dirname = expanded_dirname;
}
temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
strcpy (temp, temp_dirname);
if (temp[(strlen (temp)) - 1] != '/')
strcat (temp, "/");
strcat (temp, filename);
free (temp_dirname);
statable = (stat (temp, &finfo) == 0);
/* If we have found a regular executable file, then use it. */
if ((statable) && (S_ISREG (finfo.st_mode)) &&
(access (temp, X_OK) == 0))
return (temp);
else
free (temp);
}
return ((char *)NULL);
}
/* Return the full pathname of the system man page formatter. */
static char *
find_man_formatter ()
{
return (executable_file_in_path ("man", (char *)getenv ("PATH")));
}
static char *manpage_pagename = (char *)NULL;
static char *manpage_section = (char *)NULL;
static void
get_page_and_section (pagename)
char *pagename;
{
register int i;
if (manpage_pagename)
free (manpage_pagename);
if (manpage_section)
free (manpage_section);
manpage_pagename = (char *)NULL;
manpage_section = (char *)NULL;
for (i = 0; pagename[i] != '\0' && pagename[i] != '('; i++);
manpage_pagename = (char *)xmalloc (1 + i);
strncpy (manpage_pagename, pagename, i);
manpage_pagename[i] = '\0';
if (pagename[i] == '(')
{
int start;
start = i + 1;
for (i = start; pagename[i] != '\0' && pagename[i] != ')'; i++);
manpage_section = (char *)xmalloc (1 + (i - start));
strncpy (manpage_section, pagename + start, (i - start));
manpage_section[i - start] = '\0';
}
}
static void
reap_children (sig)
int sig;
{
unsigned int status;
wait (&status);
}
static char *
get_manpage_contents (pagename)
char *pagename;
{
static char *formatter_args[4] = { (char *)NULL };
int pipes[2];
pid_t child;
char *formatted_page = (char *)NULL;
char *section = (char *)NULL;
int arg_index = 1;
if (formatter_args[0] == (char *)NULL)
formatter_args[0] = find_man_formatter ();
if (formatter_args[0] == (char *)NULL)
return ((char *)NULL);
get_page_and_section (pagename);
if (manpage_section != (char *)NULL)
formatter_args[arg_index++] = manpage_section;
formatter_args[arg_index++] = manpage_pagename;
formatter_args[arg_index] = (char *)NULL;
/* Open a pipe to this program, read the output, and save it away
in FORMATTED_PAGE. The reader end of the pipe is pipes[0]; the
writer end is pipes[1]. */
pipe (pipes);
signal (SIGCHLD, reap_children);
child = fork ();
if (child == -1)
return ((char *)NULL);
if (child != 0)
{
/* In the parent, close the writing end of the pipe, and read from
the exec'd child. */
close (pipes[1]);
formatted_page = read_from_fd (pipes[0]);
close (pipes[0]);
}
else
{
/* In the child, close the read end of the pipe, make the write end
of the pipe be stdout, and execute the man page formatter. */
close (pipes[0]);
close (fileno (stderr));
close (fileno (stdin)); /* Don't print errors. */
dup2 (pipes[1], fileno (stdout));
execv (formatter_args[0], formatter_args);
/* If we get here, we couldn't exec, so close out the pipe and
exit. */
close (pipes[1]);
exit (0);
}
/* If we have the page, then clean it up. */
if (formatted_page)
clean_manpage (formatted_page);
return (formatted_page);
}
static void
clean_manpage (manpage)
char *manpage;
{
register int i, j;
int newline_count = 0;
char *newpage;
newpage = (char *)xmalloc (1 + strlen (manpage));
for (i = 0, j = 0; newpage[j] = manpage[i]; i++, j++)
{
if (manpage[i] == '\n')
newline_count++;
else
newline_count = 0;
if (newline_count == 3)
{
j--;
newline_count--;
}
if (manpage[i] == '\b' || manpage[i] == '\f')
j -= 2;
}
newpage[j++] = '\0';
strcpy (manpage, newpage);
free (newpage);
}
static NODE *
manpage_node_of_file_buffer (file_buffer, pagename)
FILE_BUFFER *file_buffer;
char *pagename;
{
NODE *node = (NODE *)NULL;
TAG *tag = (TAG *)NULL;
if (file_buffer->contents)
{
register int i;
for (i = 0; tag = file_buffer->tags[i]; i++)
{
if (strcasecmp (pagename, tag->nodename) == 0)
break;
}
}
if (tag)
{
node = (NODE *)xmalloc (sizeof (NODE));
node->filename = file_buffer->filename;
node->nodename = tag->nodename;
node->contents = file_buffer->contents + tag->nodestart;
node->nodelen = tag->nodelen;
node->flags = 0;
node->parent = (char *)NULL;
node->flags = (N_HasTagsTable | N_IsManPage);
node->contents += skip_node_separator (node->contents);
}
return (node);
}
static char *
read_from_fd (fd)
int fd;
{
struct timeval timeout;
char *buffer = (char *)NULL;
int bsize = 0;
int bindex = 0;
int select_result;
#if defined (FD_SET)
fd_set read_fds;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
FD_ZERO (&read_fds);
FD_SET (fd, &read_fds);
select_result = select (fd + 1, fd_set_cast (&read_fds), 0, 0, &timeout);
#else /* !FD_SET */
select_result = 1;
#endif /* !FD_SET */
switch (select_result)
{
case 0:
case -1:
break;
default:
{
int amount_read;
int done = 0;
while (!done)
{
while ((bindex + 1024) > (bsize))
buffer = (char *)xrealloc (buffer, (bsize += 1024));
buffer[bindex] = '\0';
amount_read = read (fd, buffer + bindex, 1023);
if (amount_read < 0)
{
done = 1;
}
else
{
bindex += amount_read;
buffer[bindex] = '\0';
if (amount_read == 0)
done = 1;
}
}
}
}
if ((buffer != (char *)NULL) && (*buffer == '\0'))
{
free (buffer);
buffer = (char *)NULL;
}
return (buffer);
}
static char *reference_section_starters[] =
{
"\nRELATED INFORMATION",
"\nRELATED\tINFORMATION",
"RELATED INFORMATION\n",
"RELATED\tINFORMATION\n",
"\nSEE ALSO",
"\nSEE\tALSO",
"SEE ALSO\n",
"SEE\tALSO\n",
(char *)NULL
};
static SEARCH_BINDING frs_binding;
static SEARCH_BINDING *
find_reference_section (node)
NODE *node;
{
register int i;
long position = -1;
frs_binding.buffer = node->contents;
frs_binding.start = 0;
frs_binding.end = node->nodelen;
frs_binding.flags = S_SkipDest;
for (i = 0; reference_section_starters[i] != (char *)NULL; i++)
{
position = search_forward (reference_section_starters[i], &frs_binding);
if (position != -1)
break;
}
if (position == -1)
return ((SEARCH_BINDING *)NULL);
/* We found the start of the reference section, and point is right after
the string which starts it. The text from here to the next header
(or end of buffer) contains the only references in this manpage. */
frs_binding.start = position;
for (i = frs_binding.start; i < frs_binding.end - 2; i++)
{
if ((frs_binding.buffer[i] == '\n') &&
(!whitespace (frs_binding.buffer[i + 1])))
{
frs_binding.end = i;
break;
}
}
return (&frs_binding);
}
REFERENCE **
xrefs_of_manpage (node)
NODE *node;
{
SEARCH_BINDING *reference_section;
REFERENCE **refs = (REFERENCE **)NULL;
int refs_index = 0;
int refs_slots = 0;
long position;
reference_section = find_reference_section (node);
if (reference_section == (SEARCH_BINDING *)NULL)
return ((REFERENCE **)NULL);
/* Grovel the reference section building a list of references found there.
A reference is alphabetic characters followed by non-whitespace text
within parenthesis. */
reference_section->flags = 0;
while ((position = search_forward ("(", reference_section)) != -1)
{
register int start, end;
for (start = position; start > reference_section->start; start--)
if (whitespace (reference_section->buffer[start]))
break;
start++;
for (end = position; end < reference_section->end; end++)
{
if (whitespace (reference_section->buffer[end]))
{
end = start;
break;
}
if (reference_section->buffer[end] == ')')
{
end++;
break;
}
}
if (end != start)
{
REFERENCE *entry;
int len = end - start;
entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
entry->label = (char *)xmalloc (1 + len);
strncpy (entry->label, (reference_section->buffer) + start, len);
entry->label[len] = '\0';
entry->filename = strdup (node->filename);
entry->nodename = strdup (entry->label);
entry->start = start;
entry->end = end;
add_pointer_to_array
(entry, refs_index, refs, refs_slots, 10, REFERENCE *);
}
reference_section->start = position + 1;
}
return (refs);
}
long
locate_manpage_xref (node, start, dir)
NODE *node;
long start;
int dir;
{
register int i, count;
REFERENCE **refs;
long position = -1;
refs = xrefs_of_manpage (node);
if (refs)
{
register int i, count;
REFERENCE *entry;
for (i = 0; refs[i]; i++);
count = i;
if (dir > 0)
{
for (i = 0; entry = refs[i]; i++)
if (entry->start > start)
{
position = entry->start;
break;
}
}
else
{
for (i = count - 1; i > -1; i--)
{
entry = refs[i];
if (entry->start < start)
{
position = entry->start;
break;
}
}
}
info_free_references (refs);
}
return (position);
}
/* This one was a little tricky. The binding buffer that is passed in has
a START and END value of 0 -- strlen (window-line-containing-point).
The BUFFER is a pointer to the start of that line. */
REFERENCE **
manpage_xrefs_in_binding (node, binding)
NODE *node;
SEARCH_BINDING *binding;
{
register int i;
REFERENCE **all_refs = xrefs_of_manpage (node);
REFERENCE **brefs = (REFERENCE **)NULL;
REFERENCE *entry;
int brefs_index = 0;
int brefs_slots = 0;
int start, end;
if (!all_refs)
return ((REFERENCE **)NULL);
start = binding->start + (binding->buffer - node->contents);
end = binding->end + (binding->buffer - node->contents);
for (i = 0; entry = all_refs[i]; i++)
{
if ((entry->start > start) && (entry->end < end))
{
add_pointer_to_array
(entry, brefs_index, brefs, brefs_slots, 10, REFERENCE *);
}
else
{
maybe_free (entry->label);
maybe_free (entry->filename);
maybe_free (entry->nodename);
free (entry);
}
}
free (all_refs);
return (brefs);
}
texinfo-3.7/info/man.h 100666 11732 13 2756 5770343444 13135 0 ustar bfox user /* man.h: Defines and external function declarations for man.c */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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.
Author: Brian J. Fox (bfox@ai.mit.edu) Sat May 6 16:19:13 1995. */
#if !defined (_MAN_H_)
#define _MAN_H_
#define MANPAGE_FILE_BUFFER_NAME "*manpages*"
extern NODE *make_manpage_node (/* char *pagename */);
extern NODE *get_manpage_node (/* FILE_BUFFER *file_buffer, char *pagename */);
extern FILE_BUFFER *create_manpage_file_buffer (/* void */);
extern long locate_manpage_xref (/* NODE *node, long start, int dir */);
extern REFERENCE **xrefs_of_manpage (/* NODE *node */);
extern REFERENCE **manpage_xrefs_in_binding (/* NODE *node, SEARCH_BINDING *binding */);
#endif /* !_MAN_H_ */
texinfo-3.7/info/nodemenu.c 100666 11732 13 20363 5770343303 14173 0 ustar bfox user /* nodemenu.c -- Produce a menu of all visited nodes. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
/* Return a line describing the format of a node information line. */
static char *
nodemenu_format_info ()
{
return ("\n\
* Menu:\n\
(File)Node Lines Size Containing File\n\
---------- ----- ---- ---------------");
}
/* Produce a formatted line of information about NODE. Here is what we want
the output listing to look like:
* Menu:
(File)Node Lines Size Containing File
---------- ----- ---- ---------------
* (emacs)Buffers:: 48 2230 /usr/gnu/info/emacs/emacs-1
* (autoconf)Writing configure.in:: 123 58789 /usr/gnu/info/autoconf/autoconf-1
* (dir)Top:: 40 589 /usr/gnu/info/dir
*/
static char *
format_node_info (node)
NODE *node;
{
register int i, len;
char *parent, *containing_file;
static char *line_buffer = (char *)NULL;
if (!line_buffer)
line_buffer = (char *)xmalloc (1000);
if (node->parent)
{
parent = filename_non_directory (node->parent);
if (!parent)
parent = node->parent;
}
else
parent = (char *)NULL;
containing_file = node->filename;
if (!parent && !*containing_file)
sprintf (line_buffer, "* %s::", node->nodename);
else
{
char *file = (char *)NULL;
if (parent)
file = parent;
else
file = filename_non_directory (containing_file);
if (!file)
file = containing_file;
if (!*file)
file = "dir";
sprintf (line_buffer, "* (%s)%s::", file, node->nodename);
}
len = pad_to (36, line_buffer);
{
int lines = 1;
for (i = 0; i < node->nodelen; i++)
if (node->contents[i] == '\n')
lines++;
sprintf (line_buffer + len, "%d", lines);
}
len = pad_to (44, line_buffer);
sprintf (line_buffer + len, "%d", node->nodelen);
if (node->filename && *(node->filename))
{
len = pad_to (51, line_buffer);
sprintf (line_buffer + len, node->filename);
}
return (strdup (line_buffer));
}
/* Little string comparison routine for qsort (). */
static int
compare_strings (string1, string2)
char **string1, **string2;
{
return (strcasecmp (*string1, *string2));
}
/* The name of the nodemenu node. */
static char *nodemenu_nodename = "*Node Menu*";
/* Produce an informative listing of all the visited nodes, and return it
in a node. If FILTER_FUNC is non-null, it is a function which filters
which nodes will appear in the listing. FILTER_FUNC takes an argument
of NODE, and returns non-zero if the node should appear in the listing. */
NODE *
get_visited_nodes (filter_func)
Function *filter_func;
{
register int i, iw_index;
INFO_WINDOW *info_win;
NODE *node;
char **lines = (char **)NULL;
int lines_index = 0, lines_slots = 0;
if (!info_windows)
return ((NODE *)NULL);
for (iw_index = 0; info_win = info_windows[iw_index]; iw_index++)
{
for (i = 0; i < info_win->nodes_index; i++)
{
node = info_win->nodes[i];
/* We skip mentioning "*Node Menu*" nodes. */
if (internal_info_node_p (node) &&
(strcmp (node->nodename, nodemenu_nodename) == 0))
continue;
if (node && (!filter_func || (*filter_func) (node)))
{
char *line;
line = format_node_info (node);
add_pointer_to_array
(line, lines_index, lines, lines_slots, 20, char *);
}
}
}
/* Sort the array of information lines, if there are any. */
if (lines)
{
register int j, newlen;
char **temp;
qsort (lines, lines_index, sizeof (char *), compare_strings);
/* Delete duplicates. */
for (i = 0, newlen = 1; i < lines_index - 1; i++)
{
if (strcmp (lines[i], lines[i + 1]) == 0)
{
free (lines[i]);
lines[i] = (char *)NULL;
}
else
newlen++;
}
/* We have free ()'d and marked all of the duplicate slots.
Copy the live slots rather than pruning the dead slots. */
temp = (char **)xmalloc ((1 + newlen) * sizeof (char *));
for (i = 0, j = 0; i < lines_index; i++)
if (lines[i])
temp[j++] = lines[i];
temp[j] = (char *)NULL;
free (lines);
lines = temp;
lines_index = newlen;
}
initialize_message_buffer ();
printf_to_message_buffer
("%s", replace_in_documentation
("Here is the menu of nodes you have recently visited.\n\
Select one from this menu, or use `\\[history-node]' in another window.\n"));
printf_to_message_buffer ("%s\n", nodemenu_format_info ());
for (i = 0; (lines != (char **)NULL) && (i < lines_index); i++)
{
printf_to_message_buffer ("%s\n", lines[i]);
free (lines[i]);
}
if (lines)
free (lines);
node = message_buffer_to_node ();
add_gcable_pointer (node->contents);
return (node);
}
DECLARE_INFO_COMMAND (list_visited_nodes,
"Make a window containing a menu of all of the currently visited nodes")
{
WINDOW *new;
NODE *node;
set_remembered_pagetop_and_point (window);
/* If a window is visible and showing the buffer list already, re-use it. */
for (new = windows; new; new = new->next)
{
node = new->node;
if (internal_info_node_p (node) &&
(strcmp (node->nodename, nodemenu_nodename) == 0))
break;
}
/* If we couldn't find an existing window, try to use the next window
in the chain. */
if (!new && window->next)
new = window->next;
/* If we still don't have a window, make a new one to contain the list. */
if (!new)
{
WINDOW *old_active;
old_active = active_window;
active_window = window;
new = window_make_window ((NODE *)NULL);
active_window = old_active;
}
/* If we couldn't make a new window, use this one. */
if (!new)
new = window;
/* Lines do not wrap in this window. */
new->flags |= W_NoWrap;
node = get_visited_nodes ((Function *)NULL);
name_internal_node (node, nodemenu_nodename);
/* Even if this is an internal node, we don't want the window
system to treat it specially. So we turn off the internalness
of it here. */
node->flags &= ~N_IsInternal;
/* If this window is already showing a node menu, reuse the existing node
slot. */
{
int remember_me = 1;
#if defined (NOTDEF)
if (internal_info_node_p (new->node) &&
(strcmp (new->node->nodename, nodemenu_nodename) == 0))
remember_me = 0;
#endif /* NOTDEF */
window_set_node_of_window (new, node);
if (remember_me)
remember_window_and_node (new, node);
}
active_window = new;
}
DECLARE_INFO_COMMAND (select_visited_node,
"Select a node which has been previously visited in a visible window")
{
char *line;
NODE *node;
REFERENCE **menu;
node = get_visited_nodes ((Function *)NULL);
menu = info_menu_of_node (node);
free (node);
line =
info_read_completing_in_echo_area (window, "Select visited node: ", menu);
window = active_window;
/* User aborts, just quit. */
if (!line)
{
info_abort_key (window, 0, 0);
info_free_references (menu);
return;
}
if (*line)
{
REFERENCE *entry;
/* Find the selected label in the references. */
entry = info_get_labeled_reference (line, menu);
if (!entry)
info_error ("The reference disappeared! (%s).", line);
else
info_select_reference (window, entry);
}
free (line);
info_free_references (menu);
if (!info_error_was_printed)
window_clear_echo_area ();
}
texinfo-3.7/info/nodes.c 100666 11732 13 107026 5770343310 13511 0 ustar bfox user /* nodes.c -- How to get an Info file and node. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include
#include
#include
#if defined (HAVE_SYS_FILE_H)
#include
#endif /* HAVE_SYS_FILE_H */
#include
#include
#if defined (HAVE_STRING_H)
#include
#endif /* HAVE_STRING_H */
#include "nodes.h"
#include "search.h"
#include "filesys.h"
#include "info-utils.h"
#if defined (HANDLE_MAN_PAGES)
# include "man.h"
#endif /* HANDLE_MAN_PAGES */
#if !defined (O_RDONLY)
#if defined (HAVE_SYS_FCNTL_H)
#include
#else /* !HAVE_SYS_FCNTL_H */
#include
#endif /* !HAVE_SYS_FCNTL_H */
#endif /* !O_RDONLY */
#if !defined (errno)
extern int errno;
#endif /* !errno */
/* **************************************************************** */
/* */
/* Functions Static to this File */
/* */
/* **************************************************************** */
static void forget_info_file (), remember_info_file ();
static void free_file_buffer_tags (), free_info_tag ();
static void get_nodes_of_tags_table (), get_nodes_of_info_file ();
static void get_tags_of_indirect_tags_table ();
static void info_reload_file_buffer_contents ();
static char *adjust_nodestart ();
static FILE_BUFFER *info_load_file_internal (), *info_find_file_internal ();
static NODE *info_node_of_file_buffer_tags ();
static long get_node_length ();
/* Magic number that RMS used to decide how much a tags table pointer could
be off by. I feel that it should be much smaller, like on the order of
4. */
#define DEFAULT_INFO_FUDGE 1000
/* Passed to *_internal functions. INFO_GET_TAGS says to do what is
neccessary to fill in the nodes or tags arrays in FILE_BUFFER. */
#define INFO_NO_TAGS 0
#define INFO_GET_TAGS 1
/* **************************************************************** */
/* */
/* Global Variables */
/* */
/* **************************************************************** */
/* When non-zero, this is a string describing the recent file error. */
char *info_recent_file_error = (char *)NULL;
/* The list of already loaded nodes. */
FILE_BUFFER **info_loaded_files = (FILE_BUFFER **)NULL;
/* The number of slots currently allocated to LOADED_FILES. */
int info_loaded_files_slots = 0;
/* **************************************************************** */
/* */
/* Public Functions for Node Manipulation */
/* */
/* **************************************************************** */
/* Used to build "dir" menu from "localdir" files found in INFOPATH. */
extern void maybe_build_dir_node ();
/* Return a pointer to a NODE structure for the Info node (FILENAME)NODENAME.
FILENAME can be passed as NULL, in which case the filename of "dir" is used.
NODENAME can be passed as NULL, in which case the nodename of "Top" is used.
If the node cannot be found, return a NULL pointer. */
NODE *
info_get_node (filename, nodename)
char *filename, *nodename;
{
FILE_BUFFER *file_buffer;
NODE *node;
file_buffer = (FILE_BUFFER *)NULL;
info_recent_file_error = (char *)NULL;
info_parse_node (nodename, DONT_SKIP_NEWLINES);
nodename = (char *)NULL;
if (info_parsed_filename)
filename = info_parsed_filename;
if (info_parsed_nodename)
nodename = info_parsed_nodename;
/* If FILENAME is not specified, it defaults to "dir". */
if (!filename)
filename = "dir";
/* If the file to be looked up is "dir", build the contents from all of
the "dir"s and "localdir"s found in INFOPATH. */
if (strcasecmp (filename, "dir") == 0)
maybe_build_dir_node (filename);
/* Find the correct info file. */
file_buffer = info_find_file (filename);
if (!file_buffer)
{
if (filesys_error_number)
info_recent_file_error =
filesys_error_string (filename, filesys_error_number);
return ((NODE *)NULL);
}
node = info_get_node_of_file_buffer (nodename, file_buffer);
/* If the node looked for was "Top", try again looking for the node under
a slightly different name. */
if (!node && (nodename == NULL || strcasecmp (nodename, "Top") == 0))
{
node = info_get_node_of_file_buffer ("Top", file_buffer);
if (!node)
node = info_get_node_of_file_buffer ("top", file_buffer);
if (!node)
node = info_get_node_of_file_buffer ("TOP", file_buffer);
}
return (node);
}
/* Return a pointer to a NODE structure for the Info node NODENAME in
FILE_BUFFER. NODENAME can be passed as NULL, in which case the
nodename of "Top" is used. If the node cannot be found, return a
NULL pointer. */
NODE *
info_get_node_of_file_buffer (nodename, file_buffer)
char *nodename;
FILE_BUFFER *file_buffer;
{
NODE *node = (NODE *)NULL;
/* If we are unable to find the file, we have to give up. There isn't
anything else we can do. */
if (!file_buffer)
return ((NODE *)NULL);
/* If the file buffer was gc'ed, reload the contents now. */
if (!file_buffer->contents)
info_reload_file_buffer_contents (file_buffer);
/* If NODENAME is not specified, it defaults to "Top". */
if (!nodename)
nodename = "Top";
/* If the name of the node that we wish to find is exactly "*", then the
node body is the contents of the entire file. Create and return such
a node. */
if (strcmp (nodename, "*") == 0)
{
node = (NODE *)xmalloc (sizeof (NODE));
node->filename = file_buffer->fullpath;
node->parent = (char *)NULL;
node->nodename = strdup ("*");
node->contents = file_buffer->contents;
node->nodelen = file_buffer->filesize;
node->flags = 0;
}
#if defined (HANDLE_MAN_PAGES)
/* If the file buffer is the magic one associated with manpages, call
the manpage node finding function instead. */
else if (file_buffer->flags & N_IsManPage)
{
node = get_manpage_node (file_buffer, nodename);
}
#endif /* HANDLE_MAN_PAGES */
/* If this is the "main" info file, it might contain a tags table. Search
the tags table for an entry which matches the node that we want. If
there is a tags table, get the file which contains this node, but don't
bother building a node list for it. */
else if (file_buffer->tags)
{
node = info_node_of_file_buffer_tags (file_buffer, nodename);
}
/* Return the results of our node search. */
return (node);
}
/* Locate the file named by FILENAME, and return the information structure
describing this file. The file may appear in our list of loaded files
already, or it may not. If it does not already appear, find the file,
and add it to the list of loaded files. If the file cannot be found,
return a NULL FILE_BUFFER *. */
FILE_BUFFER *
info_find_file (filename)
char *filename;
{
return (info_find_file_internal (filename, INFO_GET_TAGS));
}
/* Load the info file FILENAME, remembering information about it in a
file buffer. */
FILE_BUFFER *
info_load_file (filename)
char *filename;
{
return (info_load_file_internal (filename, INFO_GET_TAGS));
}
/* **************************************************************** */
/* */
/* Private Functions Implementation */
/* */
/* **************************************************************** */
/* The workhorse for info_find_file (). Non-zero 2nd argument says to
try to build a tags table (or otherwise glean the nodes) for this
file once found. By default, we build the tags table, but when this
function is called by info_get_node () when we already have a valid
tags table describing the nodes, it is unnecessary. */
static FILE_BUFFER *
info_find_file_internal (filename, get_tags)
char *filename;
int get_tags;
{
register int i;
register FILE_BUFFER *file_buffer;
/* First try to find the file in our list of already loaded files. */
if (info_loaded_files)
{
for (i = 0; file_buffer = info_loaded_files[i]; i++)
if ((strcmp (filename, file_buffer->filename) == 0) ||
(strcmp (filename, file_buffer->fullpath) == 0) ||
((*filename != '/') &&
strcmp (filename,
filename_non_directory (file_buffer->fullpath)) == 0))
{
struct stat new_info, *old_info;
/* This file is loaded. If the filename that we want is
specifically "dir", then simply return the file buffer. */
if (strcasecmp (filename_non_directory (filename), "dir") == 0)
return (file_buffer);
#if defined (HANDLE_MAN_PAGES)
/* Do the same for the magic MANPAGE file. */
if (file_buffer->flags & N_IsManPage)
return (file_buffer);
#endif /* HANDLE_MAN_PAGES */
/* The file appears to be already loaded, and it is not "dir".
Check to see if it has changed since the last time it was
loaded. */
if (stat (file_buffer->fullpath, &new_info) == -1)
{
filesys_error_number = errno;
return ((FILE_BUFFER *)NULL);
}
old_info = &file_buffer->finfo;
if ((new_info.st_size != old_info->st_size) ||
(new_info.st_mtime != old_info->st_mtime))
{
/* The file has changed. Forget that we ever had loaded it
in the first place. */
forget_info_file (filename);
break;
}
else
{
/* The info file exists, and has not changed since the last
time it was loaded. If the caller requested a nodes list
for this file, and there isn't one here, build the nodes
for this file_buffer. In any case, return the file_buffer
object. */
if (get_tags && !file_buffer->tags)
build_tags_and_nodes (file_buffer);
return (file_buffer);
}
}
}
/* The file wasn't loaded. Try to load it now. */
#if defined (HANDLE_MAN_PAGES)
/* If the name of the file that we want is our special file buffer for
Unix manual pages, then create the file buffer, and return it now. */
if (strcasecmp (filename, MANPAGE_FILE_BUFFER_NAME) == 0)
file_buffer = create_manpage_file_buffer ();
else
#endif /* HANDLE_MAN_PAGES */
file_buffer = info_load_file_internal (filename, get_tags);
/* If the file was loaded, remember the name under which it was found. */
if (file_buffer)
remember_info_file (file_buffer);
return (file_buffer);
}
/* The workhorse function for info_load_file (). Non-zero second argument
says to build a list of tags (or nodes) for this file. This is the
default behaviour when info_load_file () is called, but it is not
necessary when loading a subfile for which we already have tags. */
static FILE_BUFFER *
info_load_file_internal (filename, get_tags)
char *filename;
int get_tags;
{
char *fullpath, *contents;
long filesize;
struct stat finfo;
int retcode;
FILE_BUFFER *file_buffer = (FILE_BUFFER *)NULL;
/* Get the full pathname of this file, as known by the info system.
That is to say, search along INFOPATH and expand tildes, etc. */
fullpath = info_find_fullpath (filename);
/* Did we actually find the file? */
retcode = stat (fullpath, &finfo);
/* If the file referenced by the name returned from info_find_fullpath ()
doesn't exist, then try again with the last part of the filename
appearing in lowercase. */
if (retcode < 0)
{
char *lowered_name;
char *basename;
lowered_name = strdup (filename);
basename = (char *) strrchr (lowered_name, '/');
if (basename)
basename++;
else
basename = lowered_name;
while (*basename)
{
if (isupper (*basename))
*basename = tolower (*basename);
basename++;
}
fullpath = info_find_fullpath (lowered_name);
free (lowered_name);
retcode = stat (fullpath, &finfo);
}
/* If the file wasn't found, give up, returning a NULL pointer. */
if (retcode < 0)
{
filesys_error_number = errno;
return ((FILE_BUFFER *)NULL);
}
/* Otherwise, try to load the file. */
contents = filesys_read_info_file (fullpath, &filesize, &finfo);
if (!contents)
return ((FILE_BUFFER *)NULL);
/* The file was found, and can be read. Allocate FILE_BUFFER and fill
in the various members. */
file_buffer = make_file_buffer ();
file_buffer->filename = strdup (filename);
file_buffer->fullpath = strdup (fullpath);
file_buffer->finfo = finfo;
file_buffer->filesize = filesize;
file_buffer->contents = contents;
if (file_buffer->filesize != file_buffer->finfo.st_size)
file_buffer->flags |= N_IsCompressed;
/* If requested, build the tags and nodes for this file buffer. */
if (get_tags)
build_tags_and_nodes (file_buffer);
return (file_buffer);
}
/* Grovel FILE_BUFFER->contents finding tags and nodes, and filling in the
various slots. This can also be used to rebuild a tag or node table. */
void
build_tags_and_nodes (file_buffer)
FILE_BUFFER *file_buffer;
{
SEARCH_BINDING binding;
long position;
free_file_buffer_tags (file_buffer);
file_buffer->flags &= ~N_HasTagsTable;
/* See if there is a tags table in this info file. */
binding.buffer = file_buffer->contents;
binding.start = file_buffer->filesize;
binding.end = binding.start - 1000;
if (binding.end < 0)
binding.end = 0;
binding.flags = S_FoldCase;
position = search_backward (TAGS_TABLE_END_LABEL, &binding);
/* If there is a tag table, find the start of it, and grovel over it
extracting tag information. */
if (position != -1)
while (1)
{
long tags_table_begin, tags_table_end;
binding.end = position;
binding.start = binding.end - 5 - strlen (TAGS_TABLE_END_LABEL);
if (binding.start < 0)
binding.start = 0;
position = find_node_separator (&binding);
/* For this test, (and all others here) failure indicates a bogus
tags table. Grovel the file. */
if (position == -1)
break;
/* Remember the end of the tags table. */
binding.start = position;
tags_table_end = binding.start;
binding.end = 0;
/* Locate the start of the tags table. */
position = search_backward (TAGS_TABLE_BEG_LABEL, &binding);
if (position == -1)
break;
binding.end = position;
binding.start = binding.end - 5 - strlen (TAGS_TABLE_BEG_LABEL);
position = find_node_separator (&binding);
if (position == -1)
break;
/* The file contains a valid tags table. Fill the FILE_BUFFER's
tags member. */
file_buffer->flags |= N_HasTagsTable;
tags_table_begin = position;
/* If this isn't an indirect tags table, just remember the nodes
described locally in this tags table. Note that binding.end
is pointing to just after the beginning label. */
binding.start = binding.end;
binding.end = file_buffer->filesize;
if (!looking_at (TAGS_TABLE_IS_INDIRECT_LABEL, &binding))
{
binding.start = tags_table_begin;
binding.end = tags_table_end;
get_nodes_of_tags_table (file_buffer, &binding);
return;
}
else
{
/* This is an indirect tags table. Build TAGS member. */
SEARCH_BINDING indirect;
indirect.start = tags_table_begin;
indirect.end = 0;
indirect.buffer = binding.buffer;
indirect.flags = S_FoldCase;
position = search_backward (INDIRECT_TAGS_TABLE_LABEL, &indirect);
if (position == -1)
{
/* This file is malformed. Give up. */
return;
}
indirect.start = position;
indirect.end = tags_table_begin;
binding.start = tags_table_begin;
binding.end = tags_table_end;
get_tags_of_indirect_tags_table (file_buffer, &indirect, &binding);
return;
}
}
/* This file doesn't contain any kind of tags table. Grovel the
file and build node entries for it. */
get_nodes_of_info_file (file_buffer);
}
/* Search through FILE_BUFFER->contents building an array of TAG *,
one entry per each node present in the file. Store the tags in
FILE_BUFFER->tags, and the number of allocated slots in
FILE_BUFFER->tags_slots. */
static void
get_nodes_of_info_file (file_buffer)
FILE_BUFFER *file_buffer;
{
long nodestart;
int tags_index = 0;
SEARCH_BINDING binding;
binding.buffer = file_buffer->contents;
binding.start = 0;
binding.end = file_buffer->filesize;
binding.flags = S_FoldCase;
while ((nodestart = find_node_separator (&binding)) != -1)
{
int start, end;
char *nodeline;
TAG *entry;
/* Skip past the characters just found. */
binding.start = nodestart;
binding.start += skip_node_separator (binding.buffer + binding.start);
/* Move to the start of the line defining the node. */
nodeline = binding.buffer + binding.start;
/* Find "Node:" */
start = string_in_line (INFO_NODE_LABEL, nodeline);
/* If not there, this is not the start of a node. */
if (start == -1)
continue;
/* Find the start of the nodename. */
start += skip_whitespace (nodeline + start);
/* Find the end of the nodename. */
end = start +
skip_node_characters (nodeline + start, DONT_SKIP_NEWLINES);
/* Okay, we have isolated the node name, and we know where the
node starts. Remember this information in a NODE structure. */
entry = (TAG *)xmalloc (sizeof (TAG));
entry->nodename = (char *)xmalloc (1 + (end - start));
strncpy (entry->nodename, nodeline + start, end - start);
entry->nodename[end - start] = '\0';
entry->nodestart = nodestart;
{
SEARCH_BINDING node_body;
node_body.buffer = binding.buffer + binding.start;
node_body.start = 0;
node_body.end = binding.end - binding.start;
node_body.flags = S_FoldCase;
entry->nodelen = get_node_length (&node_body);
}
entry->filename = file_buffer->fullpath;
/* Add this tag to the array of tag structures in this FILE_BUFFER. */
add_pointer_to_array (entry, tags_index, file_buffer->tags,
file_buffer->tags_slots, 100, TAG *);
}
}
/* Return the length of the node which starts at BINDING. */
static long
get_node_length (binding)
SEARCH_BINDING *binding;
{
register int i;
char *body;
/* From the Info-RFC file:
[A node] ends with either a ^_, a ^L, or the end of file. */
for (i = binding->start, body = binding->buffer; i < binding->end; i++)
{
if (body[i] == INFO_FF || body[i] == INFO_COOKIE)
break;
}
return ((long) i - binding->start);
}
/* Build and save the array of nodes in FILE_BUFFER by searching through the
contents of BUFFER_BINDING for a tags table, and groveling the contents. */
static void
get_nodes_of_tags_table (file_buffer, buffer_binding)
FILE_BUFFER *file_buffer;
SEARCH_BINDING *buffer_binding;
{
int offset, tags_index = 0;
SEARCH_BINDING *search;
long position;
search = copy_binding (buffer_binding);
/* Find the start of the tags table. */
position = find_tags_table (search);
/* If none, we're all done. */
if (position == -1)
return;
/* Move to one character before the start of the actual table. */
search->start = position;
search->start += skip_node_separator (search->buffer + search->start);
search->start += strlen (TAGS_TABLE_BEG_LABEL);
search->start--;
/* The tag table consists of lines containing node names and positions.
Do each line until we find one that doesn't contain a node name. */
while ((position = search_forward ("\n", search)) != -1)
{
TAG *entry;
char *nodedef;
/* Prepare to skip this line. */
search->start = position;
search->start++;
/* Skip past informative "(Indirect)" tags table line. */
if (!tags_index && looking_at (TAGS_TABLE_IS_INDIRECT_LABEL, search))
continue;
/* Find the label preceding the node name. */
offset =
string_in_line (INFO_NODE_LABEL, search->buffer + search->start);
/* If not there, not a defining line, so we must be out of the
tags table. */
if (offset == -1)
break;
/* Point to the beginning of the node definition. */
search->start += offset;
nodedef = search->buffer + search->start;
nodedef += skip_whitespace (nodedef);
/* Move past the node's name. */
for (offset = 0;
(nodedef[offset]) && (nodedef[offset] != INFO_TAGSEP);
offset++);
if (nodedef[offset] != INFO_TAGSEP)
continue;
entry = (TAG *)xmalloc (sizeof (TAG));
entry->nodename = (char *)xmalloc (1 + offset);
strncpy (entry->nodename, nodedef, offset);
entry->nodename[offset] = '\0';
offset++;
entry->nodestart = (long) atol (nodedef + offset);
/* We don't know the length of this node yet. */
entry->nodelen = -1;
/* The filename of this node is currently known as the same as the
name of this file. */
entry->filename = file_buffer->fullpath;
/* Add this node structure to the array of node structures in this
FILE_BUFFER. */
add_pointer_to_array (entry, tags_index, file_buffer->tags,
file_buffer->tags_slots, 100, TAG *);
}
free (search);
}
/* A structure used only in get_tags_of_indirect_tags_table () to hold onto
an intermediate value. */
typedef struct {
char *filename;
long first_byte;
} SUBFILE;
/* Remember in FILE_BUFFER the nodenames, subfilenames, and offsets within the
subfiles of every node which appears in TAGS_BINDING. The 2nd argument is
a binding surrounding the indirect files list. */
static void
get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding)
FILE_BUFFER *file_buffer;
SEARCH_BINDING *indirect_binding, *tags_binding;
{
register int i;
SUBFILE **subfiles = (SUBFILE **)NULL;
int subfiles_index = 0, subfiles_slots = 0;
TAG *entry;
/* First get the list of tags from the tags table. Then lookup the
associated file in the indirect list for each tag, and update it. */
get_nodes_of_tags_table (file_buffer, tags_binding);
/* We have the list of tags in file_buffer->tags. Get the list of
subfiles from the indirect table. */
{
char *start, *end, *line;
SUBFILE *subfile;
start = indirect_binding->buffer + indirect_binding->start;
end = indirect_binding->buffer + indirect_binding->end;
line = start;
while (line < end)
{
int colon;
colon = string_in_line (":", line);
if (colon == -1)
break;
subfile = (SUBFILE *)xmalloc (sizeof (SUBFILE));
subfile->filename = (char *)xmalloc (colon);
strncpy (subfile->filename, line, colon - 1);
subfile->filename[colon - 1] = '\0';
subfile->first_byte = (long) atol (line + colon);
add_pointer_to_array
(subfile, subfiles_index, subfiles, subfiles_slots, 10, SUBFILE *);
while (*line++ != '\n');
}
}
/* If we have successfully built the indirect files table, then
merge the information in the two tables. */
if (!subfiles)
{
free_file_buffer_tags (file_buffer);
return;
}
else
{
register int tags_index;
long header_length;
SEARCH_BINDING binding;
/* Find the length of the header of the file containing the indirect
tags table. This header appears at the start of every file. We
want the absolute position of each node within each subfile, so
we subtract the start of the containing subfile from the logical
position of the node, and then add the length of the header in. */
binding.buffer = file_buffer->contents;
binding.start = 0;
binding.end = file_buffer->filesize;
binding.flags = S_FoldCase;
header_length = find_node_separator (&binding);
if (header_length == -1)
header_length = 0;
/* Build the file buffer's list of subfiles. */
{
char *containing_dir, *temp;
int len_containing_dir;
containing_dir = strdup (file_buffer->fullpath);
temp = (char *) strrchr (containing_dir, '/');
if (temp)
*temp = '\0';
len_containing_dir = strlen (containing_dir);
for (i = 0; subfiles[i]; i++);
file_buffer->subfiles = (char **) xmalloc ((1 + i) * sizeof (char *));
for (i = 0; subfiles[i]; i++)
{
char *fullpath;
fullpath = (char *) xmalloc
(2 + strlen (subfiles[i]->filename) + len_containing_dir);
sprintf (fullpath, "%s/%s",
containing_dir, subfiles[i]->filename);
file_buffer->subfiles[i] = fullpath;
}
file_buffer->subfiles[i] = (char *)NULL;
free (containing_dir);
}
/* For each node in the file's tags table, remember the starting
position. */
for (tags_index = 0;
entry = file_buffer->tags[tags_index];
tags_index++)
{
for (i = 0;
subfiles[i] && entry->nodestart >= subfiles[i]->first_byte;
i++);
/* If the Info file containing the indirect tags table is
malformed, then give up. */
if (!i)
{
/* The Info file containing the indirect tags table is
malformed. Give up. */
for (i = 0; subfiles[i]; i++)
{
free (subfiles[i]->filename);
free (subfiles[i]);
free (file_buffer->subfiles[i]);
}
file_buffer->subfiles = (char **)NULL;
free_file_buffer_tags (file_buffer);
return;
}
/* SUBFILES[i] is the index of the first subfile whose logical
first byte is greater than the logical offset of this node's
starting position. This means that the subfile directly
preceding this one is the one containing the node. */
entry->filename = file_buffer->subfiles[i - 1];
entry->nodestart -= subfiles[i -1]->first_byte;
entry->nodestart += header_length;
entry->nodelen = -1;
}
/* We have successfully built the tags table. Remember that it
was indirect. */
file_buffer->flags |= N_TagsIndirect;
}
/* Free the structures assigned to SUBFILES. Free the names as well
as the structures themselves, then finally, the array. */
for (i = 0; subfiles[i]; i++)
{
free (subfiles[i]->filename);
free (subfiles[i]);
}
free (subfiles);
}
/* Return the node from FILE_BUFFER which matches NODENAME by searching
the tags table in FILE_BUFFER. If the node could not be found, return
a NULL pointer. */
static NODE *
info_node_of_file_buffer_tags (file_buffer, nodename)
FILE_BUFFER *file_buffer;
char *nodename;
{
register int i;
TAG *tag;
for (i = 0; tag = file_buffer->tags[i]; i++)
if (strcmp (nodename, tag->nodename) == 0)
{
FILE_BUFFER *subfile;
subfile = info_find_file_internal (tag->filename, INFO_NO_TAGS);
if (!subfile)
return ((NODE *)NULL);
if (!subfile->contents)
{
info_reload_file_buffer_contents (subfile);
if (!subfile->contents)
return ((NODE *)NULL);
}
/* If we were able to find this file and load it, then return
the node within it. */
{
NODE *node;
node = (NODE *)xmalloc (sizeof (NODE));
node->filename = (subfile->fullpath);
node->nodename = tag->nodename;
node->contents = subfile->contents + tag->nodestart;
node->flags = 0;
node->parent = (char *)NULL;
if (file_buffer->flags & N_HasTagsTable)
{
node->flags |= N_HasTagsTable;
if (file_buffer->flags & N_TagsIndirect)
{
node->flags |= N_TagsIndirect;
node->parent = file_buffer->fullpath;
}
}
if (subfile->flags & N_IsCompressed)
node->flags |= N_IsCompressed;
/* If TAG->nodelen hasn't been calculated yet, then we aren't
in a position to trust the entry pointer. Adjust things so
that ENTRY->nodestart gets the exact address of the start of
the node separator which starts this node, and NODE->contents
gets the address of the line defining this node. If we cannot
do that, the node isn't really here. */
if (tag->nodelen == -1)
{
int min, max;
char *node_sep;
SEARCH_BINDING node_body;
char *buff_end;
min = max = DEFAULT_INFO_FUDGE;
if (tag->nodestart < DEFAULT_INFO_FUDGE)
min = tag->nodestart;
if (DEFAULT_INFO_FUDGE >
(subfile->filesize - tag->nodestart))
max = subfile->filesize - tag->nodestart;
/* NODE_SEP gets the address of the separator which defines
this node, or (char *)NULL if the node wasn't found.
NODE->contents is side-effected to point to right after
the separator. */
node_sep = adjust_nodestart (node, min, max);
if (node_sep == (char *)NULL)
{
free (node);
return ((NODE *)NULL);
}
/* Readjust tag->nodestart. */
tag->nodestart = node_sep - subfile->contents;
/* Calculate the length of the current node. */
buff_end = subfile->contents + subfile->filesize;
node_body.buffer = node->contents;
node_body.start = 0;
node_body.end = buff_end - node_body.buffer;
node_body.flags = 0;
tag->nodelen = get_node_length (&node_body);
}
else
{
/* Since we know the length of this node, we have already
adjusted tag->nodestart to point to the exact start of
it. Simply skip the node separator. */
node->contents += skip_node_separator (node->contents);
}
node->nodelen = tag->nodelen;
return (node);
}
}
/* There was a tag table for this file, and the node wasn't found.
Return NULL, since this file doesn't contain the desired node. */
return ((NODE *)NULL);
}
/* **************************************************************** */
/* */
/* Managing file_buffers, nodes, and tags. */
/* */
/* **************************************************************** */
/* Create a new, empty file buffer. */
FILE_BUFFER *
make_file_buffer ()
{
FILE_BUFFER *file_buffer;
file_buffer = (FILE_BUFFER *)xmalloc (sizeof (FILE_BUFFER));
file_buffer->filename = file_buffer->fullpath = (char *)NULL;
file_buffer->contents = (char *)NULL;
file_buffer->tags = (TAG **)NULL;
file_buffer->subfiles = (char **)NULL;
file_buffer->tags_slots = 0;
file_buffer->flags = 0;
return (file_buffer);
}
/* Add FILE_BUFFER to our list of already loaded info files. */
static void
remember_info_file (file_buffer)
FILE_BUFFER *file_buffer;
{
int i;
for (i = 0; info_loaded_files && info_loaded_files[i]; i++)
;
add_pointer_to_array (file_buffer, i, info_loaded_files,
info_loaded_files_slots, 10, FILE_BUFFER *);
}
/* Forget the contents, tags table, nodes list, and names of FILENAME. */
static void
forget_info_file (filename)
char *filename;
{
register int i;
FILE_BUFFER *file_buffer;
if (!info_loaded_files)
return;
for (i = 0; file_buffer = info_loaded_files[i]; i++)
if ((strcmp (filename, file_buffer->filename) == 0) ||
(strcmp (filename, file_buffer->fullpath) == 0))
{
free (file_buffer->filename);
free (file_buffer->fullpath);
if (file_buffer->contents)
free (file_buffer->contents);
/* Note that free_file_buffer_tags () also kills the subfiles
list, since the subfiles list is only of use in conjunction
with tags. */
free_file_buffer_tags (file_buffer);
while (info_loaded_files[i] = info_loaded_files[++i])
;
break;
}
}
/* Free the tags (if any) associated with FILE_BUFFER. */
static void
free_file_buffer_tags (file_buffer)
FILE_BUFFER *file_buffer;
{
register int i;
if (file_buffer->tags)
{
register TAG *tag;
for (i = 0; tag = file_buffer->tags[i]; i++)
free_info_tag (tag);
free (file_buffer->tags);
file_buffer->tags = (TAG **)NULL;
file_buffer->tags_slots = 0;
}
if (file_buffer->subfiles)
{
for (i = 0; file_buffer->subfiles[i]; i++)
free (file_buffer->subfiles[i]);
free (file_buffer->subfiles);
file_buffer->subfiles = (char **)NULL;
}
}
/* Free the data associated with TAG, as well as TAG itself. */
static void
free_info_tag (tag)
TAG *tag;
{
free (tag->nodename);
/* We don't free tag->filename, because that filename is part of the
subfiles list for the containing FILE_BUFFER. free_info_tags ()
will free the subfiles when it is appropriate. */
free (tag);
}
/* Load the contents of FILE_BUFFER->contents. This function is called
when a file buffer was loaded, and then in order to conserve memory, the
file buffer's contents were freed and the pointer was zero'ed. Note that
the file was already loaded at least once successfully, so the tags and/or
nodes members are still correctly filled. */
static void
info_reload_file_buffer_contents (fb)
FILE_BUFFER *fb;
{
#if defined (HANDLE_MAN_PAGES)
/* If this is the magic manpage node, don't try to reload, just give up. */
if (fb->flags & N_IsManPage)
return;
#endif
fb->flags &= ~N_IsCompressed;
/* Let the filesystem do all the work for us. */
fb->contents =
filesys_read_info_file (fb->fullpath, &(fb->filesize), &(fb->finfo));
if (fb->filesize != (long) (fb->finfo.st_size))
fb->flags |= N_IsCompressed;
}
/* Return the actual starting memory location of NODE, side-effecting
NODE->contents. MIN and MAX are bounds for a search if one is necessary.
Because of the way that tags are implemented, the physical nodestart may
not actually be where the tag says it is. If that is the case, but the
node was found anyway, set N_UpdateTags in NODE->flags. If the node is
found, return non-zero. NODE->contents is returned positioned right after
the node separator that precedes this node, while the return value is
position directly on the separator that precedes this node. If the node
could not be found, return a NULL pointer. */
static char *
adjust_nodestart (node, min, max)
NODE *node;
int min, max;
{
long position;
SEARCH_BINDING node_body;
/* Define the node body. */
node_body.buffer = node->contents;
node_body.start = 0;
node_body.end = max;
node_body.flags = 0;
/* Try the optimal case first. Who knows? This file may actually be
formatted (mostly) correctly. */
if (node_body.buffer[0] != INFO_COOKIE && min > 2)
node_body.buffer -= 3;
position = find_node_separator (&node_body);
/* If we found a node start, then check it out. */
if (position != -1)
{
int sep_len;
sep_len = skip_node_separator (node->contents);
/* If we managed to skip a node separator, then check for this node
being the right one. */
if (sep_len != 0)
{
char *nodedef, *nodestart;
int offset;
nodestart = node_body.buffer + position + sep_len;
nodedef = nodestart;
offset = string_in_line (INFO_NODE_LABEL, nodedef);
if (offset != -1)
{
nodedef += offset;
nodedef += skip_whitespace (nodedef);
offset = skip_node_characters (nodedef, DONT_SKIP_NEWLINES);
if ((offset == strlen (node->nodename)) &&
(strncmp (node->nodename, nodedef, offset) == 0))
{
node->contents = nodestart;
return (node_body.buffer + position);
}
}
}
}
/* Oh well, I guess we have to try to find it in a larger area. */
node_body.buffer = node->contents - min;
node_body.start = 0;
node_body.end = min + max;
node_body.flags = 0;
position = find_node_in_binding (node->nodename, &node_body);
/* If the node couldn't be found, we lose big. */
if (position == -1)
return ((char *)NULL);
/* Otherwise, the node was found, but the tags table could need updating
(if we used a tag to get here, that is). Set the flag in NODE->flags. */
node->contents = node_body.buffer + position;
node->contents += skip_node_separator (node->contents);
if (node->flags & N_HasTagsTable)
node->flags |= N_UpdateTags;
return (node_body.buffer + position);
}
texinfo-3.7/info/nodes.h 100666 11732 13 16553 5770343447 13515 0 ustar bfox user /* nodes.h -- How we represent nodes internally. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_NODES_H_)
#define _NODES_H_
#include "general.h"
/* **************************************************************** */
/* */
/* User Code Interface */
/* */
/* **************************************************************** */
/* Callers generally only want the node itself. This structure is used
to pass node information around. None of the information in this
structure should ever be directly freed. The structure itself can
be passed to free (). Note that NODE->parent is non-null if this
node's file is a subfile. In that case, NODE->parent is the logical
name of the file containing this node. Both names are given as full
paths, so you might have: node->filename = "/usr/gnu/info/emacs-1",
with node->parent = "/usr/gnu/info/emacs". */
typedef struct {
char *filename; /* The physical file containing this node. */
char *parent; /* Non-null is the logical file name. */
char *nodename; /* The name of this node. */
char *contents; /* Characters appearing in this node. */
long nodelen; /* The length of the CONTENTS member. */
int flags; /* See immediately below. */
} NODE;
/* Defines that can appear in NODE->flags. All informative. */
#define N_HasTagsTable 0x01 /* This node was found through a tags table. */
#define N_TagsIndirect 0x02 /* The tags table was an indirect one. */
#define N_UpdateTags 0x04 /* The tags table is out of date. */
#define N_IsCompressed 0x08 /* The file is compressed on disk. */
#define N_IsInternal 0x10 /* This node was made by Info. */
#define N_CannotGC 0x20 /* File buffer cannot be gc'ed. */
#define N_IsManPage 0x40 /* This node is a Un*x manpage. */
/* **************************************************************** */
/* */
/* Internal Data Structures */
/* */
/* **************************************************************** */
/* Some defines describing details about Info file contents. */
/* String Constants. */
#define INFO_FILE_LABEL "File:"
#define INFO_NODE_LABEL "Node:"
#define INFO_PREV_LABEL "Prev:"
#define INFO_ALTPREV_LABEL "Previous:"
#define INFO_NEXT_LABEL "Next:"
#define INFO_UP_LABEL "Up:"
#define INFO_MENU_LABEL "\n* Menu:"
#define INFO_MENU_ENTRY_LABEL "\n* "
#define INFO_XREF_LABEL "*Note"
#define TAGS_TABLE_END_LABEL "\nEnd Tag Table"
#define TAGS_TABLE_BEG_LABEL "Tag Table:\n"
#define INDIRECT_TAGS_TABLE_LABEL "Indirect:\n"
#define TAGS_TABLE_IS_INDIRECT_LABEL "(Indirect)"
/* Character Constants. */
#define INFO_COOKIE '\037'
#define INFO_FF '\014'
#define INFO_TAGSEP '\177'
/* For each logical file that we have loaded, we keep a list of the names
of the nodes that are found in that file. A pointer to a node in an
info file is called a "tag". For split files, the tag pointer is
"indirect"; that is, the pointer also contains the name of the split
file where the node can be found. For non-split files, the filename
member in the structure below simply contains the name of the current
file. The following structure describes a single node within a file. */
typedef struct {
char *filename; /* The file where this node can be found. */
char *nodename; /* The node pointed to by this tag. */
long nodestart; /* The offset of the start of this node. */
long nodelen; /* The length of this node. */
} TAG;
/* The following structure is used to remember information about the contents
of Info files that we have loaded at least once before. The FINFO member
is present so that we can reload the file if it has been modified since
last being loaded. All of the arrays appearing within this structure
are NULL terminated, and each array which can change size has a
corresponding SLOTS member which says how many slots have been allocated
(with malloc ()) for this array. */
typedef struct {
char *filename; /* The filename used to find this file. */
char *fullpath; /* The full pathname of this info file. */
struct stat finfo; /* Information about this file. */
char *contents; /* The contents of this particular file. */
long filesize; /* The number of bytes this file expands to. */
char **subfiles; /* If non-null, the list of subfiles. */
TAG **tags; /* If non-null, the indirect tags table. */
int tags_slots; /* Number of slots allocated for TAGS. */
int flags; /* Various flags. Mimics of N_* flags. */
} FILE_BUFFER;
/* **************************************************************** */
/* */
/* Externally Visible Functions */
/* */
/* **************************************************************** */
/* Array of FILE_BUFFER * which represents the currently loaded info files. */
extern FILE_BUFFER **info_loaded_files;
/* The number of slots currently allocated to INFO_LOADED_FILES. */
extern int info_loaded_files_slots;
/* Locate the file named by FILENAME, and return the information structure
describing this file. The file may appear in our list of loaded files
already, or it may not. If it does not already appear, find the file,
and add it to the list of loaded files. If the file cannot be found,
return a NULL FILE_BUFFER *. */
extern FILE_BUFFER *info_find_file ();
/* Force load the file named FILENAME, and return the information structure
describing this file. Even if the file was already loaded, this loads
a new buffer, rebuilds tags and nodes, and returns a new FILE_BUFFER *. */
extern FILE_BUFFER *info_load_file ();
/* Return a pointer to a NODE structure for the Info node (FILENAME)NODENAME.
FILENAME can be passed as NULL, in which case the filename of "dir" is used.
NODENAME can be passed as NULL, in which case the nodename of "Top" is used.
If the node cannot be found, return a NULL pointer. */
extern NODE *info_get_node ();
/* Return a pointer to a NODE structure for the Info node NODENAME in
FILE_BUFFER. NODENAME can be passed as NULL, in which case the
nodename of "Top" is used. If the node cannot be found, return a
NULL pointer. */
extern NODE *info_get_node_of_file_buffer ();
/* Grovel FILE_BUFFER->contents finding tags and nodes, and filling in the
various slots. This can also be used to rebuild a tag or node table. */
extern void build_tags_and_nodes ();
/* When non-zero, this is a string describing the most recent file error. */
extern char *info_recent_file_error;
/* Create a new, empty file buffer. */
extern FILE_BUFFER *make_file_buffer ();
#endif /* !_NODES_H_ */
texinfo-3.7/info/search.c 100666 11732 13 32670 5770343314 13634 0 ustar bfox user /* search.c -- How to search large bodies of text. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include
#include
#include
#include "general.h"
#include "search.h"
#include "nodes.h"
#if !defined (NULL)
# define NULL 0x0
#endif /* !NULL */
/* The search functions take two arguments:
1) a string to search for, and
2) a pointer to a SEARCH_BINDING which contains the buffer, start,
and end of the search.
They return a long, which is the offset from the start of the buffer
at which the match was found. An offset of -1 indicates failure. */
/* A function which makes a binding with buffer and bounds. */
SEARCH_BINDING *
make_binding (buffer, start, end)
char *buffer;
long start, end;
{
SEARCH_BINDING *binding;
binding = (SEARCH_BINDING *)xmalloc (sizeof (SEARCH_BINDING));
binding->buffer = buffer;
binding->start = start;
binding->end = end;
binding->flags = 0;
return (binding);
}
/* Make a copy of BINDING without duplicating the data. */
SEARCH_BINDING *
copy_binding (binding)
SEARCH_BINDING *binding;
{
SEARCH_BINDING *copy;
copy = make_binding (binding->buffer, binding->start, binding->end);
copy->flags = binding->flags;
return (copy);
}
/* **************************************************************** */
/* */
/* The Actual Searching Functions */
/* */
/* **************************************************************** */
/* Search forwards or backwards for the text delimited by BINDING.
The search is forwards if BINDING->start is greater than BINDING->end. */
long
search (string, binding)
char *string;
SEARCH_BINDING *binding;
{
long result;
/* If the search is backwards, then search backwards, otherwise forwards. */
if (binding->start > binding->end)
result = search_backward (string, binding);
else
result = search_forward (string, binding);
return (result);
}
/* Search forwards for STRING through the text delimited in BINDING. */
long
search_forward (string, binding)
char *string;
SEARCH_BINDING *binding;
{
register int c, i, len;
register char *buff, *end;
char *alternate = (char *)NULL;
len = strlen (string);
/* We match characters in the search buffer against STRING and ALTERNATE.
ALTERNATE is a case reversed version of STRING; this is cheaper than
case folding each character before comparison. Alternate is only
used if the case folding bit is turned on in the passed BINDING. */
if (binding->flags & S_FoldCase)
{
alternate = strdup (string);
for (i = 0; i < len; i++)
{
if (islower (alternate[i]))
alternate[i] = toupper (alternate[i]);
else if (isupper (alternate[i]))
alternate[i] = tolower (alternate[i]);
}
}
buff = binding->buffer + binding->start;
end = binding->buffer + binding->end + 1;
while (buff < (end - len))
{
for (i = 0; i < len; i++)
{
c = buff[i];
if ((c != string[i]) && (!alternate || c != alternate[i]))
break;
}
if (!string[i])
{
if (alternate)
free (alternate);
if (binding->flags & S_SkipDest)
buff += len;
return ((long) (buff - binding->buffer));
}
buff++;
}
if (alternate)
free (alternate);
return ((long) -1);
}
/* Search for STRING backwards through the text delimited in BINDING. */
long
search_backward (input_string, binding)
char *input_string;
SEARCH_BINDING *binding;
{
register int c, i, len;
register char *buff, *end;
char *string;
char *alternate = (char *)NULL;
len = strlen (input_string);
/* Reverse the characters in the search string. */
string = (char *)xmalloc (1 + len);
for (c = 0, i = len - 1; input_string[c]; c++, i--)
string[i] = input_string[c];
string[c] = '\0';
/* We match characters in the search buffer against STRING and ALTERNATE.
ALTERNATE is a case reversed version of STRING; this is cheaper than
case folding each character before comparison. ALTERNATE is only
used if the case folding bit is turned on in the passed BINDING. */
if (binding->flags & S_FoldCase)
{
alternate = strdup (string);
for (i = 0; i < len; i++)
{
if (islower (alternate[i]))
alternate[i] = toupper (alternate[i]);
else if (isupper (alternate[i]))
alternate[i] = tolower (alternate[i]);
}
}
buff = binding->buffer + binding->start - 1;
end = binding->buffer + binding->end;
while (buff > (end + len))
{
for (i = 0; i < len; i++)
{
c = *(buff - i);
if (c != string[i] && (alternate && c != alternate[i]))
break;
}
if (!string[i])
{
free (string);
if (alternate)
free (alternate);
if (binding->flags & S_SkipDest)
buff -= len;
return ((long) (1 + (buff - binding->buffer)));
}
buff--;
}
free (string);
if (alternate)
free (alternate);
return ((long) -1);
}
/* Find STRING in LINE, returning the offset of the end of the string.
Return an offset of -1 if STRING does not appear in LINE. The search
is bound by the end of the line (i.e., either NEWLINE or 0). */
int
string_in_line (string, line)
char *string, *line;
{
register int end;
SEARCH_BINDING binding;
/* Find the end of the line. */
for (end = 0; line[end] && line[end] != '\n'; end++);
/* Search for STRING within these confines. */
binding.buffer = line;
binding.start = 0;
binding.end = end;
binding.flags = S_FoldCase | S_SkipDest;
return (search_forward (string, &binding));
}
/* Return non-zero if STRING is the first text to appear at BINDING. */
int
looking_at (string, binding)
char *string;
SEARCH_BINDING *binding;
{
long search_end;
search_end = search (string, binding);
/* If the string was not found, SEARCH_END is -1. If the string was found,
but not right away, SEARCH_END is != binding->start. Otherwise, the
string was found at binding->start. */
return (search_end == binding->start);
}
/* **************************************************************** */
/* */
/* Small String Searches */
/* */
/* **************************************************************** */
/* Function names that start with "skip" are passed a string, and return
an offset from the start of that string. Function names that start
with "find" are passed a SEARCH_BINDING, and return an absolute position
marker of the item being searched for. "Find" functions return a value
of -1 if the item being looked for couldn't be found. */
/* Return the index of the first non-whitespace character in STRING. */
int
skip_whitespace (string)
char *string;
{
register int i;
for (i = 0; string && whitespace (string[i]); i++);
return (i);
}
/* Return the index of the first non-whitespace or newline character in
STRING. */
int
skip_whitespace_and_newlines (string)
char *string;
{
register int i;
for (i = 0; string && (whitespace (string[i]) || string[i] == '\n'); i++);
return (i);
}
/* Return the index of the first whitespace character in STRING. */
int
skip_non_whitespace (string)
char *string;
{
register int i;
for (i = 0; string && !whitespace (string[i]); i++);
return (i);
}
/* Return the index of the first non-node character in STRING. Note that
this function contains quite a bit of hair to ignore periods in some
special cases. This is because we here at GNU ship some info files which
contain nodenames that contain periods. No such nodename can start with
a period, or continue with whitespace, newline, or ')' immediately following
the period. If second argument NEWLINES_OKAY is non-zero, newlines should
be skipped while parsing out the nodename specification. */
int
skip_node_characters (string, newlines_okay)
char *string;
int newlines_okay;
{
register int c, i = 0;
int paren_seen = 0;
int paren = 0;
/* Handle special case. This is when another function has parsed out the
filename component of the node name, and we just want to parse out the
nodename proper. In that case, a period at the start of the nodename
indicates an empty nodename. */
if (string && *string == '.')
return (0);
if (string && *string == '(')
{
paren++;
paren_seen++;
i++;
}
for (; string && (c = string[i]); i++)
{
if (paren)
{
if (c == '(')
paren++;
else if (c == ')')
paren--;
continue;
}
/* If the character following the close paren is a space or period,
then this node name has no more characters associated with it. */
if (c == '\t' ||
c == ',' ||
c == INFO_TAGSEP ||
((!newlines_okay) && (c == '\n')) ||
((paren_seen && string[i - 1] == ')') &&
(c == ' ' || c == '.')) ||
(c == '.' &&
((!string[i + 1]) ||
(whitespace_or_newline (string[i + 1])) ||
(string[i + 1] == ')'))))
break;
}
return (i);
}
/* **************************************************************** */
/* */
/* Searching FILE_BUFFER's */
/* */
/* **************************************************************** */
/* Return the absolute position of the first occurence of a node separator in
BINDING-buffer. The search starts at BINDING->start. Return -1 if no node
separator was found. */
long
find_node_separator (binding)
SEARCH_BINDING *binding;
{
register long i;
char *body;
body = binding->buffer;
/* A node is started by [^L]^_[^L]\n. That is to say, the C-l's are
optional, but the DELETE and NEWLINE are not. This separator holds
true for all separated elements in an Info file, including the tags
table (if present) and the indirect tags table (if present). */
for (i = binding->start; i < binding->end - 1; i++)
if (((body[i] == INFO_FF && body[i + 1] == INFO_COOKIE) &&
(body[i + 2] == '\n' ||
(body[i + 2] == INFO_FF && body[i + 3] == '\n'))) ||
((body[i] == INFO_COOKIE) &&
(body[i + 1] == '\n' ||
(body[i + 1] == INFO_FF && body[i + 2] == '\n'))))
return (i);
return (-1);
}
/* Return the length of the node separator characters that BODY is
currently pointing at. */
int
skip_node_separator (body)
char *body;
{
register int i;
i = 0;
if (body[i] == INFO_FF)
i++;
if (body[i++] != INFO_COOKIE)
return (0);
if (body[i] == INFO_FF)
i++;
if (body[i++] != '\n')
return (0);
return (i);
}
/* Return the number of characters from STRING to the start of
the next line. */
int
skip_line (string)
char *string;
{
register int i;
for (i = 0; string && string[i] && string[i] != '\n'; i++);
if (string[i] == '\n')
i++;
return (i);
}
/* Return the absolute position of the beginning of a tags table in this
binding starting the search at binding->start. */
long
find_tags_table (binding)
SEARCH_BINDING *binding;
{
SEARCH_BINDING search;
long position;
search.buffer = binding->buffer;
search.start = binding->start;
search.end = binding->end;
search.flags = S_FoldCase;
while ((position = find_node_separator (&search)) != -1 )
{
search.start = position;
search.start += skip_node_separator (search.buffer + search.start);
if (looking_at (TAGS_TABLE_BEG_LABEL, &search))
return (position);
}
return (-1);
}
/* Return the absolute position of the node named NODENAME in BINDING.
This is a brute force search, and we wish to avoid it when possible.
This function is called when a tag (indirect or otherwise) doesn't
really point to the right node. It returns the absolute position of
the separator preceding the node. */
long
find_node_in_binding (nodename, binding)
char *nodename;
SEARCH_BINDING *binding;
{
register long position;
register int offset, namelen;
SEARCH_BINDING search;
namelen = strlen (nodename);
search.buffer = binding->buffer;
search.start = binding->start;
search.end = binding->end;
search.flags = 0;
while ((position = find_node_separator (&search)) != -1)
{
search.start = position;
search.start += skip_node_separator (search.buffer + search.start);
offset = string_in_line (INFO_NODE_LABEL, search.buffer + search.start);
if (offset == -1)
continue;
search.start += offset;
search.start += skip_whitespace (search.buffer + search.start);
offset = skip_node_characters
(search.buffer + search.start, DONT_SKIP_NEWLINES);
/* Notice that this is an exact match. You cannot grovel through
the buffer with this function looking for random nodes. */
if ((offset == namelen) &&
(search.buffer[search.start] == nodename[0]) &&
(strncmp (search.buffer + search.start, nodename, offset) == 0))
return (position);
}
return (-1);
}
texinfo-3.7/info/search.h 100666 11732 13 5506 5770343453 13623 0 ustar bfox user /* search.h -- Structure used to search large bodies of text, with bounds. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
/* The search functions take two arguments:
1) a string to search for, and
2) a pointer to a SEARCH_BINDING which contains the buffer, start,
and end of the search.
They return a long, which is the offset from the start of the buffer
at which the match was found. An offset of -1 indicates failure. */
#if !defined (_SEARCH_H_)
#define _SEARCH_H_
typedef struct {
char *buffer; /* The buffer of text to search. */
long start; /* Offset of the start of the search. */
long end; /* Offset of the end of the searh. */
int flags; /* Flags controlling the type of search. */
} SEARCH_BINDING;
#define S_FoldCase 0x01 /* Set means fold case in searches. */
#define S_SkipDest 0x02 /* Set means return pointing after the dest. */
SEARCH_BINDING *make_binding (), *copy_binding ();
extern long search_forward (), search_backward (), search ();
extern int looking_at ();
/* Note that STRING_IN_LINE () always returns the offset of the 1st character
after the string. */
extern int string_in_line ();
/* Some unixes don't have strcasecmp or strncasecmp. */
#if !defined (HAVE_STRCASECMP)
extern int strcasecmp (), strncasecmp ();
#endif /* !HAVE_STRCASECMP */
/* Function names that start with "skip" are passed a string, and return
an offset from the start of that string. Function names that start
with "find" are passed a SEARCH_BINDING, and return an absolute position
marker of the item being searched for. "Find" functions return a value
of -1 if the item being looked for couldn't be found. */
extern int skip_whitespace (), skip_non_whitespace ();
extern int skip_whitespace_and_newlines (), skip_line ();
extern int skip_node_characters (), skip_node_separator ();
#define DONT_SKIP_NEWLINES 0
#define SKIP_NEWLINES 1
extern long find_node_separator (), find_tags_table ();
extern long find_node_in_binding ();
#endif /* !_SEARCH_H_ */
texinfo-3.7/info/session.c 100666 11732 13 326263 6067070357 14102 0 ustar bfox user /* session.c -- The user windowing interface to Info. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
#if defined (HAVE_SYS_FILE_H)
#include
#endif /* HAVE_SYS_FILE_H */
#include
#include
#if defined (HAVE_SYS_TIME_H)
# include
# define HAVE_STRUCT_TIMEVAL
#endif /* HAVE_SYS_TIME_H */
#if defined (HANDLE_MAN_PAGES)
# include "man.h"
#endif
static void info_clear_pending_input (), info_set_pending_input ();
static void info_handle_pointer ();
/* **************************************************************** */
/* */
/* Running an Info Session */
/* */
/* **************************************************************** */
/* The place that we are reading input from. */
static FILE *info_input_stream = (FILE *)NULL;
/* The last executed command. */
VFunction *info_last_executed_command = (VFunction *)NULL;
/* Becomes non-zero when 'q' is typed to an Info window. */
int quit_info_immediately = 0;
/* Array of structures describing for each window which nodes have been
visited in that window. */
INFO_WINDOW **info_windows = (INFO_WINDOW **)NULL;
/* Where to add the next window, if we need to add one. */
static int info_windows_index = 0;
/* Number of slots allocated to INFO_WINDOWS. */
static int info_windows_slots = 0;
void remember_window_and_node (), forget_window_and_nodes ();
void initialize_info_session (), info_session ();
void display_startup_message_and_start ();
/* Begin an info session finding the nodes specified by FILENAME and NODENAMES.
For each loaded node, create a new window. Always split the largest of the
available windows. */
void
begin_multiple_window_info_session (filename, nodenames)
char *filename;
char **nodenames;
{
register int i;
WINDOW *window = (WINDOW *)NULL;
for (i = 0; nodenames[i]; i++)
{
NODE *node;
node = info_get_node (filename, nodenames[i]);
if (!node)
break;
/* If this is the first node, initialize the info session. */
if (!window)
{
initialize_info_session (node);
window = active_window;
}
else
{
/* Find the largest window in WINDOWS, and make that be the active
one. Then split it and add our window and node to the list
of remembered windows and nodes. Then tile the windows. */
register WINDOW *win, *largest = (WINDOW *)NULL;
int max_height = 0;
for (win = windows; win; win = win->next)
if (win->height > max_height)
{
max_height = win->height;
largest = win;
}
if (!largest)
{
display_update_display (windows);
info_error (CANT_FIND_WIND);
info_session ();
exit (0);
}
active_window = largest;
window = window_make_window (node);
if (window)
{
window_tile_windows (TILE_INTERNALS);
remember_window_and_node (window, node);
}
else
{
display_update_display (windows);
info_error (WIN_TOO_SMALL);
info_session ();
exit (0);
}
}
}
display_startup_message_and_start ();
}
/* Start an info session with INITIAL_NODE, and an error message in the echo
area made from FORMAT and ARG. */
void
begin_info_session_with_error (initial_node, format, arg)
NODE *initial_node;
char *format;
void *arg;
{
initialize_info_session (initial_node);
info_error (format, arg, (void *)NULL);
info_session ();
}
/* Start an info session with INITIAL_NODE. */
void
begin_info_session (initial_node)
NODE *initial_node;
{
initialize_info_session (initial_node);
display_startup_message_and_start ();
}
void
display_startup_message_and_start ()
{
char *format;
format = replace_in_documentation
("Welcome to Info version %s. \"\\[get-help-window]\" for help, \"\\[menu-item]\" for menu item.");
window_message_in_echo_area (format, version_string ());
info_session ();
}
/* Run an info session with an already initialized window and node. */
void
info_session ()
{
terminal_prep_terminal ();
display_update_display (windows);
info_last_executed_command = (VFunction *)NULL;
info_read_and_dispatch ();
/* On program exit, leave the cursor at the bottom of the window, and
restore the terminal I/O. */
terminal_goto_xy (0, screenheight - 1);
terminal_clear_to_eol ();
fflush (stdout);
terminal_unprep_terminal ();
close_dribble_file ();
}
/* Here is a window-location dependent event loop. Called from the
functions info_session (), and from read_xxx_in_echo_area (). */
void
info_read_and_dispatch ()
{
unsigned char key;
int done;
done = 0;
while (!done && !quit_info_immediately)
{
int lk;
/* If we haven't just gone up or down a line, there is no
goal column for this window. */
if ((info_last_executed_command != info_next_line) &&
(info_last_executed_command != info_prev_line))
active_window->goal_column = -1;
if (echo_area_is_active)
{
lk = echo_area_last_command_was_kill;
echo_area_prep_read ();
}
if (!info_any_buffered_input_p ())
display_update_display (windows);
display_cursor_at_point (active_window);
info_initialize_numeric_arg ();
initialize_keyseq ();
key = info_get_input_char ();
/* No errors yet. We just read a character, that's all. Only clear
the echo_area if it is not currently active. */
if (!echo_area_is_active)
window_clear_echo_area ();
info_error_was_printed = 0;
/* Do the selected command. */
info_dispatch_on_key (key, active_window->keymap);
if (echo_area_is_active)
{
/* Echo area commands that do killing increment the value of
ECHO_AREA_LAST_COMMAND_WAS_KILL. Thus, if there is no
change in the value of this variable, the last command
executed was not a kill command. */
if (lk == echo_area_last_command_was_kill)
echo_area_last_command_was_kill = 0;
if (ea_last_executed_command == ea_newline ||
info_aborted_echo_area)
{
ea_last_executed_command = (VFunction *)NULL;
done = 1;
}
if (info_last_executed_command == info_quit)
quit_info_immediately = 1;
}
else if (info_last_executed_command == info_quit)
done = 1;
}
}
/* Found in signals.c */
extern void initialize_info_signal_handler ();
/* Initialize the first info session by starting the terminal, window,
and display systems. */
void
initialize_info_session (node)
NODE *node;
{
char *getenv (), *term_name;
term_name = getenv ("TERM");
terminal_initialize_terminal (term_name);
if (terminal_is_dumb_p)
{
if (!term_name)
term_name = "dumb";
info_error (TERM_TOO_DUMB, term_name);
exit (1);
}
terminal_clear_screen ();
initialize_info_keymaps ();
window_initialize_windows (screenwidth, screenheight);
initialize_info_signal_handler ();
display_initialize_display (screenwidth, screenheight);
info_set_node_of_window (active_window, node);
/* Tell the window system how to notify us when a window needs to be
asynchronously deleted (e.g., user resizes window very small). */
window_deletion_notifier = forget_window_and_nodes;
/* If input has not been redirected yet, make it come from STDIN. */
if (!info_input_stream)
info_input_stream = stdin;
info_windows_initialized_p = 1;
}
/* Tell Info that input is coming from the file FILENAME. */
void
info_set_input_from_file (filename)
char *filename;
{
FILE *stream;
stream = fopen (filename, "r");
if (!stream)
return;
if ((info_input_stream != (FILE *)NULL) &&
(info_input_stream != stdin))
fclose (info_input_stream);
info_input_stream = stream;
if (stream != stdin)
display_inhibited = 1;
}
/* Return the INFO_WINDOW containing WINDOW, or NULL if there isn't one. */
static INFO_WINDOW *
get_info_window_of_window (window)
WINDOW *window;
{
register int i;
INFO_WINDOW *info_win = (INFO_WINDOW *)NULL;
for (i = 0; info_windows && (info_win = info_windows[i]); i++)
if (info_win->window == window)
break;
return (info_win);
}
/* Reset the remembered pagetop and point of WINDOW to WINDOW's current
values if the window and node are the same as the current one being
displayed. */
void
set_remembered_pagetop_and_point (window)
WINDOW *window;
{
INFO_WINDOW *info_win;
info_win = get_info_window_of_window (window);
if (!info_win)
return;
if (info_win->nodes_index &&
(info_win->nodes[info_win->current] == window->node))
{
info_win->pagetops[info_win->current] = window->pagetop;
info_win->points[info_win->current] = window->point;
}
}
void
remember_window_and_node (window, node)
WINDOW *window;
NODE *node;
{
INFO_WINDOW *info_win;
/* See if we already have this window in our list. */
info_win = get_info_window_of_window (window);
/* If the window wasn't already on our list, then make a new entry. */
if (!info_win)
{
info_win = (INFO_WINDOW *)xmalloc (sizeof (INFO_WINDOW));
info_win->window = window;
info_win->nodes = (NODE **)NULL;
info_win->pagetops = (int *)NULL;
info_win->points = (long *)NULL;
info_win->current = 0;
info_win->nodes_index = 0;
info_win->nodes_slots = 0;
add_pointer_to_array (info_win, info_windows_index, info_windows,
info_windows_slots, 10, INFO_WINDOW *);
}
/* If this node, the current pagetop, and the current point are the
same as the last saved node and pagetop, don't really add this to
the list of history nodes. */
{
int ni = info_win->nodes_index - 1;
if ((ni != -1) &&
(info_win->nodes[ni]->contents == node->contents) &&
(info_win->pagetops[ni] == window->pagetop) &&
(info_win->points[ni] == window->point))
return;
}
/* Remember this node, the currently displayed pagetop, and the current
location of point in this window. Because we are updating pagetops
and points as well as nodes, it is more efficient to avoid the
add_pointer_to_array macro here. */
if (info_win->nodes_index + 2 >= info_win->nodes_slots)
{
info_win->nodes = (NODE **)
xrealloc (info_win->nodes,
(info_win->nodes_slots += 20) * sizeof (NODE *));
info_win->pagetops = (int *)
xrealloc (info_win->pagetops, info_win->nodes_slots * sizeof (int));
info_win->points = (long *)
xrealloc (info_win->points, info_win->nodes_slots * sizeof (long));
}
info_win->nodes[info_win->nodes_index] = node;
info_win->pagetops[info_win->nodes_index] = window->pagetop;
info_win->points[info_win->nodes_index] = window->point;
info_win->current = info_win->nodes_index++;
info_win->nodes[info_win->nodes_index] = (NODE *)NULL;
info_win->pagetops[info_win->nodes_index] = 0;
info_win->points[info_win->nodes_index] = 0;
}
#define DEBUG_FORGET_WINDOW_AND_NODES
#if defined (DEBUG_FORGET_WINDOW_AND_NODES)
static void
consistency_check_info_windows ()
{
register int i;
INFO_WINDOW *info_win;
for (i = 0; i < info_windows_index; i++)
{
WINDOW *win;
for (win = windows; win; win = win->next)
if (win == info_windows[i]->window)
break;
if (!win)
abort ();
}
}
#endif /* DEBUG_FORGET_WINDOW_AND_NODES */
/* Remove WINDOW and its associated list of nodes from INFO_WINDOWS. */
void
forget_window_and_nodes (window)
WINDOW *window;
{
register int i;
INFO_WINDOW *info_win = (INFO_WINDOW *)NULL;
for (i = 0; info_windows && (info_win = info_windows[i]); i++)
if (info_win->window == window)
break;
/* If we found the window to forget, then do so. */
if (info_win)
{
while (i < info_windows_index)
{
info_windows[i] = info_windows[i + 1];
i++;
}
info_windows_index--;
info_windows[info_windows_index] = (INFO_WINDOW *)NULL;
if (info_win->nodes)
{
/* Free the node structures which held onto internal node contents
here. This doesn't free the contents; we have a garbage collector
which does that. */
for (i = 0; info_win->nodes[i]; i++)
if (internal_info_node_p (info_win->nodes[i]))
free (info_win->nodes[i]);
free (info_win->nodes);
maybe_free (info_win->pagetops);
maybe_free (info_win->points);
}
free (info_win);
}
#if defined (DEBUG_FORGET_WINDOW_AND_NODES)
consistency_check_info_windows ();
#endif /* DEBUG_FORGET_WINDOW_AND_NODES */
}
/* Set WINDOW to show NODE. Remember the new window in our list of Info
windows. If we are doing automatic footnote display, also try to display
the footnotes for this window. */
void
info_set_node_of_window (window, node)
WINDOW *window;
NODE *node;
{
/* Put this node into the window. */
window_set_node_of_window (window, node);
/* Remember this node and window in our list of info windows. */
remember_window_and_node (window, node);
/* If doing auto-footnote display/undisplay, show the footnotes belonging
to this window's node. */
if (auto_footnotes_p)
info_get_or_remove_footnotes (window);
}
/* **************************************************************** */
/* */
/* Info Movement Commands */
/* */
/* **************************************************************** */
/* Change the pagetop of WINDOW to DESIRED_TOP, perhaps scrolling the screen
to do so. */
void
set_window_pagetop (window, desired_top)
WINDOW *window;
int desired_top;
{
int point_line, old_pagetop;
if (desired_top < 0)
desired_top = 0;
else if (desired_top > window->line_count)
desired_top = window->line_count - 1;
if (window->pagetop == desired_top)
return;
old_pagetop = window->pagetop;
window->pagetop = desired_top;
/* Make sure that point appears in this window. */
point_line = window_line_of_point (window);
if ((point_line < window->pagetop) ||
((point_line - window->pagetop) > window->height - 1))
window->point =
window->line_starts[window->pagetop] - window->node->contents;
window->flags |= W_UpdateWindow;
/* Find out which direction to scroll, and scroll the window in that
direction. Do this only if there would be a savings in redisplay
time. This is true if the amount to scroll is less than the height
of the window, and if the number of lines scrolled would be greater
than 10 % of the window's height. */
if (old_pagetop < desired_top)
{
int start, end, amount;
amount = desired_top - old_pagetop;
if ((amount >= window->height) ||
(((window->height - amount) * 10) < window->height))
return;
start = amount + window->first_row;
end = window->height + window->first_row;
display_scroll_display (start, end, -amount);
}
else
{
int start, end, amount;
amount = old_pagetop - desired_top;
if ((amount >= window->height) ||
(((window->height - amount) * 10) < window->height))
return;
start = window->first_row;
end = (window->first_row + window->height) - amount;
display_scroll_display (start, end, amount);
}
}
/* Immediately make WINDOW->point visible on the screen, and move the
terminal cursor there. */
static void
info_show_point (window)
WINDOW *window;
{
int old_pagetop;
old_pagetop = window->pagetop;
window_adjust_pagetop (window);
if (old_pagetop != window->pagetop)
{
int new_pagetop;
new_pagetop = window->pagetop;
window->pagetop = old_pagetop;
set_window_pagetop (window, new_pagetop);
}
if (window->flags & W_UpdateWindow)
display_update_one_window (window);
display_cursor_at_point (window);
}
/* Move WINDOW->point from OLD line index to NEW line index. */
static void
move_to_new_line (old, new, window)
int old, new;
WINDOW *window;
{
if (old == -1)
{
info_error (CANT_FIND_POINT);
}
else
{
int goal;
if (new >= window->line_count || new < 0)
return;
goal = window_get_goal_column (window);
window->goal_column = goal;
window->point = window->line_starts[new] - window->node->contents;
window->point += window_chars_to_goal (window->line_starts[new], goal);
info_show_point (window);
}
}
/* Move WINDOW's point down to the next line if possible. */
DECLARE_INFO_COMMAND (info_next_line, "Move down to the next line")
{
int old_line, new_line;
if (count < 0)
info_prev_line (window, -count, key);
else
{
old_line = window_line_of_point (window);
new_line = old_line + count;
move_to_new_line (old_line, new_line, window);
}
}
/* Move WINDOW's point up to the previous line if possible. */
DECLARE_INFO_COMMAND (info_prev_line, "Move up to the previous line")
{
int old_line, new_line;
if (count < 0)
info_next_line (window, -count, key);
else
{
old_line = window_line_of_point (window);
new_line = old_line - count;
move_to_new_line (old_line, new_line, window);
}
}
/* Move WINDOW's point to the end of the true line. */
DECLARE_INFO_COMMAND (info_end_of_line, "Move to the end of the line")
{
register int point, len;
register char *buffer;
buffer = window->node->contents;
len = window->node->nodelen;
for (point = window->point;
(point < len) && (buffer[point] != '\n');
point++);
if (point != window->point)
{
window->point = point;
info_show_point (window);
}
}
/* Move WINDOW's point to the beginning of the true line. */
DECLARE_INFO_COMMAND (info_beginning_of_line, "Move to the start of the line")
{
register int point;
register char *buffer;
buffer = window->node->contents;
point = window->point;
for (; (point) && (buffer[point - 1] != '\n'); point--);
/* If at a line start alreay, do nothing. */
if (point != window->point)
{
window->point = point;
info_show_point (window);
}
}
/* Move point forward in the node. */
DECLARE_INFO_COMMAND (info_forward_char, "Move forward a character")
{
if (count < 0)
info_backward_char (window, -count, key);
else
{
window->point += count;
if (window->point >= window->node->nodelen)
window->point = window->node->nodelen - 1;
info_show_point (window);
}
}
/* Move point backward in the node. */
DECLARE_INFO_COMMAND (info_backward_char, "Move backward a character")
{
if (count < 0)
info_forward_char (window, -count, key);
else
{
window->point -= count;
if (window->point < 0)
window->point = 0;
info_show_point (window);
}
}
#define alphabetic(c) (islower (c) || isupper (c) || isdigit (c))
/* Move forward a word in this node. */
DECLARE_INFO_COMMAND (info_forward_word, "Move forward a word")
{
long point;
char *buffer;
int end, c;
if (count < 0)
{
info_backward_word (window, -count, key);
return;
}
point = window->point;
buffer = window->node->contents;
end = window->node->nodelen;
while (count)
{
if (point + 1 >= end)
return;
/* If we are not in a word, move forward until we are in one.
Then, move forward until we hit a non-alphabetic character. */
c = buffer[point];
if (!alphabetic (c))
{
while (++point < end)
{
c = buffer[point];
if (alphabetic (c))
break;
}
}
if (point >= end) return;
while (++point < end)
{
c = buffer[point];
if (!alphabetic (c))
break;
}
--count;
}
window->point = point;
info_show_point (window);
}
DECLARE_INFO_COMMAND (info_backward_word, "Move backward a word")
{
long point;
char *buffer;
int c;
if (count < 0)
{
info_forward_word (window, -count, key);
return;
}
buffer = window->node->contents;
point = window->point;
while (count)
{
if (point == 0)
break;
/* Like info_forward_word (), except that we look at the
characters just before point. */
c = buffer[point - 1];
if (!alphabetic (c))
{
while (--point)
{
c = buffer[point - 1];
if (alphabetic (c))
break;
}
}
while (point)
{
c = buffer[point - 1];
if (!alphabetic (c))
break;
else
--point;
}
--count;
}
window->point = point;
info_show_point (window);
}
/* Here is a list of time counter names which correspond to ordinal numbers.
It is used to print "once" instead of "1". */
static char *counter_names[] = {
"not at all", "once", "twice", "three", "four", "five", "six",
(char *)NULL
};
/* Buffer used to return values from times_description (). */
static char td_buffer[50];
/* Function returns a static string fully describing the number of times
present in COUNT. */
static char *
times_description (count)
int count;
{
register int i;
td_buffer[0] = '\0';
for (i = 0; counter_names[i]; i++)
if (count == i)
break;
if (counter_names[i])
sprintf (td_buffer, "%s%s", counter_names[i], count > 2 ? " times" : "");
else
sprintf (td_buffer, "%d times", count);
return (td_buffer);
}
/* Variable controlling the behaviour of default scrolling when you are
already at the bottom of a node. Possible values are defined in session.h.
The meanings are:
IS_Continuous Try to get first menu item, or failing that, the
"Next:" pointer, or failing that, the "Up:" and
"Next:" of the up.
IS_NextOnly Try to get "Next:" menu item.
IS_PageOnly Simply give up at the bottom of a node. */
int info_scroll_behaviour = IS_Continuous;
/* Choices used by the completer when reading a value for the user-visible
variable "scroll-behaviour". */
char *info_scroll_choices[] = {
"Continuous", "Next Only", "Page Only", (char *)NULL
};
/* Move to 1st menu item, Next, Up/Next, or error in this window. */
static void
forward_move_node_structure (window, behaviour)
WINDOW *window;
int behaviour;
{
switch (behaviour)
{
case IS_PageOnly:
info_error (AT_NODE_BOTTOM);
break;
case IS_NextOnly:
info_next_label_of_node (window->node);
if (!info_parsed_nodename && !info_parsed_filename)
info_error ("No \"Next\" pointer for this node.");
else
{
window_message_in_echo_area ("Following \"Next\" node...");
info_handle_pointer ("Next", window);
}
break;
case IS_Continuous:
{
/* First things first. If this node contains a menu, move down
into the menu. */
{
REFERENCE **menu;
menu = info_menu_of_node (window->node);
if (menu)
{
info_free_references (menu);
window_message_in_echo_area ("Selecting first menu item...");
info_menu_digit (window, 1, '1');
return;
}
}
/* Okay, this node does not contain a menu. If it contains a
"Next:" pointer, use that. */
info_next_label_of_node (window->node);
if (info_label_was_found)
{
window_message_in_echo_area ("Selecting \"Next\" node...");
info_handle_pointer ("Next", window);
return;
}
/* Okay, there wasn't a "Next:" for this node. Move "Up:" until we
can move "Next:". If that isn't possible, complain that there
are no more nodes. */
{
int up_counter, old_current;
INFO_WINDOW *info_win;
/* Remember the current node and location. */
info_win = get_info_window_of_window (window);
old_current = info_win->current;
/* Back up through the "Up:" pointers until we have found a "Next:"
that isn't the same as the first menu item found in that node. */
up_counter = 0;
while (!info_error_was_printed)
{
info_up_label_of_node (window->node);
if (info_label_was_found)
{
info_handle_pointer ("Up", window);
if (info_error_was_printed)
continue;
up_counter++;
info_next_label_of_node (window->node);
/* If no "Next" pointer, keep backing up. */
if (!info_label_was_found)
continue;
/* If this node's first menu item is the same as this node's
Next pointer, keep backing up. */
if (!info_parsed_filename)
{
REFERENCE **menu;
char *next_nodename;
/* Remember the name of the Next node, since reading
the menu can overwrite the contents of the
info_parsed_xxx strings. */
next_nodename = strdup (info_parsed_nodename);
menu = info_menu_of_node (window->node);
if (menu &&
(strcmp
(menu[0]->nodename, next_nodename) == 0))
{
info_free_references (menu);
free (next_nodename);
continue;
}
else
{
/* Restore the world to where it was before
reading the menu contents. */
info_free_references (menu);
free (next_nodename);
info_next_label_of_node (window->node);
}
}
/* This node has a "Next" pointer, and it is not the
same as the first menu item found in this node. */
window_message_in_echo_area
("Moving \"Up\" %s, then \"Next\".",
times_description (up_counter));
info_handle_pointer ("Next", window);
return;
}
else
{
/* No more "Up" pointers. Print an error, and call it
quits. */
register int i;
for (i = 0; i < up_counter; i++)
{
info_win->nodes_index--;
free (info_win->nodes[info_win->nodes_index]);
info_win->nodes[info_win->nodes_index] = (NODE *)NULL;
}
info_win->current = old_current;
window->node = info_win->nodes[old_current];
window->pagetop = info_win->pagetops[old_current];
window->point = info_win->points[old_current];
recalculate_line_starts (window);
window->flags |= W_UpdateWindow;
info_error ("No more nodes.");
}
}
}
break;
}
}
}
/* Move Prev, Up or error in WINDOW depending on BEHAVIOUR. */
static void
backward_move_node_structure (window, behaviour)
WINDOW *window;
int behaviour;
{
switch (behaviour)
{
case IS_PageOnly:
info_error (AT_NODE_TOP);
break;
case IS_NextOnly:
info_prev_label_of_node (window->node);
if (!info_parsed_nodename && !info_parsed_filename)
info_error ("No \"Prev\" for this node.");
else
{
window_message_in_echo_area ("Moving \"Prev\" in this window.");
info_handle_pointer ("Prev", window);
}
break;
case IS_Continuous:
info_prev_label_of_node (window->node);
if (!info_parsed_nodename && !info_parsed_filename)
{
info_up_label_of_node (window->node);
if (!info_parsed_nodename && !info_parsed_filename)
info_error ("No \"Prev\" or \"Up\" for this node.");
else
{
window_message_in_echo_area ("Moving \"Up\" in this window.");
info_handle_pointer ("Up", window);
}
}
else
{
REFERENCE **menu;
int inhibit_menu_traversing = 0;
/* Watch out! If this node's Prev is the same as the Up, then
move Up. Otherwise, we could move Prev, and then to the last
menu item in the Prev. This would cause the user to loop
through a subsection of the info file. */
if (!info_parsed_filename && info_parsed_nodename)
{
char *pnode;
pnode = strdup (info_parsed_nodename);
info_up_label_of_node (window->node);
if (!info_parsed_filename && info_parsed_nodename &&
strcmp (info_parsed_nodename, pnode) == 0)
{
/* The nodes are the same. Inhibit moving to the last
menu item. */
free (pnode);
inhibit_menu_traversing = 1;
}
else
{
free (pnode);
info_prev_label_of_node (window->node);
}
}
/* Move to the previous node. If this node now contains a menu,
and we have not inhibited movement to it, move to the node
corresponding to the last menu item. */
window_message_in_echo_area ("Moving \"Prev\" in this window.");
info_handle_pointer ("Prev", window);
if (!inhibit_menu_traversing)
{
while (!info_error_was_printed &&
(menu = info_menu_of_node (window->node)))
{
info_free_references (menu);
window_message_in_echo_area
("Moving to \"Prev\"'s last menu item.");
info_menu_digit (window, 1, '0');
}
}
}
break;
}
}
/* Move continuously forward through the node structure of this info file. */
DECLARE_INFO_COMMAND (info_global_next_node,
"Move forwards or down through node structure")
{
if (count < 0)
info_global_prev_node (window, -count, key);
else
{
while (count && !info_error_was_printed)
{
forward_move_node_structure (window, IS_Continuous);
count--;
}
}
}
/* Move continuously backward through the node structure of this info file. */
DECLARE_INFO_COMMAND (info_global_prev_node,
"Move backwards or up through node structure")
{
if (count < 0)
info_global_next_node (window, -count, key);
else
{
while (count && !info_error_was_printed)
{
backward_move_node_structure (window, IS_Continuous);
count--;
}
}
}
/* Show the next screen of WINDOW's node. */
DECLARE_INFO_COMMAND (info_scroll_forward, "Scroll forward in this window")
{
if (count < 0)
info_scroll_backward (window, -count, key);
else
{
int desired_top;
/* Without an explicit numeric argument, scroll the bottom two
lines to the top of this window, Or, if at bottom of window,
and the user wishes to scroll through nodes get the "Next" node
for this window. */
if (!info_explicit_arg && count == 1)
{
desired_top = window->pagetop + (window->height - 2);
/* If there are no more lines to scroll here, error, or get
another node, depending on INFO_SCROLL_BEHAVIOUR. */
if (desired_top > window->line_count)
{
int behaviour = info_scroll_behaviour;
/* Here is a hack. If the key being used is not SPC, do the
PageOnly behaviour. */
if (key != SPC && key != DEL)
behaviour = IS_PageOnly;
forward_move_node_structure (window, behaviour);
return;
}
}
else
desired_top = window->pagetop + count;
if (desired_top >= window->line_count)
desired_top = window->line_count - 2;
if (window->pagetop > desired_top)
return;
else
set_window_pagetop (window, desired_top);
}
}
/* Show the previous screen of WINDOW's node. */
DECLARE_INFO_COMMAND (info_scroll_backward, "Scroll backward in this window")
{
if (count < 0)
info_scroll_forward (window, -count, key);
else
{
int desired_top;
/* Without an explicit numeric argument, scroll the top two lines
to the bottom of this window, or move to the previous, or Up'th
node. */
if (!info_explicit_arg && count == 1)
{
desired_top = window->pagetop - (window->height - 2);
if ((desired_top < 0) && (window->pagetop == 0))
{
int behaviour = info_scroll_behaviour;
/* Same kind of hack as in info_scroll_forward. If the key
used to invoke this command is not DEL, do only the PageOnly
behaviour. */
if (key != DEL && key != SPC)
behaviour = IS_PageOnly;
backward_move_node_structure (window, behaviour);
return;
}
}
else
desired_top = window->pagetop - count;
if (desired_top < 0)
desired_top = 0;
set_window_pagetop (window, desired_top);
}
}
/* Move to the beginning of the node. */
DECLARE_INFO_COMMAND (info_beginning_of_node, "Move to the start of this node")
{
window->pagetop = window->point = 0;
window->flags |= W_UpdateWindow;
}
/* Move to the end of the node. */
DECLARE_INFO_COMMAND (info_end_of_node, "Move to the end of this node")
{
window->point = window->node->nodelen - 1;
info_show_point (window);
}
/* **************************************************************** */
/* */
/* Commands for Manipulating Windows */
/* */
/* **************************************************************** */
/* Make the next window in the chain be the active window. */
DECLARE_INFO_COMMAND (info_next_window, "Select the next window")
{
if (count < 0)
{
info_prev_window (window, -count, key);
return;
}
/* If no other window, error now. */
if (!windows->next && !echo_area_is_active)
{
info_error (ONE_WINDOW);
return;
}
while (count--)
{
if (window->next)
window = window->next;
else
{
if (window == the_echo_area || !echo_area_is_active)
window = windows;
else
window = the_echo_area;
}
}
if (active_window != window)
{
if (auto_footnotes_p)
info_get_or_remove_footnotes (window);
window->flags |= W_UpdateWindow;
active_window = window;
}
}
/* Make the previous window in the chain be the active window. */
DECLARE_INFO_COMMAND (info_prev_window, "Select the previous window")
{
if (count < 0)
{
info_next_window (window, -count, key);
return;
}
/* Only one window? */
if (!windows->next && !echo_area_is_active)
{
info_error (ONE_WINDOW);
return;
}
while (count--)
{
/* If we are in the echo area, or if the echo area isn't active and we
are in the first window, find the last window in the chain. */
if (window == the_echo_area ||
(window == windows && !echo_area_is_active))
{
register WINDOW *win, *last;
for (win = windows; win; win = win->next)
last = win;
window = last;
}
else
{
if (window == windows)
window = the_echo_area;
else
window = window->prev;
}
}
if (active_window != window)
{
if (auto_footnotes_p)
info_get_or_remove_footnotes (window);
window->flags |= W_UpdateWindow;
active_window = window;
}
}
/* Split WINDOW into two windows, both showing the same node. If we
are automatically tiling windows, re-tile after the split. */
DECLARE_INFO_COMMAND (info_split_window, "Split the current window")
{
WINDOW *split, *old_active;
int pagetop;
/* Remember the current pagetop of the window being split. If it doesn't
change, we can scroll its contents around after the split. */
pagetop = window->pagetop;
/* Make the new window. */
old_active = active_window;
active_window = window;
split = window_make_window (window->node);
active_window = old_active;
if (!split)
{
info_error (WIN_TOO_SMALL);
}
else
{
#if defined (SPLIT_BEFORE_ACTIVE)
/* Try to scroll the old window into its new postion. */
if (pagetop == window->pagetop)
{
int start, end, amount;
start = split->first_row;
end = start + window->height;
amount = split->height + 1;
display_scroll_display (start, end, amount);
}
#else /* !SPLIT_BEFORE_ACTIVE */
/* Make sure point still appears in the active window. */
info_show_point (window);
#endif /* !SPLIT_BEFORE_ACTIVE */
/* If the window just split was one internal to Info, try to display
something else in it. */
if (internal_info_node_p (split->node))
{
register int i, j;
INFO_WINDOW *iw;
NODE *node = (NODE *)NULL;
char *filename;
for (i = 0; iw = info_windows[i]; i++)
{
for (j = 0; j < iw->nodes_index; j++)
if (!internal_info_node_p (iw->nodes[j]))
{
if (iw->nodes[j]->parent)
filename = iw->nodes[j]->parent;
else
filename = iw->nodes[j]->filename;
node = info_get_node (filename, iw->nodes[j]->nodename);
if (node)
{
window_set_node_of_window (split, node);
i = info_windows_index - 1;
break;
}
}
}
}
split->pagetop = window->pagetop;
if (auto_tiling_p)
window_tile_windows (DONT_TILE_INTERNALS);
else
window_adjust_pagetop (split);
remember_window_and_node (split, split->node);
}
}
/* Delete WINDOW, forgetting the list of last visited nodes. If we are
automatically displaying footnotes, show or remove the footnotes
window. If we are automatically tiling windows, re-tile after the
deletion. */
DECLARE_INFO_COMMAND (info_delete_window, "Delete the current window")
{
if (!windows->next)
{
info_error (CANT_KILL_LAST);
}
else if (window->flags & W_WindowIsPerm)
{
info_error ("Cannot delete a permanent window");
}
else
{
info_delete_window_internal (window);
if (auto_footnotes_p)
info_get_or_remove_footnotes (active_window);
if (auto_tiling_p)
window_tile_windows (DONT_TILE_INTERNALS);
}
}
/* Do the physical deletion of WINDOW, and forget this window and
associated nodes. */
void
info_delete_window_internal (window)
WINDOW *window;
{
if (windows->next && ((window->flags & W_WindowIsPerm) == 0))
{
/* We not only delete the window from the display, we forget it from
our list of remembered windows. */
forget_window_and_nodes (window);
window_delete_window (window);
if (echo_area_is_active)
echo_area_inform_of_deleted_window (window);
}
}
/* Just keep WINDOW, deleting all others. */
DECLARE_INFO_COMMAND (info_keep_one_window, "Delete all other windows")
{
int num_deleted; /* The number of windows we deleted. */
int pagetop, start, end;
/* Remember a few things about this window. We may be able to speed up
redisplay later by scrolling its contents. */
pagetop = window->pagetop;
start = window->first_row;
end = start + window->height;
num_deleted = 0;
while (1)
{
WINDOW *win;
/* Find an eligible window and delete it. If no eligible windows
are found, we are done. A window is eligible for deletion if
is it not permanent, and it is not WINDOW. */
for (win = windows; win; win = win->next)
if (win != window && ((win->flags & W_WindowIsPerm) == 0))
break;
if (!win)
break;
info_delete_window_internal (win);
num_deleted++;
}
/* Scroll the contents of this window into the right place so that the
user doesn't have to wait any longer than necessary for redisplay. */
if (num_deleted)
{
int amount;
amount = (window->first_row - start);
amount -= (window->pagetop - pagetop);
display_scroll_display (start, end, amount);
}
window->flags |= W_UpdateWindow;
}
/* Scroll the "other" window of WINDOW. */
DECLARE_INFO_COMMAND (info_scroll_other_window, "Scroll the other window")
{
WINDOW *other;
/* If only one window, give up. */
if (!windows->next)
{
info_error (ONE_WINDOW);
return;
}
other = window->next;
if (!other)
other = window->prev;
info_scroll_forward (other, count, key);
}
/* Change the size of WINDOW by AMOUNT. */
DECLARE_INFO_COMMAND (info_grow_window, "Grow (or shrink) this window")
{
window_change_window_height (window, count);
}
/* When non-zero, tiling takes place automatically when info_split_window
is called. */
int auto_tiling_p = 0;
/* Tile all of the visible windows. */
DECLARE_INFO_COMMAND (info_tile_windows,
"Divide the available screen space among the visible windows")
{
window_tile_windows (TILE_INTERNALS);
}
/* Toggle the state of this window's wrapping of lines. */
DECLARE_INFO_COMMAND (info_toggle_wrap,
"Toggle the state of line wrapping in the current window")
{
window_toggle_wrap (window);
}
/* **************************************************************** */
/* */
/* Info Node Commands */
/* */
/* **************************************************************** */
/* Using WINDOW for various defaults, select the node referenced by ENTRY
in it. If the node is selected, the window and node are remembered. */
void
info_select_reference (window, entry)
WINDOW *window;
REFERENCE *entry;
{
NODE *node;
char *filename, *nodename, *file_system_error;
file_system_error = (char *)NULL;
filename = entry->filename;
if (!filename)
filename = window->node->parent;
if (!filename)
filename = window->node->filename;
if (filename)
filename = strdup (filename);
if (entry->nodename)
nodename = strdup (entry->nodename);
else
nodename = strdup ("Top");
node = info_get_node (filename, nodename);
/* Try something a little weird. If the node couldn't be found, and the
reference was of the form "foo::", see if the entry->label can be found
as a file, with a node of "Top". */
if (!node)
{
if (info_recent_file_error)
file_system_error = strdup (info_recent_file_error);
if (entry->nodename && (strcmp (entry->nodename, entry->label) == 0))
{
node = info_get_node (entry->label, "Top");
if (!node && info_recent_file_error)
{
maybe_free (file_system_error);
file_system_error = strdup (info_recent_file_error);
}
}
}
if (!node)
{
if (file_system_error)
info_error (file_system_error);
else
info_error (CANT_FIND_NODE, nodename);
}
maybe_free (file_system_error);
maybe_free (filename);
maybe_free (nodename);
if (node)
{
set_remembered_pagetop_and_point (window);
info_set_node_of_window (window, node);
}
}
/* Parse the node specification in LINE using WINDOW to default the filename.
Select the parsed node in WINDOW and remember it, or error if the node
couldn't be found. */
static void
info_parse_and_select (line, window)
char *line;
WINDOW *window;
{
REFERENCE entry;
info_parse_node (line, DONT_SKIP_NEWLINES);
entry.nodename = info_parsed_nodename;
entry.filename = info_parsed_filename;
entry.label = "*info-parse-and-select*";
info_select_reference (window, &entry);
}
/* Given that the values of INFO_PARSED_FILENAME and INFO_PARSED_NODENAME
are previously filled, try to get the node represented by them into
WINDOW. The node should have been pointed to by the LABEL pointer of
WINDOW->node. */
static void
info_handle_pointer (label, window)
char *label;
WINDOW *window;
{
if (info_parsed_filename || info_parsed_nodename)
{
char *filename, *nodename;
NODE *node;
filename = nodename = (char *)NULL;
if (info_parsed_filename)
filename = strdup (info_parsed_filename);
else
{
if (window->node->parent)
filename = strdup (window->node->parent);
else if (window->node->filename)
filename = strdup (window->node->filename);
}
if (info_parsed_nodename)
nodename = strdup (info_parsed_nodename);
else
nodename = strdup ("Top");
node = info_get_node (filename, nodename);
if (node)
{
INFO_WINDOW *info_win;
info_win = get_info_window_of_window (window);
if (info_win)
{
info_win->pagetops[info_win->current] = window->pagetop;
info_win->points[info_win->current] = window->point;
}
set_remembered_pagetop_and_point (window);
info_set_node_of_window (window, node);
}
else
{
if (info_recent_file_error)
info_error (info_recent_file_error);
else
info_error (CANT_FILE_NODE, filename, nodename);
}
free (filename);
free (nodename);
}
else
{
info_error (NO_POINTER, label);
}
}
/* Make WINDOW display the "Next:" node of the node currently being
displayed. */
DECLARE_INFO_COMMAND (info_next_node, "Select the `Next' node")
{
info_next_label_of_node (window->node);
info_handle_pointer ("Next", window);
}
/* Make WINDOW display the "Prev:" node of the node currently being
displayed. */
DECLARE_INFO_COMMAND (info_prev_node, "Select the `Prev' node")
{
info_prev_label_of_node (window->node);
info_handle_pointer ("Prev", window);
}
/* Make WINDOW display the "Up:" node of the node currently being
displayed. */
DECLARE_INFO_COMMAND (info_up_node, "Select the `Up' node")
{
info_up_label_of_node (window->node);
info_handle_pointer ("Up", window);
}
/* Make WINDOW display the last node of this info file. */
DECLARE_INFO_COMMAND (info_last_node, "Select the last node in this file")
{
register int i;
FILE_BUFFER *fb = file_buffer_of_window (window);
NODE *node = (NODE *)NULL;
if (fb && fb->tags)
{
for (i = 0; fb->tags[i]; i++);
node = info_get_node (fb->filename, fb->tags[i - 1]->nodename);
}
if (!node)
info_error ("This window has no additional nodes");
else
{
set_remembered_pagetop_and_point (window);
info_set_node_of_window (window, node);
}
}
/* Make WINDOW display the first node of this info file. */
DECLARE_INFO_COMMAND (info_first_node, "Select the first node in this file")
{
FILE_BUFFER *fb = file_buffer_of_window (window);
NODE *node = (NODE *)NULL;
if (fb && fb->tags)
node = info_get_node (fb->filename, fb->tags[0]->nodename);
if (!node)
info_error ("This window has no additional nodes");
else
{
set_remembered_pagetop_and_point (window);
info_set_node_of_window (window, node);
}
}
/* Make WINDOW display the previous node displayed in this window. */
DECLARE_INFO_COMMAND (info_history_node,
"Select the most recently selected node")
{
INFO_WINDOW *info_win;
/* Find the INFO_WINDOW which contains WINDOW. */
info_win = get_info_window_of_window (window);
if (!info_win)
{
info_error ("Requested window is not present!");
return;
}
set_remembered_pagetop_and_point (window);
if (!info_win->current)
{
if (info_win->nodes_index > 1)
{
window_message_in_echo_area
("Now wrapped around to beginning of history.");
info_win->current = info_win->nodes_index;
}
else
{
info_error ("No earlier nodes in this window.");
return;
}
}
info_win->current--;
window_set_node_of_window (window, info_win->nodes[info_win->current]);
window->pagetop = info_win->pagetops[info_win->current];
window->point = info_win->points[info_win->current];
window->flags |= W_UpdateWindow;
if (auto_footnotes_p)
info_get_or_remove_footnotes (window);
}
/* Select the last menu item in WINDOW->node. */
DECLARE_INFO_COMMAND (info_last_menu_item,
"Select the last item in this node's menu")
{
info_menu_digit (window, 1, '0');
}
/* Use KEY (a digit) to select the Nth menu item in WINDOW->node. */
DECLARE_INFO_COMMAND (info_menu_digit, "Select this menu item")
{
register int i, item;
register REFERENCE *entry, **menu;
menu = info_menu_of_node (window->node);
if (!menu)
{
info_error (NO_MENU_NODE);
return;
}
/* We have the menu. See if there are this many items in it. */
item = key - '0';
/* Special case. Item "0" is the last item in this menu. */
if (item == 0)
for (i = 0; menu[i + 1]; i++);
else
{
for (i = 0; entry = menu[i]; i++)
if (i == item - 1)
break;
}
if (menu[i])
info_select_reference (window, menu[i]);
else
info_error ("There aren't %d items in this menu.", item);
info_free_references (menu);
return;
}
/* Read a menu or followed reference from the user defaulting to the
reference found on the current line, and select that node. The
reading is done with completion. BUILDER is the function used
to build the list of references. ASK_P is non-zero if the user
should be prompted, or zero to select the default item. */
static void
info_menu_or_ref_item (window, count, key, builder, ask_p)
WINDOW *window;
int count;
unsigned char key;
REFERENCE **(*builder) ();
int ask_p;
{
REFERENCE **menu, *entry, *defentry = (REFERENCE *)NULL;
char *line;
menu = (*builder) (window->node);
if (!menu)
{
if (builder == info_menu_of_node)
info_error (NO_MENU_NODE);
else
info_error (NO_XREF_NODE);
return;
}
/* Default the selected reference to the one which is on the line that
point is in. */
{
REFERENCE **refs = (REFERENCE **)NULL;
int point_line;
point_line = window_line_of_point (window);
if (point_line != -1)
{
SEARCH_BINDING binding;
binding.buffer = window->node->contents;
binding.start = window->line_starts[point_line] - binding.buffer;
if (window->line_starts[point_line + 1])
binding.end = window->line_starts[point_line + 1] - binding.buffer;
else
binding.end = window->node->nodelen;
binding.flags = 0;
if (builder == info_menu_of_node)
{
if (point_line)
{
binding.start--;
refs = info_menu_items (&binding);
}
}
else
{
#if defined (HANDLE_MAN_PAGES)
if (window->node->flags & N_IsManPage)
refs = manpage_xrefs_in_binding (window->node, &binding);
else
#endif /* HANDLE_MAN_PAGES */
refs = info_xrefs (&binding);
}
if (refs)
{
if ((strcmp (refs[0]->label, "Menu") != 0) ||
(builder == info_xrefs_of_node))
{
int which = 0;
/* Find the closest reference to point. */
if (builder == info_xrefs_of_node)
{
int closest = -1;
for (; refs[which]; which++)
{
if ((window->point >= refs[which]->start) &&
(window->point <= refs[which]->end))
{
closest = which;
break;
}
else if (window->point < refs[which]->start)
{
break;
}
}
if (closest == -1)
which--;
else
which = closest;
}
defentry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
defentry->label = strdup (refs[which]->label);
defentry->filename = refs[which]->filename;
defentry->nodename = refs[which]->nodename;
if (defentry->filename)
defentry->filename = strdup (defentry->filename);
if (defentry->nodename)
defentry->nodename = strdup (defentry->nodename);
}
info_free_references (refs);
}
}
}
/* If we are going to ask the user a question, do it now. */
if (ask_p)
{
char *prompt;
/* Build the prompt string. */
if (defentry)
prompt = (char *)xmalloc (20 + strlen (defentry->label));
else
prompt = (char *)xmalloc (20);
if (builder == info_menu_of_node)
{
if (defentry)
sprintf (prompt, "Menu item (%s): ", defentry->label);
else
sprintf (prompt, "Menu item: ");
}
else
{
if (defentry)
sprintf (prompt, "Follow xref (%s): ", defentry->label);
else
sprintf (prompt, "Follow xref: ");
}
line = info_read_completing_in_echo_area (window, prompt, menu);
free (prompt);
window = active_window;
/* User aborts, just quit. */
if (!line)
{
maybe_free (defentry);
info_free_references (menu);
info_abort_key (window, 0, 0);
return;
}
/* If we had a default and the user accepted it, use that. */
if (!*line)
{
free (line);
if (defentry)
line = strdup (defentry->label);
else
line = (char *)NULL;
}
}
else
{
/* Not going to ask any questions. If we have a default entry, use
that, otherwise return. */
if (!defentry)
return;
else
line = strdup (defentry->label);
}
if (line)
{
/* Find the selected label in the references. */
entry = info_get_labeled_reference (line, menu);
if (!entry && defentry)
info_error ("The reference disappeared! (%s).", line);
else
{
NODE *orig;
orig = window->node;
info_select_reference (window, entry);
if ((builder == info_xrefs_of_node) && (window->node != orig))
{
long offset;
long start;
if (window->line_count > 0)
start = window->line_starts[1] - window->node->contents;
else
start = 0;
offset =
info_target_search_node (window->node, entry->label, start);
if (offset != -1)
{
window->point = offset;
window_adjust_pagetop (window);
}
}
}
free (line);
if (defentry)
{
free (defentry->label);
maybe_free (defentry->filename);
maybe_free (defentry->nodename);
free (defentry);
}
}
info_free_references (menu);
if (!info_error_was_printed)
window_clear_echo_area ();
}
/* Read a line (with completion) which is the name of a menu item,
and select that item. */
DECLARE_INFO_COMMAND (info_menu_item, "Read a menu item and select its node")
{
info_menu_or_ref_item (window, count, key, info_menu_of_node, 1);
}
/* Read a line (with completion) which is the name of a reference to
follow, and select the node. */
DECLARE_INFO_COMMAND
(info_xref_item, "Read a footnote or cross reference and select its node")
{
info_menu_or_ref_item (window, count, key, info_xrefs_of_node, 1);
}
/* Position the cursor at the start of this node's menu. */
DECLARE_INFO_COMMAND (info_find_menu, "Move to the start of this node's menu")
{
SEARCH_BINDING binding;
long position;
binding.buffer = window->node->contents;
binding.start = 0;
binding.end = window->node->nodelen;
binding.flags = S_FoldCase | S_SkipDest;
position = search (INFO_MENU_LABEL, &binding);
if (position == -1)
info_error (NO_MENU_NODE);
else
{
window->point = position;
window_adjust_pagetop (window);
window->flags |= W_UpdateWindow;
}
}
/* Visit as many menu items as is possible, each in a separate window. */
DECLARE_INFO_COMMAND (info_visit_menu,
"Visit as many menu items at once as possible")
{
register int i;
REFERENCE *entry, **menu;
menu = info_menu_of_node (window->node);
if (!menu)
info_error (NO_MENU_NODE);
for (i = 0; (!info_error_was_printed) && (entry = menu[i]); i++)
{
WINDOW *new;
new = window_make_window (window->node);
window_tile_windows (TILE_INTERNALS);
if (!new)
info_error (WIN_TOO_SMALL);
else
{
active_window = new;
info_select_reference (new, entry);
}
}
}
/* Read a line of input which is a node name, and go to that node. */
DECLARE_INFO_COMMAND (info_goto_node, "Read a node name and select it")
{
char *line;
NODE *node;
#define GOTO_COMPLETES
#if defined (GOTO_COMPLETES)
/* Build a completion list of all of the known nodes. */
{
register int fbi, i;
FILE_BUFFER *current;
REFERENCE **items = (REFERENCE **)NULL;
int items_index = 0;
int items_slots = 0;
current = file_buffer_of_window (window);
for (fbi = 0; info_loaded_files && info_loaded_files[fbi]; fbi++)
{
FILE_BUFFER *fb;
REFERENCE *entry;
int this_is_the_current_fb;
fb = info_loaded_files[fbi];
this_is_the_current_fb = (current == fb);
entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
entry->filename = entry->nodename = (char *)NULL;
entry->label = (char *)xmalloc (4 + strlen (fb->filename));
sprintf (entry->label, "(%s)*", fb->filename);
add_pointer_to_array
(entry, items_index, items, items_slots, 10, REFERENCE *);
if (fb->tags)
{
for (i = 0; fb->tags[i]; i++)
{
entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
entry->filename = entry->nodename = (char *)NULL;
entry->label = (char *) xmalloc
(4 + strlen (fb->filename) + strlen (fb->tags[i]->nodename));
sprintf (entry->label, "(%s)%s",
fb->filename, fb->tags[i]->nodename);
add_pointer_to_array
(entry, items_index, items, items_slots, 100, REFERENCE *);
}
if (this_is_the_current_fb)
{
for (i = 0; fb->tags[i]; i++)
{
entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
entry->filename = entry->nodename = (char *)NULL;
entry->label = strdup (fb->tags[i]->nodename);
add_pointer_to_array (entry, items_index, items,
items_slots, 100, REFERENCE *);
}
}
}
}
line = info_read_maybe_completing (window, "Goto Node: ", items);
info_free_references (items);
}
#else /* !GOTO_COMPLETES */
line = info_read_in_echo_area (window, "Goto Node: ");
#endif /* !GOTO_COMPLETES */
/* If the user aborted, quit now. */
if (!line)
{
info_abort_key (window, 0, 0);
return;
}
canonicalize_whitespace (line);
if (*line)
info_parse_and_select (line, window);
free (line);
if (!info_error_was_printed)
window_clear_echo_area ();
}
#if defined (HANDLE_MAN_PAGES)
DECLARE_INFO_COMMAND (info_man, "Read a manpage reference and select it")
{
char *line;
NODE *node;
line = info_read_in_echo_area (window, "Get Manpage: ");
if (!line)
{
info_abort_key (window, 0, 0);
return;
}
canonicalize_whitespace (line);
if (*line)
{
char *goto_command;
goto_command = (char *)xmalloc
(4 + strlen (MANPAGE_FILE_BUFFER_NAME) + strlen (line));
sprintf (goto_command, "(%s)%s", MANPAGE_FILE_BUFFER_NAME, line);
info_parse_and_select (goto_command, window);
free (goto_command);
}
free (line);
if (!info_error_was_printed)
window_clear_echo_area ();
}
#endif /* HANDLE_MAN_PAGES */
/* Move to the "Top" node in this file. */
DECLARE_INFO_COMMAND (info_top_node, "Select the node `Top' in this file")
{
info_parse_and_select ("Top", window);
}
/* Move to the node "(dir)Top". */
DECLARE_INFO_COMMAND (info_dir_node, "Select the node `(dir)'")
{
info_parse_and_select ("(dir)Top", window);
}
/* Try to delete the current node appearing in this window, showing the most
recently selected node in this window. */
DECLARE_INFO_COMMAND (info_kill_node, "Kill this node")
{
register int iw, i;
register INFO_WINDOW *info_win;
char *nodename = (char *)NULL;
NODE *temp = (NODE *)NULL;
/* Read the name of a node to kill. The list of available nodes comes
from the nodes appearing in the current window configuration. */
{
REFERENCE **menu = (REFERENCE **)NULL;
int menu_index = 0, menu_slots = 0;
char *default_nodename, *prompt;
for (iw = 0; info_win = info_windows[iw]; iw++)
{
REFERENCE *entry;
entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
entry->label = strdup (info_win->window->node->nodename);
entry->filename = entry->nodename = (char *)NULL;
add_pointer_to_array
(entry, menu_index, menu, menu_slots, 10, REFERENCE *);
}
default_nodename = strdup (active_window->node->nodename);
prompt = (char *)xmalloc (40 + strlen (default_nodename));
sprintf (prompt, "Kill node (%s): ", default_nodename);
nodename = info_read_completing_in_echo_area (window, prompt, menu);
free (prompt);
info_free_references (menu);
if (nodename && !*nodename)
{
free (nodename);
nodename = default_nodename;
}
else
free (default_nodename);
}
/* If there is no nodename to kill, quit now. */
if (!nodename)
{
info_abort_key (window, 0, 0);
return;
}
/* If there is a nodename, find it in our window list. */
for (iw = 0; info_win = info_windows[iw]; iw++)
if (strcmp (nodename, info_win->nodes[info_win->current]->nodename) == 0)
break;
if (!info_win)
{
if (*nodename)
info_error ("Cannot kill the node `%s'", nodename);
else
window_clear_echo_area ();
return;
}
/* If there are no more nodes left anywhere to view, complain and exit. */
if (info_windows_index == 1 && info_windows[0]->nodes_index == 1)
{
info_error ("Cannot kill the last node");
return;
}
/* INFO_WIN contains the node that the user wants to stop viewing.
Delete this node from the list of nodes previously shown in this
window. */
for (i = info_win->current; i < info_win->nodes_index; i++)
info_win->nodes[i] = info_win->nodes[i++];
/* There is one less node in this window's history list. */
info_win->nodes_index--;
/* Make this window show the most recent history node. */
info_win->current = info_win->nodes_index - 1;
/* If there aren't any nodes left in this window, steal one from the
next window. */
if (info_win->current < 0)
{
INFO_WINDOW *stealer;
int which, pagetop;
long point;
if (info_windows[iw + 1])
stealer = info_windows[iw + 1];
else
stealer = info_windows[0];
/* If the node being displayed in the next window is not the most
recently loaded one, get the most recently loaded one. */
if ((stealer->nodes_index - 1) != stealer->current)
which = stealer->nodes_index - 1;
/* Else, if there is another node behind the stealers current node,
use that one. */
else if (stealer->current > 0)
which = stealer->current - 1;
/* Else, just use the node appearing in STEALER's window. */
else
which = stealer->current;
/* Copy this node. */
{
NODE *copy;
temp = stealer->nodes[which];
point = stealer->points[which];
pagetop = stealer->pagetops[which];
copy = (NODE *)xmalloc (sizeof (NODE));
copy->filename = temp->filename;
copy->parent = temp->parent;
copy->nodename = temp->nodename;
copy->contents = temp->contents;
copy->nodelen = temp->nodelen;
copy->flags = temp->flags;
temp = copy;
}
window_set_node_of_window (info_win->window, temp);
window->point = point;
window->pagetop = pagetop;
remember_window_and_node (info_win->window, temp);
}
else
{
temp = info_win->nodes[info_win->current];
window_set_node_of_window (info_win->window, temp);
}
if (!info_error_was_printed)
window_clear_echo_area ();
}
/* Read the name of a file and select the entire file. */
DECLARE_INFO_COMMAND (info_view_file, "Read the name of a file and select it")
{
char *line;
line = info_read_in_echo_area (window, "Find file: ");
if (!line)
{
info_abort_key (active_window, 1, 0);
return;
}
if (*line)
{
NODE *node;
node = info_get_node (line, "*");
if (!node)
{
if (info_recent_file_error)
info_error (info_recent_file_error);
else
info_error ("Cannot find \"%s\".", line);
}
else
{
set_remembered_pagetop_and_point (active_window);
info_set_node_of_window (window, node);
}
free (line);
}
if (!info_error_was_printed)
window_clear_echo_area ();
}
/* **************************************************************** */
/* */
/* Dumping and Printing Nodes */
/* */
/* **************************************************************** */
#define VERBOSE_NODE_DUMPING
static void write_node_to_stream ();
static void dump_node_to_stream ();
static void initialize_dumping ();
/* Dump the nodes specified by FILENAME and NODENAMES to the file named
in OUTPUT_FILENAME. If DUMP_SUBNODES is non-zero, recursively dump
the nodes which appear in the menu of each node dumped. */
void
dump_nodes_to_file (filename, nodenames, output_filename, dump_subnodes)
char *filename;
char **nodenames;
char *output_filename;
int dump_subnodes;
{
register int i;
FILE *output_stream;
/* Get the stream to print the nodes to. Special case of an output
filename of "-" means to dump the nodes to stdout. */
if (strcmp (output_filename, "-") == 0)
output_stream = stdout;
else
output_stream = fopen (output_filename, "w");
if (!output_stream)
{
info_error ("Could not create output file \"%s\".", output_filename);
return;
}
/* Print each node to stream. */
initialize_dumping ();
for (i = 0; nodenames[i]; i++)
dump_node_to_stream (filename, nodenames[i], output_stream, dump_subnodes);
if (output_stream != stdout)
fclose (output_stream);
#if defined (VERBOSE_NODE_DUMPING)
info_error ("Done.");
#endif /* VERBOSE_NODE_DUMPING */
}
/* A place to remember already dumped nodes. */
static char **dumped_already = (char **)NULL;
static int dumped_already_index = 0;
static int dumped_already_slots = 0;
static void
initialize_dumping ()
{
dumped_already_index = 0;
}
/* Get and print the node specified by FILENAME and NODENAME to STREAM.
If DUMP_SUBNODES is non-zero, recursively dump the nodes which appear
in the menu of each node dumped. */
static void
dump_node_to_stream (filename, nodename, stream, dump_subnodes)
char *filename, *nodename;
FILE *stream;
int dump_subnodes;
{
register int i;
NODE *node;
node = info_get_node (filename, nodename);
if (!node)
{
if (info_recent_file_error)
info_error (info_recent_file_error);
else
{
if (filename && *nodename != '(')
info_error
(CANT_FILE_NODE, filename_non_directory (filename), nodename);
else
info_error (CANT_FIND_NODE, nodename);
}
return;
}
/* If we have already dumped this node, don't dump it again. */
for (i = 0; i < dumped_already_index; i++)
if (strcmp (node->nodename, dumped_already[i]) == 0)
{
free (node);
return;
}
add_pointer_to_array (node->nodename, dumped_already_index, dumped_already,
dumped_already_slots, 50, char *);
#if defined (VERBOSE_NODE_DUMPING)
/* Maybe we should print some information about the node being output. */
if (node->filename)
info_error ("Writing node \"(%s)%s\"...",
filename_non_directory (node->filename), node->nodename);
else
info_error ("Writing node \"%s\"...", node->nodename);
#endif /* VERBOSE_NODE_DUMPING */
write_node_to_stream (node, stream);
/* If we are dumping subnodes, get the list of menu items in this node,
and dump each one recursively. */
if (dump_subnodes)
{
REFERENCE **menu = (REFERENCE **)NULL;
/* If this node is an Index, do not dump the menu references. */
if (string_in_line ("Index", node->nodename) == -1)
menu = info_menu_of_node (node);
if (menu)
{
for (i = 0; menu[i]; i++)
{
/* We don't dump Info files which are different than the
current one. */
if (!menu[i]->filename)
dump_node_to_stream
(filename, menu[i]->nodename, stream, dump_subnodes);
}
info_free_references (menu);
}
}
free (node);
}
/* Dump NODE to FILENAME. If DUMP_SUBNODES is non-zero, recursively dump
the nodes which appear in the menu of each node dumped. */
void
dump_node_to_file (node, filename, dump_subnodes)
NODE *node;
char *filename;
int dump_subnodes;
{
FILE *output_stream;
char *nodes_filename;
/* Get the stream to print this node to. Special case of an output
filename of "-" means to dump the nodes to stdout. */
if (strcmp (filename, "-") == 0)
output_stream = stdout;
else
output_stream = fopen (filename, "w");
if (!output_stream)
{
info_error ("Could not create output file \"%s\".", filename);
return;
}
if (node->parent)
nodes_filename = node->parent;
else
nodes_filename = node->filename;
initialize_dumping ();
dump_node_to_stream
(nodes_filename, node->nodename, output_stream, dump_subnodes);
if (output_stream != stdout)
fclose (output_stream);
#if defined (VERBOSE_NODE_DUMPING)
info_error ("Done.");
#endif /* VERBOSE_NODE_DUMPING */
}
#if !defined (DEFAULT_INFO_PRINT_COMMAND)
# define DEFAULT_INFO_PRINT_COMMAND "lpr"
#endif /* !DEFAULT_INFO_PRINT_COMMAND */
DECLARE_INFO_COMMAND (info_print_node,
"Pipe the contents of this node through INFO_PRINT_COMMAND")
{
print_node (window->node);
}
/* Print NODE on a printer piping it into INFO_PRINT_COMMAND. */
void
print_node (node)
NODE *node;
{
char *print_command, *getenv ();
FILE *printer_pipe;
print_command = getenv ("INFO_PRINT_COMMAND");
if (!print_command || !*print_command)
print_command = DEFAULT_INFO_PRINT_COMMAND;
printer_pipe = popen (print_command, "w");
if (!printer_pipe)
{
info_error ("Cannot open pipe to \"%s\".", print_command);
return;
}
#if defined (VERBOSE_NODE_DUMPING)
/* Maybe we should print some information about the node being output. */
if (node->filename)
info_error ("Printing node \"(%s)%s\"...",
filename_non_directory (node->filename), node->nodename);
else
info_error ("Printing node \"%s\"...", node->nodename);
#endif /* VERBOSE_NODE_DUMPING */
write_node_to_stream (node, printer_pipe);
pclose (printer_pipe);
#if defined (VERBOSE_NODE_DUMPING)
info_error ("Done.");
#endif /* VERBOSE_NODE_DUMPING */
}
static void
write_node_to_stream (node, stream)
NODE *node;
FILE *stream;
{
fwrite (node->contents, 1, node->nodelen, stream);
}
/* **************************************************************** */
/* */
/* Info Searching Commands */
/* */
/* **************************************************************** */
/* Variable controlling the garbage collection of files briefly visited
during searches. Such files are normally gc'ed, unless they were
compressed to begin with. If this variable is non-zero, it says
to gc even those file buffer contents which had to be uncompressed. */
int gc_compressed_files = 0;
static void info_gc_file_buffers ();
static char *search_string = (char *)NULL;
static int search_string_index = 0;
static int search_string_size = 0;
static int isearch_is_active = 0;
/* Return the file buffer which belongs to WINDOW's node. */
FILE_BUFFER *
file_buffer_of_window (window)
WINDOW *window;
{
/* If this window has no node, then it has no file buffer. */
if (!window->node)
return ((FILE_BUFFER *)NULL);
if (window->node->parent)
return (info_find_file (window->node->parent));
if (window->node->filename)
return (info_find_file (window->node->filename));
return ((FILE_BUFFER *)NULL);
}
/* Search for STRING in NODE starting at START. Return -1 if the string
was not found, or the location of the string if it was. If WINDOW is
passed as non-null, set the window's node to be NODE, its point to be
the found string, and readjust the window's pagetop. Final argument
DIR says which direction to search in. If it is positive, search
forward, else backwards. */
long
info_search_in_node (string, node, start, window, dir)
char *string;
NODE *node;
long start;
WINDOW *window;
int dir;
{
SEARCH_BINDING binding;
long offset;
binding.buffer = node->contents;
binding.start = start;
binding.end = node->nodelen;
binding.flags = S_FoldCase;
if (dir < 0)
{
binding.end = 0;
binding.flags |= S_SkipDest;
}
if (binding.start < 0)
return (-1);
/* For incremental searches, we always wish to skip past the string. */
if (isearch_is_active)
binding.flags |= S_SkipDest;
offset = search (string, &binding);
if (offset != -1 && window)
{
set_remembered_pagetop_and_point (window);
if (window->node != node)
window_set_node_of_window (window, node);
window->point = offset;
window_adjust_pagetop (window);
}
return (offset);
}
/* Search NODE, looking for the largest possible match of STRING. Start the
search at START. Return the absolute position of the match, or -1, if
no part of the string could be found. */
long
info_target_search_node (node, string, start)
NODE *node;
char *string;
long start;
{
register int i;
long offset;
char *target;
target = strdup (string);
i = strlen (target);
/* Try repeatedly searching for this string while removing words from
the end of it. */
while (i)
{
target[i] = '\0';
offset = info_search_in_node (target, node, start, (WINDOW *)NULL, 1);
if (offset != -1)
break;
/* Delete the last word from TARGET. */
for (; i && (!whitespace (target[i]) && (target[i] != ',')); i--);
}
free (target);
return (offset);
}
/* Search for STRING starting in WINDOW at point. If the string is found
in this node, set point to that position. Otherwise, get the file buffer
associated with WINDOW's node, and search through each node in that file.
If the search fails, return non-zero, else zero. Side-effect window
leaving the node and point where the string was found current. */
static char *last_searched_for_string = (char *)NULL;
static int
info_search_internal (string, window, dir)
char *string;
WINDOW *window;
int dir;
{
register int i;
FILE_BUFFER *file_buffer;
char *initial_nodename;
long ret, start = 0;
file_buffer = file_buffer_of_window (window);
initial_nodename = window->node->nodename;
if ((info_last_executed_command == info_search) &&
(last_searched_for_string) &&
(strcmp (last_searched_for_string, string) == 0))
{
ret = info_search_in_node
(string, window->node, window->point + dir, window, dir);
}
else
{
ret = info_search_in_node
(string, window->node, window->point, window, dir);
}
maybe_free (last_searched_for_string);
last_searched_for_string = strdup (string);
if (ret != -1)
{
/* We won! */
if (!echo_area_is_active && !isearch_is_active)
window_clear_echo_area ();
return (0);
}
/* The string wasn't found in the current node. Search through the
window's file buffer, iff the current node is not "*". */
if (!file_buffer || (strcmp (initial_nodename, "*") == 0))
return (-1);
/* If this file has tags, search through every subfile, starting at
this node's subfile and node. Otherwise, search through the
file's node list. */
if (file_buffer->tags)
{
register int current_tag, number_of_tags;
char *last_subfile;
TAG *tag;
/* Find number of tags and current tag. */
last_subfile = (char *)NULL;
for (i = 0; file_buffer->tags[i]; i++)
if (strcmp (initial_nodename, file_buffer->tags[i]->nodename) == 0)
{
current_tag = i;
last_subfile = file_buffer->tags[i]->filename;
}
number_of_tags = i;
/* If there is no last_subfile, our tag wasn't found. */
if (!last_subfile)
return (-1);
/* Search through subsequent nodes, wrapping around to the top
of the info file until we find the string or return to this
window's node and point. */
while (1)
{
NODE *node;
/* Allow C-g to quit the search, failing it if pressed. */
return_if_control_g (-1);
current_tag += dir;
if (current_tag < 0)
current_tag = number_of_tags - 1;
else if (current_tag == number_of_tags)
current_tag = 0;
tag = file_buffer->tags[current_tag];
if (!echo_area_is_active && (last_subfile != tag->filename))
{
window_message_in_echo_area
("Searching subfile \"%s\"...",
filename_non_directory (tag->filename));
last_subfile = tag->filename;
}
node = info_get_node (file_buffer->filename, tag->nodename);
if (!node)
{
/* If not doing i-search... */
if (!echo_area_is_active)
{
if (info_recent_file_error)
info_error (info_recent_file_error);
else
info_error (CANT_FILE_NODE,
filename_non_directory (file_buffer->filename),
tag->nodename);
}
return (-1);
}
if (dir < 0)
start = tag->nodelen;
ret =
info_search_in_node (string, node, start, window, dir);
/* Did we find the string in this node? */
if (ret != -1)
{
/* Yes! We win. */
remember_window_and_node (window, node);
if (!echo_area_is_active)
window_clear_echo_area ();
return (0);
}
/* No. Free this node, and make sure that we haven't passed
our starting point. */
free (node);
if (strcmp (initial_nodename, tag->nodename) == 0)
return (-1);
}
}
return (-1);
}
DECLARE_INFO_COMMAND (info_search, "Read a string and search for it")
{
char *line, *prompt;
int result, old_pagetop;
int direction;
if (count < 0)
direction = -1;
else
direction = 1;
/* Read a string from the user, defaulting the search to SEARCH_STRING. */
if (!search_string)
{
search_string = (char *)xmalloc (search_string_size = 100);
search_string[0] = '\0';
}
prompt = (char *)xmalloc (50 + strlen (search_string));
sprintf (prompt, "%s for string [%s]: ",
direction < 0 ? "Search backward" : "Search",
search_string);
line = info_read_in_echo_area (window, prompt);
free (prompt);
if (!line)
{
info_abort_key ();
return;
}
if (*line)
{
if (strlen (line) + 1 > search_string_size)
search_string = (char *)
xrealloc (search_string, (search_string_size += 50 + strlen (line)));
strcpy (search_string, line);
search_string_index = strlen (line);
free (line);
}
old_pagetop = active_window->pagetop;
result = info_search_internal (search_string, active_window, direction);
if (result != 0 && !info_error_was_printed)
info_error ("Search failed.");
else if (old_pagetop != active_window->pagetop)
{
int new_pagetop;
new_pagetop = active_window->pagetop;
active_window->pagetop = old_pagetop;
set_window_pagetop (active_window, new_pagetop);
if (auto_footnotes_p)
info_get_or_remove_footnotes (active_window);
}
/* Perhaps free the unreferenced file buffers that were searched, but
not retained. */
info_gc_file_buffers ();
}
/* **************************************************************** */
/* */
/* Incremental Searching */
/* */
/* **************************************************************** */
static void incremental_search ();
DECLARE_INFO_COMMAND (isearch_forward,
"Search interactively for a string as you type it")
{
incremental_search (window, count, key);
}
DECLARE_INFO_COMMAND (isearch_backward,
"Search interactively for a string as you type it")
{
incremental_search (window, -count, key);
}
/* Incrementally search for a string as it is typed. */
/* The last accepted incremental search string. */
static char *last_isearch_accepted = (char *)NULL;
/* The current incremental search string. */
static char *isearch_string = (char *)NULL;
static int isearch_string_index = 0;
static int isearch_string_size = 0;
static unsigned char isearch_terminate_search_key = ESC;
/* Structure defining the current state of an incremental search. */
typedef struct {
WINDOW_STATE_DECL; /* The node, pagetop and point. */
int search_index; /* Offset of the last char in the search string. */
int direction; /* The direction that this search is heading in. */
int failing; /* Whether or not this search failed. */
} SEARCH_STATE;
/* Array of search states. */
static SEARCH_STATE **isearch_states = (SEARCH_STATE **)NULL;
static int isearch_states_index = 0;
static int isearch_states_slots = 0;
/* Push the state of this search. */
static void
push_isearch (window, search_index, direction, failing)
WINDOW *window;
int search_index, direction, failing;
{
SEARCH_STATE *state;
state = (SEARCH_STATE *)xmalloc (sizeof (SEARCH_STATE));
window_get_state (window, state);
state->search_index = search_index;
state->direction = direction;
state->failing = failing;
add_pointer_to_array (state, isearch_states_index, isearch_states,
isearch_states_slots, 20, SEARCH_STATE *);
}
/* Pop the state of this search to WINDOW, SEARCH_INDEX, and DIRECTION. */
static void
pop_isearch (window, search_index, direction, failing)
WINDOW *window;
int *search_index, *direction, *failing;
{
SEARCH_STATE *state;
if (isearch_states_index)
{
isearch_states_index--;
state = isearch_states[isearch_states_index];
window_set_state (window, state);
*search_index = state->search_index;
*direction = state->direction;
*failing = state->failing;
free (state);
isearch_states[isearch_states_index] = (SEARCH_STATE *)NULL;
}
}
/* Free the memory used by isearch_states. */
static void
free_isearch_states ()
{
register int i;
for (i = 0; i < isearch_states_index; i++)
{
free (isearch_states[i]);
isearch_states[i] = (SEARCH_STATE *)NULL;
}
isearch_states_index = 0;
}
/* Display the current search in the echo area. */
static void
show_isearch_prompt (dir, string, failing_p)
int dir;
unsigned char *string;
int failing_p;
{
register int i;
char *prefix, *prompt, *p_rep;
int prompt_len, p_rep_index, p_rep_size;
if (dir < 0)
prefix = "I-search backward: ";
else
prefix = "I-search: ";
p_rep_index = p_rep_size = 0;
p_rep = (char *)NULL;
for (i = 0; string[i]; i++)
{
char *rep;
switch (string[i])
{
case ' ': rep = " "; break;
case LFD: rep = "\\n"; break;
case TAB: rep = "\\t"; break;
default:
rep = pretty_keyname (string[i]);
}
if ((p_rep_index + strlen (rep) + 1) >= p_rep_size)
p_rep = (char *)xrealloc (p_rep, p_rep_size += 100);
strcpy (p_rep + p_rep_index, rep);
p_rep_index += strlen (rep);
}
prompt_len = strlen (prefix) + p_rep_index + 20;
prompt = (char *)xmalloc (prompt_len);
sprintf (prompt, "%s%s%s", failing_p ? "Failing " : "", prefix,
p_rep ? p_rep : "");
window_message_in_echo_area ("%s", prompt);
maybe_free (p_rep);
free (prompt);
display_cursor_at_point (active_window);
}
static void
incremental_search (window, count, ignore)
WINDOW *window;
int count;
unsigned char ignore;
{
unsigned char key;
int last_search_result, search_result, dir;
SEARCH_STATE mystate, orig_state;
if (count < 0)
dir = -1;
else
dir = 1;
last_search_result = search_result = 0;
window_get_state (window, &orig_state);
isearch_string_index = 0;
if (!isearch_string_size)
isearch_string = (char *)xmalloc (isearch_string_size = 50);
/* Show the search string in the echo area. */
isearch_string[isearch_string_index] = '\0';
show_isearch_prompt (dir, isearch_string, search_result);
isearch_is_active = 1;
while (isearch_is_active)
{
VFunction *func = (VFunction *)NULL;
int quoted = 0;
/* If a recent display was interrupted, then do the redisplay now if
it is convenient. */
if (!info_any_buffered_input_p () && display_was_interrupted_p)
{
display_update_one_window (window);
display_cursor_at_point (active_window);
}
/* Read a character and dispatch on it. */
key = info_get_input_char ();
window_get_state (window, &mystate);
if (key == DEL)
{
/* User wants to delete one level of search? */
if (!isearch_states_index)
{
terminal_ring_bell ();
continue;
}
else
{
pop_isearch
(window, &isearch_string_index, &dir, &search_result);
isearch_string[isearch_string_index] = '\0';
show_isearch_prompt (dir, isearch_string, search_result);
goto after_search;
}
}
else if (key == Control ('q'))
{
key = info_get_input_char ();
quoted = 1;
}
/* We are about to search again, or quit. Save the current search. */
push_isearch (window, isearch_string_index, dir, search_result);
if (quoted)
goto insert_and_search;
if (!Meta_p (key) || (ISO_Latin_p && key < 160))
{
func = window->keymap[key].function;
/* If this key invokes an incremental search, then this means that
we will either search again in the same direction, search
again in the reverse direction, or insert the last search
string that was accepted through incremental searching. */
if (func == isearch_forward || func == isearch_backward)
{
if ((func == isearch_forward && dir > 0) ||
(func == isearch_backward && dir < 0))
{
/* If the user has typed no characters, then insert the
last successful search into the current search string. */
if (isearch_string_index == 0)
{
/* Of course, there must be something to insert. */
if (last_isearch_accepted)
{
if (strlen (last_isearch_accepted) + 1 >=
isearch_string_size)
isearch_string = (char *)
xrealloc (isearch_string,
isearch_string_size += 10 +
strlen (last_isearch_accepted));
strcpy (isearch_string, last_isearch_accepted);
isearch_string_index = strlen (isearch_string);
goto search_now;
}
else
continue;
}
else
{
/* Search again in the same direction. This means start
from a new place if the last search was successful. */
if (search_result == 0)
window->point += dir;
}
}
else
{
/* Reverse the direction of the search. */
dir = -dir;
}
}
else if (isprint (key) || func == (VFunction *)NULL)
{
insert_and_search:
if (isearch_string_index + 2 >= isearch_string_size)
isearch_string = (char *)xrealloc
(isearch_string, isearch_string_size += 100);
isearch_string[isearch_string_index++] = key;
isearch_string[isearch_string_index] = '\0';
goto search_now;
}
else if (func == info_abort_key)
{
/* If C-g pressed, and the search is failing, pop the search
stack back to the last unfailed search. */
if (isearch_states_index && (search_result != 0))
{
terminal_ring_bell ();
while (isearch_states_index && (search_result != 0))
pop_isearch
(window, &isearch_string_index, &dir, &search_result);
isearch_string[isearch_string_index] = '\0';
show_isearch_prompt (dir, isearch_string, search_result);
continue;
}
else
goto exit_search;
}
else
goto exit_search;
}
else
{
exit_search:
/* The character is not printable, or it has a function which is
non-null. Exit the search, remembering the search string. If
the key is not the same as the isearch_terminate_search_key,
then push it into pending input. */
if (isearch_string_index && func != info_abort_key)
{
maybe_free (last_isearch_accepted);
last_isearch_accepted = strdup (isearch_string);
}
if (key != isearch_terminate_search_key)
info_set_pending_input (key);
if (func == info_abort_key)
{
if (isearch_states_index)
window_set_state (window, &orig_state);
}
if (!echo_area_is_active)
window_clear_echo_area ();
if (auto_footnotes_p)
info_get_or_remove_footnotes (active_window);
isearch_is_active = 0;
continue;
}
/* Search for the contents of isearch_string. */
search_now:
show_isearch_prompt (dir, isearch_string, search_result);
if (search_result == 0)
{
/* Check to see if the current search string is right here. If
we are looking at it, then don't bother calling the search
function. */
if (((dir < 0) &&
(strncasecmp (window->node->contents + window->point,
isearch_string, isearch_string_index) == 0)) ||
((dir > 0) &&
((window->point - isearch_string_index) >= 0) &&
(strncasecmp (window->node->contents +
(window->point - (isearch_string_index - 1)),
isearch_string, isearch_string_index) == 0)))
{
if (dir > 0)
window->point++;
}
else
search_result = info_search_internal (isearch_string, window, dir);
}
/* If this search failed, and we didn't already have a failed search,
then ring the terminal bell. */
if (search_result != 0 && last_search_result == 0)
terminal_ring_bell ();
after_search:
show_isearch_prompt (dir, isearch_string, search_result);
if (search_result == 0)
{
if ((mystate.node == window->node) &&
(mystate.pagetop != window->pagetop))
{
int newtop = window->pagetop;
window->pagetop = mystate.pagetop;
set_window_pagetop (window, newtop);
}
display_update_one_window (window);
display_cursor_at_point (window);
}
last_search_result = search_result;
}
/* Free the memory used to remember each search state. */
free_isearch_states ();
/* Perhaps GC some file buffers. */
info_gc_file_buffers ();
/* After searching, leave the window in the correct state. */
if (!echo_area_is_active)
window_clear_echo_area ();
}
/* GC some file buffers. A file buffer can be gc-ed if there we have
no nodes in INFO_WINDOWS that reference this file buffer's contents.
Garbage collecting a file buffer means to free the file buffers
contents. */
static void
info_gc_file_buffers ()
{
register int fb_index, iw_index, i;
register FILE_BUFFER *fb;
register INFO_WINDOW *iw;
if (!info_loaded_files)
return;
for (fb_index = 0; fb = info_loaded_files[fb_index]; fb_index++)
{
int fb_referenced_p = 0;
/* If already gc-ed, do nothing. */
if (!fb->contents)
continue;
/* If this file had to be uncompressed, check to see if we should
gc it. This means that the user-variable "gc-compressed-files"
is non-zero. */
if ((fb->flags & N_IsCompressed) && !gc_compressed_files)
continue;
/* If this file's contents are not gc-able, move on. */
if (fb->flags & N_CannotGC)
continue;
/* Check each INFO_WINDOW to see if it has any nodes which reference
this file. */
for (iw_index = 0; iw = info_windows[iw_index]; iw_index++)
{
for (i = 0; iw->nodes && iw->nodes[i]; i++)
{
if ((strcmp (fb->fullpath, iw->nodes[i]->filename) == 0) ||
(strcmp (fb->filename, iw->nodes[i]->filename) == 0))
{
fb_referenced_p = 1;
break;
}
}
}
/* If this file buffer wasn't referenced, free its contents. */
if (!fb_referenced_p)
{
free (fb->contents);
fb->contents = (char *)NULL;
}
}
}
/* **************************************************************** */
/* */
/* Traversing and Selecting References */
/* */
/* **************************************************************** */
/* Move to the next or previous cross reference in this node. */
static void
info_move_to_xref (window, count, key, dir)
WINDOW *window;
int count;
unsigned char key;
int dir;
{
long firstmenu, firstxref;
long nextmenu, nextxref;
long placement = -1;
long start = 0;
NODE *node = window->node;
if (dir < 0)
start = node->nodelen;
/* This search is only allowed to fail if there is no menu or cross
reference in the current node. Otherwise, the first menu or xref
found is moved to. */
firstmenu = info_search_in_node
(INFO_MENU_ENTRY_LABEL, node, start, (WINDOW *)NULL, dir);
/* FIRSTMENU may point directly to the line defining the menu. Skip that
and go directly to the first item. */
if (firstmenu != -1)
{
char *text = node->contents + firstmenu;
if (strncmp (text, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL)) == 0)
firstmenu = info_search_in_node
(INFO_MENU_ENTRY_LABEL, node, firstmenu + dir, (WINDOW *)NULL, dir);
}
firstxref =
info_search_in_node (INFO_XREF_LABEL, node, start, (WINDOW *)NULL, dir);
#if defined (HANDLE_MAN_PAGES)
if ((firstxref == -1) && (node->flags & N_IsManPage))
{
firstxref = locate_manpage_xref (node, start, dir);
}
#endif /* HANDLE_MAN_PAGES */
if (firstmenu == -1 && firstxref == -1)
{
info_error ("No cross references in this node.");
return;
}
/* There is at least one cross reference or menu entry in this node.
Try hard to find the next available one. */
nextmenu = info_search_in_node
(INFO_MENU_ENTRY_LABEL, node, window->point + dir, (WINDOW *)NULL, dir);
nextxref = info_search_in_node
(INFO_XREF_LABEL, node, window->point + dir, (WINDOW *)NULL, dir);
#if defined (HANDLE_MAN_PAGES)
if ((nextxref == -1) && (node->flags & N_IsManPage) && (firstxref != -1))
nextxref = locate_manpage_xref (node, window->point + dir, dir);
#endif /* HANDLE_MAN_PAGES */
/* Ignore "Menu:" as a menu item. */
if (nextmenu != -1)
{
char *text = node->contents + nextmenu;
if (strncmp (text, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL)) == 0)
nextmenu = info_search_in_node
(INFO_MENU_ENTRY_LABEL, node, nextmenu + dir, (WINDOW *)NULL, dir);
}
/* If there is both a next menu entry, and a next xref entry, choose the
one which occurs first. Otherwise, select the one which actually
appears in this node following point. */
if (nextmenu != -1 && nextxref != -1)
{
if (((dir == 1) && (nextmenu < nextxref)) ||
((dir == -1) && (nextmenu > nextxref)))
placement = nextmenu + 1;
else
placement = nextxref;
}
else if (nextmenu != -1)
placement = nextmenu + 1;
else if (nextxref != -1)
placement = nextxref;
/* If there was neither a menu or xref entry appearing in this node after
point, choose the first menu or xref entry appearing in this node. */
if (placement == -1)
{
if (firstmenu != -1 && firstxref != -1)
{
if (((dir == 1) && (firstmenu < firstxref)) ||
((dir == -1) && (firstmenu > firstxref)))
placement = firstmenu + 1;
else
placement = firstxref;
}
else if (firstmenu != -1)
placement = firstmenu + 1;
else
placement = firstxref;
}
window->point = placement;
window_adjust_pagetop (window);
window->flags |= W_UpdateWindow;
}
DECLARE_INFO_COMMAND (info_move_to_prev_xref,
"Move to the previous cross reference")
{
if (count < 0)
info_move_to_prev_xref (window, -count, key);
else
info_move_to_xref (window, count, key, -1);
}
DECLARE_INFO_COMMAND (info_move_to_next_xref,
"Move to the next cross reference")
{
if (count < 0)
info_move_to_next_xref (window, -count, key);
else
info_move_to_xref (window, count, key, 1);
}
/* Select the menu item or reference that appears on this line. */
DECLARE_INFO_COMMAND (info_select_reference_this_line,
"Select reference or menu item appearing on this line")
{
char *line;
NODE *orig;
line = window->line_starts[window_line_of_point (window)];
orig = window->node;
/* If this line contains a menu item, select that one. */
if (strncmp ("* ", line, 2) == 0)
info_menu_or_ref_item (window, count, key, info_menu_of_node, 0);
else
info_menu_or_ref_item (window, count, key, info_xrefs_of_node, 0);
}
/* **************************************************************** */
/* */
/* Miscellaneous Info Commands */
/* */
/* **************************************************************** */
/* What to do when C-g is pressed in a window. */
DECLARE_INFO_COMMAND (info_abort_key, "Cancel current operation")
{
/* If error printing doesn't oridinarily ring the bell, do it now,
since C-g always rings the bell. Otherwise, let the error printer
do it. */
if (!info_error_rings_bell_p)
terminal_ring_bell ();
info_error ("Quit");
info_initialize_numeric_arg ();
info_clear_pending_input ();
info_last_executed_command = (VFunction *)NULL;
}
/* Move the cursor to the desired line of the window. */
DECLARE_INFO_COMMAND (info_move_to_window_line,
"Move to the cursor to a specific line of the window")
{
int line;
/* With no numeric argument of any kind, default to the center line. */
if (!info_explicit_arg && count == 1)
line = (window->height / 2) + window->pagetop;
else
{
if (count < 0)
line = (window->height + count) + window->pagetop;
else
line = window->pagetop + count;
}
/* If the line doesn't appear in this window, make it do so. */
if ((line - window->pagetop) >= window->height)
line = window->pagetop + (window->height - 1);
/* If the line is too small, make it fit. */
if (line < window->pagetop)
line = window->pagetop;
/* If the selected line is past the bottom of the node, force it back. */
if (line >= window->line_count)
line = window->line_count - 1;
window->point = (window->line_starts[line] - window->node->contents);
}
/* Clear the screen and redraw its contents. Given a numeric argument,
move the line the cursor is on to the COUNT'th line of the window. */
DECLARE_INFO_COMMAND (info_redraw_display, "Redraw the display")
{
if ((!info_explicit_arg && count == 1) || echo_area_is_active)
{
terminal_clear_screen ();
display_clear_display (the_display);
window_mark_chain (windows, W_UpdateWindow);
display_update_display (windows);
}
else
{
int desired_line, point_line;
int new_pagetop;
point_line = window_line_of_point (window) - window->pagetop;
if (count < 0)
desired_line = window->height + count;
else
desired_line = count;
if (desired_line < 0)
desired_line = 0;
if (desired_line >= window->height)
desired_line = window->height - 1;
if (desired_line == point_line)
return;
new_pagetop = window->pagetop + (point_line - desired_line);
set_window_pagetop (window, new_pagetop);
}
}
/* This command does nothing. It is the fact that a key is bound to it
that has meaning. See the code at the top of info_session (). */
DECLARE_INFO_COMMAND (info_quit, "Quit using Info")
{}
/* **************************************************************** */
/* */
/* Reading Keys and Dispatching on Them */
/* */
/* **************************************************************** */
/* Declaration only. Special cased in info_dispatch_on_key (). */
DECLARE_INFO_COMMAND (info_do_lowercase_version, "")
{}
static void
dispatch_error (keyseq)
char *keyseq;
{
char *rep;
rep = pretty_keyseq (keyseq);
if (!echo_area_is_active)
info_error ("Unknown command (%s).", rep);
else
{
char *temp;
temp = (char *)xmalloc (1 + strlen (rep) + strlen ("\"\" is invalid"));
sprintf (temp, "\"%s\" is invalid", rep);
terminal_ring_bell ();
inform_in_echo_area (temp);
free (temp);
}
}
/* Keeping track of key sequences. */
static char *info_keyseq = (char *)NULL;
static char keyseq_rep[100];
static int info_keyseq_index = 0;
static int info_keyseq_size = 0;
static int info_keyseq_displayed_p = 0;
/* Initialize the length of the current key sequence. */
void
initialize_keyseq ()
{
info_keyseq_index = 0;
info_keyseq_displayed_p = 0;
}
/* Add CHARACTER to the current key sequence. */
void
add_char_to_keyseq (character)
char character;
{
if (info_keyseq_index + 2 >= info_keyseq_size)
info_keyseq = (char *)xrealloc (info_keyseq, info_keyseq_size += 10);
info_keyseq[info_keyseq_index++] = character;
info_keyseq[info_keyseq_index] = '\0';
}
/* Return the pretty printable string which represents KEYSEQ. */
char *
pretty_keyseq (keyseq)
char *keyseq;
{
register int i;
keyseq_rep[0] = '\0';
for (i = 0; keyseq[i]; i++)
{
sprintf (keyseq_rep + strlen (keyseq_rep), "%s%s",
strlen (keyseq_rep) ? " " : "",
pretty_keyname (keyseq[i]));
}
return (keyseq_rep);
}
/* Display the current value of info_keyseq. If argument EXPECTING is
non-zero, input is expected to be read after the key sequence is
displayed, so add an additional prompting character to the sequence. */
void
display_info_keyseq (expecting_future_input)
int expecting_future_input;
{
char *rep;
rep = pretty_keyseq (info_keyseq);
if (expecting_future_input)
strcat (rep, "-");
if (echo_area_is_active)
inform_in_echo_area (rep);
else
{
window_message_in_echo_area (rep);
display_cursor_at_point (active_window);
}
info_keyseq_displayed_p = 1;
}
/* Called by interactive commands to read a keystroke. */
unsigned char
info_get_another_input_char ()
{
int ready = 0;
/* If there isn't any input currently available, then wait a
moment looking for input. If we don't get it fast enough,
prompt a little bit with the current key sequence. */
if (!info_keyseq_displayed_p &&
!info_any_buffered_input_p () &&
!info_input_pending_p ())
{
#if defined (FD_SET)
struct timeval timer;
fd_set readfds;
FD_ZERO (&readfds);
FD_SET (fileno (info_input_stream), &readfds);
timer.tv_sec = 1;
timer.tv_usec = 750;
ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
#endif /* FD_SET */
}
if (!ready)
display_info_keyseq (1);
return (info_get_input_char ());
}
/* Do the command associated with KEY in MAP. If the associated command is
really a keymap, then read another key, and dispatch into that map. */
void
info_dispatch_on_key (key, map)
unsigned char key;
Keymap map;
{
if (Meta_p (key) && (!ISO_Latin_p || map[key].function != ea_insert))
{
if (map[ESC].type == ISKMAP)
{
map = (Keymap)map[ESC].function;
add_char_to_keyseq (ESC);
key = UnMeta (key);
info_dispatch_on_key (key, map);
}
else
{
dispatch_error (info_keyseq);
}
return;
}
switch (map[key].type)
{
case ISFUNC:
{
VFunction *func;
func = map[key].function;
if (func != (VFunction *)NULL)
{
/* Special case info_do_lowercase_version (). */
if (func == info_do_lowercase_version)
{
info_dispatch_on_key (tolower (key), map);
return;
}
add_char_to_keyseq (key);
if (info_keyseq_displayed_p)
display_info_keyseq (0);
{
WINDOW *where;
where = active_window;
(*map[key].function)
(active_window, info_numeric_arg * info_numeric_arg_sign, key);
/* If we have input pending, then the last command was a prefix
command. Don't change the value of the last function vars.
Otherwise, remember the last command executed in the var
appropriate to the window in which it was executed. */
if (!info_input_pending_p ())
{
if (where == the_echo_area)
ea_last_executed_command = map[key].function;
else
info_last_executed_command = map[key].function;
}
}
}
else
{
add_char_to_keyseq (key);
dispatch_error (info_keyseq);
return;
}
}
break;
case ISKMAP:
add_char_to_keyseq (key);
if (map[key].function != (VFunction *)NULL)
{
unsigned char newkey;
newkey = info_get_another_input_char ();
info_dispatch_on_key (newkey, (Keymap)map[key].function);
}
else
{
dispatch_error (info_keyseq);
return;
}
break;
}
}
/* **************************************************************** */
/* */
/* Numeric Arguments */
/* */
/* **************************************************************** */
/* Handle C-u style numeric args, as well as M--, and M-digits. */
/* Non-zero means that an explicit argument has been passed to this
command, as in C-u C-v. */
int info_explicit_arg = 0;
/* The sign of the numeric argument. */
int info_numeric_arg_sign = 1;
/* The value of the argument itself. */
int info_numeric_arg = 1;
/* Add the current digit to the argument in progress. */
DECLARE_INFO_COMMAND (info_add_digit_to_numeric_arg,
"Add this digit to the current numeric argument")
{
info_numeric_arg_digit_loop (window, 0, key);
}
/* C-u, universal argument. Multiply the current argument by 4.
Read a key. If the key has nothing to do with arguments, then
dispatch on it. If the key is the abort character then abort. */
DECLARE_INFO_COMMAND (info_universal_argument,
"Start (or multiply by 4) the current numeric argument")
{
info_numeric_arg *= 4;
info_numeric_arg_digit_loop (window, 0, 0);
}
/* Create a default argument. */
void
info_initialize_numeric_arg ()
{
info_numeric_arg = info_numeric_arg_sign = 1;
info_explicit_arg = 0;
}
DECLARE_INFO_COMMAND (info_numeric_arg_digit_loop,
"Internally used by \\[universal-argument]")
{
unsigned char pure_key;
Keymap keymap = window->keymap;
while (1)
{
if (key)
pure_key = key;
else
{
if (display_was_interrupted_p && !info_any_buffered_input_p ())
display_update_display (windows);
if (active_window != the_echo_area)
display_cursor_at_point (active_window);
pure_key = key = info_get_another_input_char ();
if (Meta_p (key))
add_char_to_keyseq (ESC);
add_char_to_keyseq (UnMeta (key));
}
if (Meta_p (key))
key = UnMeta (key);
if (keymap[key].type == ISFUNC &&
keymap[key].function == info_universal_argument)
{
info_numeric_arg *= 4;
key = 0;
continue;
}
if (isdigit (key))
{
if (info_explicit_arg)
info_numeric_arg = (info_numeric_arg * 10) + (key - '0');
else
info_numeric_arg = (key - '0');
info_explicit_arg = 1;
}
else
{
if (key == '-' && !info_explicit_arg)
{
info_numeric_arg_sign = -1;
info_numeric_arg = 1;
}
else
{
info_keyseq_index--;
info_dispatch_on_key (pure_key, keymap);
return;
}
}
key = 0;
}
}
/* **************************************************************** */
/* */
/* Input Character Buffering */
/* */
/* **************************************************************** */
/* Character waiting to be read next. */
static int pending_input_character = 0;
/* How to make there be no pending input. */
static void
info_clear_pending_input ()
{
pending_input_character = 0;
}
/* How to set the pending input character. */
static void
info_set_pending_input (key)
unsigned char key;
{
pending_input_character = key;
}
/* How to see if there is any pending input. */
unsigned char
info_input_pending_p ()
{
return (pending_input_character);
}
/* Largest number of characters that we can read in advance. */
#define MAX_INFO_INPUT_BUFFERING 512
static int pop_index = 0, push_index = 0;
static unsigned char info_input_buffer[MAX_INFO_INPUT_BUFFERING];
/* Add KEY to the buffer of characters to be read. */
static void
info_push_typeahead (key)
unsigned char key;
{
/* Flush all pending input in the case of C-g pressed. */
if (key == Control ('g'))
{
push_index = pop_index;
info_set_pending_input (Control ('g'));
}
else
{
info_input_buffer[push_index++] = key;
if (push_index >= sizeof (info_input_buffer))
push_index = 0;
}
}
/* Return the amount of space available in INFO_INPUT_BUFFER for new chars. */
static int
info_input_buffer_space_available ()
{
if (pop_index > push_index)
return (pop_index - push_index);
else
return (sizeof (info_input_buffer - (push_index - pop_index)));
}
/* Get a key from the buffer of characters to be read.
Return the key in KEY.
Result is non-zero if there was a key, or 0 if there wasn't. */
static int
info_get_key_from_typeahead (key)
unsigned char *key;
{
if (push_index == pop_index)
return (0);
*key = info_input_buffer[pop_index++];
if (pop_index >= sizeof (info_input_buffer))
pop_index = 0;
return (1);
}
int
info_any_buffered_input_p ()
{
info_gather_typeahead ();
return (push_index != pop_index);
}
/* Push KEY into the *front* of the input buffer. Returns non-zero if
successful, zero if there is no space left in the buffer. */
static int
info_replace_key_to_typeahead (key)
unsigned char key;
{
if (info_input_buffer_space_available ())
{
pop_index--;
if (pop_index < 0)
pop_index = sizeof (info_input_buffer) - 1;
info_input_buffer[pop_index] = key;
return (1);
}
return (0);
}
/* If characters are available to be read, then read them and stuff them into
info_input_buffer. Otherwise, do nothing. */
void
info_gather_typeahead ()
{
int tty, space_avail;
long chars_avail;
unsigned char input[MAX_INFO_INPUT_BUFFERING];
tty = fileno (info_input_stream);
chars_avail = 0;
space_avail = info_input_buffer_space_available ();
/* If we can just find out how many characters there are to read, do so. */
#if defined (FIONREAD)
{
ioctl (tty, FIONREAD, &chars_avail);
if (chars_avail > space_avail)
chars_avail = space_avail;
if (chars_avail)
read (tty, &input[0], chars_avail);
}
#else /* !FIONREAD */
# if defined (O_NDELAY)
{
int flags;
flags = fcntl (tty, F_GETFL, 0);
fcntl (tty, F_SETFL, (flags | O_NDELAY));
chars_avail = read (tty, &input[0], space_avail);
fcntl (tty, F_SETFL, flags);
if (chars_avail == -1)
chars_avail = 0;
}
# endif /* O_NDELAY */
#endif /* !FIONREAD */
/* Store the input characters just read into our input buffer. */
{
register int i;
for (i = 0; i < chars_avail; i++)
info_push_typeahead (input[i]);
}
}
/* How to read a single character. */
unsigned char
info_get_input_char ()
{
unsigned char keystroke;
info_gather_typeahead ();
if (pending_input_character)
{
keystroke = pending_input_character;
pending_input_character = 0;
}
else if (info_get_key_from_typeahead (&keystroke) == 0)
{
int rawkey;
rawkey = getc (info_input_stream);
keystroke = rawkey;
if (rawkey == EOF)
{
if (info_input_stream != stdin)
{
fclose (info_input_stream);
info_input_stream = stdin;
display_inhibited = 0;
display_update_display (windows);
display_cursor_at_point (active_window);
rawkey = getc (info_input_stream);
keystroke = rawkey;
}
if (rawkey == EOF)
{
terminal_unprep_terminal ();
close_dribble_file ();
exit (0);
}
}
}
if (info_dribble_file)
dribble (keystroke);
return (keystroke);
}
texinfo-3.7/info/session.h 100666 11732 13 13442 5770343456 14062 0 ustar bfox user /* session.h -- Functions found in session.c. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_SESSION_H_)
#define _SESSION_H_
#include "general.h"
#include "dribble.h"
/* All commands that can be invoked from within info_session () receive
arguments in the same way. This simple define declares the header
of a function named NAME, with associated documentation DOC. The
documentation string is groveled out of the source files by the
utility program `makedoc', which is also responsible for making
the documentation/function-pointer maps. */
#define DECLARE_INFO_COMMAND(name, doc) \
void name (window, count, key) WINDOW *window; int count; unsigned char key;
/* Variables found in session.h. */
extern VFunction *info_last_executed_command;
/* Variable controlling the garbage collection of files briefly visited
during searches. Such files are normally gc'ed, unless they were
compressed to begin with. If this variable is non-zero, it says
to gc even those file buffer contents which had to be uncompressed. */
extern int gc_compressed_files;
/* When non-zero, tiling takes place automatically when info_split_window
is called. */
extern int auto_tiling_p;
/* Variable controlling the behaviour of default scrolling when you are
already at the bottom of a node. */
extern int info_scroll_behaviour;
extern char *info_scroll_choices[];
/* Values for info_scroll_behaviour. */
#define IS_Continuous 0 /* Try to get first menu item, or failing that, the
"Next:" pointer, or failing that, the "Up:" and
"Next:" of the up. */
#define IS_NextOnly 1 /* Try to get "Next:" menu item. */
#define IS_PageOnly 2 /* Simply give up at the bottom of a node. */
/* Utility functions found in session.c */
extern void info_dispatch_on_key ();
extern unsigned char info_get_input_char (), info_get_another_input_char ();
extern unsigned char info_input_pending_p ();
extern void remember_window_and_node (), set_remembered_pagetop_and_point ();
extern void set_window_pagetop (), info_set_node_of_window ();
extern char *pretty_keyseq ();
extern void initialize_keyseq (), add_char_to_keyseq ();
extern void info_gather_typeahead ();
extern FILE_BUFFER *file_buffer_of_window ();
extern long info_search_in_node (), info_target_search_node ();
extern void info_select_reference ();
extern int info_any_buffered_input_p ();
extern void print_node ();
extern void dump_node_to_file (), dump_nodes_to_file ();
/* Do the physical deletion of WINDOW, and forget this window and
associated nodes. */
extern void info_delete_window_internal ();
/* Tell Info that input is coming from the file FILENAME. */
extern void info_set_input_from_file ();
#define return_if_control_g(val) \
do { \
info_gather_typeahead (); \
if (info_input_pending_p () == Control ('g')) \
return (val); \
} while (0)
/* The names of the functions that run an info session. */
/* Starting an info session. */
extern void begin_multiple_window_info_session (), begin_info_session ();
extern void begin_info_session_with_error (), info_session ();
extern void info_read_and_dispatch ();
/* Moving the point within a node. */
extern void info_next_line (), info_prev_line ();
extern void info_end_of_line (), info_beginning_of_line ();
extern void info_forward_char (), info_backward_char ();
extern void info_forward_word (), info_backward_word ();
extern void info_beginning_of_node (), info_end_of_node ();
extern void info_move_to_prev_xref (), info_move_to_next_xref ();
/* Scrolling text within a window. */
extern void info_scroll_forward (), info_scroll_backward ();
extern void info_redraw_display (), info_toggle_wrap ();
extern void info_move_to_window_line ();
/* Manipulating multiple windows. */
extern void info_split_window (), info_delete_window ();
extern void info_keep_one_window (), info_grow_window ();
extern void info_scroll_other_window (), info_tile_windows ();
extern void info_next_window (), info_prev_window ();
/* Selecting nodes. */
extern void info_next_node (), info_prev_node (), info_up_node ();
extern void info_last_node (), info_first_node (), info_history_node ();
extern void info_goto_node (), info_top_node (), info_dir_node ();
extern void info_global_next_node (), info_global_prev_node ();
extern void info_kill_node (), info_view_file ();
/* Selecting cross references. */
extern void info_menu_digit (), info_menu_item (), info_xref_item ();
extern void info_find_menu (), info_select_reference_this_line ();
/* Hacking numeric arguments. */
extern int info_explicit_arg, info_numeric_arg, info_numeric_arg_sign;
extern void info_add_digit_to_numeric_arg (), info_universal_argument ();
extern void info_initialize_numeric_arg (), info_numeric_arg_digit_loop ();
/* Searching commands. */
extern void info_search (), isearch_forward (), isearch_backward ();
/* Dumping and printing nodes. */
extern void info_print_node ();
/* Miscellaneous commands. */
extern void info_abort_key (), info_quit (), info_do_lowercase_version ();
#endif /* _SESSION_H_ */
texinfo-3.7/info/signals.c 100666 11732 13 11433 5770343330 14017 0 ustar bfox user /* signals.c -- Install and maintain Info signal handlers. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993, 1994, 1995 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). */
#include "info.h"
#include "signals.h"
/* **************************************************************** */
/* */
/* Pretending That We Have POSIX Signals */
/* */
/* **************************************************************** */
#if !defined (HAVE_SIGPROCMASK) && defined (HAVE_SIGSETMASK)
/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
static void
sigprocmask (operation, newset, oldset)
int operation, *newset, *oldset;
{
switch (operation)
{
case SIG_UNBLOCK:
sigsetmask (sigblock (0) & ~(*newset));
break;
case SIG_BLOCK:
*oldset = sigblock (*newset);
break;
case SIG_SETMASK:
sigsetmask (*newset);
break;
default:
abort ();
}
}
#endif /* !HAVE_SIGPROCMASK && HAVE_SIGSETMASK */
/* **************************************************************** */
/* */
/* Signal Handling for Info */
/* */
/* **************************************************************** */
typedef void SigHandlerType;
typedef SigHandlerType SigHandler ();
static SigHandlerType info_signal_handler ();
static SigHandler *old_TSTP, *old_TTOU, *old_TTIN;
static SigHandler *old_WINCH, *old_INT;
void
initialize_info_signal_handler ()
{
#if defined (SIGTSTP)
old_TSTP = (SigHandler *) signal (SIGTSTP, info_signal_handler);
old_TTOU = (SigHandler *) signal (SIGTTOU, info_signal_handler);
old_TTIN = (SigHandler *) signal (SIGTTIN, info_signal_handler);
#endif /* SIGTSTP */
#if defined (SIGWINCH)
old_WINCH = (SigHandler *) signal (SIGWINCH, info_signal_handler);
#endif
#if defined (SIGINT)
old_INT = (SigHandler *) signal (SIGINT, info_signal_handler);
#endif
}
static void
redisplay_after_signal ()
{
terminal_clear_screen ();
display_clear_display (the_display);
window_mark_chain (windows, W_UpdateWindow);
display_update_display (windows);
display_cursor_at_point (active_window);
fflush (stdout);
}
static SigHandlerType
info_signal_handler (sig)
int sig;
{
SigHandler **old_signal_handler;
switch (sig)
{
#if defined (SIGTSTP)
case SIGTSTP:
case SIGTTOU:
case SIGTTIN:
#endif
#if defined (SIGINT)
case SIGINT:
#endif
{
#if defined (SIGTSTP)
if (sig == SIGTSTP)
old_signal_handler = &old_TSTP;
if (sig == SIGTTOU)
old_signal_handler = &old_TTOU;
if (sig == SIGTTIN)
old_signal_handler = &old_TTIN;
#endif /* SIGTSTP */
if (sig == SIGINT)
old_signal_handler = &old_INT;
/* For stop signals, restore the terminal IO, leave the cursor
at the bottom of the window, and stop us. */
terminal_goto_xy (0, screenheight - 1);
terminal_clear_to_eol ();
fflush (stdout);
terminal_unprep_terminal ();
signal (sig, *old_signal_handler);
UNBLOCK_SIGNAL (sig);
kill (getpid (), sig);
/* The program is returning now. Restore our signal handler,
turn on terminal handling, redraw the screen, and place the
cursor where it belongs. */
terminal_prep_terminal ();
*old_signal_handler = (SigHandler *) signal (sig, info_signal_handler);
redisplay_after_signal ();
fflush (stdout);
}
break;
#if defined (SIGWINCH)
case SIGWINCH:
{
/* Turn off terminal IO, tell our parent that the window has changed,
then reinitialize the terminal and rebuild our windows. */
old_signal_handler = &old_WINCH;
terminal_goto_xy (0, 0);
fflush (stdout);
terminal_unprep_terminal ();
signal (sig, *old_signal_handler);
UNBLOCK_SIGNAL (sig);
kill (getpid (), sig);
/* After our old signal handler returns... */
terminal_get_screen_size ();
terminal_prep_terminal ();
display_initialize_display (screenwidth, screenheight);
window_new_screen_size (screenwidth, screenheight, (VFunction *)NULL);
*old_signal_handler = (SigHandler *) signal (sig, info_signal_handler);
redisplay_after_signal ();
}
break;
#endif /* SIGWINCH */
}
}
texinfo-3.7/info/signals.h 100666 11732 13 5412 5770343461 14011 0 ustar bfox user /* signals.h -- Header to include system dependent signal definitions. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993, 1994, 1995 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). */
#if !defined (_SIGNALS_H_)
#define _SIGNALS_H_
#include
#if !defined (HAVE_SIGPROCMASK) && !defined (sigmask)
# define sigmask(x) (1 << ((x)-1))
#endif /* !HAVE_SIGPROCMASK && !sigmask */
#if !defined (HAVE_SIGPROCMASK)
# if !defined (SIG_BLOCK)
# define SIG_UNBLOCK 1
# define SIG_BLOCK 2
# define SIG_SETMASK 3
# endif /* SIG_BLOCK */
/* Type of a signal set. */
# define sigset_t int
/* Make SET have no signals in it. */
# define sigemptyset(set) (*(set) = (sigset_t)0x0)
/* Make SET have the full range of signal specifications possible. */
# define sigfillset(set) (*(set) = (sigset_t)0xffffffffff)
/* Add SIG to the contents of SET. */
# define sigaddset(set, sig) *(set) |= sigmask (sig)
/* Delete SIG from the contents of SET. */
# define sigdelset(set, sig) *(set) &= ~(sigmask (sig))
/* Tell if SET contains SIG. */
# define sigismember(set, sig) (*(set) & (sigmask (sig)))
/* Suspend the process until the reception of one of the signals
not present in SET. */
# define sigsuspend(set) sigpause (*(set))
#endif /* !HAVE_SIGPROCMASK */
#if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK)
/* These definitions are used both in POSIX and non-POSIX implementations. */
#define BLOCK_SIGNAL(sig) \
do { \
sigset_t nvar, ovar; \
sigemptyset (&nvar); \
sigemptyset (&ovar); \
sigaddset (&nvar, sig); \
sigprocmask (SIG_BLOCK, &nvar, &ovar); \
} while (0)
#define UNBLOCK_SIGNAL(sig) \
do { \
sigset_t nvar, ovar; \
sigemptyset (&ovar); \
sigemptyset (&nvar); \
sigaddset (&nvar, sig); \
sigprocmask (SIG_UNBLOCK, &nvar, &ovar); \
} while (0)
#else /* !HAVE_SIGPROCMASK && !HAVE_SIGSETMASK */
# define BLOCK_SIGNAL(sig)
# define UNBLOCK_SIGNAL(sig)
#endif /* !HAVE_SIGPROCMASK && !HAVE_SIGSETMASK */
#endif /* !_SIGNALS_H_ */
texinfo-3.7/info/termdep.h 100666 11732 13 3756 5770343465 14026 0 ustar bfox user /* termdep.h -- System things that terminal.c depends on. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_TERMDEP_H_)
# define _TERMDEP_H_
#if defined (HAVE_SYS_FCNTL_H)
# include
#else
# include
#endif /* !HAVE_SYS_FCNTL_H */
#if defined (HAVE_TERMIO_H)
# include
# include
# if defined (HAVE_SYS_PTEM_H)
# if defined (M_UNIX) || !defined (M_XENIX)
# include
# include
# undef TIOCGETC
# else /* M_XENIX */
# define tchars tc
# endif /* M_XENIX */
# endif /* HAVE_SYS_PTEM_H */
#else /* !HAVE_TERMIO_H */
# if defined (HAVE_SYS_FILE_H)
# include
# endif /* HAVE_SYS_FILE_H */
# include
# include
#endif /* !HAVE_TERMIO_H */
#if defined (HAVE_SYS_TTOLD_H)
# include
#endif /* HAVE_SYS_TTOLD_H */
#if !defined (HAVE_STRCHR)
# undef strchr
# undef strrchr
# define strchr index
# define strrchr rindex
#endif /* !HAVE_STRCHR */
#if !defined (HAVE_MEMCPY)
#undef memcpy
#define memcpy(dest, source, count) bcopy(source, dest, count)
#endif /* !HAVE_MEMCPY */
#endif /* _TERMDEP_H_ */
texinfo-3.7/info/terminal.c 100666 11732 13 45021 5770343335 14177 0 ustar bfox user /* terminal.c -- How to handle the physical terminal for Info. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
This file has appeared in prior works by the Free Software Foundation;
thus it carries copyright dates from 1988 through 1993.
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 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). */
#include
#include
#include "terminal.h"
#include "termdep.h"
extern void *xmalloc (), *xrealloc ();
/* The Unix termcap interface code. */
extern int tgetnum (), tgetflag (), tgetent ();
extern char *tgetstr (), *tgoto ();
extern char *getenv ();
extern void tputs ();
/* Function "hooks". If you make one of these point to a function, that
function is called when appropriate instead of its namesake. Your
function is called with exactly the same arguments that were passed
to the namesake function. */
VFunction *terminal_begin_inverse_hook = (VFunction *)NULL;
VFunction *terminal_end_inverse_hook = (VFunction *)NULL;
VFunction *terminal_prep_terminal_hook = (VFunction *)NULL;
VFunction *terminal_unprep_terminal_hook = (VFunction *)NULL;
VFunction *terminal_up_line_hook = (VFunction *)NULL;
VFunction *terminal_down_line_hook = (VFunction *)NULL;
VFunction *terminal_clear_screen_hook = (VFunction *)NULL;
VFunction *terminal_clear_to_eol_hook = (VFunction *)NULL;
VFunction *terminal_get_screen_size_hook = (VFunction *)NULL;
VFunction *terminal_goto_xy_hook = (VFunction *)NULL;
VFunction *terminal_initialize_terminal_hook = (VFunction *)NULL;
VFunction *terminal_new_terminal_hook = (VFunction *)NULL;
VFunction *terminal_put_text_hook = (VFunction *)NULL;
VFunction *terminal_ring_bell_hook = (VFunction *)NULL;
VFunction *terminal_write_chars_hook = (VFunction *)NULL;
VFunction *terminal_scroll_terminal_hook = (VFunction *)NULL;
/* **************************************************************** */
/* */
/* Terminal and Termcap */
/* */
/* **************************************************************** */
/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
Unfortunately, PC is a global variable used by the termcap library. */
#undef PC
/* TERMCAP requires these variables, whether we access them or not. */
char PC;
char *BC, *UP;
short ospeed;
/* A buffer which holds onto the current terminal description, and a pointer
used to float within it. */
static char *term_buffer = (char *)NULL;
static char *term_string_buffer = (char *)NULL;
/* Some strings to control terminal actions. These are output by tputs (). */
static char *term_goto, *term_clreol, *term_cr, *term_clrpag;
static char *term_begin_use, *term_end_use;
static char *term_AL, *term_DL, *term_al, *term_dl;
/* How to go up a line. */
static char *term_up;
/* How to go down a line. */
static char *term_dn;
/* An audible bell, if the terminal can be made to make noise. */
static char *audible_bell;
/* A visible bell, if the terminal can be made to flash the screen. */
static char *visible_bell;
/* The string to write to turn on the meta key, if this term has one. */
static char *term_mm;
/* The string to write to turn off the meta key, if this term has one. */
static char *term_mo;
/* The string to turn on inverse mode, if this term has one. */
static char *term_invbeg;
/* The string to turn off inverse mode, if this term has one. */
static char *term_invend;
static void
output_character_function (c)
int c;
{
putc (c, stdout);
}
/* Macro to send STRING to the terminal. */
#define send_to_terminal(string) \
do { \
if (string) \
tputs (string, 1, output_character_function); \
} while (0)
/* Tell the terminal that we will be doing cursor addressable motion. */
static void
terminal_begin_using_terminal ()
{
send_to_terminal (term_begin_use);
}
/* Tell the terminal that we will not be doing any more cursor addressable
motion. */
static void
terminal_end_using_terminal ()
{
send_to_terminal (term_end_use);
}
/* **************************************************************** */
/* */
/* Necessary Terminal Functions */
/* */
/* **************************************************************** */
/* The functions and variables on this page implement the user visible
portion of the terminal interface. */
/* The width and height of the terminal. */
int screenwidth, screenheight;
/* Non-zero means this terminal can't really do anything. */
int terminal_is_dumb_p = 0;
/* Non-zero means that this terminal has a meta key. */
int terminal_has_meta_p = 0;
/* Non-zero means that this terminal can produce a visible bell. */
int terminal_has_visible_bell_p = 0;
/* Non-zero means to use that visible bell if at all possible. */
int terminal_use_visible_bell_p = 0;
/* Non-zero means that the terminal can do scrolling. */
int terminal_can_scroll = 0;
/* The key sequences output by the arrow keys, if this terminal has any. */
char *term_ku, *term_kd, *term_kr, *term_kl;
/* Move the cursor to the terminal location of X and Y. */
void
terminal_goto_xy (x, y)
int x, y;
{
if (terminal_goto_xy_hook)
(*terminal_goto_xy_hook) (x, y);
else
{
if (term_goto)
tputs (tgoto (term_goto, x, y), 1, output_character_function);
}
}
/* Print STRING to the terminal at the current position. */
void
terminal_put_text (string)
char *string;
{
if (terminal_put_text_hook)
(*terminal_put_text_hook) (string);
else
{
printf ("%s", string);
}
}
/* Print NCHARS from STRING to the terminal at the current position. */
void
terminal_write_chars (string, nchars)
char *string;
int nchars;
{
if (terminal_write_chars_hook)
(*terminal_write_chars_hook) (string, nchars);
else
{
if (nchars)
fwrite (string, 1, nchars, stdout);
}
}
/* Clear from the current position of the cursor to the end of the line. */
void
terminal_clear_to_eol ()
{
if (terminal_clear_to_eol_hook)
(*terminal_clear_to_eol_hook) ();
else
{
send_to_terminal (term_clreol);
}
}
/* Clear the entire terminal screen. */
void
terminal_clear_screen ()
{
if (terminal_clear_screen_hook)
(*terminal_clear_screen_hook) ();
else
{
send_to_terminal (term_clrpag);
}
}
/* Move the cursor up one line. */
void
terminal_up_line ()
{
if (terminal_up_line_hook)
(*terminal_up_line_hook) ();
else
{
send_to_terminal (term_up);
}
}
/* Move the cursor down one line. */
void
terminal_down_line ()
{
if (terminal_down_line_hook)
(*terminal_down_line_hook) ();
else
{
send_to_terminal (term_dn);
}
}
/* Turn on reverse video if possible. */
void
terminal_begin_inverse ()
{
if (terminal_begin_inverse_hook)
(*terminal_begin_inverse_hook) ();
else
{
send_to_terminal (term_invbeg);
}
}
/* Turn off reverse video if possible. */
void
terminal_end_inverse ()
{
if (terminal_end_inverse_hook)
(*terminal_end_inverse_hook) ();
else
{
send_to_terminal (term_invend);
}
}
/* Ring the terminal bell. The bell is run visibly if it both has one and
terminal_use_visible_bell_p is non-zero. */
void
terminal_ring_bell ()
{
if (terminal_ring_bell_hook)
(*terminal_ring_bell_hook) ();
else
{
if (terminal_has_visible_bell_p && terminal_use_visible_bell_p)
send_to_terminal (visible_bell);
else
send_to_terminal (audible_bell);
}
}
/* At the line START, delete COUNT lines from the terminal display. */
static void
terminal_delete_lines (start, count)
int start, count;
{
int lines;
/* Normalize arguments. */
if (start < 0)
start = 0;
lines = screenheight - start;
terminal_goto_xy (0, start);
if (term_DL)
tputs (tgoto (term_DL, 0, count), lines, output_character_function);
else
{
while (count--)
tputs (term_dl, lines, output_character_function);
}
fflush (stdout);
}
/* At the line START, insert COUNT lines in the terminal display. */
static void
terminal_insert_lines (start, count)
int start, count;
{
int lines;
/* Normalize arguments. */
if (start < 0)
start = 0;
lines = screenheight - start;
terminal_goto_xy (0, start);
if (term_AL)
tputs (tgoto (term_AL, 0, count), lines, output_character_function);
else
{
while (count--)
tputs (term_al, lines, output_character_function);
}
fflush (stdout);
}
/* Scroll an area of the terminal, starting with the region from START
to END, AMOUNT lines. If AMOUNT is negative, the lines are scrolled
towards the top of the screen, else they are scrolled towards the
bottom of the screen. */
void
terminal_scroll_terminal (start, end, amount)
int start, end, amount;
{
if (!terminal_can_scroll)
return;
/* Any scrolling at all? */
if (amount == 0)
return;
if (terminal_scroll_terminal_hook)
(*terminal_scroll_terminal_hook) (start, end, amount);
else
{
/* If we are scrolling down, delete AMOUNT lines at END. Then insert
AMOUNT lines at START. */
if (amount > 0)
{
terminal_delete_lines (end, amount);
terminal_insert_lines (start, amount);
}
/* If we are scrolling up, delete AMOUNT lines before START. This
actually does the upwards scroll. Then, insert AMOUNT lines
after the already scrolled region (i.e., END - AMOUNT). */
if (amount < 0)
{
int abs_amount = -amount;
terminal_delete_lines (start - abs_amount, abs_amount);
terminal_insert_lines (end - abs_amount, abs_amount);
}
}
}
/* Re-initialize the terminal considering that the TERM/TERMCAP variable
has changed. */
void
terminal_new_terminal (terminal_name)
char *terminal_name;
{
if (terminal_new_terminal_hook)
(*terminal_new_terminal_hook) (terminal_name);
else
{
terminal_initialize_terminal (terminal_name);
}
}
/* Set the global variables SCREENWIDTH and SCREENHEIGHT. */
void
terminal_get_screen_size ()
{
if (terminal_get_screen_size_hook)
(*terminal_get_screen_size_hook) ();
else
{
screenwidth = screenheight = 0;
#if defined (TIOCGWINSZ)
{
struct winsize window_size;
if (ioctl (fileno (stdout), TIOCGWINSZ, &window_size) == 0)
{
screenwidth = (int) window_size.ws_col;
screenheight = (int) window_size.ws_row;
}
}
#endif /* TIOCGWINSZ */
/* Environment variable COLUMNS overrides setting of "co". */
if (screenwidth <= 0)
{
char *sw = getenv ("COLUMNS");
if (sw)
screenwidth = atoi (sw);
if (screenwidth <= 0)
screenwidth = tgetnum ("co");
}
/* Environment variable LINES overrides setting of "li". */
if (screenheight <= 0)
{
char *sh = getenv ("LINES");
if (sh)
screenheight = atoi (sh);
if (screenheight <= 0)
screenheight = tgetnum ("li");
}
/* If all else fails, default to 80x24 terminal. */
if (screenwidth <= 0)
screenwidth = 80;
if (screenheight <= 0)
screenheight = 24;
}
}
/* Initialize the terminal which is known as TERMINAL_NAME. If this terminal
doesn't have cursor addressability, TERMINAL_IS_DUMB_P becomes non-zero.
The variables SCREENHEIGHT and SCREENWIDTH are set to the dimensions that
this terminal actually has. The variable TERMINAL_HAS_META_P becomes non-
zero if this terminal supports a Meta key. Finally, the terminal screen is
cleared. */
void
terminal_initialize_terminal (terminal_name)
char *terminal_name;
{
char *term, *buffer;
terminal_is_dumb_p = 0;
if (terminal_initialize_terminal_hook)
{
(*terminal_initialize_terminal_hook) (terminal_name);
return;
}
term = terminal_name ? terminal_name : getenv ("TERM");
if (!term_string_buffer)
term_string_buffer = (char *)xmalloc (2048);
if (!term_buffer)
term_buffer = (char *)xmalloc (2048);
buffer = term_string_buffer;
term_clrpag = term_cr = term_clreol = (char *)NULL;
if (!term)
term = "dumb";
if (tgetent (term_buffer, term) <= 0)
{
terminal_is_dumb_p = 1;
screenwidth = 80;
screenheight = 24;
term_cr = "\r";
term_up = term_dn = audible_bell = visible_bell = (char *)NULL;
term_ku = term_kd = term_kl = term_kr = (char *)NULL;
return;
}
BC = tgetstr ("pc", &buffer);
PC = BC ? *BC : 0;
#if defined (TIOCGETP)
{
struct sgttyb sg;
if (ioctl (fileno (stdout), TIOCGETP, &sg) != -1)
ospeed = sg.sg_ospeed;
else
ospeed = B9600;
}
#else
ospeed = B9600;
#endif /* !TIOCGETP */
term_cr = tgetstr ("cr", &buffer);
term_clreol = tgetstr ("ce", &buffer);
term_clrpag = tgetstr ("cl", &buffer);
term_goto = tgetstr ("cm", &buffer);
/* Find out about this terminals scrolling capability. */
term_AL = tgetstr ("AL", &buffer);
term_DL = tgetstr ("DL", &buffer);
term_al = tgetstr ("al", &buffer);
term_dl = tgetstr ("dl", &buffer);
terminal_can_scroll = ((term_AL || term_al) && (term_DL || term_dl));
term_invbeg = tgetstr ("mr", &buffer);
if (term_invbeg)
term_invend = tgetstr ("me", &buffer);
else
term_invend = (char *)NULL;
if (!term_cr)
term_cr = "\r";
terminal_get_screen_size ();
term_up = tgetstr ("up", &buffer);
term_dn = tgetstr ("dn", &buffer);
visible_bell = tgetstr ("vb", &buffer);
terminal_has_visible_bell_p = (visible_bell != (char *)NULL);
audible_bell = tgetstr ("bl", &buffer);
if (!audible_bell)
audible_bell = "\007";
term_begin_use = tgetstr ("ti", &buffer);
term_end_use = tgetstr ("te", &buffer);
/* Check to see if this terminal has a meta key. */
terminal_has_meta_p = (tgetflag ("km") || tgetflag ("MT"));
if (terminal_has_meta_p)
{
term_mm = tgetstr ("mm", &buffer);
term_mo = tgetstr ("mo", &buffer);
}
else
{
term_mm = (char *)NULL;
term_mo = (char *)NULL;
}
/* Attempt to find the arrow keys. */
term_ku = tgetstr ("ku", &buffer);
term_kd = tgetstr ("kd", &buffer);
term_kr = tgetstr ("kr", &buffer);
term_kl = tgetstr ("kl", &buffer);
/* If this terminal is not cursor addressable, then it is really dumb. */
if (!term_goto)
terminal_is_dumb_p = 1;
terminal_begin_using_terminal ();
}
/* **************************************************************** */
/* */
/* How to Read Characters From the Terminal */
/* */
/* **************************************************************** */
#if defined (TIOCGETC)
/* A buffer containing the terminal interrupt characters upon entry
to Info. */
struct tchars original_tchars;
#endif
#if defined (TIOCGLTC)
/* A buffer containing the local terminal mode characters upon entry
to Info. */
struct ltchars original_ltchars;
#endif
#if defined (HAVE_TERMIO_H)
/* A buffer containing the terminal mode flags upon entry to info. */
struct termio original_termio, ttybuff;
#else /* !HAVE_TERMIO_H */
/* Buffers containing the terminal mode flags upon entry to info. */
int original_tty_flags = 0;
int original_lmode;
struct sgttyb ttybuff;
#endif /* !HAVE_TERMIO_H */
/* Prepare to start using the terminal to read characters singly. */
void
terminal_prep_terminal ()
{
int tty;
if (terminal_prep_terminal_hook)
{
(*terminal_prep_terminal_hook) ();
return;
}
tty = fileno (stdin);
#if defined (HAVE_TERMIO_H)
ioctl (tty, TCGETA, &original_termio);
ioctl (tty, TCGETA, &ttybuff);
ttybuff.c_iflag &= (~ISTRIP & ~INLCR & ~IGNCR & ~ICRNL & ~IXON);
ttybuff.c_oflag &= (~ONLCR & ~OCRNL);
ttybuff.c_lflag &= (~ICANON & ~ECHO);
ttybuff.c_cc[VMIN] = 1;
ttybuff.c_cc[VTIME] = 0;
if (ttybuff.c_cc[VINTR] == '\177')
ttybuff.c_cc[VINTR] = -1;
if (ttybuff.c_cc[VQUIT] == '\177')
ttybuff.c_cc[VQUIT] = -1;
ioctl (tty, TCSETA, &ttybuff);
#else /* !HAVE_TERMIO_H */
ioctl (tty, TIOCGETP, &ttybuff);
if (!original_tty_flags)
original_tty_flags = ttybuff.sg_flags;
/* Make this terminal pass 8 bits around while we are using it. */
#if defined (PASS8)
ttybuff.sg_flags |= PASS8;
#endif /* PASS8 */
#if defined (TIOCLGET) && defined (LPASS8)
{
int flags;
ioctl (tty, TIOCLGET, &flags);
original_lmode = flags;
flags |= LPASS8;
ioctl (tty, TIOCLSET, &flags);
}
#endif /* TIOCLGET && LPASS8 */
#if defined (TIOCGETC)
{
struct tchars temp;
ioctl (tty, TIOCGETC, &original_tchars);
temp = original_tchars;
/* C-s and C-q. */
temp.t_startc = temp.t_stopc = -1;
/* Often set to C-d. */
temp.t_eofc = -1;
/* If the a quit or interrupt character conflicts with one of our
commands, then make it go away. */
if (temp.t_intrc == '\177')
temp.t_intrc = -1;
if (temp.t_quitc == '\177')
temp.t_quitc = -1;
ioctl (tty, TIOCSETC, &temp);
}
#endif /* TIOCGETC */
#if defined (TIOCGLTC)
{
struct ltchars temp;
ioctl (tty, TIOCGLTC, &original_ltchars);
temp = original_ltchars;
/* Make the interrupt keys go away. Just enough to make people happy. */
temp.t_lnextc = -1; /* C-v. */
temp.t_dsuspc = -1; /* C-y. */
temp.t_flushc = -1; /* C-o. */
ioctl (tty, TIOCSLTC, &temp);
}
#endif /* TIOCGLTC */
ttybuff.sg_flags &= ~ECHO;
ttybuff.sg_flags |= CBREAK;
ioctl (tty, TIOCSETN, &ttybuff);
#endif /* !HAVE_TERMIO_H */
}
/* Restore the tty settings back to what they were before we started using
this terminal. */
void
terminal_unprep_terminal ()
{
int tty;
if (terminal_unprep_terminal_hook)
{
(*terminal_unprep_terminal_hook) ();
return;
}
tty = fileno (stdin);
#if defined (HAVE_TERMIO_H)
ioctl (tty, TCSETA, &original_termio);
#else /* !HAVE_TERMIO_H */
ioctl (tty, TIOCGETP, &ttybuff);
ttybuff.sg_flags = original_tty_flags;
ioctl (tty, TIOCSETN, &ttybuff);
#if defined (TIOCGETC)
ioctl (tty, TIOCSETC, &original_tchars);
#endif /* TIOCGETC */
#if defined (TIOCGLTC)
ioctl (tty, TIOCSLTC, &original_ltchars);
#endif /* TIOCGLTC */
#if defined (TIOCLGET) && defined (LPASS8)
ioctl (tty, TIOCLSET, &original_lmode);
#endif /* TIOCLGET && LPASS8 */
#endif /* !HAVE_TERMIO_H */
terminal_end_using_terminal ();
}
texinfo-3.7/info/tilde.c 100666 11732 13 22365 5771355114 13472 0 ustar bfox user /* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
This file has appeared in prior works by the Free Software Foundation;
thus it carries copyright dates from 1988 through 1993.
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 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). */
#if defined (__GNUC__)
# define alloca __builtin_alloca
#else /* !__GNUC__ */
# if defined (_AIX)
#pragma alloca
# else /* !_AIX */
# if defined (HAVE_ALLOCA_H)
# include
# endif /* HAVE_ALLOCA_H */
# endif /* !AIX */
#endif /* !__GNUC__ */
#if defined (HAVE_STDLIB_H)
#include
#endif
#include "tilde.h"
#include
#if defined (HAVE_STRING_H)
#include
#endif
#include "clib.h"
#if !defined (NULL)
# define NULL 0x0
#endif
#if defined (TEST) || defined (STATIC_MALLOC)
static void *xmalloc (), *xrealloc ();
#else
extern void *xmalloc (), *xrealloc ();
#endif /* TEST || STATIC_MALLOC */
/* The default value of tilde_additional_prefixes. This is set to
whitespace preceding a tilde so that simple programs which do not
perform any word separation get desired behaviour. */
static char *default_prefixes[] =
{ " ~", "\t~", (char *)NULL };
/* The default value of tilde_additional_suffixes. This is set to
whitespace or newline so that simple programs which do not
perform any word separation get desired behaviour. */
static char *default_suffixes[] =
{ " ", "\n", (char *)NULL };
/* If non-null, this contains the address of a function to call if the
standard meaning for expanding a tilde fails. The function is called
with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
which is the expansion, or a NULL pointer if there is no expansion. */
CFunction *tilde_expansion_failure_hook = (CFunction *)NULL;
/* When non-null, this is a NULL terminated array of strings which
are duplicates for a tilde prefix. Bash uses this to expand
`=~' and `:~'. */
char **tilde_additional_prefixes = default_prefixes;
/* When non-null, this is a NULL terminated array of strings which match
the end of a username, instead of just "/". Bash sets this to
`:' and `=~'. */
char **tilde_additional_suffixes = default_suffixes;
/* Find the start of a tilde expansion in STRING, and return the index of
the tilde which starts the expansion. Place the length of the text
which identified this tilde starter in LEN, excluding the tilde itself. */
static int
tilde_find_prefix (string, len)
char *string;
int *len;
{
register int i, j, string_len;
register char **prefixes = tilde_additional_prefixes;
string_len = strlen (string);
*len = 0;
if (!*string || *string == '~')
return (0);
if (prefixes)
{
for (i = 0; i < string_len; i++)
{
for (j = 0; prefixes[j]; j++)
{
if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
{
*len = strlen (prefixes[j]) - 1;
return (i + *len);
}
}
}
}
return (string_len);
}
/* Find the end of a tilde expansion in STRING, and return the index of
the character which ends the tilde definition. */
static int
tilde_find_suffix (string)
char *string;
{
register int i, j, string_len;
register char **suffixes = tilde_additional_suffixes;
string_len = strlen (string);
for (i = 0; i < string_len; i++)
{
if (string[i] == '/' || !string[i])
break;
for (j = 0; suffixes && suffixes[j]; j++)
{
if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
return (i);
}
}
return (i);
}
/* Return a new string which is the result of tilde expanding STRING. */
char *
tilde_expand (string)
char *string;
{
char *result, *tilde_expand_word ();
int result_size, result_index;
result_size = result_index = 0;
result = (char *)NULL;
/* Scan through STRING expanding tildes as we come to them. */
while (1)
{
register int start, end;
char *tilde_word, *expansion;
int len;
/* Make START point to the tilde which starts the expansion. */
start = tilde_find_prefix (string, &len);
/* Copy the skipped text into the result. */
if ((result_index + start + 1) > result_size)
result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
strncpy (result + result_index, string, start);
result_index += start;
/* Advance STRING to the starting tilde. */
string += start;
/* Make END be the index of one after the last character of the
username. */
end = tilde_find_suffix (string);
/* If both START and END are zero, we are all done. */
if (!start && !end)
break;
/* Expand the entire tilde word, and copy it into RESULT. */
tilde_word = (char *)xmalloc (1 + end);
strncpy (tilde_word, string, end);
tilde_word[end] = '\0';
string += end;
expansion = tilde_expand_word (tilde_word);
free (tilde_word);
len = strlen (expansion);
if ((result_index + len + 1) > result_size)
result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
strcpy (result + result_index, expansion);
result_index += len;
free (expansion);
}
result[result_index] = '\0';
return (result);
}
/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
tilde. If there is no expansion, call tilde_expansion_failure_hook. */
char *
tilde_expand_word (filename)
char *filename;
{
char *dirname;
dirname = filename ? strdup (filename) : (char *)NULL;
if (dirname && *dirname == '~')
{
char *temp_name;
if (!dirname[1] || dirname[1] == '/')
{
/* Prepend $HOME to the rest of the string. */
char *temp_home = (char *)getenv ("HOME");
/* If there is no HOME variable, look up the directory in
the password database. */
if (!temp_home)
{
struct passwd *entry;
entry = (struct passwd *) getpwuid (getuid ());
if (entry)
temp_home = entry->pw_dir;
}
temp_name = (char *)
alloca (1 + strlen (&dirname[1])
+ (temp_home ? strlen (temp_home) : 0));
temp_name[0] = '\0';
if (temp_home)
strcpy (temp_name, temp_home);
strcat (temp_name, &dirname[1]);
free (dirname);
dirname = strdup (temp_name);
}
else
{
struct passwd *user_entry;
char *username = (char *)alloca (257);
int i, c;
for (i = 1; c = dirname[i]; i++)
{
if (c == '/')
break;
else
username[i - 1] = c;
}
username[i - 1] = '\0';
if (!(user_entry = (struct passwd *) getpwnam (username)))
{
/* If the calling program has a special syntax for
expanding tildes, and we couldn't find a standard
expansion, then let them try. */
if (tilde_expansion_failure_hook)
{
char *expansion;
expansion = (*tilde_expansion_failure_hook) (username);
if (expansion)
{
temp_name = (char *)alloca
(1 + strlen (expansion) + strlen (&dirname[i]));
strcpy (temp_name, expansion);
strcat (temp_name, &dirname[i]);
free (expansion);
goto return_name;
}
}
/* We shouldn't report errors. */
}
else
{
temp_name = (char *)alloca
(1 + strlen (user_entry->pw_dir) + strlen (&dirname[i]));
strcpy (temp_name, user_entry->pw_dir);
strcat (temp_name, &dirname[i]);
return_name:
free (dirname);
dirname = strdup (temp_name);
}
endpwent ();
}
}
return (dirname);
}
#if defined (TEST)
#undef NULL
#include
main (argc, argv)
int argc;
char **argv;
{
char *result, line[512];
int done = 0;
while (!done)
{
printf ("~expand: ");
fflush (stdout);
if (!gets (line))
strcpy (line, "done");
if ((strcmp (line, "done") == 0) ||
(strcmp (line, "quit") == 0) ||
(strcmp (line, "exit") == 0))
{
done = 1;
break;
}
result = tilde_expand (line);
printf (" --> %s\n", result);
free (result);
}
exit (0);
}
static void memory_error_and_abort ();
static void *
xmalloc (bytes)
int bytes;
{
void *temp = (void *)malloc (bytes);
if (!temp)
memory_error_and_abort ();
return (temp);
}
static void *
xrealloc (pointer, bytes)
void *pointer;
int bytes;
{
void *temp;
if (!pointer)
temp = (char *)malloc (bytes);
else
temp = (char *)realloc (pointer, bytes);
if (!temp)
memory_error_and_abort ();
return (temp);
}
static void
memory_error_and_abort ()
{
fprintf (stderr, "readline: Out of virtual memory!\n");
abort ();
}
#endif /* TEST */
texinfo-3.7/info/terminal.h 100666 11732 13 11262 5770343470 14204 0 ustar bfox user /* terminal.h -- The external interface to terminal I/O. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_TERMINAL_H_)
#define _TERMINAL_H_
/* We use the following data type to talk about pointers to functions. */
#if !defined (__FUNCTION_DEF)
# define __FUNCTION_DEF
typedef int Function ();
typedef void VFunction ();
#endif /* _FUNCTION_DEF */
/* For almost every function externally visible from terminal.c, there is
a corresponding "hook" function which can be bound in order to replace
the functionality of the one found in terminal.c. This is how we go
about implemented X window display. */
/* The width and height of the terminal. */
extern int screenwidth, screenheight;
/* Non-zero means this terminal can't really do anything. */
extern int terminal_is_dumb_p;
/* Non-zero means that this terminal has a meta key. */
extern int terminal_has_meta_p;
/* Non-zero means that this terminal can produce a visible bell. */
extern int terminal_has_visible_bell_p;
/* Non-zero means to use that visible bell if at all possible. */
extern int terminal_use_visible_bell_p;
/* Non-zero means that this terminal can scroll lines up and down. */
extern int terminal_can_scroll;
/* Initialize the terminal which is known as TERMINAL_NAME. If this terminal
doesn't have cursor addressability, TERMINAL_IS_DUMB_P becomes non-zero.
The variables SCREENHEIGHT and SCREENWIDTH are set to the dimensions that
this terminal actually has. The variable TERMINAL_HAS_META_P becomes non-
zero if this terminal supports a Meta key. */
extern void terminal_initialize_terminal ();
extern VFunction *terminal_initialize_terminal_hook;
/* Return the current screen width and height in the variables
SCREENWIDTH and SCREENHEIGHT. */
extern void terminal_get_screen_size ();
extern VFunction *terminal_get_screen_size_hook;
/* Save and restore tty settings. */
extern void terminal_prep_terminal (), terminal_unprep_terminal ();
extern VFunction *terminal_prep_terminal_hook, *terminal_unprep_terminal_hook;
/* Re-initialize the terminal to TERMINAL_NAME. */
extern void terminal_new_terminal ();
extern VFunction *terminal_new_terminal_hook;
/* Move the cursor to the terminal location of X and Y. */
extern void terminal_goto_xy ();
extern VFunction *terminal_goto_xy_hook;
/* Print STRING to the terminal at the current position. */
extern void terminal_put_text ();
extern VFunction *terminal_put_text_hook;
/* Print NCHARS from STRING to the terminal at the current position. */
extern void terminal_write_chars ();
extern VFunction *terminal_write_chars_hook;
/* Clear from the current position of the cursor to the end of the line. */
extern void terminal_clear_to_eol ();
extern VFunction *terminal_clear_to_eol_hook;
/* Clear the entire terminal screen. */
extern void terminal_clear_screen ();
extern VFunction *terminal_clear_screen_hook;
/* Move the cursor up one line. */
extern void terminal_up_line ();
extern VFunction *terminal_up_line_hook;
/* Move the cursor down one line. */
extern void terminal_down_line ();
extern VFunction *terminal_down_line_hook;
/* Turn on reverse video if possible. */
extern void terminal_begin_inverse ();
extern VFunction *terminal_begin_inverse_hook;
/* Turn off reverse video if possible. */
extern void terminal_end_inverse ();
extern VFunction *terminal_end_inverse_hook;
/* Scroll an area of the terminal, starting with the region from START
to END, AMOUNT lines. If AMOUNT is negative, the lines are scrolled
towards the top of the screen, else they are scrolled towards the
bottom of the screen. */
extern void terminal_scroll_terminal ();
extern VFunction *terminal_scroll_terminal_hook;
/* Ring the terminal bell. The bell is run visibly if it both has one and
terminal_use_visible_bell_p is non-zero. */
extern void terminal_ring_bell ();
extern VFunction *terminal_ring_bell_hook;
#endif /* !_TERMINAL_H_ */
texinfo-3.7/info/tilde.h 100666 11732 13 4527 5770343473 13463 0 ustar bfox user /* tilde.h: Externally available variables and function in libtilde.a. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
This file has appeared in prior works by the Free Software Foundation;
thus it carries copyright dates from 1988 through 1993.
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 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). */
/* Function pointers can be declared as (Function *)foo. */
#if !defined (__FUNCTION_DEF)
# define __FUNCTION_DEF
typedef int Function ();
typedef void VFunction ();
typedef char *CFunction ();
#endif /* _FUNCTION_DEF */
/* If non-null, this contains the address of a function to call if the
standard meaning for expanding a tilde fails. The function is called
with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
which is the expansion, or a NULL pointer if there is no expansion. */
extern CFunction *tilde_expansion_failure_hook;
/* When non-null, this is a NULL terminated array of strings which
are duplicates for a tilde prefix. Bash uses this to expand
`=~' and `:~'. */
extern char **tilde_additional_prefixes;
/* When non-null, this is a NULL terminated array of strings which match
the end of a username, instead of just "/". Bash sets this to
`:' and `=~'. */
extern char **tilde_additional_suffixes;
/* Return a new string which is the result of tilde expanding STRING. */
extern char *tilde_expand ();
/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
tilde. If there is no expansion, call tilde_expansion_failure_hook. */
extern char *tilde_expand_word ();
texinfo-3.7/info/userdoc.texi 100666 11732 13 132041 5764640676 14611 0 ustar bfox user @c This file is meant to be included in any arbitrary piece of
@c documentation that wishes to describe the info program. Some day
@c info-stnd.texi should probably use this file instead of duplicating
@c its contents.
@c
@c This file documents the use of the standalone GNU Info program,
@c versions 2.7 and later.
@ifclear InfoProgVer
@set InfoProgVer 2.11
@end ifclear
@synindex vr cp
@synindex fn cp
@synindex ky cp
@heading What is Info?
This text documents the use of the GNU Info program, version
@value{InfoProgVer}.
@dfn{Info} is a program which is used to view info files on an ASCII
terminal. @dfn{info files} are the result of processing texinfo files
with the program @code{makeinfo} or with the Emacs command @code{M-x
texinfo-format-buffer}. Finally, @dfn{texinfo} is a documentation
language which allows a printed manual and online documentation (an info
file) to be produced from a single source file.
@menu
* Options:: Options you can pass on the command line.
* Cursor Commands:: Commands which move the cursor within a node.
* Scrolling Commands:: Commands for moving the node around in a window.
* Node Commands:: Commands for selecting a new node.
* Searching Commands:: Commands for searching an info file.
* Xref Commands:: Commands for selecting cross references.
* Window Commands:: Commands which manipulate multiple windows.
* Printing Nodes:: How to print out the contents of a node.
* Miscellaneous Commands:: A few commands that defy categories.
* Variables:: How to change the default behaviour of Info.
@ifset NOTSET
* Info for Sys Admins:: How to setup Info. Using special options.
@end ifset
@ifset STANDALONE
* GNU Info Global Index:: Global index containing keystrokes, command names,
variable names, and general concepts.
@end ifset
@end menu
@node Options
@chapter Command Line Options
@cindex command line options
@cindex arguments, command line
GNU Info accepts several options to control the initial node being
viewed, and to specify which directories to search for info files. Here
is a template showing an invocation of GNU Info from the shell:
@example
info [--@var{option-name} @var{option-value}] @var{menu-item}@dots{}
@end example
The following @var{option-names} are available when invoking Info from
the shell:
@table @code
@cindex directory path
@item --directory @var{directory-path}
@itemx -d @var{directory-path}
Adds @var{directory-path} to the list of directory paths searched when
Info needs to find a file. You may issue @code{--directory} multiple
times; once for each directory which contains info files.
Alternatively, you may specify a value for the environment variable
@code{INFOPATH}; if @code{--directory} is not given, the value of
@code{INFOPATH} is used. The value of @code{INFOPATH} is a colon
separated list of directory names. If you do not supply
@code{INFOPATH} or @code{--directory-path} a default path is used.
@item --file @var{filename}
@itemx -f @var{filename}
@cindex info file, selecting
Specifies a particular info file to visit. Instead of visiting the file
@code{dir}, Info will start with @code{(@var{filename})Top} as the first
file and node.
@item --node @var{nodename}
@itemx -n @var{nodename}
@cindex node, selecting
Specifies a particular node to visit in the initial file loaded. This
is especially useful in conjunction with @code{--file}@footnote{Of
course, you can specify both the file and node in a @code{--node}
command; but don't forget to escape the open and close parentheses from
the shell as in: @code{info --node '(emacs)Buffers'}}. You may specify
@code{--node} multiple times; for an interactive Info, each
@var{nodename} is visited in its own window, for a non-interactive Info
(such as when @code{--output} is given) each @var{nodename} is processed
sequentially.
@item --output @var{filename}
@itemx -o @var{filename}
@cindex file, outputting to
@cindex outputting to a file
Specify @var{filename} as the name of a file to output to. Each node
that Info visits will be output to @var{filename} instead of
interactively viewed. A value of @code{-} for @var{filename} specifies
the standard output.
@item --subnodes
@cindex @code{--subnodes}, command line option
This option only has meaning when given in conjunction with
@code{--output}. It means to recursively output the nodes appearing in
the menus of each node being output. Menu items which resolve to
external info files are not output, and neither are menu items which are
members of an index. Each node is only output once.
@item --help
@itemx -h
Produces a relatively brief description of the available Info options.
@item --version
@cindex version information
Prints the version information of Info and exits.
@item @var{menu-item}
@cindex menu, following
Remaining arguments to Info are treated as the names of menu items. The
first argument would be a menu item in the initial node visited, while
the second argument would be a menu item in the first argument's node.
You can easily move to the node of your choice by specifying the menu
names which describe the path to that node. For example,
@example
info emacs buffers
@end example
first selects the menu item @samp{Emacs} in the node @samp{(dir)Top},
and then selects the menu item @samp{Buffers} in the node
@samp{(emacs)Top}.
@end table
@node Cursor Commands
@chapter Moving the Cursor
@cindex cursor, moving
Many people find that reading screens of text page by page is made
easier when one is able to indicate particular pieces of text with some
kind of pointing device. Since this is the case, GNU Info (both the
Emacs and standalone versions) have several commands which allow you to
move the cursor about the screen. The notation used in this manual to
describe keystrokes is identical to the notation used within the Emacs
manual, and the GNU Readline manual. @xref{Characters, , Character
Conventions, emacs, the GNU Emacs Manual}, if you are unfamilar with the
notation.
The following table lists the basic cursor movement commands in Info.
Each entry consists of the key sequence you should type to execute the
cursor movement, the @code{M-x}@footnote{@code{M-x} is also a command; it
invokes @code{execute-extended-command}. @xref{M-x, , Executing an
extended command, emacs, the GNU Emacs Manual}, for more detailed
information.} command name (displayed in parentheses), and a short
description of what the command does. All of the cursor motion commands
can take an @dfn{numeric} argument (@pxref{Miscellaneous Commands,
@code{universal-argument}}), to find out how to supply them. With a
numeric argument, the motion commands are simply executed that
many times; for example, a numeric argument of 4 given to
@code{next-line} causes the cursor to move down 4 lines. With a
negative numeric argument, the motion is reversed; an argument of -4
given to the @code{next-line} command would cause the cursor to move
@emph{up} 4 lines.
@table @asis
@item @code{C-n} (@code{next-line})
@kindex C-n
@findex next-line
Moves the cursor down to the next line.
@item @code{C-p} (@code{prev-line})
@kindex C-p
@findex prev-line
Move the cursor up to the previous line.
@item @code{C-a} (@code{beginning-of-line})
@kindex C-a, in Info windows
@findex beginning-of-line
Move the cursor to the start of the current line.
@item @code{C-e} (@code{end-of-line})
@kindex C-e, in Info windows
@findex end-of-line
Moves the cursor to the end of the current line.
@item @code{C-f} (@code{forward-char})
@kindex C-f, in Info windows
@findex forward-char
Move the cursor forward a character.
@item @code{C-b} (@code{backward-char})
@kindex C-b, in Info windows
@findex backward-char
Move the cursor backward a character.
@item @code{M-f} (@code{forward-word})
@kindex M-f, in Info windows
@findex forward-word
Moves the cursor forward a word.
@item @code{M-b} (@code{backward-word})
@kindex M-b, in Info winows
@findex backward-word
Moves the cursor backward a word.
@item @code{M-<} (@code{beginning-of-node})
@itemx @code{b}
@kindex b, in Info winows
@kindex M-<
@findex beginning-of-node
Moves the cursor to the start of the current node.
@item @code{M->} (@code{end-of-node})
@kindex M->
@findex end-of-node
Moves the cursor to the end of the current node.
@item @code{M-r} (@code{move-to-window-line})
@kindex M-r
@findex move-to-window-line
Moves the cursor to a specific line of the window. Without a numeric
argument, @code{M-r} moves the cursor to the start of the line in the
center of the window. With a numeric argument of @var{n}, @code{M-r}
moves the cursor to the start of the @var{n}th line in the window.
@end table
@node Scrolling Commands
@chapter Moving Text Within a Window
@cindex scrolling
Sometimes you are looking at a screenful of text, and only part of the
current paragraph you are reading is visible on the screen. The
commands detailed in this section are used to shift which part of the
current node is visible on the screen.
@table @asis
@item @code{SPC} (@code{scroll-forward})
@itemx @code{C-v}
@kindex SPC, in Info windows
@kindex C-v
@findex scroll-forward
Shift the text in this window up. That is, show more of the node which
is currently below the bottom of the window. With a numeric argument,
show that many more lines at the bottom of the window; a numeric
argument of 4 would shift all of the text in the window up 4 lines
(discarding the top 4 lines), and show you four new lines at the bottom
of the window. Without a numeric argument, @key{SPC} takes the bottom
two lines of the window and places them at the top of the window,
redisplaying almost a completely new screenful of lines.
@item @code{DEL} (@code{scroll-backward})
@itemx @code{M-v}
@kindex DEL, in Info windows
@kindex M-v
@findex scroll-backward
Shift the text in this window down. The inverse of
@code{scroll-forward}.
@end table
@cindex scrolling through node structure
The @code{scroll-forward} and @code{scroll-backward} commands can also
move forward and backward through the node structure of the file. If
you press @key{SPC} while viewing the end of a node, or @key{DEL} while
viewing the beginning of a node, what happens is controlled by the
variable @code{scroll-behaviour}. @xref{Variables,
@code{scroll-behaviour}}, for more information.
@table @asis
@item @code{C-l} (@code{redraw-display})
@kindex C-l
@findex redraw-display
Redraw the display from scratch, or shift the line containing the cursor
to a specified location. With no numeric argument, @samp{C-l} clears
the screen, and then redraws its entire contents. Given a numeric
argument of @var{n}, the line containing the cursor is shifted so that
it is on the @var{n}th line of the window.
@item @code{C-x w} (@code{toggle-wrap})
@kindex C-w
@findex toggle-wrap
Toggles the state of line wrapping in the current window. Normally,
lines which are longer than the screen width @dfn{wrap}, i.e., they are
continued on the next line. Lines which wrap have a @samp{\} appearing
in the rightmost column of the screen. You can cause such lines to be
terminated at the rightmost column by changing the state of line
wrapping in the window with @code{C-x w}. When a line which needs more
space than one screen width to display is displayed, a @samp{$} appears
in the rightmost column of the screen, and the remainder of the line is
invisible.
@end table
@node Node Commands
@chapter Selecting a New Node
@cindex nodes, selection of
This section details the numerous Info commands which select a new node
to view in the current window.
The most basic node commands are @samp{n}, @samp{p}, @samp{u}, and
@samp{l}.
When you are viewing a node, the top line of the node contains some Info
@dfn{pointers} which describe where the next, previous, and up nodes
are. Info uses this line to move about the node structure of the file
when you use the following commands:
@table @asis
@item @code{n} (@code{next-node})
@kindex n
@findex next-node
Selects the `Next' node.
@item @code{p} (@code{prev-node})
@kindex p
@findex prev-node
Selects the `Prev' node.
@item @code{u} (@code{up-node})
@kindex u
@findex up-node
Selects the `Up' node.
@end table
You can easily select a node that you have already viewed in this window
by using the @samp{l} command -- this name stands for "last", and
actually moves through the list of already visited nodes for this
window. @samp{l} with a negative numeric argument moves forward through
the history of nodes for this window, so you can quickly step between
two adjacent (in viewing history) nodes.
@table @asis
@item @code{l} (@code{history-node})
@kindex l
@findex history-node
Selects the most recently selected node in this window.
@end table
Two additional commands make it easy to select the most commonly
selected nodes; they are @samp{t} and @samp{d}.
@table @asis
@item @code{t} (@code{top-node})
@kindex t
@findex top-node
Selects the node @samp{Top} in the current info file.
@item @code{d} (@code{dir-node})
@kindex d
@findex dir-node
Selects the directory node (i.e., the node @samp{(dir)}).
@end table
Here are some other commands which immediately result in the selection
of a different node in the current window:
@table @asis
@item @code{<} (@code{first-node})
@kindex <
@findex first-node
Selects the first node which appears in this file. This node is most
often @samp{Top}, but it doesn't have to be.
@item @code{>} (@code{last-node})
@kindex >
@findex last-node
Selects the last node which appears in this file.
@item @code{]} (@code{global-next-node})
@kindex ]
@findex global-next-node
Moves forward or down through node structure. If the node that you are
currently viewing has a @samp{Next} pointer, that node is selected.
Otherwise, if this node has a menu, the first menu item is selected. If
there is no @samp{Next} and no menu, the same process is tried with the
@samp{Up} node of this node.
@item @code{[} (@code{global-prev-node})
@kindex [
@findex global-prev-node
Moves backward or up through node structure. If the node that you are
currently viewing has a @samp{Prev} pointer, that node is selected.
Otherwise, if the node has an @samp{Up} pointer, that node is selected,
and if it has a menu, the last item in the menu is selected.
@end table
You can get the same behaviour as @code{global-next-node} and
@code{global-prev-node} while simply scrolling through the file with
@key{SPC} and @key{DEL}; @xref{Variables, @code{scroll-behaviour}}, for
more information.
@table @asis
@item @code{g} (@code{goto-node})
@kindex g
@findex goto-node
Reads the name of a node and selects it. No completion is done while
reading the node name, since the desired node may reside in a separate
file. The node must be typed exactly as it appears in the info file. A
file name may be included as with any node specification, for example
@example
@code{g(emacs)Buffers}
@end example
finds the node @samp{Buffers} in the info file @file{emacs}.
@item @code{C-x k} (@code{kill-node})
@kindex C-x k
@findex kill-node
Kills a node. The node name is prompted for in the echo area, with a
default of the current node. @dfn{Killing} a node means that Info tries
hard to forget about it, removing it from the list of history nodes kept
for the window where that node is found. Another node is selected in
the window which contained the killed node.
@item @code{C-x C-f} (@code{view-file})
@kindex C-x C-f
@findex view-file
Reads the name of a file and selects the entire file. The command
@example
@code{C-x C-f @var{filename}}
@end example
is equivalent to typing
@example
@code{g(@var{filename})*}
@end example
@item @code{C-x C-b} (@code{list-visited-nodes})
@kindex C-x C-b
@findex list-visited-nodes
Makes a window containing a menu of all of the currently visited nodes.
This window becomes the selected window, and you may use the standard
Info commands within it.
@item @code{C-x b} (@code{select-visited-node})
@kindex C-x b
@findex select-visited-node
Selects a node which has been previously visited in a visible window.
This is similar to @samp{C-x C-b} followed by @samp{m}, but no window is
created.
@end table
@node Searching Commands
@chapter Searching an Info File
@cindex searching
GNU Info allows you to search for a sequence of characters throughout an
entire info file, search through the indices of an info file, or find
areas within an info file which discuss a particular topic.
@table @asis
@item @code{s} (@code{search})
@kindex s
@findex search
Reads a string in the echo area and searches for it.
@item @code{C-s} (@code{isearch-forward})
@kindex C-s
@findex isearch-forward
Interactively searches forward through the info file for a string as you
type it.
@item @code{C-r} (@code{isearch-backward})
@kindex C-r
@findex isearch-backward
Interactively searches backward through the info file for a string as
you type it.
@item @code{i} (@code{index-search})
@kindex i
@findex index-search
Looks up a string in the indices for this info file, and selects a node
where the found index entry points to.
@item @code{,} (@code{next-index-match})
@kindex ,
@findex next-index-match
Moves to the node containing the next matching index item from the last
@samp{i} command.
@end table
The most basic searching command is @samp{s} (@code{search}). The
@samp{s} command prompts you for a string in the echo area, and then
searches the remainder of the info file for an ocurrence of that string.
If the string is found, the node containing it is selected, and the
cursor is left positioned at the start of the found string. Subsequent
@samp{s} commands show you the default search string within @samp{[} and
@samp{]}; pressing @key{RET} instead of typing a new string will use the
default search string.
@dfn{Incremental searching} is similar to basic searching, but the
string is looked up while you are typing it, instead of waiting until
the entire search string has been specified.
@node Xref Commands
@chapter Selecting Cross References
We have already discussed the @samp{Next}, @samp{Prev}, and @samp{Up}
pointers which appear at the top of a node. In addition to these
pointers, a node may contain other pointers which refer you to a
different node, perhaps in another info file. Such pointers are called
@dfn{cross references}, or @dfn{xrefs} for short.
@menu
* Parts of an Xref:: What a cross reference is made of.
* Selecting Xrefs:: Commands for selecting menu or note items.
@end menu
@node Parts of an Xref
@section Parts of an Xref
Cross references have two major parts: the first part is called the
@dfn{label}; it is the name that you can use to refer to the cross
reference, and the second is the @dfn{target}; it is the full name of
the node that the cross reference points to.
The target is separated from the label by a colon @samp{:}; first the
label appears, and then the target. For example, in the sample menu
cross reference below, the single colon separates the label from the
target.
@example
* Foo Label: Foo Target. More information about Foo.
@end example
Note the @samp{.} which ends the name of the target. The @samp{.} is
not part of the target; it serves only to let Info know where the target
name ends.
A shorthand way of specifying references allows two adjacent colons to
stand for a target name which is the same as the label name:
@example
* Foo Commands:: Commands pertaining to Foo.
@end example
In the above example, the name of the target is the same as the name of
the label, in this case @code{Foo Commands}.
You will normally see two types of cross references while viewing nodes:
@dfn{menu} references, and @dfn{note} references. Menu references
appear within a node's menu; they begin with a @samp{*} at the beginning
of a line, and continue with a label, a target, and a comment which
describes what the contents of the node pointed to contains.
Note references appear within the body of the node text; they begin with
@code{*Note}, and continue with a label and a target.
Like @samp{Next}, @samp{Prev} and @samp{Up} pointers, cross references
can point to any valid node. They are used to refer you to a place
where more detailed information can be found on a particular subject.
Here is a cross reference which points to a node within the Texinfo
documentation: @xref{xref, , Writing an Xref, texinfo, the Texinfo
Manual}, for more information on creating your own texinfo cross
references.
@node Selecting Xrefs
@section Selecting Xrefs
The following table lists the Info commands which operate on menu items.
@table @asis
@item @code{1} (@code{menu-digit})
@itemx @code{2} @dots{} @code{9}
@cindex 1 @dots{} 9, in Info windows
@kindex 1 @dots{} 9, in Info windows
@findex menu-digit
Within an Info window, pressing a single digit, (such as @samp{1}),
selects that menu item, and places its node in the current window.
For convenience, there is one exception; pressing @samp{0} selects the
@emph{last} item in the node's menu.
@item @code{0} (@code{last-menu-item})
@kindex 0, in Info windows
@findex last-menu-item
Select the last item in the current node's menu.
@item @code{m} (@code{menu-item})
@kindex m
@findex menu-item
Reads the name of a menu item in the echo area and selects its node.
Completion is available while reading the menu label.
@item @code{M-x find-menu}
@findex find-menu
Moves the cursor to the start of this node's menu.
@end table
This table lists the Info commands which operate on note cross references.
@table @asis
@item @code{f} (@code{xref-item})
@itemx @code{r}
@kindex f
@kindex r
@findex xref-item
Reads the name of a note cross reference in the echo area and selects
its node. Completion is available while reading the cross reference
label.
@end table
Finally, the next few commands operate on menu or note references alike:
@table @asis
@item @code{TAB} (@code{move-to-next-xref})
@kindex TAB, in Info windows
@findex move-to-next-xref
Moves the cursor to the start of the next nearest menu item or note
reference in this node. You can then use @key{RET}
(@code{select-reference-this-line} to select the menu or note reference.
@item @code{M-TAB} (@code{move-to-prev-xref})
@kindex M-TAB, in Info windows
@findex move-to-prev-xref
Moves the cursor the start of the nearest previous menu item or note
reference in this node.
@item @code{RET} (@code{select-reference-this-line})
@kindex RET, in Info windows
@findex select-reference-this-line
Selects the menu item or note reference appearing on this line.
@end table
@node Window Commands
@chapter Manipulating Multiple Windows
@cindex windows, manipulating
A @dfn{window} is a place to show the text of a node. Windows have a
view area where the text of the node is displayed, and an associated
@dfn{mode line}, which briefly describes the node being viewed.
GNU Info supports multiple windows appearing in a single screen; each
window is separated from the next by its modeline. At any time, there
is only one @dfn{active} window, that is, the window in which the cursor
appears. There are commands available for creating windows, changing
the size of windows, selecting which window is active, and for deleting
windows.
@menu
* The Mode Line:: What appears in the mode line?
* Basic Windows:: Manipulating windows in Info.
* The Echo Area:: Used for displaying errors and reading input.
@end menu
@node The Mode Line
@section The Mode Line
A @dfn{mode line} is a line of inverse video which appears at the bottom
of an info window. It describes the contents of the window just above
it; this information includes the name of the file and node appearing in
that window, the number of screen lines it takes to display the node,
and the percentage of text that is above the top of the window. It can
also tell you if the indirect tags table for this info file needs to be
updated, and whether or not the info file was compressed when stored on
disk.
Here is a sample mode line for a window containing an uncompressed file
named @file{dir}, showing the node @samp{Top}.
@example
-----Info: (dir)Top, 40 lines --Top---------------------------------------
^^ ^ ^^^ ^^
(file)Node #lines where
@end example
When a node comes from a file which is compressed on disk, this is
indicated in the mode line with two small @samp{z}'s. In addition, if
the info file containing the node has been split into subfiles, the name
of the subfile containing the node appears in the modeline as well:
@example
--zz-Info: (emacs)Top, 291 lines --Top-- Subfile: emacs-1.Z---------------
@end example
When Info makes a node internally, such that there is no corresponding
info file on disk, the name of the node is surrounded by asterisks
(@samp{*}). The name itself tells you what the contents of the window
are; the sample mode line below shows an internally constructed node
showing possible completions:
@example
-----Info: *Completions*, 7 lines --All-----------------------------------
@end example
@node Basic Windows
@section Window Commands
It can be convenient to view more than one node at a time. To allow
this, Info can display more than one @dfn{window}. Each window has its
own mode line (@pxref{The Mode Line}) and history of nodes viewed in that
window (@pxref{Node Commands, , @code{history-node}}).
@table @asis
@item @code{C-x o} (@code{next-window})
@cindex windows, selecting
@kindex C-x o
@findex next-window
Selects the next window on the screen. Note that the echo area can only be
selected if it is already in use, and you have left it temporarily.
Normally, @samp{C-x o} simply moves the cursor into the next window on
the screen, or if you are already within the last window, into the first
window on the screen. Given a numeric argument, @samp{C-x o} moves over
that many windows. A negative argument causes @samp{C-x o} to select
the previous window on the screen.
@item @code{M-x prev-window}
@findex prev-window
Selects the previous window on the screen. This is identical to
@samp{C-x o} with a negative argument.
@item @code{C-x 2} (@code{split-window})
@cindex windows, creating
@kindex C-x 2
@findex split-window
Splits the current window into two windows, both showing the same node.
Each window is one half the size of the original window, and the cursor
remains in the original window. The variable @code{automatic-tiling}
can cause all of the windows on the screen to be resized for you
automatically, please @pxref{Variables, , automatic-tiling} for more
information.
@item @code{C-x 0} (@code{delete-window})
@cindex windows, deleting
@kindex C-x 0
@findex delete-window
Deletes the current window from the screen. If you have made too many
windows and your screen appears cluttered, this is the way to get rid of
some of them.
@item @code{C-x 1} (@code{keep-one-window})
@kindex C-x 1
@findex keep-one-window
Deletes all of the windows excepting the current one.
@item @code{ESC C-v} (@code{scroll-other-window})
@kindex ESC C-v, in Info windows
@findex scroll-other-window
Scrolls the other window, in the same fashion that @samp{C-v} might
scroll the current window. Given a negative argument, the "other"
window is scrolled backward.
@item @code{C-x ^} (@code{grow-window})
@kindex C-x ^
@findex grow-window
Grows (or shrinks) the current window. Given a numeric argument, grows
the current window that many lines; with a negative numeric argument,
the window is shrunk instead.
@item @code{C-x t} (@code{tile-windows})
@cindex tiling
@kindex C-x t
@findex tile-windows
Divides the available screen space among all of the visible windows.
Each window is given an equal portion of the screen in which to display
its contents. The variable @code{automatic-tiling} can cause
@code{tile-windows} to be called when a window is created or deleted.
@xref{Variables, , @code{automatic-tiling}}.
@end table
@node The Echo Area
@section The Echo Area
@cindex echo area
The @dfn{echo area} is a one line window which appears at the bottom of
the screen. It is used to display informative or error messages, and to
read lines of input from you when that is necessary. Almost all of the
commands available in the echo area are identical to their Emacs
counterparts, so please refer to that documentation for greater depth of
discussion on the concepts of editing a line of text. The following
table briefly lists the commands that are available while input is being
read in the echo area:
@table @asis
@item @code{C-f} (@code{echo-area-forward})
@kindex C-f, in the echo area
@findex echo-area-forward
Moves forward a character.
@item @code{C-b} (@code{echo-area-backward})
@kindex C-b, in the echo area
@findex echo-area-backward
Moves backward a character.
@item @code{C-a} (@code{echo-area-beg-of-line})
@kindex C-a, in the echo area
@findex echo-area-beg-of-line
Moves to the start of the input line.
@item @code{C-e} (@code{echo-area-end-of-line})
@kindex C-e, in the echo area
@findex echo-area-end-of-line
Moves to the end of the input line.
@item @code{M-f} (@code{echo-area-forward-word})
@kindex M-f, in the echo area
@findex echo-area-forward-word
Moves forward a word.
@item @code{M-b} (@code{echo-area-backward-word})
@kindex M-b, in the echo area
@findex echo-area-backward-word
Moves backward a word.
@item @code{C-d} (@code{echo-area-delete})
@kindex C-d, in the echo area
@findex echo-area-delete
Deletes the character under the cursor.
@item @code{DEL} (@code{echo-area-rubout})
@kindex DEL, in the echo area
@findex echo-area-rubout
Deletes the character behind the cursor.
@item @code{C-g} (@code{echo-area-abort})
@kindex C-g, in the echo area
@findex echo-area-abort
Cancels or quits the current operation. If completion is being read,
@samp{C-g} discards the text of the input line which does not match any
completion. If the input line is empty, @samp{C-g} aborts the calling
function.
@item @code{RET} (@code{echo-area-newline})
@kindex RET, in the echo area
@findex echo-area-newline
Accepts (or forces completion of) the current input line.
@item @code{C-q} (@code{echo-area-quoted-insert})
@kindex C-q, in the echo area
@findex echo-area-quoted-insert
Inserts the next character verbatim. This is how you can insert control
characters into a search string, for example.
@item @var{printing character} (@code{echo-area-insert})
@kindex printing characters, in the echo area
@findex echo-area-insert
Inserts the character.
@item @code{M-TAB} (@code{echo-area-tab-insert})
@kindex M-TAB, in the echo area
@findex echo-area-tab-insert
Inserts a TAB character.
@item @code{C-t} (@code{echo-area-transpose-chars})
@kindex C-t, in the echo area
@findex echo-area-transpose-chars
Transposes the characters at the cursor.
@end table
The next group of commands deal with @dfn{killing}, and @dfn{yanking}
text. For an in depth discussion of killing and yanking,
@pxref{Killing, , Killing and Deleting, emacs, the GNU Emacs Manual}
@table @asis
@item @code{M-d} (@code{echo-area-kill-word})
@kindex M-d, in the echo area
@findex echo-area-kill-word
Kills the word following the cursor.
@item @code{M-DEL} (@code{echo-area-backward-kill-word})
@kindex M-DEL, in the echo area
@findex echo-area-backward-kill-word
Kills the word preceding the cursor.
@item @code{C-k} (@code{echo-area-kill-line})
@kindex C-k, in the echo area
@findex echo-area-kill-line
Kills the text from the cursor to the end of the line.
@item @code{C-x DEL} (@code{echo-area-backward-kill-line})
@kindex C-x DEL, in the echo area
@findex echo-area-backward-kill-line
Kills the text from the cursor to the beginning of the line.
@item @code{C-y} (@code{echo-area-yank})
@kindex C-y, in the echo area
@findex echo-area-yank
Yanks back the contents of the last kill.
@item @code{M-y} (@code{echo-area-yank-pop})
@kindex M-y, in the echo area
@findex echo-area-yank-pop
Yanks back a previous kill, removing the last yanked text first.
@end table
Sometimes when reading input in the echo area, the command that needed
input will only accept one of a list of several choices. The choices
represent the @dfn{possible completions}, and you must respond with one
of them. Since there are a limited number of responses you can make,
Info allows you to abbreviate what you type, only typing as much of the
response as is necessary to uniquely identify it. In addition, you can
request Info to fill in as much of the response as is possible; this
is called @dfn{completion}.
The following commands are available when completing in the echo area:
@table @asis
@item @code{TAB} (@code{echo-area-complete})
@itemx @code{SPC}
@kindex TAB, in the echo area
@kindex SPC, in the echo area
@findex echo-area-complete
Inserts as much of a completion as is possible.
@item @code{?} (@code{echo-area-possible-completions})
@kindex ?, in the echo area
@findex echo-area-possible-completions
Displays a window containing a list of the possible completions of what
you have typed so far. For example, if the available choices are:
@example
bar
foliate
food
forget
@end example
and you have typed an @samp{f}, followed by @samp{?}, the possible
completions would contain:
@example
foliate
food
forget
@end example
i.e., all of the choices which begin with @samp{f}. Pressing @key{SPC}
or @key{TAB} would result in @samp{fo} appearing in the echo area, since
all of the choices which begin with @samp{f} continue with @samp{o}.
Now, typing @samp{l} followed by @samp{TAB} results in @samp{foliate}
appearing in the echo area, since that is the only choice which begins
with @samp{fol}.
@item @code{ESC C-v} (@code{echo-area-scroll-completions-window})
@kindex ESC C-v, in the echo area
@findex echo-area-scroll-completions-window
Scrolls the completions window, if that is visible, or the "other"
window if not.
@end table
@node Printing Nodes
@chapter Printing Out Nodes
@cindex printing
You may wish to print out the contents of a node as a quick reference
document for later use. Info provides you with a command for doing
this. In general, we recommend that you use @TeX{} to format the
document and print sections of it, by running @code{tex} on the texinfo
source file.
@table @asis
@item @code{M-x print-node}
@findex print-node
@cindex INFO_PRINT_COMMAND, environment variable
Pipes the contents of the current node through the command in the
environment variable @code{INFO_PRINT_COMMAND}. If the variable doesn't
exist, the node is simply piped to @code{lpr}.
@end table
@node Miscellaneous Commands
@chapter Miscellaneous Commands
GNU Info contains several commands which self-document GNU Info:
@table @asis
@item @code{M-x describe-command}
@cindex functions, describing
@cindex commands, describing
@findex describe-command
Reads the name of an Info command in the echo area and then displays a
brief description of what that command does.
@item @code{M-x describe-key}
@cindex keys, describing
@findex describe-key
Reads a key sequence in the echo area, and then displays the name and
documentation of the Info command that the key sequence invokes.
@item @code{M-x describe-variable}
Reads the name of a variable in the echo area and then displays a brief
description of what the variable affects.
@item @code{M-x where-is}
@findex where-is
Reads the name of an Info command in the echo area, and then displays
a key sequence which can be typed in order to invoke that command.
@item @code{C-h} (@code{get-help-window})
@itemx @code{?}
@kindex C-h
@kindex ?, in Info windows
@findex get-help-window
Creates (or moves into) the window displaying @code{*Help*}, and places
a node containing a quick reference card into it. This window displays
the most concise information about GNU Info available.
@item @code{h} (@code{get-info-help-node})
@kindex h
@findex get-info-help-node
Tries hard to visit the node @code{(info)Help}. The info file
@file{info.texi} distributed with GNU Info contains this node. Of
course, the file must first be processed with @code{makeinfo}, and then
placed into the location of your info directory.
@end table
Here are the commands for creating a numeric argument:
@table @asis
@item @code{C-u} (@code{universal-argument})
@cindex numeric arguments
@kindex C-u
@findex universal-argument
Starts (or multiplies by 4) the current numeric argument. @samp{C-u} is
a good way to give a small numeric argument to cursor movement or
scrolling commands; @samp{C-u C-v} scrolls the screen 4 lines, while
@samp{C-u C-u C-n} moves the cursor down 16 lines.
@item @code{M-1} (@code{add-digit-to-numeric-arg})
@itemx @code{M-2} @dots{} @code{M-9}
@kindex M-1 @dots{} M-9
@findex add-digit-to-numeric-arg
Adds the digit value of the invoking key to the current numeric
argument. Once Info is reading a numeric argument, you may just type
the digits of the argument, without the Meta prefix. For example, you
might give @samp{C-l} a numeric argument of 32 by typing:
@example
@kbd{C-u 3 2 C-l}
@end example
or
@example
@kbd{M-3 2 C-l}
@end example
@end table
@samp{C-g} is used to abort the reading of a multi-character key
sequence, to cancel lengthy operations (such as multi-file searches) and
to cancel reading input in the echo area.
@table @asis
@item @code{C-g} (@code{abort-key})
@cindex cancelling typeahead
@cindex cancelling the current operation
@kindex C-g, in Info windows
@findex abort-key
Cancels current operation.
@end table
The @samp{q} command of Info simply quits running Info.
@table @asis
@item @code{q} (@code{quit})
@cindex quitting
@kindex q
@findex quit
Exits GNU Info.
@end table
If the operating system tells GNU Info that the screen is 60 lines tall,
and it is actually only 40 lines tall, here is a way to tell Info that
the operating system is correct.
@table @asis
@item @code{M-x set-screen-height}
@findex set-screen-height
@cindex screen, changing the height of
Reads a height value in the echo area and sets the height of the
displayed screen to that value.
@end table
Finally, Info provides a convenient way to display footnotes which might
be associated with the current node that you are viewing:
@table @asis
@item @code{ESC C-f} (@code{show-footnotes})
@kindex ESC C-f
@findex show-footnotes
@cindex footnotes, displaying
Shows the footnotes (if any) associated with the current node in another
window. You can have Info automatically display the footnotes
associated with a node when the node is selected by setting the variable
@code{automatic-footnotes}. @xref{Variables, , @code{automatic-footnotes}}.
@end table
@node Variables
@chapter Manipulating Variables
GNU Info contains several @dfn{variables} whose values are looked at by various
Info commands. You can change the values of these variables, and thus
change the behaviour of Info to more closely match your environment and
info file reading manner.
@table @asis
@item @code{M-x set-variable}
@cindex variables, setting
@findex set-variable
Reads the name of a variable, and the value for it, in the echo area and
then sets the variable to that value. Completion is available when
reading the variable name; often, completion is available when reading
the value to give to the variable, but that depends on the variable
itself. If a variable does @emph{not} supply multiple choices to
complete over, it expects a numeric value.
@item @code{M-x describe-variable}
@cindex variables, describing
@findex describe-variable
Reads the name of a variable in the echo area and then displays a brief
description of what the variable affects.
@end table
Here is a list of the variables that you can set in Info.
@table @code
@item automatic-footnotes
@vindex automatic-footnotes
When set to @code{On}, footnotes appear and disappear automatically.
This variable is @code{On} by default. When a node is selected, a
window containing the footnotes which appear in that node is created,
and the footnotes are displayed within the new window. The window that
Info creates to contain the footnotes is called @samp{*Footnotes*}. If
a node is selected which contains no footnotes, and a @samp{*Footnotes*}
window is on the screen, the @samp{*Footnotes*} window is deleted.
Footnote windows created in this fashion are not automatically tiled so
that they can use as little of the display as is possible.
@item automatic-tiling
@vindex automatic-tiling
When set to @code{On}, creating or deleting a window resizes other
windows. This variable is @code{Off} by default. Normally, typing
@samp{C-x 2} divides the current window into two equal parts. When
@code{automatic-tiling} is set to @code{On}, all of the windows are
resized automatically, keeping an equal number of lines visible in each
window. There are exceptions to the automatic tiling; specifically, the
windows @samp{*Completions*} and @samp{*Footnotes*} are @emph{not}
resized through automatic tiling; they remain their original size.
@item visible-bell
@vindex visible-bell
When set to @code{On}, GNU Info attempts to flash the screen instead of
ringing the bell. This variable is @code{Off} by default. Of course,
Info can only flash the screen if the terminal allows it; in the case
that the terminal does not allow it, the setting of this variable has no
effect. However, you can make Info perform quietly by setting the
@code{errors-ring-bell} variable to @code{Off}.
@item errors-ring-bell
@vindex errors-ring-bell
When set to @code{On}, errors cause the bell to ring. The default
setting of this variable is @code{On}.
@item gc-compressed-files
@vindex gc-compressed-files
When set to @code{On}, Info garbage collects files which had to be
uncompressed. The default value of this variable is @code{Off}.
Whenever a node is visited in Info, the info file containing that node
is read into core, and Info reads information about the tags and nodes
contained in that file. Once the tags information is read by Info, it
is never forgotten. However, the actual text of the nodes does not need
to remain in core unless a particular info window needs it. For
non-compressed files, the text of the nodes does not remain in core when
it is no longer in use. But de-compressing a file can be a time
consuming operation, and so Info tries hard not to do it twice.
@code{gc-compressed-files} tells Info it is okay to garbage collect the
text of the nodes of a file which was compressed on disk.
@item show-index-match
@vindex show-index-match
When set to @code{On}, the portion of the matched search string is
highlighted in the message which explains where the matched search
string was found. The default value of this variable is @code{On}.
When Info displays the location where an index match was found,
(@pxref{Searching Commands, , @code{next-index-match}}), the portion of the
string that you had typed is highlighted by displaying it in the inverse
case from its surrounding characters.
@item scroll-behaviour
@vindex scroll-behaviour
Controls what happens when forward scrolling is requested at the end of
a node, or when backward scrolling is requested at the beginning of a
node. The default value for this variable is @code{Continuous}. There
are three possible values for this variable:
@table @code
@item Continuous
Tries to get the first item in this node's menu, or failing that, the
@samp{Next} node, or failing that, the @samp{Next} of the @samp{Up}.
This behaviour is identical to using the @samp{]}
(@code{global-next-node}) and @samp{[} (@code{global-prev-node})
commands.
@item Next Only
Only tries to get the @samp{Next} node.
@item Page Only
Simply gives up, changing nothing. If @code{scroll-behaviour} is
@code{Page Only}, no scrolling command can change the node that is being
viewed.
@end table
@item scroll-step
@vindex scroll-step
The number of lines to scroll when the cursor moves out of the window.
Scrolling happens automatically if the cursor has moved out of the
visible portion of the node text when it is time to display. Usually
the scrolling is done so as to put the cursor on the center line of the
current window. However, if the variable @code{scroll-step} has a
nonzero value, Info attempts to scroll the node text by that many lines;
if that is enough to bring the cursor back into the window, that is what
is done. The default value of this variable is 0, thus placing the
cursor (and the text it is attached to) in the center of the window.
Setting this variable to 1 causes a kind of "smooth scrolling" which
some people prefer.
@item ISO-Latin
@cindex ISO Latin characters
@vindex ISO-Latin
When set to @code{On}, Info accepts and displays ISO Latin characters.
By default, Info assumes an ASCII character set. @code{ISO-Latin} tells
Info that it is running in an environment where the European standard
character set is in use, and allows you to input such characters to
Info, as well as display them.
@end table
@c The following node and its children are currently unfinished. Please feel
@c free to finish it!
@ifset NOTSET
@node Info for Sys Admins
@chapter Info for System Administrators
This text describes some common ways of setting up an Info heierarchy
from scratch, and details the various options that are available when
installing Info. This text is designed for the person who is installing
GNU Info on the system; although users may find the information present
in this section interesting, none of it is vital to understanding how to
use GNU Info.
@menu
* Setting the INFOPATH:: Where are my Info files kept?
* Editing the DIR node:: What goes in `DIR', and why?
* Storing Info files:: Alternate formats allow flexibilty in setups.
* Using `localdir':: Building DIR on the fly.
* Example setups:: Some common ways to origanize Info files.
@end menu
@node Setting the INFOPATH
@section Setting the INFOPATH
Where are my Info files kept?
@node Editing the DIR node
@section Editing the DIR node
What goes in `DIR', and why?
@node Storing Info files
@section Storing Info files
Alternate formats allow flexibilty in setups.
@node Using `localdir'
@section Using `localdir'
Building DIR on the fly.
@node Example setups
@section Example setups
Some common ways to origanize Info files.
@end ifset
@ifset STANDALONE
@node GNU Info Global Index
@appendix Global Index
@printindex cp
@end ifset
texinfo-3.7/info/variables.c 100666 11732 13 16377 5770343343 14347 0 ustar bfox user /* variables.c -- How to manipulate user visible variables in Info. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include "info.h"
#include "variables.h"
/* **************************************************************** */
/* */
/* User Visible Variables in Info */
/* */
/* **************************************************************** */
/* Choices used by the completer when reading a zero/non-zero value for
a variable. */
static char *on_off_choices[] = { "Off", "On", (char *)NULL };
VARIABLE_ALIST info_variables[] = {
{ "automatic-footnotes",
"When \"On\", footnotes appear and disappear automatically",
&auto_footnotes_p, (char **)on_off_choices },
{ "automatic-tiling",
"When \"On\", creating or deleting a window resizes other windows",
&auto_tiling_p, (char **)on_off_choices },
{ "visible-bell",
"When \"On\", flash the screen instead of ringing the bell",
&terminal_use_visible_bell_p, (char **)on_off_choices },
{ "errors-ring-bell",
"When \"On\", errors cause the bell to ring",
&info_error_rings_bell_p, (char **)on_off_choices },
{ "gc-compressed-files",
"When \"On\", Info garbage collects files which had to be uncompressed",
&gc_compressed_files, (char **)on_off_choices },
{ "show-index-match",
"When \"On\", the portion of the matched search string is highlighted",
&show_index_match, (char **)on_off_choices },
{ "scroll-behaviour",
"Controls what happens when scrolling is requested at the end of a node",
&info_scroll_behaviour, (char **)info_scroll_choices },
{ "scroll-step",
"The number lines to scroll when the cursor moves out of the window",
&window_scroll_step, (char **)NULL },
{ "ISO-Latin",
"When \"On\", Info accepts and displays ISO Latin characters",
&ISO_Latin_p, (char **)on_off_choices },
{ (char *)NULL, (char *)NULL, (int *)NULL, (char **)NULL }
};
DECLARE_INFO_COMMAND (describe_variable, "Explain the use of a variable")
{
VARIABLE_ALIST *var;
char *description;
/* Get the variable's name. */
var = read_variable_name ("Describe variable: ", window);
if (!var)
return;
description = (char *)xmalloc (20 + strlen (var->name) + strlen (var->doc));
if (var->choices)
sprintf (description, "%s (%s): %s.",
var->name, var->choices[*(var->value)], var->doc);
else
sprintf (description, "%s (%d): %s.", var->name, *(var->value), var->doc);
window_message_in_echo_area ("%s", description);
free (description);
}
DECLARE_INFO_COMMAND (set_variable, "Set the value of an Info variable")
{
VARIABLE_ALIST *var;
char *line;
/* Get the variable's name and value. */
var = read_variable_name ("Set variable: ", window);
if (!var)
return;
/* Read a new value for this variable. */
{
char prompt[100];
if (!var->choices)
{
int potential_value;
if (info_explicit_arg || count != 1)
potential_value = count;
else
potential_value = *(var->value);
sprintf (prompt, "Set %s to value (%d): ",
var->name, potential_value);
line = info_read_in_echo_area (active_window, prompt);
/* If no error was printed, clear the echo area. */
if (!info_error_was_printed)
window_clear_echo_area ();
/* User aborted? */
if (!line)
return;
/* If the user specified a value, get that, otherwise, we are done. */
canonicalize_whitespace (line);
if (*line)
*(var->value) = atoi (line);
else
*(var->value) = potential_value;
free (line);
}
else
{
register int i;
REFERENCE **array = (REFERENCE **)NULL;
int array_index = 0;
int array_slots = 0;
for (i = 0; var->choices[i]; i++)
{
REFERENCE *entry;
entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
entry->label = strdup (var->choices[i]);
entry->nodename = (char *)NULL;
entry->filename = (char *)NULL;
add_pointer_to_array
(entry, array_index, array, array_slots, 10, REFERENCE *);
}
sprintf (prompt, "Set %s to value (%s): ",
var->name, var->choices[*(var->value)]);
/* Ask the completer to read a variable value for us. */
line = info_read_completing_in_echo_area (window, prompt, array);
info_free_references (array);
if (!echo_area_is_active)
window_clear_echo_area ();
/* User aborted? */
if (!line)
{
info_abort_key (active_window, 0, 0);
return;
}
/* User accepted default choice? If so, no change. */
if (!*line)
{
free (line);
return;
}
/* Find the choice in our list of choices. */
for (i = 0; var->choices[i]; i++)
if (strcmp (var->choices[i], line) == 0)
break;
if (var->choices[i])
*(var->value) = i;
}
}
}
/* Read the name of an Info variable in the echo area and return the
address of a VARIABLE_ALIST member. A return value of NULL indicates
that no variable could be read. */
VARIABLE_ALIST *
read_variable_name (prompt, window)
char *prompt;
WINDOW *window;
{
register int i;
char *line;
REFERENCE **variables;
/* Get the completion array of variable names. */
variables = make_variable_completions_array ();
/* Ask the completer to read a variable for us. */
line =
info_read_completing_in_echo_area (window, prompt, variables);
info_free_references (variables);
if (!echo_area_is_active)
window_clear_echo_area ();
/* User aborted? */
if (!line)
{
info_abort_key (active_window, 0, 0);
return ((VARIABLE_ALIST *)NULL);
}
/* User accepted "default"? (There is none.) */
if (!*line)
{
free (line);
return ((VARIABLE_ALIST *)NULL);
}
/* Find the variable in our list of variables. */
for (i = 0; info_variables[i].name; i++)
if (strcmp (info_variables[i].name, line) == 0)
break;
if (!info_variables[i].name)
return ((VARIABLE_ALIST *)NULL);
else
return (&(info_variables[i]));
}
/* Make an array of REFERENCE which actually contains the names of the
variables available in Info. */
REFERENCE **
make_variable_completions_array ()
{
register int i;
REFERENCE **array = (REFERENCE **)NULL;
int array_index = 0, array_slots = 0;
for (i = 0; info_variables[i].name; i++)
{
REFERENCE *entry;
entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
entry->label = strdup (info_variables[i].name);
entry->nodename = (char *)NULL;
entry->filename = (char *)NULL;
add_pointer_to_array
(entry, array_index, array, array_slots, 200, REFERENCE *);
}
return (array);
}
texinfo-3.7/info/variables.h 100666 11732 13 4611 5770343476 14327 0 ustar bfox user /* variables.h -- Description of user visible variables in Info. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_VARIABLES_H_)
#define _VARIABLES_H_
/* A variable (in the Info sense) is an integer value with a user-visible
name. You may supply an array of strings to complete over when the
variable is set; in that case, the variable is set to the index of the
string that the user chose. If you supply a null list, the user can
set the variable to a numeric value. */
/* Structure describing a user visible variable. */
typedef struct {
char *name; /* Polite name. */
char *doc; /* Documentation string. */
int *value; /* Address of value. */
char **choices; /* Array of strings or NULL if numeric only. */
} VARIABLE_ALIST;
/* Read the name of an Info variable in the echo area and return the
address of a VARIABLE_ALIST member. A return value of NULL indicates
that no variable could be read. */
extern VARIABLE_ALIST *read_variable_name ();
/* Make an array of REFERENCE which actually contains the names of the
variables available in Info. */
extern REFERENCE **make_variable_completions_array ();
/* Set the value of an info variable. */
extern void set_variable ();
/* The list of user-visible variables. */
extern int auto_footnotes_p;
extern int auto_tiling_p;
extern int terminal_use_visible_bell_p;
extern int info_error_rings_bell_p;
extern int gc_compressed_files;
extern int show_index_match;
extern int info_scroll_behaviour;
extern int window_scroll_step;
extern int ISO_Latin_p;
#endif /* _VARIABLES_H_ */
texinfo-3.7/info/window.c 100666 11732 13 115772 5771357764 13742 0 ustar bfox user /* window.c -- Windows in Info. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#include
#include
#include
#include
#include "nodes.h"
#include "window.h"
#include "display.h"
#include "info-utils.h"
#include "infomap.h"
/* The window which describes the screen. */
WINDOW *the_screen = (WINDOW *)NULL;
/* The window which describes the echo area. */
WINDOW *the_echo_area = (WINDOW *)NULL;
/* The list of windows in Info. */
WINDOW *windows = (WINDOW *)NULL;
/* Pointer to the active window in WINDOW_LIST. */
WINDOW *active_window = (WINDOW *)NULL;
/* The size of the echo area in Info. It never changes, irregardless of the
size of the screen. */
#define ECHO_AREA_HEIGHT 1
/* Macro returns the amount of space that the echo area truly requires relative
to the entire screen. */
#define echo_area_required (1 + the_echo_area->height)
/* Initalize the window system by creating THE_SCREEN and THE_ECHO_AREA.
Create the first window ever.
You pass the dimensions of the total screen size. */
void
window_initialize_windows (width, height)
int width, height;
{
the_screen = (WINDOW *)xmalloc (sizeof (WINDOW));
the_echo_area = (WINDOW *)xmalloc (sizeof (WINDOW));
windows = (WINDOW *)xmalloc (sizeof (WINDOW));
active_window = windows;
zero_mem (the_screen, sizeof (WINDOW));
zero_mem (the_echo_area, sizeof (WINDOW));
zero_mem (active_window, sizeof (WINDOW));
/* None of these windows has a goal column yet. */
the_echo_area->goal_column = -1;
active_window->goal_column = -1;
the_screen->goal_column = -1;
/* The active and echo_area windows are visible.
The echo_area is permanent.
The screen is permanent. */
active_window->flags = W_WindowVisible;
the_echo_area->flags = W_WindowIsPerm | W_InhibitMode | W_WindowVisible;
the_screen->flags = W_WindowIsPerm;
/* The height of the echo area never changes. It is statically set right
here, and it must be at least 1 line for display. The size of the
initial window cannot be the same size as the screen, since the screen
includes the echo area. So, we make the height of the initial window
equal to the screen's displayable region minus the height of the echo
area. */
the_echo_area->height = ECHO_AREA_HEIGHT;
active_window->height = the_screen->height - 1 - the_echo_area->height;
window_new_screen_size (width, height, (VFunction *)NULL);
/* The echo area uses a different keymap than normal info windows. */
the_echo_area->keymap = echo_area_keymap;
active_window->keymap = info_keymap;
}
/* Given that the size of the screen has changed to WIDTH and HEIGHT
from whatever it was before (found in the_screen->height, ->width),
change the size (and possibly location) of each window in the screen.
If a window would become too small, call the function DELETER on it,
after deleting the window from our chain of windows. If DELETER is NULL,
nothing extra is done. The last window can never be deleted, but it can
become invisible. */
/* If non-null, a function to call with WINDOW as argument when the function
window_new_screen_size () has deleted WINDOW. */
VFunction *window_deletion_notifier = (VFunction *)NULL;
void
window_new_screen_size (width, height)
int width, height;
{
register WINDOW *win;
int delta_height, delta_each, delta_leftover;
int numwins;
/* If no change, do nothing. */
if (width == the_screen->width && height == the_screen->height)
return;
/* If the new window height is too small, make it be zero. */
if (height < (WINDOW_MIN_SIZE + the_echo_area->height))
height = 0;
if (width < 0)
width = 0;
/* Find out how many windows will change. */
for (numwins = 0, win = windows; win; win = win->next, numwins++);
/* See if some windows will need to be deleted. This is the case if
the screen is getting smaller, and the available space divided by
the number of windows is less than WINDOW_MIN_SIZE. In that case,
delete some windows and try again until there is either enough
space to divy up among the windows, or until there is only one
window left. */
while ((height - echo_area_required) / numwins <= WINDOW_MIN_SIZE)
{
/* If only one window, make the size of it be zero, and return
immediately. */
if (!windows->next)
{
windows->height = 0;
maybe_free (windows->line_starts);
windows->line_starts = (char **)NULL;
windows->line_count = 0;
break;
}
/* If we have some temporary windows, delete one of them. */
for (win = windows; win; win = win->next)
if (win->flags & W_TempWindow)
break;
/* Otherwise, delete the first window, and try again. */
if (!win)
win = windows;
if (window_deletion_notifier)
(*window_deletion_notifier) (win);
window_delete_window (win);
numwins--;
}
/* The screen has changed height and width. */
delta_height = height - the_screen->height; /* This is how much. */
the_screen->height = height; /* This is the new height. */
the_screen->width = width; /* This is the new width. */
/* Set the start of the echo area. */
the_echo_area->first_row = height - the_echo_area->height;
the_echo_area->width = width;
/* Check to see if the screen can really be changed this way. */
if ((!windows->next) && ((windows->height == 0) && (delta_height < 0)))
return;
/* Divide the change in height among the available windows. */
delta_each = delta_height / numwins;
delta_leftover = delta_height - (delta_each * numwins);
/* Change the height of each window in the chain by delta_each. Change
the height of the last window in the chain by delta_each and by the
leftover amount of change. Change the width of each window to be
WIDTH. */
for (win = windows; win; win = win->next)
{
if ((win->width != width) && ((win->flags & W_InhibitMode) == 0))
{
win->width = width;
maybe_free (win->modeline);
win->modeline = (char *)xmalloc (1 + width);
}
win->height += delta_each;
/* If the previous height of this window was zero, it was the only
window, and it was not visible. Thus we need to compensate for
the echo_area. */
if (win->height == delta_each)
win->height -= (1 + the_echo_area->height);
/* If this is not the first window in the chain, then change the
first row of it. We cannot just add delta_each to the first row,
since this window's first row is the sum of the collective increases
that have gone before it. So we just add one to the location of the
previous window's modeline. */
if (win->prev)
win->first_row = (win->prev->first_row + win->prev->height) + 1;
/* The last window in the chain gets the extra space (or shrinkage). */
if (!win->next)
win->height += delta_leftover;
if (win->node)
recalculate_line_starts (win);
win->flags |= W_UpdateWindow;
}
/* If the screen got smaller, check over the windows just shrunk to
keep them within bounds. Some of the windows may have gotten smaller
than WINDOW_MIN_HEIGHT in which case some of the other windows are
larger than the available display space in the screen. Because of our
intial test above, we know that there is enough space for all of the
windows. */
if ((delta_each < 0) && ((windows->height != 0) && windows->next))
{
int avail;
avail = the_screen->height - (numwins + the_echo_area->height);
win = windows;
while (win)
{
if ((win->height < WINDOW_MIN_HEIGHT) ||
(win->height > avail))
{
WINDOW *lastwin;
/* Split the space among the available windows. */
delta_each = avail / numwins;
delta_leftover = avail - (delta_each * numwins);
for (win = windows; win; win = win->next)
{
lastwin = win;
if (win->prev)
win->first_row =
(win->prev->first_row + win->prev->height) + 1;
win->height = delta_each;
}
/* Give the leftover space (if any) to the last window. */
lastwin->height += delta_leftover;
break;
}
else
win= win->next;
}
}
}
/* Make a new window showing NODE, and return that window structure.
If NODE is passed as NULL, then show the node showing in the active
window. If the window could not be made return a NULL pointer. The
active window is not changed.*/
WINDOW *
window_make_window (node)
NODE *node;
{
WINDOW *window;
if (!node)
node = active_window->node;
/* If there isn't enough room to make another window, return now. */
if ((active_window->height / 2) < WINDOW_MIN_SIZE)
return ((WINDOW *)NULL);
/* Make and initialize the new window.
The fudging about with -1 and +1 is because the following window in the
chain cannot start at window->height, since that is where the modeline
for the previous window is displayed. The inverse adjustment is made
in window_delete_window (). */
window = (WINDOW *)xmalloc (sizeof (WINDOW));
window->width = the_screen->width;
window->height = (active_window->height / 2) - 1;
#if defined (SPLIT_BEFORE_ACTIVE)
window->first_row = active_window->first_row;
#else
window->first_row = active_window->first_row +
(active_window->height - window->height);
#endif
window->keymap = info_keymap;
window->goal_column = -1;
window->modeline = (char *)xmalloc (1 + window->width);
window->line_starts = (char **)NULL;
window->flags = W_UpdateWindow | W_WindowVisible;
window_set_node_of_window (window, node);
/* Adjust the height of the old active window. */
active_window->height -= (window->height + 1);
#if defined (SPLIT_BEFORE_ACTIVE)
active_window->first_row += (window->height + 1);
#endif
active_window->flags |= W_UpdateWindow;
/* Readjust the new and old windows so that their modelines and contents
will be displayed correctly. */
#if defined (NOTDEF)
/* We don't have to do this for WINDOW since window_set_node_of_window ()
already did. */
window_adjust_pagetop (window);
window_make_modeline (window);
#endif /* NOTDEF */
/* We do have to readjust the existing active window. */
window_adjust_pagetop (active_window);
window_make_modeline (active_window);
#if defined (SPLIT_BEFORE_ACTIVE)
/* This window is just before the active one. The active window gets
bumped down one. The active window is not changed. */
window->next = active_window;
window->prev = active_window->prev;
active_window->prev = window;
if (window->prev)
window->prev->next = window;
else
windows = window;
#else
/* This window is just after the active one. Which window is active is
not changed. */
window->prev = active_window;
window->next = active_window->next;
active_window->next = window;
if (window->next)
window->next->prev = window;
#endif /* !SPLIT_BEFORE_ACTIVE */
return (window);
}
/* These useful macros make it possible to read the code in
window_change_window_height (). */
#define grow_me_shrinking_next(me, next, diff) \
do { \
me->height += diff; \
next->height -= diff; \
next->first_row += diff; \
window_adjust_pagetop (next); \
} while (0)
#define grow_me_shrinking_prev(me, prev, diff) \
do { \
me->height += diff; \
prev->height -= diff; \
me->first_row -=diff; \
window_adjust_pagetop (prev); \
} while (0)
#define shrink_me_growing_next(me, next, diff) \
do { \
me->height -= diff; \
next->height += diff; \
next->first_row -= diff; \
window_adjust_pagetop (next); \
} while (0)
#define shrink_me_growing_prev(me, prev, diff) \
do { \
me->height -= diff; \
prev->height += diff; \
me->first_row += diff; \
window_adjust_pagetop (prev); \
} while (0)
/* Change the height of WINDOW by AMOUNT. This also automagically adjusts
the previous and next windows in the chain. If there is only one user
window, then no change takes place. */
void
window_change_window_height (window, amount)
WINDOW *window;
int amount;
{
register WINDOW *win, *prev, *next;
/* If there is only one window, or if the amount of change is zero,
return immediately. */
if (!windows->next || amount == 0)
return;
/* Find this window in our chain. */
for (win = windows; win; win = win->next)
if (win == window)
break;
/* If the window is isolated (i.e., doesn't appear in our window list,
then quit now. */
if (!win)
return;
/* Change the height of this window by AMOUNT, if that is possible.
It can be impossible if there isn't enough available room on the
screen, or if the resultant window would be too small. */
prev = window->prev;
next = window->next;
/* WINDOW decreasing in size? */
if (amount < 0)
{
int abs_amount = -amount; /* It is easier to deal with this way. */
/* If the resultant window would be too small, stop here. */
if ((window->height - abs_amount) < WINDOW_MIN_HEIGHT)
return;
/* If we have two neighboring windows, choose the smaller one to get
larger. */
if (next && prev)
{
if (prev->height < next->height)
shrink_me_growing_prev (window, prev, abs_amount);
else
shrink_me_growing_next (window, next, abs_amount);
}
else if (next)
shrink_me_growing_next (window, next, abs_amount);
else
shrink_me_growing_prev (window, prev, abs_amount);
}
/* WINDOW increasing in size? */
if (amount > 0)
{
int total_avail, next_avail = 0, prev_avail = 0;
if (next)
next_avail = next->height - WINDOW_MIN_SIZE;
if (prev)
prev_avail = prev->height - WINDOW_MIN_SIZE;
total_avail = next_avail + prev_avail;
/* If there isn't enough space available to grow this window, give up. */
if (amount > total_avail)
return;
/* If there aren't two neighboring windows, or if one of the neighbors
is larger than the other one by at least AMOUNT, grow that one. */
if ((next && !prev) || ((next_avail - amount) >= prev_avail))
grow_me_shrinking_next (window, next, amount);
else if ((prev && !next) || ((prev_avail - amount) >= next_avail))
grow_me_shrinking_prev (window, prev, amount);
else
{
int change;
/* This window has two neighbors. They both must be shrunk in to
make enough space for WINDOW to grow. Make them both the same
size. */
if (prev_avail > next_avail)
{
change = prev_avail - next_avail;
grow_me_shrinking_prev (window, prev, change);
amount -= change;
}
else
{
change = next_avail - prev_avail;
grow_me_shrinking_next (window, next, change);
amount -= change;
}
/* Both neighbors are the same size. Split the difference in
AMOUNT between them. */
while (amount)
{
window->height++;
amount--;
/* Odd numbers grow next, even grow prev. */
if (amount & 1)
{
prev->height--;
window->first_row--;
}
else
{
next->height--;
next->first_row++;
}
}
window_adjust_pagetop (prev);
window_adjust_pagetop (next);
}
}
if (prev)
prev->flags |= W_UpdateWindow;
if (next)
next->flags |= W_UpdateWindow;
window->flags |= W_UpdateWindow;
window_adjust_pagetop (window);
}
/* Tile all of the windows currently displayed in the global variable
WINDOWS. If argument STYLE is TILE_INTERNALS, tile windows displaying
internal nodes as well, otherwise do not change the height of such
windows. */
void
window_tile_windows (style)
int style;
{
WINDOW *win, *last_adjusted;
int numwins, avail, per_win_height, leftover;
int do_internals;
numwins = avail = 0;
do_internals = (style == TILE_INTERNALS);
for (win = windows; win; win = win->next)
if (do_internals || !win->node ||
(win->node->flags & N_IsInternal) == 0)
{
avail += win->height;
numwins++;
}
if (numwins <= 1 || !the_screen->height)
return;
/* Find the size for each window. Divide the size of the usable portion
of the screen by the number of windows. */
per_win_height = avail / numwins;
leftover = avail - (per_win_height * numwins);
last_adjusted = (WINDOW *)NULL;
for (win = windows; win; win = win->next)
{
if (do_internals || !win->node ||
(win->node->flags & N_IsInternal) == 0)
{
last_adjusted = win;
win->height = per_win_height;
}
}
if (last_adjusted)
last_adjusted->height += leftover;
/* Readjust the first_row of every window in the chain. */
for (win = windows; win; win = win->next)
{
if (win->prev)
win->first_row = win->prev->first_row + win->prev->height + 1;
window_adjust_pagetop (win);
win->flags |= W_UpdateWindow;
}
}
/* Toggle the state of line wrapping in WINDOW. This can do a bit of fancy
redisplay. */
void
window_toggle_wrap (window)
WINDOW *window;
{
if (window->flags & W_NoWrap)
window->flags &= ~W_NoWrap;
else
window->flags |= W_NoWrap;
if (window != the_echo_area)
{
char **old_starts;
int old_lines, old_pagetop;
old_starts = window->line_starts;
old_lines = window->line_count;
old_pagetop = window->pagetop;
calculate_line_starts (window);
/* Make sure that point appears within this window. */
window_adjust_pagetop (window);
/* If the pagetop hasn't changed maybe we can do some scrolling now
to speed up the display. Many of the line starts will be the same,
so scrolling here is a very good optimization.*/
if (old_pagetop == window->pagetop)
display_scroll_line_starts
(window, old_pagetop, old_starts, old_lines);
maybe_free (old_starts);
}
window->flags |= W_UpdateWindow;
}
/* Set WINDOW to display NODE. */
void
window_set_node_of_window (window, node)
WINDOW *window;
NODE *node;
{
window->node = node;
window->pagetop = 0;
window->point = 0;
recalculate_line_starts (window);
window->flags |= W_UpdateWindow;
window_adjust_pagetop (window);
window_make_modeline (window);
}
/* Delete WINDOW from the list of known windows. If this window was the
active window, make the next window in the chain be the active window.
If the active window is the next or previous window, choose that window
as the recipient of the extra space. Otherwise, prefer the next window. */
void
window_delete_window (window)
WINDOW *window;
{
WINDOW *next, *prev, *window_to_fix;
next = window->next;
prev = window->prev;
/* You cannot delete the only window or a permanent window. */
if ((!next && !prev) || (window->flags & W_WindowIsPerm))
return;
if (next)
next->prev = prev;
if (!prev)
windows = next;
else
prev->next = next;
if (window->line_starts)
free (window->line_starts);
if (window->modeline)
free (window->modeline);
if (window == active_window)
{
/* If there isn't a next window, then there must be a previous one,
since we cannot delete the last window. If there is a next window,
prefer to use that as the active window. */
if (next)
active_window = next;
else
active_window = prev;
}
if (next && active_window == next)
window_to_fix = next;
else if (prev && active_window == prev)
window_to_fix = prev;
else if (next)
window_to_fix = next;
else if (prev)
window_to_fix = prev;
else
window_to_fix = windows;
if (window_to_fix->first_row > window->first_row)
{
int diff;
/* Try to adjust the visible part of the node so that as little
text as possible has to move. */
diff = window_to_fix->first_row - window->first_row;
window_to_fix->first_row = window->first_row;
window_to_fix->pagetop -= diff;
if (window_to_fix->pagetop < 0)
window_to_fix->pagetop = 0;
}
/* The `+ 1' is to offset the difference between the first_row locations.
See the code in window_make_window (). */
window_to_fix->height += window->height + 1;
window_to_fix->flags |= W_UpdateWindow;
free (window);
}
/* For every window in CHAIN, set the flags member to have FLAG set. */
void
window_mark_chain (chain, flag)
WINDOW *chain;
int flag;
{
register WINDOW *win;
for (win = chain; win; win = win->next)
win->flags |= flag;
}
/* For every window in CHAIN, clear the flags member of FLAG. */
void
window_unmark_chain (chain, flag)
WINDOW *chain;
int flag;
{
register WINDOW *win;
for (win = chain; win; win = win->next)
win->flags &= ~flag;
}
/* Return the number of characters it takes to display CHARACTER on the
screen at HPOS. */
int
character_width (character, hpos)
int character, hpos;
{
int printable_limit = 127;
int width = 1;
if (ISO_Latin_p)
printable_limit = 160;
if (character > printable_limit)
width = 3;
else if (iscntrl (character))
{
switch (character)
{
case '\r':
case '\n':
width = the_screen->width - hpos;
break;
case '\t':
width = ((hpos + 8) & 0xf8) - hpos;
break;
default:
width = 2;
}
}
else if (character == DEL)
width = 2;
return (width);
}
/* Return the number of characters it takes to display STRING on the screen
at HPOS. */
int
string_width (string, hpos)
char *string;
int hpos;
{
register int i, width, this_char_width;
for (width = 0, i = 0; string[i]; i++)
{
this_char_width = character_width (string[i], hpos);
width += this_char_width;
hpos += this_char_width;
}
return (width);
}
/* Quickly guess the approximate number of lines to that NODE would
take to display. This really only counts carriage returns. */
int
window_physical_lines (node)
NODE *node;
{
register int i, lines;
char *contents;
if (!node)
return (0);
contents = node->contents;
for (i = 0, lines = 1; i < node->nodelen; i++)
if (contents[i] == '\n')
lines++;
return (lines);
}
/* Calculate a list of line starts for the node belonging to WINDOW. The line
starts are pointers to the actual text within WINDOW->NODE. */
void
calculate_line_starts (window)
WINDOW *window;
{
register int i, hpos;
char **line_starts = (char **)NULL;
int line_starts_index = 0, line_starts_slots = 0;
int bump_index;
NODE *node;
window->line_starts = (char **)NULL;
window->line_count = 0;
node = window->node;
if (!node)
return;
/* Grovel the node starting at the top, and for each line calculate the
width of the characters appearing in that line. Add each line start
to our array. */
i = 0;
hpos = 0;
bump_index = 0;
while (i < node->nodelen)
{
char *line = node->contents + i;
unsigned int cwidth, c;
add_pointer_to_array (line, line_starts_index, line_starts,
line_starts_slots, 100, char *);
if (bump_index)
{
i++;
bump_index = 0;
}
while (1)
{
c = node->contents[i];
cwidth = character_width (c, hpos);
/* If this character fits within this line, just do the next one. */
if ((hpos + cwidth) < window->width)
{
i++;
hpos += cwidth;
continue;
}
else
{
/* If this character would position the cursor at the start of
the next printed screen line, then do the next line. */
if (c == '\n' || c == '\r' || c == '\t')
{
i++;
hpos = 0;
break;
}
else
{
/* This character passes the window width border. Postion
the cursor after the printed character, but remember this
line start as where this character is. A bit tricky. */
/* If this window doesn't wrap lines, proceed to the next
physical line here. */
if (window->flags & W_NoWrap)
{
hpos = 0;
while (i < node->nodelen && node->contents[i] != '\n')
i++;
if (node->contents[i] == '\n')
i++;
}
else
{
hpos = the_screen->width - hpos;
bump_index++;
}
break;
}
}
}
}
window->line_starts = line_starts;
window->line_count = line_starts_index;
}
/* Given WINDOW, recalculate the line starts for the node it displays. */
void
recalculate_line_starts (window)
WINDOW *window;
{
maybe_free (window->line_starts);
calculate_line_starts (window);
}
/* Global variable control redisplay of scrolled windows. If non-zero, it
is the desired number of lines to scroll the window in order to make
point visible. A user might set this to 1 for smooth scrolling. If
set to zero, the line containing point is centered within the window. */
int window_scroll_step = 0;
/* Adjust the pagetop of WINDOW such that the cursor point will be visible. */
void
window_adjust_pagetop (window)
WINDOW *window;
{
register int line = 0;
char *contents;
if (!window->node)
return;
contents = window->node->contents;
/* Find the first printed line start which is after WINDOW->point. */
for (line = 0; line < window->line_count; line++)
{
char *line_start;
line_start = window->line_starts[line];
if ((line_start - contents) > window->point)
break;
}
/* The line index preceding the line start which is past point is the
one containing point. */
line--;
/* If this line appears in the current displayable page, do nothing.
Otherwise, adjust the top of the page to make this line visible. */
if ((line < window->pagetop) ||
(line - window->pagetop > (window->height - 1)))
{
/* The user-settable variable "scroll-step" is used to attempt
to make point visible, iff it is non-zero. If that variable
is zero, then the line containing point is centered within
the window. */
if (window_scroll_step < window->height)
{
if ((line < window->pagetop) &&
((window->pagetop - window_scroll_step) <= line))
window->pagetop -= window_scroll_step;
else if ((line - window->pagetop > (window->height - 1)) &&
((line - (window->pagetop + window_scroll_step)
< window->height)))
window->pagetop += window_scroll_step;
else
window->pagetop = line - ((window->height - 1) / 2);
}
else
window->pagetop = line - ((window->height - 1) / 2);
if (window->pagetop < 0)
window->pagetop = 0;
window->flags |= W_UpdateWindow;
}
}
/* Return the index of the line containing point. */
int
window_line_of_point (window)
WINDOW *window;
{
register int i, start = 0;
/* Try to optimize. Check to see if point is past the pagetop for
this window, and if so, start searching forward from there. */
if ((window->pagetop > -1 && window->pagetop < window->line_count) &&
(window->line_starts[window->pagetop] - window->node->contents)
<= window->point)
start = window->pagetop;
for (i = start; i < window->line_count; i++)
{
if ((window->line_starts[i] - window->node->contents) > window->point)
break;
}
return (i - 1);
}
/* Get and return the goal column for this window. */
int
window_get_goal_column (window)
WINDOW *window;
{
if (!window->node)
return (-1);
if (window->goal_column != -1)
return (window->goal_column);
/* Okay, do the work. Find the printed offset of the cursor
in this window. */
return (window_get_cursor_column (window));
}
/* Get and return the printed column offset of the cursor in this window. */
int
window_get_cursor_column (window)
WINDOW *window;
{
int i, hpos, end;
char *line;
i = window_line_of_point (window);
if (i < 0)
return (-1);
line = window->line_starts[i];
end = window->point - (line - window->node->contents);
for (hpos = 0, i = 0; i < end; i++)
hpos += character_width (line[i], hpos);
return (hpos);
}
/* Count the number of characters in LINE that precede the printed column
offset of GOAL. */
int
window_chars_to_goal (line, goal)
char *line;
int goal;
{
register int i, check, hpos;
for (hpos = 0, i = 0; line[i] != '\n'; i++)
{
check = hpos + character_width (line[i], hpos);
if (check > goal)
break;
hpos = check;
}
return (i);
}
/* Create a modeline for WINDOW, and store it in window->modeline. */
void
window_make_modeline (window)
WINDOW *window;
{
register int i;
char *modeline;
char location_indicator[4];
int lines_remaining;
/* Only make modelines for those windows which have one. */
if (window->flags & W_InhibitMode)
return;
/* Find the number of lines actually displayed in this window. */
lines_remaining = window->line_count - window->pagetop;
if (window->pagetop == 0)
{
if (lines_remaining <= window->height)
strcpy (location_indicator, "All");
else
strcpy (location_indicator, "Top");
}
else
{
if (lines_remaining <= window->height)
strcpy (location_indicator, "Bot");
else
{
float pt, lc;
int percentage;
pt = (float)window->pagetop;
lc = (float)window->line_count;
percentage = 100 * (pt / lc);
sprintf (location_indicator, "%2d%%", percentage);
}
}
/* Calculate the maximum size of the information to stick in MODELINE. */
{
int modeline_len = 0;
char *parent = (char *)NULL, *filename = "*no file*";
char *nodename = "*no node*";
char *update_message = (char *)NULL;
NODE *node = window->node;
if (node)
{
if (node->nodename)
nodename = node->nodename;
if (node->parent)
{
parent = filename_non_directory (node->parent);
modeline_len += strlen ("Subfile: ") + strlen (node->filename);
}
if (node->filename)
filename = filename_non_directory (node->filename);
if (node->flags & N_UpdateTags)
update_message = "--*** Tags out of Date ***";
}
if (update_message)
modeline_len += strlen (update_message);
modeline_len += strlen (filename);
modeline_len += strlen (nodename);
modeline_len += 4; /* strlen (location_indicator). */
/* 10 for the decimal representation of the number of lines in this
node, and the remainder of the text that can appear in the line. */
modeline_len += 10 + strlen ("-----Info: (), lines ----, ");
modeline_len += window->width;
modeline = (char *)xmalloc (1 + modeline_len);
/* Special internal windows have no filename. */
if (!parent && !*filename)
sprintf (modeline, "-%s---Info: %s, %d lines --%s--",
(window->flags & W_NoWrap) ? "$" : "-",
nodename, window->line_count, location_indicator);
else
sprintf (modeline, "-%s%s-Info: (%s)%s, %d lines --%s--",
(window->flags & W_NoWrap) ? "$" : "-",
(node && (node->flags & N_IsCompressed)) ? "zz" : "--",
parent ? parent : filename,
nodename, window->line_count, location_indicator);
if (parent)
sprintf (modeline + strlen (modeline), " Subfile: %s", filename);
if (update_message)
sprintf (modeline + strlen (modeline), "%s", update_message);
i = strlen (modeline);
if (i >= window->width)
modeline[window->width] = '\0';
else
{
while (i < window->width)
modeline[i++] = '-';
modeline[i] = '\0';
}
strcpy (window->modeline, modeline);
free (modeline);
}
}
/* Make WINDOW start displaying at PERCENT percentage of its node. */
void
window_goto_percentage (window, percent)
WINDOW *window;
int percent;
{
int desired_line;
if (!percent)
desired_line = 0;
else
desired_line =
(int) ((float)window->line_count * ((float)percent / 100.0));
window->pagetop = desired_line;
window->point =
window->line_starts[window->pagetop] - window->node->contents;
window->flags |= W_UpdateWindow;
window_make_modeline (window);
}
/* Get the state of WINDOW, and save it in STATE. */
void
window_get_state (window, state)
WINDOW *window;
WINDOW_STATE *state;
{
state->node = window->node;
state->pagetop = window->pagetop;
state->point = window->point;
}
/* Set the node, pagetop, and point of WINDOW. */
void
window_set_state (window, state)
WINDOW *window;
WINDOW_STATE *state;
{
if (window->node != state->node)
window_set_node_of_window (window, state->node);
window->pagetop = state->pagetop;
window->point = state->point;
}
/* **************************************************************** */
/* */
/* Manipulating Home-Made Nodes */
/* */
/* **************************************************************** */
/* A place to buffer echo area messages. */
static NODE *echo_area_node = (NODE *)NULL;
/* Make the node of the_echo_area be an empty one. */
static void
free_echo_area ()
{
if (echo_area_node)
{
maybe_free (echo_area_node->contents);
free (echo_area_node);
}
echo_area_node = (NODE *)NULL;
window_set_node_of_window (the_echo_area, echo_area_node);
}
/* Clear the echo area, removing any message that is already present.
The echo area is cleared immediately. */
void
window_clear_echo_area ()
{
free_echo_area ();
display_update_one_window (the_echo_area);
}
/* Make a message appear in the echo area, built from FORMAT, ARG1 and ARG2.
The arguments are treated similar to printf () arguments, but not all of
printf () hair is present. The message appears immediately. If there was
already a message appearing in the echo area, it is removed. */
void
window_message_in_echo_area (format, arg1, arg2)
char *format;
void *arg1, *arg2;
{
free_echo_area ();
echo_area_node = build_message_node (format, arg1, arg2);
window_set_node_of_window (the_echo_area, echo_area_node);
display_update_one_window (the_echo_area);
}
/* Place a temporary message in the echo area built from FORMAT, ARG1
and ARG2. The message appears immediately, but does not destroy
any existing message. A future call to unmessage_in_echo_area ()
restores the old contents. */
static NODE **old_echo_area_nodes = (NODE **)NULL;
static int old_echo_area_nodes_index = 0;
static int old_echo_area_nodes_slots = 0;
void
message_in_echo_area (format, arg1, arg2)
char *format;
void *arg1, *arg2;
{
if (echo_area_node)
{
add_pointer_to_array (echo_area_node, old_echo_area_nodes_index,
old_echo_area_nodes, old_echo_area_nodes_slots,
4, NODE *);
}
echo_area_node = (NODE *)NULL;
window_message_in_echo_area (format, arg1, arg2);
}
void
unmessage_in_echo_area ()
{
free_echo_area ();
if (old_echo_area_nodes_index)
echo_area_node = old_echo_area_nodes[--old_echo_area_nodes_index];
window_set_node_of_window (the_echo_area, echo_area_node);
display_update_one_window (the_echo_area);
}
/* A place to build a message. */
static char *message_buffer = (char *)NULL;
static int message_buffer_index = 0;
static int message_buffer_size = 0;
/* Ensure that there is enough space to stuff LENGTH characters into
MESSAGE_BUFFER. */
static void
message_buffer_resize (length)
int length;
{
if (!message_buffer)
{
message_buffer_size = length + 1;
message_buffer = (char *)xmalloc (message_buffer_size);
message_buffer_index = 0;
}
while (message_buffer_size <= message_buffer_index + length)
message_buffer = (char *)
xrealloc (message_buffer,
message_buffer_size += 100 + (2 * length));
}
/* Format MESSAGE_BUFFER with the results of printing FORMAT with ARG1 and
ARG2. */
static void
build_message_buffer (format, arg1, arg2)
char *format;
void *arg1, *arg2;
{
register int i, len;
void *args[2];
int arg_index = 0;
args[0] = arg1;
args[1] = arg2;
len = strlen (format);
message_buffer_resize (len);
for (i = 0; format[i]; i++)
{
if (format[i] != '%')
{
message_buffer[message_buffer_index++] = format[i];
len--;
}
else
{
char c;
c = format[++i];
switch (c)
{
case '%': /* Insert a percent sign. */
message_buffer_resize (len + 1);
message_buffer[message_buffer_index++] = '%';
break;
case 's': /* Insert the current arg as a string. */
{
char *string;
int string_len;
string = (char *)args[arg_index++];
string_len = strlen (string);
message_buffer_resize (len + string_len);
sprintf
(message_buffer + message_buffer_index, "%s", string);
message_buffer_index += string_len;
}
break;
case 'd': /* Insert the current arg as an integer. */
{
long long_val;
int integer;
long_val = (long)args[arg_index++];
integer = (int)long_val;
message_buffer_resize (len + 32);
sprintf
(message_buffer + message_buffer_index, "%d", integer);
message_buffer_index = strlen (message_buffer);
}
break;
case 'c': /* Insert the current arg as a character. */
{
long long_val;
int character;
long_val = (long)args[arg_index++];
character = (int)long_val;
message_buffer_resize (len + 1);
message_buffer[message_buffer_index++] = character;
}
break;
default:
abort ();
}
}
}
message_buffer[message_buffer_index] = '\0';
}
/* Build a new node which has FORMAT printed with ARG1 and ARG2 as the
contents. */
NODE *
build_message_node (format, arg1, arg2)
char *format;
void *arg1, *arg2;
{
NODE *node;
message_buffer_index = 0;
build_message_buffer (format, arg1, arg2);
node = message_buffer_to_node ();
return (node);
}
/* Convert the contents of the message buffer to a node. */
NODE *
message_buffer_to_node ()
{
NODE *node;
node = (NODE *)xmalloc (sizeof (NODE));
node->filename = (char *)NULL;
node->parent = (char *)NULL;
node->nodename = (char *)NULL;
node->flags = 0;
/* Make sure that this buffer ends with a newline. */
node->nodelen = 1 + strlen (message_buffer);
node->contents = (char *)xmalloc (1 + node->nodelen);
strcpy (node->contents, message_buffer);
node->contents[node->nodelen - 1] = '\n';
node->contents[node->nodelen] = '\0';
return (node);
}
/* Useful functions can be called from outside of window.c. */
void
initialize_message_buffer ()
{
message_buffer_index = 0;
}
/* Print FORMAT with ARG1,2 to the end of the current message buffer. */
void
printf_to_message_buffer (format, arg1, arg2)
char *format;
void *arg1, *arg2;
{
build_message_buffer (format, arg1, arg2);
}
/* Return the current horizontal position of the "cursor" on the most
recently output message buffer line. */
int
message_buffer_length_this_line ()
{
register int i;
if (!message_buffer_index)
return (0);
for (i = message_buffer_index; i && message_buffer[i - 1] != '\n'; i--);
return (string_width (message_buffer + i, 0));
}
/* Pad STRING to COUNT characters by inserting blanks. */
int
pad_to (count, string)
int count;
char *string;
{
register int i;
i = strlen (string);
if (i >= count)
string[i++] = ' ';
else
{
while (i < count)
string[i++] = ' ';
}
string[i] = '\0';
return (i);
}
texinfo-3.7/info/window.h 100666 11732 13 23410 5770343503 13673 0 ustar bfox user /* window.h -- Structure and flags used in manipulating Info windows. */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
Copyright (C) 1993 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). */
#if !defined (_WINDOW_H_)
#define _WINDOW_H_
#include "nodes.h"
#include "infomap.h"
/* Smallest number of visible lines in a window. The actual height is
always one more than this number because each window has a modeline. */
#define WINDOW_MIN_HEIGHT 2
/* Smallest number of screen lines that can be used to fully present a
window. This number includes the modeline of the window. */
#define WINDOW_MIN_SIZE (WINDOW_MIN_HEIGHT + 1)
/* The exact same elements are used within the WINDOW_STATE structure and a
subsection of the WINDOW structure. We could define a structure which
contains this elements, and include that structure in each of WINDOW_STATE
and WINDOW. But that would lead references in the code such as
window->state->node which we would like to avoid. Instead, we #define the
elements here, and simply include the define in both data structures. Thus,
if you need to change window state information, here is where you would
do it. NB> The last element does NOT end with a semi-colon. */
#define WINDOW_STATE_DECL \
NODE *node; /* The node displayed in this window. */ \
int pagetop; /* LINE_STARTS[PAGETOP] is first line in WINDOW. */ \
long point /* Offset within NODE of the cursor position. */
/* Structure which defines a window. Windows are doubly linked, next
and prev. The list of windows is kept on WINDOWS. The structure member
window->height is the total height of the window. The position location
(0, window->height + window->first_row) is the first character of this
windows modeline. The number of lines that can be displayed in a window
is equal to window->height - 1. */
typedef struct __window__ {
struct __window__ *next; /* Next window in this chain. */
struct __window__ *prev; /* Previous window in this chain. */
int width; /* Width of this window. */
int height; /* Height of this window. */
int first_row; /* Offset of the first line in the_screen. */
int goal_column; /* The column we would like the cursor to appear in. */
Keymap keymap; /* Keymap used to read commands in this window. */
WINDOW_STATE_DECL; /* Node, pagetop and point. */
char *modeline; /* Calculated text of the modeline for this window. */
char **line_starts; /* Array of printed line starts for this node. */
int line_count; /* Number of lines appearing in LINE_STARTS. */
int flags; /* See below for details. */
} WINDOW;
typedef struct {
WINDOW_STATE_DECL; /* What gets saved. */
} WINDOW_STATE;
#define W_UpdateWindow 0x01 /* WINDOW needs updating. */
#define W_WindowIsPerm 0x02 /* This WINDOW is a permanent object. */
#define W_WindowVisible 0x04 /* This WINDOW is currently visible. */
#define W_InhibitMode 0x08 /* This WINDOW has no modeline. */
#define W_NoWrap 0x10 /* Lines do not wrap in this window. */
#define W_InputWindow 0x20 /* Window accepts input. */
#define W_TempWindow 0x40 /* Window is less important. */
extern WINDOW *windows; /* List of visible Info windows. */
extern WINDOW *active_window; /* The currently active window. */
extern WINDOW *the_screen; /* The Info screen is just another window. */
extern WINDOW *the_echo_area; /* THE_ECHO_AREA is a window in THE_SCREEN. */
/* Global variable control redisplay of scrolled windows. If non-zero, it
is the desired number of lines to scroll the window in order to make
point visible. A user might set this to 1 for smooth scrolling. If
set to zero, the line containing point is centered within the window. */
extern int window_scroll_step;
/* Make the modeline member for WINDOW. */
extern void window_make_modeline ();
/* Initalize the window system by creating THE_SCREEN and THE_ECHO_AREA.
Create the first window ever, and make it permanent.
You pass WIDTH and HEIGHT; the dimensions of the total screen size. */
extern void window_initialize_windows ();
/* Make a new window showing NODE, and return that window structure.
The new window is made to be the active window. If NODE is passed
as NULL, then show the node showing in the active window. If the
window could not be made return a NULL pointer. The active window
is not changed.*/
extern WINDOW *window_make_window ();
/* Delete WINDOW from the list of known windows. If this window was the
active window, make the next window in the chain be the active window,
or the previous window in the chain if there is no next window. */
extern void window_delete_window ();
/* A function to call when the screen changes size, and some windows have
to get deleted. The function is called with the window to be deleted
as an argument, and it can't do anything about the window getting deleted;
it can only clean up dangling references to that window. */
extern VFunction *window_deletion_notifier;
/* Set WINDOW to display NODE. */
extern void window_set_node_of_window ();
/* Tell the window system that the size of the screen has changed. This
causes lots of interesting things to happen. The permanent windows
are resized, as well as every visible window. You pass WIDTH and HEIGHT;
the dimensions of the total screen size. */
extern void window_new_screen_size ();
/* Change the height of WINDOW by AMOUNT. This also automagically adjusts
the previous and next windows in the chain. If there is only one user
window, then no change takes place. */
extern void window_change_window_height ();
/* Adjust the pagetop of WINDOW such that the cursor point will be visible. */
extern void window_adjust_pagetop ();
/* Tile all of the windows currently displayed in the global variable
WINDOWS. If argument DO_INTERNALS is non-zero, tile windows displaying
internal nodes as well. */
#define DONT_TILE_INTERNALS 0
#define TILE_INTERNALS 1
extern void window_tile_windows ();
/* Toggle the state of line wrapping in WINDOW. This can do a bit of fancy
redisplay. */
extern void window_toggle_wrap ();
/* For every window in CHAIN, set the flags member to have FLAG set. */
extern void window_mark_chain ();
/* For every window in CHAIN, clear the flags member of FLAG. */
extern void window_unmark_chain ();
/* Make WINDOW start displaying at PERCENT percentage of its node. */
extern void window_goto_percentage ();
/* Build a new node which has FORMAT printed with ARG1 and ARG2 as the
contents. */
extern NODE *build_message_node ();
/* Useful functions can be called from outside of window.c. */
extern void initialize_message_buffer ();
/* Print FORMAT with ARG1,2 to the end of the current message buffer. */
extern void printf_to_message_buffer ();
/* Convert the contents of the message buffer to a node. */
extern NODE *message_buffer_to_node ();
/* Return the length of the most recently printed line in message buffer. */
extern int message_buffer_length_this_line ();
/* Pad STRING to COUNT characters by inserting blanks. */
extern int pad_to ();
/* Make a message appear in the echo area, built from FORMAT, ARG1 and ARG2.
The arguments are treated similar to printf () arguments, but not all of
printf () hair is present. The message appears immediately. If there was
already a message appearing in the echo area, it is removed. */
extern void window_message_in_echo_area ();
/* Place a temporary message in the echo area built from FORMAT, ARG1
and ARG2. The message appears immediately, but does not destroy
any existing message. A future call to unmessage_in_echo_area ()
restores the old contents. */
extern void message_in_echo_area ();
extern void unmessage_in_echo_area ();
/* Clear the echo area, removing any message that is already present.
The echo area is cleared immediately. */
extern void window_clear_echo_area ();
/* Quickly guess the approximate number of lines to that NODE would
take to display. This really only counts carriage returns. */
extern int window_physical_lines ();
/* Calculate a list of line starts for the node belonging to WINDOW. The line
starts are pointers to the actual text within WINDOW->NODE. */
extern void calculate_line_starts ();
/* Given WINDOW, recalculate the line starts for the node it displays. */
extern void recalculate_line_starts ();
/* Return the number of characters it takes to display CHARACTER on the
screen at HPOS. */
extern int character_width ();
/* Return the number of characters it takes to display STRING on the
screen at HPOS. */
extern int string_width ();
/* Return the index of the line containing point. */
extern int window_line_of_point ();
/* Get and return the goal column for this window. */
extern int window_get_goal_column ();
/* Get and return the printed column offset of the cursor in this window. */
extern int window_get_cursor_column ();
/* Get and Set the node, pagetop, and point of WINDOW. */
extern void window_get_state (), window_set_state ();
/* Count the number of characters in LINE that precede the printed column
offset of GOAL. */
extern int window_chars_to_goal ();
#endif /* !_WINDOW_H_ */
texinfo-3.7/info/xmalloc.c 100666 11732 13 4307 5771354307 14007 0 ustar bfox user /* xmalloc.c -- safe versions of malloc and realloc */
/* This file is part of GNU Info, a program for reading online documentation
stored in Info format.
This file has appeared in prior works by the Free Software Foundation;
thus it carries copyright dates from 1988 through 1993.
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 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). */
#if !defined (ALREADY_HAVE_XMALLOC)
#include
#include
extern void *malloc (), *realloc ();
static void memory_error_and_abort ();
/* **************************************************************** */
/* */
/* Memory Allocation and Deallocation. */
/* */
/* **************************************************************** */
/* Return a pointer to free()able block of memory large enough
to hold BYTES number of bytes. If the memory cannot be allocated,
print an error message and abort. */
void *
xmalloc (bytes)
int bytes;
{
void *temp = malloc (bytes);
if (!temp)
memory_error_and_abort ("xmalloc");
return (temp);
}
void *
xrealloc (pointer, bytes)
void *pointer;
int bytes;
{
void *temp;
if (!pointer)
temp = malloc (bytes);
else
temp = realloc (pointer, bytes);
if (!temp)
memory_error_and_abort ("xrealloc");
return (temp);
}
static void
memory_error_and_abort (fname)
char *fname;
{
fprintf (stderr, "%s: Out of virtual memory!\n", fname);
abort ();
}
#endif /* !ALREADY_HAVE_XMALLOC */
texinfo-3.7/util/ 40777 11732 13 0 6067136361 12122 5 ustar bfox user texinfo-3.7/util/Makefile.in 100666 11732 13 4365 5771744434 14303 0 ustar bfox user # Makefile for GNU Texindex.
# Copyright (C) 1990, 1991, 1992 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.
#### Start of system configuration section. ####
srcdir = @srcdir@
VPATH = $(srcdir):$(common)
common = $(srcdir)/../libtxi
CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
LN = ln
RM = rm -f
TAR = tar
MKDIR = mkdir
DEFS = @DEFS@
LIBS = -L../libtxi -ltxi @LIBS@
LOADLIBES = $(LIBS)
SHELL = /bin/sh
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = $(exec_prefix)/bin
# Prefix for each installed program, normally empty or `g'.
binprefix =
libdir = $(prefix)/lib
# Prefix for each installed man page, normally empty or `g'.
manprefix =
mandir = $(prefix)/man/man1
manext = 1
infodir = $(prefix)/info
#### End of system configuration section. ####
all: texindex
sub-all: all
.c.o:
$(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) -I$(common) $(CFLAGS) $<
install: all
$(INSTALL_PROGRAM) texindex $(bindir)/texindex
$(INSTALL_PROGRAM) $(srcdir)/texi2dvi $(bindir)/texi2dvi
uninstall:
rm -f $(bindir)/texindex $(bindir)/texi2dvi
Makefile: Makefile.in ../config.status
cd ..; sh config.status
TAGS:
etags *.c *.h $(common)/getopt*.c $(common)/getopt.h
clean:
rm -f *.o a.out core core.* texindex
mostlyclean: clean
distclean: clean
rm -f Makefile config.status
realclean: distclean
rm -f TAGS
texindex: texindex.o ../libtxi/libtxi.a
$(CC) $(LDFLAGS) -o texindex texindex.o $(LOADLIBES)
texindex.o: texindex.c $(common)/getopt.h
# Prevent GNU make v3 from overflowing arg limit on SysV.
.NOEXPORT:
texinfo-3.7/util/deref.c 100666 21641 13 10757 5302574253 14326 0 ustar friedman user /*
* deref.c
* compile command: gcc -g -o deref deref.c
* execute command: deref filename.texi > newfile.texi
* To: bob@gnu.ai.mit.edu
* Subject: another tool
* Date: 18 Dec 91 16:03:13 EST (Wed)
* From: gatech!skeeve!arnold@eddie.mit.edu (Arnold D. Robbins)
*
* Here is deref.c. It turns texinfo cross references back into the
* one argument form. It has the same limitations as fixref; one xref per
* line and can't cross lines. You can use it to find references that do
* cross a line boundary this way:
*
* deref < manual > /dev/null 2>errs
*
* (This assumes bash or /bin/sh.) The file errs will have list of lines
* where deref could not find matching braces.
*
* A gawk manual processed by deref goes through makeinfo without complaint.
* Compile with gcc and you should be set.
*
* Enjoy,
*
* Arnold
* -----------
*/
/*
* deref.c
*
* Make all texinfo references into the one argument form.
*
* Arnold Robbins
* arnold@skeeve.atl.ga.us
* December, 1991
*
* Copyright, 1991, Arnold Robbins
*/
/*
* LIMITATIONS:
* One texinfo cross reference per line.
* Cross references may not cross newlines.
* Use of fgets for input (to be fixed).
*/
#include
#include
#include
/* for gcc on the 3B1, delete if this gives you grief */
extern int fclose (FILE * fp);
extern int fprintf (FILE * fp, const char *str,...);
extern char *strerror (int errno);
extern char *strchr (char *cp, int ch);
extern int strncmp (const char *s1, const char *s2, int count);
extern int errno;
void process (FILE * fp);
void repair (char *line, char *ref, int toffset);
int Errs = 0;
char *Name = "stdin";
int Line = 0;
char *Me;
/* main --- handle arguments, global vars for errors */
int
main (int argc, char **argv)
{
FILE *fp;
Me = argv[0];
if (argc == 1)
process (stdin);
else
for (argc--, argv++; *argv != NULL; argc--, argv++)
{
if (argv[0][0] == '-' && argv[0][1] == '\0')
{
Name = "stdin";
Line = 0;
process (stdin);
}
else if ((fp = fopen (*argv, "r")) != NULL)
{
Name = *argv;
Line = 0;
process (fp);
fclose (fp);
}
else
{
fprintf (stderr, "%s: can not open: %s\n",
*argv, strerror (errno));
Errs++;
}
}
return Errs != 0;
}
/* isref --- decide if we've seen a texinfo cross reference */
int
isref (char *cp)
{
if (strncmp (cp, "@ref{", 5) == 0)
return 5;
if (strncmp (cp, "@xref{", 6) == 0)
return 6;
if (strncmp (cp, "@pxref{", 7) == 0)
return 7;
return 0;
}
/* process --- read files, look for references, fix them up */
void
process (FILE * fp)
{
char buf[BUFSIZ];
char *cp;
int count;
while (fgets (buf, sizeof buf, fp) != NULL)
{
Line++;
cp = strchr (buf, '@');
if (cp == NULL)
{
fputs (buf, stdout);
continue;
}
do
{
count = isref (cp);
if (count == 0)
{
cp++;
cp = strchr (cp, '@');
if (cp == NULL)
{
fputs (buf, stdout);
goto next;
}
continue;
}
/* got one */
repair (buf, cp, count);
break;
}
while (cp != NULL);
next:;
}
}
/* repair --- turn all texinfo cross references into the one argument form */
void
repair (char *line, char *ref, int toffset)
{
int braces = 1; /* have seen first left brace */
char *cp;
ref += toffset;
/* output line up to and including left brace in reference */
for (cp = line; cp <= ref; cp++)
putchar (*cp);
/* output node name */
for (; *cp && *cp != '}' && *cp != ',' && *cp != '\n'; cp++)
putchar (*cp);
if (*cp != '}')
{ /* could have been one arg xref */
/* skip to matching right brace */
for (; braces > 0; cp++)
{
switch (*cp)
{
case '@':
cp++; /* blindly skip next character */
break;
case '{':
braces++;
break;
case '}':
braces--;
break;
case '\n':
case '\0':
Errs++;
fprintf (stderr,
"%s: %s: %d: mismatched braces\n",
Me, Name, Line);
goto out;
default:
break;
}
}
out:
;
}
putchar ('}');
if (*cp == '}')
cp++;
/* now the rest of the line */
for (; *cp; cp++)
putchar (*cp);
return;
}
/* strerror --- return error string, delete if in your library */
char *
strerror (int errno)
{
static char buf[100];
extern int sys_nerr;
extern char *sys_errlist[];
if (errno < sys_nerr && errno >= 0)
return sys_errlist[errno];
sprintf (buf, "unknown error %d", errno);
return buf;
}
texinfo-3.7/util/fixfonts 100777 21641 13 4670 5363505733 14644 0 ustar friedman user #!/bin/sh
# Make links named `lcircle10' for all TFM and GF/PK files, if no
# lcircle10 files already exist.
# Don't override definition of prefix and/or libdir if they are
# already defined in the environment.
if test "z${prefix}" = "z" ; then
prefix=/usr/local
else
# prefix may contain references to other variables, thanks to make.
eval prefix=\""${prefix}"\"
fi
if test "z${libdir}" = "z" ; then
libdir="${prefix}/lib/tex"
else
# libdir may contain references to other variables, thanks to make.
eval libdir=\""${libdir}"\"
fi
texlibdir="${libdir}"
texfontdir="${texlibdir}/fonts"
# Directories for the different font formats, in case they're not all
# stored in one place.
textfmdir="${textfmdir-${texfontdir}}"
texpkdir="${texpkdir-${texfontdir}}"
texgfdir="${texgfdir-${texfontdir}}"
test "z${TMPDIR}" = "z" && TMPDIR="/tmp"
tempfile="${TMPDIR}/circ$$"
tempfile2="${TMPDIR}/circ2$$"
# EXIT SIGHUP SIGINT SIGQUIT SIGTERM
#trap 'rm -f "${tempfile}" "${tempfile2}"' 0 1 2 3 15
# Find all the fonts with names that include `circle'.
(cd "${texfontdir}"; find . -name '*circle*' -print > "${tempfile}")
# If they have lcircle10.tfm, assume everything is there, and quit.
if grep 'lcircle10\.tfm' "${tempfile}" > /dev/null 2>&1 ; then
echo "Found lcircle10.tfm."
exit 0
fi
# No TFM file for lcircle. Make a link to circle10.tfm if it exists,
# and then make a link to the bitmap files.
grep 'circle10\.tfm' "${tempfile}" > "${tempfile2}" \
|| {
echo "I can't find any circle fonts in ${texfontdir}.
If it isn't installed somewhere else, you need to get the Metafont sources
from somewhere, e.g., labrea.stanford.edu:pub/tex/latex/circle10.mf, and
run Metafont on them."
exit 1
}
# We have circle10.tfm. (If we have it more than once, take the first
# one.) Make the link.
tempfile2_line1="`sed -ne '1p;q' \"${tempfile2}\"`"
ln "${tempfile2_line1}" "${textfmdir}/lcircle10.tfm"
echo "Linked to ${tempfile2_line1}."
# Now make a link for the PK files, if any.
(cd "${texpkdir}"
for f in `grep 'circle10.*pk' "${tempfile}"` ; do
set - `echo "$f" \
| sed -ne '/\//!s/^/.\//;s/\(.*\)\/\([^\/][^\/]*\)$/\1 \2/;p'`
ln "$f" "${1}/l${2}"
echo "Linked to $f."
done
)
# And finally for the GF files.
(cd "${texgfdir}"
for f in `grep 'circle10.*gf' "${tempfile}"` ; do
set - `echo "$f" \
| sed -ne '/\//!s/^/.\//;s/\(.*\)\/\([^\/][^\/]*\)$/\1 \2/;p'`
ln "$f" "${1}/l${2}"
echo "Linked to $f."
done
)
# eof
texinfo-3.7/util/gen-dir-node 100777 11732 13 12373 5767171657 14460 0 ustar bfox user #!/bin/sh
# Generate the top-level Info node, given a directory of Info files
# and (optionally) a skeleton file. The output will be suitable for a
# dir.info file. The skeleton file contains info topic names in the
# order they should appear in the output. There are three special
# lines that alter the behavior: a line consisting of just "--" causes
# the next line to be echoed verbatim to the output. A line
# containing just "%%" causes all the remaining filenames (wildcards
# allowed) in the rest of the file to be ignored. A line containing
# just "!!" exits the script when reached (unless preceded by a line
# containing just "--"). Once the script reaches the end of the
# skeleton file, it goes through the remaining files in the directory
# in order, putting their entries at the end. The script will use the
# ENTRY information in each info file if it exists. Otherwise it will
# make a minimal entry.
# sent by Jeffrey Osier , who thinks it came from
# zoo@winternet.com (david d `zoo' zuhn)
# modified 7 April 1995 by Joe Harrington to
# take special flags
INFODIR=$1
if [ $# = 2 ] ; then
SKELETON=$2
else
SKELETON=/dev/null
fi
skip=
if [ $# -gt 2 ] ; then
echo usage: $0 info-directory [ skeleton-file ] 1>&2
exit 1
else
true
fi
if [ ! -d ${INFODIR} ] ; then
echo "$0: first argument must specify a directory"
exit 1
fi
### output the dir.info header
echo "-*- Text -*-"
echo "This file was generated automatically by the gen-dir-node script."
echo "This version was generated on `date`"
echo "by `whoami`@`hostname` for `(cd ${INFODIR}; pwd)`"
cat << moobler
This is the file .../info/dir, which contains the topmost node of the
Info hierarchy. The first time you invoke Info you start off
looking at that node, which is (dir)Top.
File: dir Node: Top This is the top of the INFO tree
This (the Directory node) gives a menu of major topics.
Typing "d" returns here, "q" exits, "?" lists all INFO commands, "h"
gives a primer for first-timers, "mTexinfo" visits Texinfo topic,
etc.
Or click mouse button 2 on a menu item or cross reference to select it.
--- PLEASE ADD DOCUMENTATION TO THIS TREE. (See INFO topic first.) ---
* Menu: The list of major topics begins on the next line.
moobler
### go through the list of files in the skeleton. If an info file
### exists, grab the ENTRY information from it. If an entry exists
### use it, otherwise create a minimal dir entry.
###
### Then remove that file from the list of existing files. If any
### additional files remain (ones that don't have a skeleton entry),
### then generate entries for those in the same way, putting the info for
### those at the end....
infofiles=`(cd ${INFODIR}; ls | egrep -v '\-|^dir$|^dir\.info$|^dir\.orig$')`
# echoing gets clobbered by backquotes; we do it the hard way...
lines=`wc $SKELETON | awk '{print $1}'`
line=1
while [ $lines -ge $line ] ; do
# Read one line from the file. This is so that we can echo lines with
# whitespace and quoted characters in them.
fileline=`awk NR==$line $SKELETON`
# flag fancy features
if [ ! -z "$echoline" ] ; then # echo line
echo "$fileline"
fileline=
echoline=
elif [ "${fileline}" = "--" ] ; then # should we echo the next line?
echoline=1
elif [ "${fileline}" = "%%" ] ; then # eliminate remaining files from dir?
skip=1
elif [ "${fileline}" = "!!" ] ; then # quit now
exit 0
fi
# handle files if they exist
for file in $fileline"" ; do # expand wildcards ("" handles blank lines)
fname=
if [ -z "$echoline" -a ! -z "$file" ] ; then
# Find the file to operate upon. Check both possible names.
infoname=`echo $file | sed 's/\.info$//'`
noext=
ext=
if [ -f ${INFODIR}/$infoname ] ; then
noext=$infoname
fi
if [ -f ${INFODIR}/${infoname}.info ] ; then
ext=${infoname}.info
fi
# If it exists with both names take what was said in the file.
if [ ! -z "$ext" -a ! -z "$noext" ]; then
fname=$file
warn="### Warning: $ext and $noext both exist! Using ${file}. ###"
elif [ ! \( -z "$ext" -a -z "$noext" \) ]; then
# just take the name if it exists only once
fname=${noext}${ext}
fi
# if we found something and aren't skipping, do the entry
if [ ! -z "$fname" ] ; then
if [ -z "$skip" ] ; then
if [ ! -z "$warn" ] ; then # issue any warning
echo $warn
warn=
fi
entry=`sed -e '1,/START-INFO-DIR-ENTRY/d' \
-e '/END-INFO-DIR-ENTRY/,$d' ${INFODIR}/$fname`
if [ ! -z "${entry}" ] ; then
echo "${entry}"
else
echo "* ${infoname}: (${fname})."
fi
fi
# remove the name from the directory listing
infofiles=`echo ${infofiles} | sed -e "s/ ${fname} / /" \
-e "s/^${fname} //" \
-e "s/ ${fname}$//"`
fi
fi
done
line=`expr $line + 1`
done
if [ -z "${infofiles}" ] ; then
exit 0
else
echo
fi
for file in ${infofiles}; do
infoname=`echo $file | sed 's/\.info$//'`
entry=`sed -e '1,/START-INFO-DIR-ENTRY/d' \
-e '/END-INFO-DIR-ENTRY/,$d' ${INFODIR}/${file}`
if [ ! -z "${entry}" ] ; then
echo "${entry}"
else
echo "* ${infoname}: (${file})."
fi
done
texinfo-3.7/util/mkinstalldirs 100555 11732 13 1136 6005342376 15015 0 ustar bfox user #! /bin/sh
# mkinstalldirs --- make directory hierarchy
# Author: Noah Friedman
# Created: 1993-05-16
# Public domain
errstatus=0
for file
do
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
shift
pathcomp=
for d in ${1+"$@"} ; do
pathcomp="$pathcomp$d"
case "$pathcomp" in
-* ) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp" 1>&2
mkdir "$pathcomp" || errstatus=$?
fi
pathcomp="$pathcomp/"
done
done
exit $errstatus
# mkinstalldirs ends here
texinfo-3.7/util/tex3patch 100777 21641 13 3465 5354651173 14710 0 ustar friedman user #!/bin/sh
# Auxiliary script to work around TeX 3.0 bug. ---- tex3patch ----
# patches texinfo.tex in current directory, or in directory given as arg.
ANYVERSION=no
for arg in $1 $2
do
case $arg in
--dammit | -d ) ANYVERSION=yes ;;
* ) dir=$arg
esac
done
if [ -z "$dir" ]; then
dir='.'
fi
if [ \( 2 -lt $# \) -o \
\( ! -f $dir/texinfo.tex \) ]; then
echo "To patch texinfo.tex for peaceful coexistence with Unix TeX 3.0,"
echo "run $0"
echo "with no arguments in the same directory as texinfo.tex; or run"
echo " $0 DIRECTORY"
echo "(where DIRECTORY is a path leading to texinfo.tex)."
exit
fi
if [ -z "$TMPDIR" ]; then
TMPDIR=/tmp
fi
echo "Checking for \`dummy.tfm'"
( cd $TMPDIR; tex '\relax \batchmode \font\foo=dummy \bye' )
grep -s '3.0' $TMPDIR/texput.log
if [ 1 = "$?" -a "$ANYVERSION" != "yes" ]; then
echo "You probably do not need this patch,"
echo "since your TeX does not seem to be version 3.0."
echo "If you insist on applying the patch, run $0"
echo "again with the option \`--dammit'"
exit
fi
grep -s 'file not found' $TMPDIR/texput.log
if [ 0 = $? ]; then
echo "This patch requires the dummy font metric file \`dummy.tfm',"
echo "which does not seem to be part of your TeX installation."
echo "Please get your TeX maintainer to install \`dummy.tfm',"
echo "then run this script again."
exit
fi
rm $TMPDIR/texput.log
echo "Patching $dir/texinfo.tex"
sed -e 's/%%*\\font\\nullfont/\\font\\nullfont/' \
$dir/texinfo.tex >$TMPDIR/texinfo.tex
mv $dir/texinfo.tex $dir/texinfo.tex-distrib; mv $TMPDIR/texinfo.tex $dir
if [ 0 = $? ]; then
echo "Patched $dir/texinfo.tex to avoid TeX 3.0 bug."
echo "The original version is saved as $dir/texinfo.tex-distrib."
else
echo "Patch failed. Sorry."
fi
----------------------------------------tex3patch ends
texinfo-3.7/util/texi2dvi 100555 21641 13 23610 5771430307 14544 0 ustar friedman user #! /bin/sh
# texi2dvi --- smartly produce DVI files from texinfo sources
# Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
# $Id: texi2dvi,v 0.5 1995/06/20 02:21:36 friedman Exp $
# 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, you can either send email to this
# program's maintainer or write to: The Free Software Foundation,
# Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.
# Commentary:
# Author: Noah Friedman
# Please send bug reports, etc. to bug-texinfo@prep.ai.mit.edu
# If possible, please send a copy of the output of the script called with
# the `--debug' option when making a bug report.
# In the interest of general portability, some common bourne shell
# constructs were avoided because they weren't guaranteed to be available
# in some earlier implementations. I've tried to make this program as
# portable as possible. Welcome to unix, where the lowest common
# denominator is rapidly diminishing.
#
# Among the more interesting lossages I noticed with some bourne shells
# are:
# * No shell functions.
# * No `unset' builtin.
# * `shift' cannot take a numeric argument, and signals an error if
# there are no arguments to shift.
# Code:
# Name by which this script was invoked.
progname=`echo "$0" | sed -e 's/[^\/]*\///g'`
# This string is expanded by rcs automatically when this file is checked out.
rcs_revision='$Revision: 0.5 $'
version=`set - $rcs_revision; echo $2`
# To prevent hairy quoting and escaping later.
bq='`'
eq="'"
usage="Usage: $progname {options} [file1] {file2 {...}}
(version $version)
Options are:
-D, --debug Turn on shell debugging ($bq${bq}set -x$eq$eq).
-h, --help You're looking at it.
-v, --version Print version number.
Arguments in brackets are required. Those in braces are optional.
"
# Initialize variables.
# Don't use `unset' since old bourne shells don't have this command.
# Instead, assign them an empty value.
# Some of these, like TEX and TEXINDEX, may be inherited from the environment
backup_extension=.bak
debug=
orig_pwd="`pwd`"
verbose=
texindex="${TEXINDEX-texindex}"
tex="${TEX-tex}"
# Save this so we can construct a new TEXINPUTS path for each file to be
# processed.
TEXINPUTS_orig="$TEXINPUTS"
export TEXINPUTS
# Parse command line arguments.
# Make sure that all wildcarded options are long enough to be unambiguous.
# It's a good idea to document the full long option name in each case.
# Long options which take arguments will need a `*' appended to the
# canonical name to match the value appended after the `=' character.
while : ; do
case $# in 0) break ;; esac
case "$1" in
-D | --debug | --d* )
debug=t
shift
;;
-h | --help | --h* )
echo "$usage" 1>&2
exit 0
;;
-v | --version | --v* )
echo "texi2dvi version $version" 1>&2
exit 0
;;
-- ) # Stop option processing
shift
break
;;
-* )
case "$1" in
--*=* ) arg=`echo "$1" | sed -e 's/=.*//'` ;;
* ) arg="$1" ;;
esac
exec 1>&2
echo "$progname: unknown or ambiguous option $bq$arg$eq"
echo "$progname: Use $bq--help$eq for a list of options."
exit 1
;;
* )
break
;;
esac
done
# See if there are any command line args left (which will be interpreted as
# filename arguments)
case $# in
0 )
exec 1>&2
echo "$progname: at least one file name is required as an argument."
echo "$progname: Use $bq--help$eq for a description of command syntax."
exit 2
;;
esac
case "$debug" in t ) set -x ;; esac
# Texify files
for command_line_filename in ${1+"$@"} ; do
# Roughly equivalent to `dirname ...`, but more portable
directory="`echo ${command_line_filename} | sed 's/\/[^\/]*$//'`"
filename_texi="`basename ${command_line_filename}`"
# Strip off the last extension part (probably .texinfo or .texi)
filename_noext="`echo ${filename_texi} | sed 's/\.[^.]*$//'`"
# If directory and file are the same, then it's probably because there's
# no pathname component. Set dirname to `.', the current directory.
if test "z${directory}" = "z${command_line_filename}" ; then
directory="."
fi
# Source file might @include additional texinfo sources. Put `.' and
# directory where source file(s) reside in TEXINPUTS before anything
# else. `.' goes first to ensure that any old .aux, .cps, etc. files in
# ${directory} don't get used in preference to fresher files in `.'.
TEXINPUTS=".:${directory}:${TEXINPUTS_orig}"
# "Unset" variables that might have values from previous iterations and
# which won't be completely reset later.
definite_index_files=""
# See if file exists here. If it doesn't we're in trouble since, even
# though the user may be able to reenter a valid filename at the tex
# prompt (assuming they're attending the terminal), this script won't be
# able to find the right index files and so forth.
if test ! -r "${command_line_filename}" ; then
echo "${progname}: ${command_line_filename}: No such file or permission denied." 1>&2
continue;
fi
# Find all files having root filename with a two-letter extension,
# determine whether they're really index files, and save them. Foo.aux
# is actually the cross-references file, but we need to keep track of
# that too.
possible_index_files="`eval echo ${filename_noext}.?? ${filename_noext}.aux`"
for this_file in ${possible_index_files} ; do
# If file is empty, forget it.
if test ! -s "${this_file}" ; then
continue;
fi
# Examine first character of file. If it's not a backslash or
# single quote, then it's definitely not an index or xref file.
first_character="`sed -n '1s/^\(.\).*$/\1/p;q' ${this_file}`"
if test "${first_character}" = "\\" -o "${first_character}" = "'" ; then
definite_index_files="${definite_index_files} ${this_file}"
fi
done
orig_index_files="${definite_index_files}"
orig_index_files_sans_aux="`echo ${definite_index_files} \
| sed 's/'${filename_noext}'\.aux//;
s/^[ ]*//;s/[ ]*$//;'`"
# Now save copies of original index files so we have some means of
# comparison later.
for index_file_to_save in ${orig_index_files} ; do
cp "${index_file_to_save}" "${index_file_to_save}${backup_extension}"
done
# Run texindex on current index files. If they already exist, and
# after running TeX a first time the index files don't change, then
# there's no reason to run TeX again. But we won't know that if the
# index files are out of date or nonexistent.
if test "${orig_index_files_sans_aux}" ; then
${texindex} ${orig_index_files_sans_aux}
fi
if ${tex} ${command_line_filename} ; then # TeX run first time
definite_index_files=""
# Get list of new index files
possible_index_files="`eval echo ${filename_noext}.?? ${filename_noext}.aux`"
for this_file in ${possible_index_files} ; do
# If file is empty, forget it.
if test ! -s ${this_file} ; then
continue;
fi
# Examine first character of file. If it's not a backslash or
# single quote, then it's definitely not an index or xref file.
first_character="`sed -n '1s/^\(.\).*$/\1/p;q' ${this_file}`"
if test "${first_character}" = "\\" -o "${first_character}" = "'" ; then
definite_index_files="${definite_index_files} ${this_file}"
fi
done
new_index_files="${definite_index_files}"
new_index_files_sans_aux="`echo ${definite_index_files} \
| sed 's/'${filename_noext}'\.aux//;
s/^[ ]*//;s/[ ]*$//;'`"
# If old and new list don't at least have the same file list, then one
# file or another has definitely changed.
if test "${orig_index_files}" != "${new_index_files}" ; then
index_files_changed_p=t
else
# File list is the same. We must compare each file until we find a
# difference.
index_files_changed_p=""
for this_file in ${new_index_files} ; do
# cmp -s will return nonzero exit status if files differ.
cmp -s "${this_file}" "${this_file}${backup_extension}"
if test $? -ne 0 ; then
# We only need to keep comparing until we find *one* that
# differs, because we'll have to run texindex & tex no
# matter what.
index_files_changed_p=t
break
fi
done
fi
# If index files have changed since TeX has been run, or if the aux
# file wasn't present originally, run texindex and TeX again.
if test "${index_files_changed_p}" ; then
retval=0
if test "${new_index_files_sans_aux}" ; then
${texindex} ${new_index_files_sans_aux}
retval=$?
fi
if test ${retval} -eq 0 ; then
${tex} "${command_line_filename}"
fi
fi
fi
# Generate list of files to delete, then call rm once with the entire
# list. This is significantly faster than multiple executions of rm.
file_list=""
for file in ${orig_index_files} ; do
file_list="${file_list} ${file}${backup_extension}"
done
if test "${file_list}" ; then
rm -f ${file_list}
fi
done
# texi2dvi ends here
texinfo-3.7/util/texindex.c 100666 11732 13 122276 5770345015 14263 0 ustar bfox user /* Prepare TeX index dribble output into an actual index.
Version 1.45
Copyright (C) 1987, 1991, 1992 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. */
#include
#include
#include
#include "getopt.h"
#define TEXINDEX_VERSION_STRING "GNU Texindex 2.0 for Texinfo release 3.4"
#if defined (emacs)
# include "../src/config.h"
/* Some s/os.h files redefine these. */
# undef read
# undef close
# undef write
# undef open
#endif
#if defined (HAVE_STRING_H)
# include
#endif /* HAVE_STRING_H */
#if !defined (HAVE_STRCHR)
char *strrchr ();
#endif /* !HAVE_STRCHR */
#if defined (STDC_HEADERS)
# include
#else /* !STDC_HEADERS */
char *getenv (), *malloc (), *realloc ();
#endif /* !STDC_HEADERS */
#if defined (HAVE_UNISTD_H)
# include
#else /* !HAVE_UNISTD_H */
off_t lseek ();
#endif /* !HAVE_UNISTD_H */
#if !defined (HAVE_MEMSET)
#undef memset
#define memset(ptr, ignore, count) bzero (ptr, count)
#endif
char *mktemp ();
#if defined (VMS)
# include
# define TI_NO_ERROR ((1 << 28) | 1)
# define TI_FATAL_ERROR ((1 << 28) | 4)
# define unlink delete
#else /* !VMS */
# if defined (HAVE_SYS_FCNTL_H)
# include
# include
# endif /* HAVE_SYS_FCNTL_H */
# if defined (_AIX) || !defined (_POSIX_VERSION)
# include
# else /* !AIX && _POSIX_VERSION */
# if !defined (HAVE_SYS_FCNTL_H)
# include
# endif /* !HAVE_FCNTL_H */
# endif /* !_AIX && _POSIX_VERSION */
# define TI_NO_ERROR 0
# define TI_FATAL_ERROR 1
#endif /* !VMS */
#if !defined (SEEK_SET)
# define SEEK_SET 0
# define SEEK_CUR 1
# define SEEK_END 2
#endif /* !SEEK_SET */
#if !defined (errno)
extern int errno;
#endif
char *strerror ();
/* When sorting in core, this structure describes one line
and the position and length of its first keyfield. */
struct lineinfo
{
char *text; /* The actual text of the line. */
union {
char *text; /* The start of the key (for textual comparison). */
long number; /* The numeric value (for numeric comparison). */
} key;
long keylen; /* Length of KEY field. */
};
/* This structure describes a field to use as a sort key. */
struct keyfield
{
int startwords; /* Number of words to skip. */
int startchars; /* Number of additional chars to skip. */
int endwords; /* Number of words to ignore at end. */
int endchars; /* Ditto for characters of last word. */
char ignore_blanks; /* Non-zero means ignore spaces and tabs. */
char fold_case; /* Non-zero means case doesn't matter. */
char reverse; /* Non-zero means compare in reverse order. */
char numeric; /* Non-zeros means field is ASCII numeric. */
char positional; /* Sort according to file position. */
char braced; /* Count balanced-braced groupings as fields. */
};
/* Vector of keyfields to use. */
struct keyfield keyfields[3];
/* Number of keyfields stored in that vector. */
int num_keyfields = 3;
/* Vector of input file names, terminated with a null pointer. */
char **infiles;
/* Vector of corresponding output file names, or NULL, meaning default it
(add an `s' to the end). */
char **outfiles;
/* Length of `infiles'. */
int num_infiles;
/* Pointer to the array of pointers to lines being sorted. */
char **linearray;
/* The allocated length of `linearray'. */
long nlines;
/* Directory to use for temporary files. On Unix, it ends with a slash. */
char *tempdir;
/* Start of filename to use for temporary files. */
char *tempbase;
/* Number of last temporary file. */
int tempcount;
/* Number of last temporary file already deleted.
Temporary files are deleted by `flush_tempfiles' in order of creation. */
int last_deleted_tempcount;
/* During in-core sort, this points to the base of the data block
which contains all the lines of data. */
char *text_base;
/* Additional command switches .*/
/* Nonzero means do not delete tempfiles -- for debugging. */
int keep_tempfiles;
/* The name this program was run with. */
char *program_name;
/* Forward declarations of functions in this file. */
void decode_command ();
void sort_in_core ();
void sort_offline ();
char **parsefile ();
char *find_field ();
char *find_pos ();
long find_value ();
char *find_braced_pos ();
char *find_braced_end ();
void writelines ();
int compare_field ();
int compare_full ();
long readline ();
int merge_files ();
int merge_direct ();
void pfatal_with_name ();
void fatal ();
void error ();
void *xmalloc (), *xrealloc ();
char *concat ();
char *maketempname ();
void flush_tempfiles ();
char *tempcopy ();
#define MAX_IN_CORE_SORT 500000
void
main (argc, argv)
int argc;
char **argv;
{
int i;
tempcount = 0;
last_deleted_tempcount = 0;
program_name = strrchr (argv[0], '/');
if (program_name != (char *)NULL)
program_name++;
else
program_name = argv[0];
/* Describe the kind of sorting to do. */
/* The first keyfield uses the first braced field and folds case. */
keyfields[0].braced = 1;
keyfields[0].fold_case = 1;
keyfields[0].endwords = -1;
keyfields[0].endchars = -1;
/* The second keyfield uses the second braced field, numerically. */
keyfields[1].braced = 1;
keyfields[1].numeric = 1;
keyfields[1].startwords = 1;
keyfields[1].endwords = -1;
keyfields[1].endchars = -1;
/* The third keyfield (which is ignored while discarding duplicates)
compares the whole line. */
keyfields[2].endwords = -1;
keyfields[2].endchars = -1;
decode_command (argc, argv);
tempbase = mktemp (concat ("txiXXXXXX", "", ""));
/* Process input files completely, one by one. */
for (i = 0; i < num_infiles; i++)
{
int desc;
long ptr;
char *outfile;
desc = open (infiles[i], O_RDONLY, 0);
if (desc < 0)
pfatal_with_name (infiles[i]);
lseek (desc, (off_t) 0, SEEK_END);
ptr = (long) lseek (desc, (off_t) 0, SEEK_CUR);
close (desc);
outfile = outfiles[i];
if (!outfile)
{
outfile = concat (infiles[i], "s", "");
}
if (ptr < MAX_IN_CORE_SORT)
/* Sort a small amount of data. */
sort_in_core (infiles[i], ptr, outfile);
else
sort_offline (infiles[i], ptr, outfile);
}
flush_tempfiles (tempcount);
exit (TI_NO_ERROR);
}
typedef struct
{
char *long_name;
char *short_name;
int *variable_ref;
int variable_value;
char *arg_name;
char *doc_string;
} TEXINDEX_OPTION;
TEXINDEX_OPTION texindex_options[] = {
{ "--keep", "-k", &keep_tempfiles, 1, (char *)NULL,
"Keep temporary files around after processing" },
{ "--no-keep", 0, &keep_tempfiles, 0, (char *)NULL,
"Do not keep temporary files around after processing (default)" },
{ "--output", "-o", (int *)NULL, 0, "FILE",
"Send output to FILE" },
{ "--version", (char *)NULL, (int *)NULL, 0, (char *)NULL,
"Show version information" },
{ "--help", "-h", (int *)NULL, 0, (char *)NULL, "Produce this listing" },
{ (char *)NULL, (char *)NULL, (int *)NULL, 0, (char *)NULL }
};
void
usage (result_value)
int result_value;
{
register int i;
fprintf (stderr, "Usage: %s [OPTIONS] FILE...\n", program_name);
fprintf (stderr, " Generate a permuted index for the TeX files given.\n");
fprintf (stderr, " Usually FILE... is `foo.??' for the source file `foo.tex'.\n");
fprintf (stderr, " The OPTIONS are:\n");
for (i = 0; texindex_options[i].long_name; i++)
{
fprintf (stderr, " %s %s",
texindex_options[i].long_name,
texindex_options[i].arg_name ?
texindex_options[i].arg_name : "");
if (texindex_options[i].short_name)
fprintf (stderr, " \n or %s %s",
texindex_options[i].short_name,
texindex_options[i].arg_name ?
texindex_options[i].arg_name : "");
fprintf (stderr, "\t%s\n", texindex_options[i].doc_string);
}
exit (result_value);
}
/* Decode the command line arguments to set the parameter variables
and set up the vector of keyfields and the vector of input files. */
void
decode_command (argc, argv)
int argc;
char **argv;
{
int arg_index = 1;
int optc;
char **ip;
char **op;
/* Store default values into parameter variables. */
tempdir = getenv ("TMPDIR");
#ifdef VMS
if (tempdir == NULL)
tempdir = "sys$scratch:";
#else
if (tempdir == NULL)
tempdir = "/tmp/";
else
tempdir = concat (tempdir, "/", "");
#endif
keep_tempfiles = 0;
/* Allocate ARGC input files, which must be enough. */
infiles = (char **) xmalloc (argc * sizeof (char *));
outfiles = (char **) xmalloc (argc * sizeof (char *));
ip = infiles;
op = outfiles;
while (arg_index < argc)
{
char *arg = argv[arg_index++];
if (*arg == '-')
{
if (strcmp (arg, "--version") == 0)
{
fprintf (stderr, "%s\n", TEXINDEX_VERSION_STRING);
exit (0);
}
else if ((strcmp (arg, "--keep") == 0) ||
(strcmp (arg, "-k") == 0))
{
keep_tempfiles = 1;
}
else if ((strcmp (arg, "--help") == 0) ||
(strcmp (arg, "-h") == 0))
{
usage (0);
}
else if ((strcmp (arg, "--output") == 0) ||
(strcmp (arg, "-o") == 0))
{
if (argv[arg_index] != (char *)NULL)
{
arg_index++;
if (op > outfiles)
*(op - 1) = argv[arg_index];
}
else
usage (1);
}
else
usage (1);
}
else
{
*ip++ = arg;
*op++ = (char *)NULL;
}
}
/* Record number of keyfields and terminate list of filenames. */
num_infiles = ip - infiles;
*ip = (char *)NULL;
if (num_infiles == 0)
usage (1);
}
/* Return a name for a temporary file. */
char *
maketempname (count)
int count;
{
char tempsuffix[10];
sprintf (tempsuffix, "%d", count);
return concat (tempdir, tempbase, tempsuffix);
}
/* Delete all temporary files up to TO_COUNT. */
void
flush_tempfiles (to_count)
int to_count;
{
if (keep_tempfiles)
return;
while (last_deleted_tempcount < to_count)
unlink (maketempname (++last_deleted_tempcount));
}
/* Copy the input file open on IDESC into a temporary file
and return the temporary file name. */
#define BUFSIZE 1024
char *
tempcopy (idesc)
int idesc;
{
char *outfile = maketempname (++tempcount);
int odesc;
char buffer[BUFSIZE];
odesc = open (outfile, O_WRONLY | O_CREAT, 0666);
if (odesc < 0)
pfatal_with_name (outfile);
while (1)
{
int nread = read (idesc, buffer, BUFSIZE);
write (odesc, buffer, nread);
if (!nread)
break;
}
close (odesc);
return outfile;
}
/* Compare LINE1 and LINE2 according to the specified set of keyfields. */
int
compare_full (line1, line2)
char **line1, **line2;
{
int i;
/* Compare using the first keyfield;
if that does not distinguish the lines, try the second keyfield;
and so on. */
for (i = 0; i < num_keyfields; i++)
{
long length1, length2;
char *start1 = find_field (&keyfields[i], *line1, &length1);
char *start2 = find_field (&keyfields[i], *line2, &length2);
int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base,
start2, length2, *line2 - text_base);
if (tem)
{
if (keyfields[i].reverse)
return -tem;
return tem;
}
}
return 0; /* Lines match exactly. */
}
/* Compare LINE1 and LINE2, described by structures
in which the first keyfield is identified in advance.
For positional sorting, assumes that the order of the lines in core
reflects their nominal order. */
int
compare_prepared (line1, line2)
struct lineinfo *line1, *line2;
{
int i;
int tem;
char *text1, *text2;
/* Compare using the first keyfield, which has been found for us already. */
if (keyfields->positional)
{
if (line1->text - text_base > line2->text - text_base)
tem = 1;
else
tem = -1;
}
else if (keyfields->numeric)
tem = line1->key.number - line2->key.number;
else
tem = compare_field (keyfields, line1->key.text, line1->keylen, 0,
line2->key.text, line2->keylen, 0);
if (tem)
{
if (keyfields->reverse)
return -tem;
return tem;
}
text1 = line1->text;
text2 = line2->text;
/* Compare using the second keyfield;
if that does not distinguish the lines, try the third keyfield;
and so on. */
for (i = 1; i < num_keyfields; i++)
{
long length1, length2;
char *start1 = find_field (&keyfields[i], text1, &length1);
char *start2 = find_field (&keyfields[i], text2, &length2);
int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base,
start2, length2, text2 - text_base);
if (tem)
{
if (keyfields[i].reverse)
return -tem;
return tem;
}
}
return 0; /* Lines match exactly. */
}
/* Like compare_full but more general.
You can pass any strings, and you can say how many keyfields to use.
POS1 and POS2 should indicate the nominal positional ordering of
the two lines in the input. */
int
compare_general (str1, str2, pos1, pos2, use_keyfields)
char *str1, *str2;
long pos1, pos2;
int use_keyfields;
{
int i;
/* Compare using the first keyfield;
if that does not distinguish the lines, try the second keyfield;
and so on. */
for (i = 0; i < use_keyfields; i++)
{
long length1, length2;
char *start1 = find_field (&keyfields[i], str1, &length1);
char *start2 = find_field (&keyfields[i], str2, &length2);
int tem = compare_field (&keyfields[i], start1, length1, pos1,
start2, length2, pos2);
if (tem)
{
if (keyfields[i].reverse)
return -tem;
return tem;
}
}
return 0; /* Lines match exactly. */
}
/* Find the start and length of a field in STR according to KEYFIELD.
A pointer to the starting character is returned, and the length
is stored into the int that LENGTHPTR points to. */
char *
find_field (keyfield, str, lengthptr)
struct keyfield *keyfield;
char *str;
long *lengthptr;
{
char *start;
char *end;
char *(*fun) ();
if (keyfield->braced)
fun = find_braced_pos;
else
fun = find_pos;
start = (*fun) (str, keyfield->startwords, keyfield->startchars,
keyfield->ignore_blanks);
if (keyfield->endwords < 0)
{
if (keyfield->braced)
end = find_braced_end (start);
else
{
end = start;
while (*end && *end != '\n')
end++;
}
}
else
{
end = (*fun) (str, keyfield->endwords, keyfield->endchars, 0);
if (end - str < start - str)
end = start;
}
*lengthptr = end - start;
return start;
}
/* Return a pointer to a specified place within STR,
skipping (from the beginning) WORDS words and then CHARS chars.
If IGNORE_BLANKS is nonzero, we skip all blanks
after finding the specified word. */
char *
find_pos (str, words, chars, ignore_blanks)
char *str;
int words, chars;
int ignore_blanks;
{
int i;
char *p = str;
for (i = 0; i < words; i++)
{
char c;
/* Find next bunch of nonblanks and skip them. */
while ((c = *p) == ' ' || c == '\t')
p++;
while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t'))
p++;
if (!*p || *p == '\n')
return p;
}
while (*p == ' ' || *p == '\t')
p++;
for (i = 0; i < chars; i++)
{
if (!*p || *p == '\n')
break;
p++;
}
return p;
}
/* Like find_pos but assumes that each field is surrounded by braces
and that braces within fields are balanced. */
char *
find_braced_pos (str, words, chars, ignore_blanks)
char *str;
int words, chars;
int ignore_blanks;
{
int i;
int bracelevel;
char *p = str;
char c;
for (i = 0; i < words; i++)
{
bracelevel = 1;
while ((c = *p++) != '{' && c != '\n' && c)
/* Do nothing. */ ;
if (c != '{')
return p - 1;
while (bracelevel)
{
c = *p++;
if (c == '{')
bracelevel++;
if (c == '}')
bracelevel--;
if (c == 0 || c == '\n')
return p - 1;
}
}
while ((c = *p++) != '{' && c != '\n' && c)
/* Do nothing. */ ;
if (c != '{')
return p - 1;
if (ignore_blanks)
while ((c = *p) == ' ' || c == '\t')
p++;
for (i = 0; i < chars; i++)
{
if (!*p || *p == '\n')
break;
p++;
}
return p;
}
/* Find the end of the balanced-brace field which starts at STR.
The position returned is just before the closing brace. */
char *
find_braced_end (str)
char *str;
{
int bracelevel;
char *p = str;
char c;
bracelevel = 1;
while (bracelevel)
{
c = *p++;
if (c == '{')
bracelevel++;
if (c == '}')
bracelevel--;
if (c == 0 || c == '\n')
return p - 1;
}
return p - 1;
}
long
find_value (start, length)
char *start;
long length;
{
while (length != 0L)
{
if (isdigit (*start))
return atol (start);
length--;
start++;
}
return 0l;
}
/* Vector used to translate characters for comparison.
This is how we make all alphanumerics follow all else,
and ignore case in the first sorting. */
int char_order[256];
void
init_char_order ()
{
int i;
for (i = 1; i < 256; i++)
char_order[i] = i;
for (i = '0'; i <= '9'; i++)
char_order[i] += 512;
for (i = 'a'; i <= 'z'; i++)
{
char_order[i] = 512 + i;
char_order[i + 'A' - 'a'] = 512 + i;
}
}
/* Compare two fields (each specified as a start pointer and a character count)
according to KEYFIELD.
The sign of the value reports the relation between the fields. */
int
compare_field (keyfield, start1, length1, pos1, start2, length2, pos2)
struct keyfield *keyfield;
char *start1;
long length1;
long pos1;
char *start2;
long length2;
long pos2;
{
if (keyfields->positional)
{
if (pos1 > pos2)
return 1;
else
return -1;
}
if (keyfield->numeric)
{
long value = find_value (start1, length1) - find_value (start2, length2);
if (value > 0)
return 1;
if (value < 0)
return -1;
return 0;
}
else
{
char *p1 = start1;
char *p2 = start2;
char *e1 = start1 + length1;
char *e2 = start2 + length2;
while (1)
{
int c1, c2;
if (p1 == e1)
c1 = 0;
else
c1 = *p1++;
if (p2 == e2)
c2 = 0;
else
c2 = *p2++;
if (char_order[c1] != char_order[c2])
return char_order[c1] - char_order[c2];
if (!c1)
break;
}
/* Strings are equal except possibly for case. */
p1 = start1;
p2 = start2;
while (1)
{
int c1, c2;
if (p1 == e1)
c1 = 0;
else
c1 = *p1++;
if (p2 == e2)
c2 = 0;
else
c2 = *p2++;
if (c1 != c2)
/* Reverse sign here so upper case comes out last. */
return c2 - c1;
if (!c1)
break;
}
return 0;
}
}
/* A `struct linebuffer' is a structure which holds a line of text.
`readline' reads a line from a stream into a linebuffer
and works regardless of the length of the line. */
struct linebuffer
{
long size;
char *buffer;
};
/* Initialize LINEBUFFER for use. */
void
initbuffer (linebuffer)
struct linebuffer *linebuffer;
{
linebuffer->size = 200;
linebuffer->buffer = (char *) xmalloc (200);
}
/* Read a line of text from STREAM into LINEBUFFER.
Return the length of the line. */
long
readline (linebuffer, stream)
struct linebuffer *linebuffer;
FILE *stream;
{
char *buffer = linebuffer->buffer;
char *p = linebuffer->buffer;
char *end = p + linebuffer->size;
while (1)
{
int c = getc (stream);
if (p == end)
{
buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
p += buffer - linebuffer->buffer;
end += buffer - linebuffer->buffer;
linebuffer->buffer = buffer;
}
if (c < 0 || c == '\n')
{
*p = 0;
break;
}
*p++ = c;
}
return p - buffer;
}
/* Sort an input file too big to sort in core. */
void
sort_offline (infile, nfiles, total, outfile)
char *infile;
int nfiles;
long total;
char *outfile;
{
/* More than enough. */
int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT;
char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
FILE *istream = fopen (infile, "r");
int i;
struct linebuffer lb;
long linelength;
int failure = 0;
initbuffer (&lb);
/* Read in one line of input data. */
linelength = readline (&lb, istream);
if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
{
error ("%s: not a texinfo index file", infile);
return;
}
/* Split up the input into `ntemps' temporary files, or maybe fewer,
and put the new files' names into `tempfiles' */
for (i = 0; i < ntemps; i++)
{
char *outname = maketempname (++tempcount);
FILE *ostream = fopen (outname, "w");
long tempsize = 0;
if (!ostream)
pfatal_with_name (outname);
tempfiles[i] = outname;
/* Copy lines into this temp file as long as it does not make file
"too big" or until there are no more lines. */
while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT)
{
tempsize += linelength + 1;
fputs (lb.buffer, ostream);
putc ('\n', ostream);
/* Read another line of input data. */
linelength = readline (&lb, istream);
if (!linelength && feof (istream))
break;
if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
{
error ("%s: not a texinfo index file", infile);
failure = 1;
goto fail;
}
}
fclose (ostream);
if (feof (istream))
break;
}
free (lb.buffer);
fail:
/* Record number of temp files we actually needed. */
ntemps = i;
/* Sort each tempfile into another tempfile.
Delete the first set of tempfiles and put the names of the second
into `tempfiles'. */
for (i = 0; i < ntemps; i++)
{
char *newtemp = maketempname (++tempcount);
sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp);
if (!keep_tempfiles)
unlink (tempfiles[i]);
tempfiles[i] = newtemp;
}
if (failure)
return;
/* Merge the tempfiles together and indexify. */
merge_files (tempfiles, ntemps, outfile);
}
/* Sort INFILE, whose size is TOTAL,
assuming that is small enough to be done in-core,
then indexify it and send the output to OUTFILE (or to stdout). */
void
sort_in_core (infile, total, outfile)
char *infile;
long total;
char *outfile;
{
char **nextline;
char *data = (char *) xmalloc (total + 1);
char *file_data;
long file_size;
int i;
FILE *ostream = stdout;
struct lineinfo *lineinfo;
/* Read the contents of the file into the moby array `data'. */
int desc = open (infile, O_RDONLY, 0);
if (desc < 0)
fatal ("failure reopening %s", infile);
for (file_size = 0;;)
{
i = read (desc, data + file_size, total - file_size);
if (i <= 0)
break;
file_size += i;
}
file_data = data;
data[file_size] = 0;
close (desc);
if (file_size > 0 && data[0] != '\\' && data[0] != '@')
{
error ("%s: not a texinfo index file", infile);
return;
}
init_char_order ();
/* Sort routines want to know this address. */
text_base = data;
/* Create the array of pointers to lines, with a default size
frequently enough. */
nlines = total / 50;
if (!nlines)
nlines = 2;
linearray = (char **) xmalloc (nlines * sizeof (char *));
/* `nextline' points to the next free slot in this array.
`nlines' is the allocated size. */
nextline = linearray;
/* Parse the input file's data, and make entries for the lines. */
nextline = parsefile (infile, nextline, file_data, file_size);
if (nextline == 0)
{
error ("%s: not a texinfo index file", infile);
return;
}
/* Sort the lines. */
/* If we have enough space, find the first keyfield of each line in advance.
Make a `struct lineinfo' for each line, which records the keyfield
as well as the line, and sort them. */
lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo));
if (lineinfo)
{
struct lineinfo *lp;
char **p;
for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
{
lp->text = *p;
lp->key.text = find_field (keyfields, *p, &lp->keylen);
if (keyfields->numeric)
lp->key.number = find_value (lp->key.text, lp->keylen);
}
qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), compare_prepared);
for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
*p = lp->text;
free (lineinfo);
}
else
qsort (linearray, nextline - linearray, sizeof (char *), compare_full);
/* Open the output file. */
if (outfile)
{
ostream = fopen (outfile, "w");
if (!ostream)
pfatal_with_name (outfile);
}
writelines (linearray, nextline - linearray, ostream);
if (outfile)
fclose (ostream);
free (linearray);
free (data);
}
/* Parse an input string in core into lines.
DATA is the input string, and SIZE is its length.
Data goes in LINEARRAY starting at NEXTLINE.
The value returned is the first entry in LINEARRAY still unused.
Value 0 means input file contents are invalid. */
char **
parsefile (filename, nextline, data, size)
char *filename;
char **nextline;
char *data;
long size;
{
char *p, *end;
char **line = nextline;
p = data;
end = p + size;
*end = 0;
while (p != end)
{
if (p[0] != '\\' && p[0] != '@')
return 0;
*line = p;
while (*p && *p != '\n')
p++;
if (p != end)
p++;
line++;
if (line == linearray + nlines)
{
char **old = linearray;
linearray = (char **) xrealloc (linearray, sizeof (char *) * (nlines *= 4));
line += linearray - old;
}
}
return line;
}
/* Indexification is a filter applied to the sorted lines
as they are being written to the output file.
Multiple entries for the same name, with different page numbers,
get combined into a single entry with multiple page numbers.
The first braced field, which is used for sorting, is discarded.
However, its first character is examined, folded to lower case,
and if it is different from that in the previous line fed to us
a \initial line is written with one argument, the new initial.
If an entry has four braced fields, then the second and third
constitute primary and secondary names.
In this case, each change of primary name
generates a \primary line which contains only the primary name,
and in between these are \secondary lines which contain
just a secondary name and page numbers. */
/* The last primary name we wrote a \primary entry for.
If only one level of indexing is being done, this is the last name seen. */
char *lastprimary;
/* Length of storage allocated for lastprimary. */
int lastprimarylength;
/* Similar, for the secondary name. */
char *lastsecondary;
int lastsecondarylength;
/* Zero if we are not in the middle of writing an entry.
One if we have written the beginning of an entry but have not
yet written any page numbers into it.
Greater than one if we have written the beginning of an entry
plus at least one page number. */
int pending;
/* The initial (for sorting purposes) of the last primary entry written.
When this changes, a \initial {c} line is written */
char *lastinitial;
int lastinitiallength;
/* When we need a string of length 1 for the value of lastinitial,
store it here. */
char lastinitial1[2];
/* Initialize static storage for writing an index. */
void
init_index ()
{
pending = 0;
lastinitial = lastinitial1;
lastinitial1[0] = 0;
lastinitial1[1] = 0;
lastinitiallength = 0;
lastprimarylength = 100;
lastprimary = (char *) xmalloc (lastprimarylength + 1);
memset (lastprimary, '\0', lastprimarylength + 1);
lastsecondarylength = 100;
lastsecondary = (char *) xmalloc (lastsecondarylength + 1);
memset (lastsecondary, '\0', lastsecondarylength + 1);
}
/* Indexify. Merge entries for the same name,
insert headers for each initial character, etc. */
void
indexify (line, ostream)
char *line;
FILE *ostream;
{
char *primary, *secondary, *pagenumber;
int primarylength, secondarylength = 0, pagelength;
int nosecondary;
int initiallength;
char *initial;
char initial1[2];
register char *p;
/* First, analyze the parts of the entry fed to us this time. */
p = find_braced_pos (line, 0, 0, 0);
if (*p == '{')
{
initial = p;
/* Get length of inner pair of braces starting at `p',
including that inner pair of braces. */
initiallength = find_braced_end (p + 1) + 1 - p;
}
else
{
initial = initial1;
initial1[0] = *p;
initial1[1] = 0;
initiallength = 1;
if (initial1[0] >= 'a' && initial1[0] <= 'z')
initial1[0] -= 040;
}
pagenumber = find_braced_pos (line, 1, 0, 0);
pagelength = find_braced_end (pagenumber) - pagenumber;
if (pagelength == 0)
abort ();
primary = find_braced_pos (line, 2, 0, 0);
primarylength = find_braced_end (primary) - primary;
secondary = find_braced_pos (line, 3, 0, 0);
nosecondary = !*secondary;
if (!nosecondary)
secondarylength = find_braced_end (secondary) - secondary;
/* If the primary is different from before, make a new primary entry. */
if (strncmp (primary, lastprimary, primarylength))
{
/* Close off current secondary entry first, if one is open. */
if (pending)
{
fputs ("}\n", ostream);
pending = 0;
}
/* If this primary has a different initial, include an entry for
the initial. */
if (initiallength != lastinitiallength ||
strncmp (initial, lastinitial, initiallength))
{
fprintf (ostream, "\\initial {");
fwrite (initial, 1, initiallength, ostream);
fprintf (ostream, "}\n", initial);
if (initial == initial1)
{
lastinitial = lastinitial1;
*lastinitial1 = *initial1;
}
else
{
lastinitial = initial;
}
lastinitiallength = initiallength;
}
/* Make the entry for the primary. */
if (nosecondary)
fputs ("\\entry {", ostream);
else
fputs ("\\primary {", ostream);
fwrite (primary, primarylength, 1, ostream);
if (nosecondary)
{
fputs ("}{", ostream);
pending = 1;
}
else
fputs ("}\n", ostream);
/* Record name of most recent primary. */
if (lastprimarylength < primarylength)
{
lastprimarylength = primarylength + 100;
lastprimary = (char *) xrealloc (lastprimary,
1 + lastprimarylength);
}
strncpy (lastprimary, primary, primarylength);
lastprimary[primarylength] = 0;
/* There is no current secondary within this primary, now. */
lastsecondary[0] = 0;
}
/* Should not have an entry with no subtopic following one with a subtopic. */
if (nosecondary && *lastsecondary)
error ("entry %s follows an entry with a secondary name", line);
/* Start a new secondary entry if necessary. */
if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength))
{
if (pending)
{
fputs ("}\n", ostream);
pending = 0;
}
/* Write the entry for the secondary. */
fputs ("\\secondary {", ostream);
fwrite (secondary, secondarylength, 1, ostream);
fputs ("}{", ostream);
pending = 1;
/* Record name of most recent secondary. */
if (lastsecondarylength < secondarylength)
{
lastsecondarylength = secondarylength + 100;
lastsecondary = (char *) xrealloc (lastsecondary,
1 + lastsecondarylength);
}
strncpy (lastsecondary, secondary, secondarylength);
lastsecondary[secondarylength] = 0;
}
/* Here to add one more page number to the current entry. */
if (pending++ != 1)
fputs (", ", ostream); /* Punctuate first, if this is not the first. */
fwrite (pagenumber, pagelength, 1, ostream);
}
/* Close out any unfinished output entry. */
void
finish_index (ostream)
FILE *ostream;
{
if (pending)
fputs ("}\n", ostream);
free (lastprimary);
free (lastsecondary);
}
/* Copy the lines in the sorted order.
Each line is copied out of the input file it was found in. */
void
writelines (linearray, nlines, ostream)
char **linearray;
int nlines;
FILE *ostream;
{
char **stop_line = linearray + nlines;
char **next_line;
init_index ();
/* Output the text of the lines, and free the buffer space. */
for (next_line = linearray; next_line != stop_line; next_line++)
{
/* If -u was specified, output the line only if distinct from previous one. */
if (next_line == linearray
/* Compare previous line with this one, using only the
explicitly specd keyfields. */
|| compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1))
{
char *p = *next_line;
char c;
while ((c = *p++) && c != '\n')
/* Do nothing. */ ;
*(p - 1) = 0;
indexify (*next_line, ostream);
}
}
finish_index (ostream);
}
/* Assume (and optionally verify) that each input file is sorted;
merge them and output the result.
Returns nonzero if any input file fails to be sorted.
This is the high-level interface that can handle an unlimited
number of files. */
#define MAX_DIRECT_MERGE 10
int
merge_files (infiles, nfiles, outfile)
char **infiles;
int nfiles;
char *outfile;
{
char **tempfiles;
int ntemps;
int i;
int value = 0;
int start_tempcount = tempcount;
if (nfiles <= MAX_DIRECT_MERGE)
return merge_direct (infiles, nfiles, outfile);
/* Merge groups of MAX_DIRECT_MERGE input files at a time,
making a temporary file to hold each group's result. */
ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE;
tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
for (i = 0; i < ntemps; i++)
{
int nf = MAX_DIRECT_MERGE;
if (i + 1 == ntemps)
nf = nfiles - i * MAX_DIRECT_MERGE;
tempfiles[i] = maketempname (++tempcount);
value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]);
}
/* All temporary files that existed before are no longer needed
since their contents have been merged into our new tempfiles.
So delete them. */
flush_tempfiles (start_tempcount);
/* Now merge the temporary files we created. */
merge_files (tempfiles, ntemps, outfile);
free (tempfiles);
return value;
}
/* Assume (and optionally verify) that each input file is sorted;
merge them and output the result.
Returns nonzero if any input file fails to be sorted.
This version of merging will not work if the number of
input files gets too high. Higher level functions
use it only with a bounded number of input files. */
int
merge_direct (infiles, nfiles, outfile)
char **infiles;
int nfiles;
char *outfile;
{
struct linebuffer *lb1, *lb2;
struct linebuffer **thisline, **prevline;
FILE **streams;
int i;
int nleft;
int lossage = 0;
int *file_lossage;
struct linebuffer *prev_out = 0;
FILE *ostream = stdout;
if (outfile)
{
ostream = fopen (outfile, "w");
}
if (!ostream)
pfatal_with_name (outfile);
init_index ();
if (nfiles == 0)
{
if (outfile)
fclose (ostream);
return 0;
}
/* For each file, make two line buffers.
Also, for each file, there is an element of `thisline'
which points at any time to one of the file's two buffers,
and an element of `prevline' which points to the other buffer.
`thisline' is supposed to point to the next available line from the file,
while `prevline' holds the last file line used,
which is remembered so that we can verify that the file is properly sorted. */
/* lb1 and lb2 contain one buffer each per file. */
lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
/* thisline[i] points to the linebuffer holding the next available line in file i,
or is zero if there are no lines left in that file. */
thisline = (struct linebuffer **)
xmalloc (nfiles * sizeof (struct linebuffer *));
/* prevline[i] points to the linebuffer holding the last used line
from file i. This is just for verifying that file i is properly
sorted. */
prevline = (struct linebuffer **)
xmalloc (nfiles * sizeof (struct linebuffer *));
/* streams[i] holds the input stream for file i. */
streams = (FILE **) xmalloc (nfiles * sizeof (FILE *));
/* file_lossage[i] is nonzero if we already know file i is not
properly sorted. */
file_lossage = (int *) xmalloc (nfiles * sizeof (int));
/* Allocate and initialize all that storage. */
for (i = 0; i < nfiles; i++)
{
initbuffer (&lb1[i]);
initbuffer (&lb2[i]);
thisline[i] = &lb1[i];
prevline[i] = &lb2[i];
file_lossage[i] = 0;
streams[i] = fopen (infiles[i], "r");
if (!streams[i])
pfatal_with_name (infiles[i]);
readline (thisline[i], streams[i]);
}
/* Keep count of number of files not at eof. */
nleft = nfiles;
while (nleft)
{
struct linebuffer *best = 0;
struct linebuffer *exch;
int bestfile = -1;
int i;
/* Look at the next avail line of each file; choose the least one. */
for (i = 0; i < nfiles; i++)
{
if (thisline[i] &&
(!best ||
0 < compare_general (best->buffer, thisline[i]->buffer,
(long) bestfile, (long) i, num_keyfields)))
{
best = thisline[i];
bestfile = i;
}
}
/* Output that line, unless it matches the previous one and we
don't want duplicates. */
if (!(prev_out &&
!compare_general (prev_out->buffer,
best->buffer, 0L, 1L, num_keyfields - 1)))
indexify (best->buffer, ostream);
prev_out = best;
/* Now make the line the previous of its file, and fetch a new
line from that file. */
exch = prevline[bestfile];
prevline[bestfile] = thisline[bestfile];
thisline[bestfile] = exch;
while (1)
{
/* If the file has no more, mark it empty. */
if (feof (streams[bestfile]))
{
thisline[bestfile] = 0;
/* Update the number of files still not empty. */
nleft--;
break;
}
readline (thisline[bestfile], streams[bestfile]);
if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile]))
break;
}
}
finish_index (ostream);
/* Free all storage and close all input streams. */
for (i = 0; i < nfiles; i++)
{
fclose (streams[i]);
free (lb1[i].buffer);
free (lb2[i].buffer);
}
free (file_lossage);
free (lb1);
free (lb2);
free (thisline);
free (prevline);
free (streams);
if (outfile)
fclose (ostream);
return lossage;
}
/* Print error message and exit. */
void
fatal (format, arg)
char *format, *arg;
{
error (format, arg);
exit (TI_FATAL_ERROR);
}
/* Print error message. FORMAT is printf control string, ARG is arg for it. */
void
error (format, arg)
char *format, *arg;
{
printf ("%s: ", program_name);
printf (format, arg);
if (format[strlen (format) -1] != '\n')
printf ("\n");
}
void
perror_with_name (name)
char *name;
{
char *s;
s = strerror (errno);
printf ("%s: ", program_name);
printf ("%s; for file `%s'.\n", s, name);
}
void
pfatal_with_name (name)
char *name;
{
char *s;
s = strerror (errno);
printf ("%s: ", program_name);
printf ("%s; for file `%s'.\n", s, name);
exit (TI_FATAL_ERROR);
}
/* Return a newly-allocated string whose contents concatenate those of
S1, S2, S3. */
char *
concat (s1, s2, s3)
char *s1, *s2, *s3;
{
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
strcpy (result, s1);
strcpy (result + len1, s2);
strcpy (result + len1 + len2, s3);
*(result + len1 + len2 + len3) = 0;
return result;
}
#if !defined (HAVE_STRERROR)
extern char *sys_errlist[];
extern int sys_nerr;
char *
strerror (num)
int num;
{
if (num >= sys_nerr)
return ("");
else
return (sys_errlist[num]);
}
#endif /* !HAVE_STRERROR */
#if !defined (HAVE_STRCHR)
char *
strrchr (string, character)
char *string;
int character;
{
register int i;
for (i = strlen (string) - 1; i > -1; i--)
if (string[i] == character)
return (string + i);
return ((char *)NULL);
}
#endif /* HAVE_STRCHR */
/* Just like malloc, but kills the program in case of fatal error. */
void *
xmalloc (nbytes)
int nbytes;
{
void *temp = (void *) malloc (nbytes);
if (nbytes && temp == (void *)NULL)
memory_error ("xmalloc", nbytes);
return (temp);
}
/* Like realloc (), but barfs if there isn't enough memory. */
void *
xrealloc (pointer, nbytes)
void *pointer;
int nbytes;
{
void *temp;
if (!pointer)
temp = (void *)xmalloc (nbytes);
else
temp = (void *)realloc (pointer, nbytes);
if (nbytes && !temp)
memory_error ("xrealloc", nbytes);
return (temp);
}
memory_error (callers_name, bytes_wanted)
char *callers_name;
int bytes_wanted;
{
char printable_string[80];
sprintf (printable_string,
"Virtual memory exhausted in %s ()! Needed %d bytes.",
callers_name, bytes_wanted);
error (printable_string);
abort ();
}
texinfo-3.7/libtxi/ 40777 11732 13 0 6067136355 12443 5 ustar bfox user texinfo-3.7/libtxi/Makefile.in 100666 11732 13 4500 5771744354 14611 0 ustar bfox user # Makefile for GNU texinfo/libtxi. -*- Indented-Text -*-
# Copyright (C) 1993 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.
#### Start of system configuration section. ####
srcdir = @srcdir@
VPATH = $(srcdir)
CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
LN = ln
RM = rm -f
TAR = tar
MKDIR = mkdir
COMPRESS= compress
RANLIB = @RANLIB@
DEFS = @DEFS@
LIBS = @LIBS@
LOADLIBES = $(LIBS)
# This is normally inherited from parent make, but if someone wants to
# build libtxi.a alone, this variable will still be properly defined.
ALLOCA = @ALLOCA@
SHELL = /bin/sh
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = $(exec_prefix)/bin
# Prefix for each installed program, normally empty or `g'.
binprefix =
libdir = $(prefix)/lib
# Prefix for each installed man page, normally empty or `g'.
manprefix =
mandir = $(prefix)/man/man1
manext = 1
infodir = $(prefix)/info
#### End of system configuration section. ####
SRCS = getopt.c getopt.h getopt1.c bzero.c
OBJS = getopt.o getopt1.o bzero.o $(ALLOCA)
PROGS = libtxi.a
all: $(PROGS)
sub-all: all
.c.o:
$(CC) -c $(CPPFLAGS) -I. -I$(srcdir) $(DEFS) $(CFLAGS) $<
libtxi.a: $(OBJS)
ar qcv libtxi.a $(OBJS)
$(RANLIB) libtxi.a
getopt.o: getopt.c getopt.h
getopt1.o: getopt1.c getopt.h
alloca.o: alloca.c
install:
uninstall:
TAGS: $(SRCS)
etags $(SRCS)
clean:
rm -f *.o a.out core core.* $(PROGS)
mostlyclean: clean
distclean: clean
rm -f Makefile config.status
realclean: distclean
rm -f TAGS
Makefile: Makefile.in ../config.status
cd ..; sh config.status
# Prevent GNU make v3 from overflowing arg limit on SysV.
.NOEXPORT:
# eof
texinfo-3.7/libtxi/alloca.c 100444 11732 13 33405 5641641234 14150 0 ustar bfox user /* alloca.c -- allocate automatically reclaimed memory
(Mostly) portable public-domain implementation -- D A Gwyn
This implementation of the PWB library alloca function,
which is used to allocate space off the run-time stack so
that it is automatically reclaimed upon procedure exit,
was inspired by discussions with J. Q. Johnson of Cornell.
J.Otto Tennant contributed the Cray support.
There are some preprocessor constants that can
be defined when compiling for your specific system, for
improved efficiency; however, the defaults should be okay.
The general concept of this implementation is to keep
track of all alloca-allocated blocks, and reclaim any
that are found to be deeper in the stack than the current
invocation. This heuristic does not reclaim storage as
soon as it becomes invalid, but it will do so eventually.
As a special case, alloca(0) reclaims storage without
allocating any. It is a good idea to use alloca(0) in
your main control loop, etc. to force garbage collection. */
#ifdef HAVE_CONFIG_H
#include
#endif
#ifdef emacs
#include "blockinput.h"
#endif
/* If compiling with GCC 2, this file's not needed. */
#if !defined (__GNUC__) || __GNUC__ < 2
/* If someone has defined alloca as a macro,
there must be some other way alloca is supposed to work. */
#ifndef alloca
#ifdef emacs
#ifdef static
/* actually, only want this if static is defined as ""
-- this is for usg, in which emacs must undefine static
in order to make unexec workable
*/
#ifndef STACK_DIRECTION
you
lose
-- must know STACK_DIRECTION at compile-time
#endif /* STACK_DIRECTION undefined */
#endif /* static */
#endif /* emacs */
/* If your stack is a linked list of frames, you have to
provide an "address metric" ADDRESS_FUNCTION macro. */
#if defined (CRAY) && defined (CRAY_STACKSEG_END)
long i00afunc ();
#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
#else
#define ADDRESS_FUNCTION(arg) &(arg)
#endif
#if __STDC__
typedef void *pointer;
#else
typedef char *pointer;
#endif
#define NULL 0
/* Different portions of Emacs need to call different versions of
malloc. The Emacs executable needs alloca to call xmalloc, because
ordinary malloc isn't protected from input signals. On the other
hand, the utilities in lib-src need alloca to call malloc; some of
them are very simple, and don't have an xmalloc routine.
Non-Emacs programs expect this to call use xmalloc.
Callers below should use malloc. */
#ifndef emacs
#define malloc xmalloc
#endif
extern pointer malloc ();
/* Define STACK_DIRECTION if you know the direction of stack
growth for your system; otherwise it will be automatically
deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
#ifndef STACK_DIRECTION
#define STACK_DIRECTION 0 /* Direction unknown. */
#endif
#if STACK_DIRECTION != 0
#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
#else /* STACK_DIRECTION == 0; need run-time code. */
static int stack_dir; /* 1 or -1 once known. */
#define STACK_DIR stack_dir
static void
find_stack_direction ()
{
static char *addr = NULL; /* Address of first `dummy', once known. */
auto char dummy; /* To get stack address. */
if (addr == NULL)
{ /* Initial entry. */
addr = ADDRESS_FUNCTION (dummy);
find_stack_direction (); /* Recurse once. */
}
else
{
/* Second entry. */
if (ADDRESS_FUNCTION (dummy) > addr)
stack_dir = 1; /* Stack grew upward. */
else
stack_dir = -1; /* Stack grew downward. */
}
}
#endif /* STACK_DIRECTION == 0 */
/* An "alloca header" is used to:
(a) chain together all alloca'ed blocks;
(b) keep track of stack depth.
It is very important that sizeof(header) agree with malloc
alignment chunk size. The following default should work okay. */
#ifndef ALIGN_SIZE
#define ALIGN_SIZE sizeof(double)
#endif
typedef union hdr
{
char align[ALIGN_SIZE]; /* To force sizeof(header). */
struct
{
union hdr *next; /* For chaining headers. */
char *deep; /* For stack depth measure. */
} h;
} header;
static header *last_alloca_header = NULL; /* -> last alloca header. */
/* Return a pointer to at least SIZE bytes of storage,
which will be automatically reclaimed upon exit from
the procedure that called alloca. Originally, this space
was supposed to be taken from the current stack frame of the
caller, but that method cannot be made to work for some
implementations of C, for example under Gould's UTX/32. */
pointer
alloca (size)
unsigned size;
{
auto char probe; /* Probes stack depth: */
register char *depth = ADDRESS_FUNCTION (probe);
#if STACK_DIRECTION == 0
if (STACK_DIR == 0) /* Unknown growth direction. */
find_stack_direction ();
#endif
/* Reclaim garbage, defined as all alloca'd storage that
was allocated from deeper in the stack than currently. */
{
register header *hp; /* Traverses linked list. */
#ifdef emacs
BLOCK_INPUT;
#endif
for (hp = last_alloca_header; hp != NULL;)
if ((STACK_DIR > 0 && hp->h.deep > depth)
|| (STACK_DIR < 0 && hp->h.deep < depth))
{
register header *np = hp->h.next;
free ((pointer) hp); /* Collect garbage. */
hp = np; /* -> next header. */
}
else
break; /* Rest are not deeper. */
last_alloca_header = hp; /* -> last valid storage. */
#ifdef emacs
UNBLOCK_INPUT;
#endif
}
if (size == 0)
return NULL; /* No allocation required. */
/* Allocate combined header + user data storage. */
{
register pointer new = malloc (sizeof (header) + size);
/* Address of header. */
((header *) new)->h.next = last_alloca_header;
((header *) new)->h.deep = depth;
last_alloca_header = (header *) new;
/* User storage begins just after header. */
return (pointer) ((char *) new + sizeof (header));
}
}
#if defined (CRAY) && defined (CRAY_STACKSEG_END)
#ifdef DEBUG_I00AFUNC
#include
#endif
#ifndef CRAY_STACK
#define CRAY_STACK
#ifndef CRAY2
/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
struct stack_control_header
{
long shgrow:32; /* Number of times stack has grown. */
long shaseg:32; /* Size of increments to stack. */
long shhwm:32; /* High water mark of stack. */
long shsize:32; /* Current size of stack (all segments). */
};
/* The stack segment linkage control information occurs at
the high-address end of a stack segment. (The stack
grows from low addresses to high addresses.) The initial
part of the stack segment linkage control information is
0200 (octal) words. This provides for register storage
for the routine which overflows the stack. */
struct stack_segment_linkage
{
long ss[0200]; /* 0200 overflow words. */
long sssize:32; /* Number of words in this segment. */
long ssbase:32; /* Offset to stack base. */
long:32;
long sspseg:32; /* Offset to linkage control of previous
segment of stack. */
long:32;
long sstcpt:32; /* Pointer to task common address block. */
long sscsnm; /* Private control structure number for
microtasking. */
long ssusr1; /* Reserved for user. */
long ssusr2; /* Reserved for user. */
long sstpid; /* Process ID for pid based multi-tasking. */
long ssgvup; /* Pointer to multitasking thread giveup. */
long sscray[7]; /* Reserved for Cray Research. */
long ssa0;
long ssa1;
long ssa2;
long ssa3;
long ssa4;
long ssa5;
long ssa6;
long ssa7;
long sss0;
long sss1;
long sss2;
long sss3;
long sss4;
long sss5;
long sss6;
long sss7;
};
#else /* CRAY2 */
/* The following structure defines the vector of words
returned by the STKSTAT library routine. */
struct stk_stat
{
long now; /* Current total stack size. */
long maxc; /* Amount of contiguous space which would
be required to satisfy the maximum
stack demand to date. */
long high_water; /* Stack high-water mark. */
long overflows; /* Number of stack overflow ($STKOFEN) calls. */
long hits; /* Number of internal buffer hits. */
long extends; /* Number of block extensions. */
long stko_mallocs; /* Block allocations by $STKOFEN. */
long underflows; /* Number of stack underflow calls ($STKRETN). */
long stko_free; /* Number of deallocations by $STKRETN. */
long stkm_free; /* Number of deallocations by $STKMRET. */
long segments; /* Current number of stack segments. */
long maxs; /* Maximum number of stack segments so far. */
long pad_size; /* Stack pad size. */
long current_address; /* Current stack segment address. */
long current_size; /* Current stack segment size. This
number is actually corrupted by STKSTAT to
include the fifteen word trailer area. */
long initial_address; /* Address of initial segment. */
long initial_size; /* Size of initial segment. */
};
/* The following structure describes the data structure which trails
any stack segment. I think that the description in 'asdef' is
out of date. I only describe the parts that I am sure about. */
struct stk_trailer
{
long this_address; /* Address of this block. */
long this_size; /* Size of this block (does not include
this trailer). */
long unknown2;
long unknown3;
long link; /* Address of trailer block of previous
segment. */
long unknown5;
long unknown6;
long unknown7;
long unknown8;
long unknown9;
long unknown10;
long unknown11;
long unknown12;
long unknown13;
long unknown14;
};
#endif /* CRAY2 */
#endif /* not CRAY_STACK */
#ifdef CRAY2
/* Determine a "stack measure" for an arbitrary ADDRESS.
I doubt that "lint" will like this much. */
static long
i00afunc (long *address)
{
struct stk_stat status;
struct stk_trailer *trailer;
long *block, size;
long result = 0;
/* We want to iterate through all of the segments. The first
step is to get the stack status structure. We could do this
more quickly and more directly, perhaps, by referencing the
$LM00 common block, but I know that this works. */
STKSTAT (&status);
/* Set up the iteration. */
trailer = (struct stk_trailer *) (status.current_address
+ status.current_size
- 15);
/* There must be at least one stack segment. Therefore it is
a fatal error if "trailer" is null. */
if (trailer == 0)
abort ();
/* Discard segments that do not contain our argument address. */
while (trailer != 0)
{
block = (long *) trailer->this_address;
size = trailer->this_size;
if (block == 0 || size == 0)
abort ();
trailer = (struct stk_trailer *) trailer->link;
if ((block <= address) && (address < (block + size)))
break;
}
/* Set the result to the offset in this segment and add the sizes
of all predecessor segments. */
result = address - block;
if (trailer == 0)
{
return result;
}
do
{
if (trailer->this_size <= 0)
abort ();
result += trailer->this_size;
trailer = (struct stk_trailer *) trailer->link;
}
while (trailer != 0);
/* We are done. Note that if you present a bogus address (one
not in any segment), you will get a different number back, formed
from subtracting the address of the first block. This is probably
not what you want. */
return (result);
}
#else /* not CRAY2 */
/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
Determine the number of the cell within the stack,
given the address of the cell. The purpose of this
routine is to linearize, in some sense, stack addresses
for alloca. */
static long
i00afunc (long address)
{
long stkl = 0;
long size, pseg, this_segment, stack;
long result = 0;
struct stack_segment_linkage *ssptr;
/* Register B67 contains the address of the end of the
current stack segment. If you (as a subprogram) store
your registers on the stack and find that you are past
the contents of B67, you have overflowed the segment.
B67 also points to the stack segment linkage control
area, which is what we are really interested in. */
stkl = CRAY_STACKSEG_END ();
ssptr = (struct stack_segment_linkage *) stkl;
/* If one subtracts 'size' from the end of the segment,
one has the address of the first word of the segment.
If this is not the first segment, 'pseg' will be
nonzero. */
pseg = ssptr->sspseg;
size = ssptr->sssize;
this_segment = stkl - size;
/* It is possible that calling this routine itself caused
a stack overflow. Discard stack segments which do not
contain the target address. */
while (!(this_segment <= address && address <= stkl))
{
#ifdef DEBUG_I00AFUNC
fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
#endif
if (pseg == 0)
break;
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
this_segment = stkl - size;
}
result = address - this_segment;
/* If you subtract pseg from the current end of the stack,
you get the address of the previous stack segment's end.
This seems a little convoluted to me, but I'll bet you save
a cycle somewhere. */
while (pseg != 0)
{
#ifdef DEBUG_I00AFUNC
fprintf (stderr, "%011o %011o\n", pseg, size);
#endif
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
result += size;
}
return (result);
}
#endif /* not CRAY2 */
#endif /* CRAY */
#endif /* no alloca */
#endif /* not GCC version 2 */
texinfo-3.7/libtxi/bzero.c 100666 11732 13 2527 5770343615 14032 0 ustar bfox user /*
* Copyright (C) 1993 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 59 Temple Place - Suite 330. Boston, MA 02111-1307, USA.
*/
#if !defined (HAVE_MEMSET) && !defined (HAVE_BZERO)
void
bzero (b, length)
register char *b;
register int length;
{
#ifdef VMS /* but this is definitely VMS-specific */
short zero = 0;
long max_str = 65535;
while (length > max_str)
{
(void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
length -= max_str;
b += max_str;
}
(void) LIB$MOVC5 (&zero, &zero, &zero, &length, b);
#else
while (length-- > 0)
*b++ = 0;
#endif /* not VMS */
}
#endif /* not HAVE_MEMSET && not HAVE_BZERO */
texinfo-3.7/libtxi/getopt.c 100666 11732 13 53266 5770343621 14236 0 ustar bfox user /* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This tells Alpha OSF/1 not to define a getopt prototype in .
Ditto for AIX 3.2 and . */
#ifndef _NO_PROTO
#define _NO_PROTO
#endif
#ifdef HAVE_CONFIG_H
#include
#endif
#if !defined (__STDC__) || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
#include
#endif /* GNU C library. */
/* This is for other GNU distributions with internationalized messages.
The GNU C Library itself does not yet support such messages. */
#if HAVE_LIBINTL_H
# include
#else
# define gettext(msgid) (msgid)
#endif
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
#include "getopt.h"
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = NULL;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* XXX 1003.2 says this must be 1 before any call. */
int optind = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
int optopt = '?';
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Value of POSIXLY_CORRECT environment variable. */
static char *posixly_correct;
#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
#include
#define my_index strchr
#else
/* Avoid depending on library functions or files
whose names are inconsistent. */
char *getenv ();
static char *
my_index (str, chr)
const char *str;
int chr;
{
while (*str)
{
if (*str == chr)
return (char *) str;
str++;
}
return 0;
}
/* If using GCC, we can safely declare strlen this way.
If not using GCC, it is ok not to declare it. */
#ifdef __GNUC__
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
That was relevant to code that was here before. */
#if !defined (__STDC__) || !__STDC__
/* gcc with -traditional declares the built-in strlen to return int,
and has done so at least since version 2.4.5. -- rms. */
extern int strlen (const char *);
#endif /* not __STDC__ */
#endif /* __GNUC__ */
#endif /* not __GNU_LIBRARY__ */
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
static void
exchange (argv)
char **argv;
{
int bottom = first_nonopt;
int middle = last_nonopt;
int top = optind;
char *tem;
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
register int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
register int i;
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
}
}
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* Initialize the internal data when the first call is made. */
static const char *
_getopt_initialize (optstring)
const char *optstring;
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
first_nonopt = last_nonopt = optind = 1;
nextchar = NULL;
posixly_correct = getenv ("POSIXLY_CORRECT");
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
return optstring;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns `EOF'.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
int
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int argc;
char *const *argv;
const char *optstring;
const struct option *longopts;
int *longind;
int long_only;
{
optarg = NULL;
if (optind == 0)
{
optstring = _getopt_initialize (optstring);
optind = 1; /* Don't scan ARGV[0], the program name. */
}
if (nextchar == NULL || *nextchar == '\0')
{
/* Advance to the next ARGV-element. */
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0'))
optind++;
last_nonopt = optind;
}
/* The special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return EOF;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Skip the initial punctuation. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
/* Decode the current option-ARGV-element. */
/* Check whether the ARGV-element is a long option.
If long_only and the ARGV-element has the form "-f", where f is
a valid short option, don't consider it an abbreviated form of
a long option that starts with f. Otherwise there would be no
way to give the -f short option.
On the other hand, if there's a long option "fubar" and
the ARGV-element is "-fu", do consider that an abbreviation of
the long option, just like "--fu", and not "-f" with arg "u".
This distinction seems to be the most useful approach. */
if (longopts != NULL
&& (argv[optind][1] == '-'
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound;
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if (nameend - nextchar == strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, gettext ("%s: option `%s' is ambiguous\n"),
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (opterr)
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
gettext ("%s: option `--%s' doesn't allow an argument\n"),
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
gettext ("%s: option `%c%s' doesn't allow an argument\n"),
argv[0], argv[optind - 1][0], pfound->name);
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr,
gettext ("%s: option `%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, gettext ("%s: unrecognized option `--%s'\n"),
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, gettext ("%s: unrecognized option `%c%s'\n"),
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
return '?';
}
}
/* Look at and handle the next short option-character. */
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (opterr)
{
if (posixly_correct)
/* 1003.2 specifies the format of this message. */
fprintf (stderr, gettext ("%s: illegal option -- %c\n"),
argv[0], c);
else
fprintf (stderr, gettext ("%s: invalid option -- %c\n"),
argv[0], c);
}
optopt = c;
return '?';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = NULL;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr,
gettext ("%s: option requires an argument -- %c\n"),
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int
getopt (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}
#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */
texinfo-3.7/libtxi/getopt.h 100666 11732 13 10547 5770343630 14236 0 ustar bfox user /* Declarations for getopt.
Copyright (C) 1989, 90, 91, 92, 93, 94 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if defined (__STDC__) && __STDC__
#ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt ();
#endif /* __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H */
texinfo-3.7/libtxi/getopt1.c 100666 11732 13 10257 5770343625 14314 0 ustar bfox user /* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifdef HAVE_CONFIG_H
#include
#endif
#include "getopt.h"
#if !defined (__STDC__) || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include
#else
char *getenv ();
#endif
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
#include
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == EOF)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */
texinfo-3.7/emacs/ 40777 11732 13 0 6067136362 12236 5 ustar bfox user texinfo-3.7/emacs/Makefile.in 100666 11732 13 5447 6067061545 14412 0 ustar bfox user # Makefile for Texinfo/emacs. -*- Indented-Text -*-
# Copyright (C) 1995 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Author: Brian J. Fox (bfox@ai.mit.edu)
#
#### Start of system configuration section. ####
RM = rm -f
CP = cp
srcdir = @srcdir@
VPATH = $(srcdir)
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = $(exec_prefix)/bin
# Prefix for each installed program, normally empty or `g'.
binprefix =
libdir = $(prefix)/lib
# Prefix for each installed man page, normally empty or `g'.
manprefix =
mandir = $(prefix)/man/man1
manext = 1
infodir = $(prefix)/info
lispdir = $(libdir)/emacs/site-lisp
#### End of system configuration section. ####
ELISP_SRCS = info.el makeinfo.el texinfo.el texnfo-upd.el \
texnfo-tex.el texinfmt.el informat.el detexinfo.el
ELISP_OBJS = info.elc makeinfo.elc texinfo.elc texnfo-upd.elc \
texnfo-tex.elc texinfmt.elc informat.elc detexinfo.elc
.SUFFIXES: .el .elc
.el.elc:
$(srcdir)/elisp-comp $<
all: $(ELISP_OBJS)
sub-all: all
# Nobody likes any of these install targets. Fine. Install it
# manually, then.
install:
@echo Please install the lisp files manually.
uninstall:
@echo Nothing to be done for uninstall.
# install: $(ELISP_OBJS)
# @(echo "(print (car load-path))" >/tmp/elc.$$$$; \
# lispdir=`emacs -batch -q -l /tmp/elc.$$$$ -nw | grep site-lisp`; \
# rm /tmp/elc.$$$$; \
# if [ "$$lispdir" != "" ]; then \
# lispdir=`echo $$lispdir | sed -e 's/"//g'`; \
# echo "Installing .elc files in $$lispdir."; \
# $(CP) $(ELISP_OBJS) $$lispdir; \
# else \
# echo "To install the elisp files, please copy *.elc to the"; \
# echo "emacs site-lisp directory."; \
# fi)
#
# install: $(ELISP_OBJS)
# for file in $(ELISP_OBJS); do \
# $(INSTALL_DATA) $$file $(lispdir); \
# done
#
# uninstall: $(ELISP_OBJS)
# cd $(lispdir) && rm -f $(ELISP_OBJS)
#
informat.elc: info.elc
makeinfo.elc: texinfo.elc
texinfmt.elc: texinfo.elc
texinfmt.elc: texnfo-upd.elc
Makefile: $(srcdir)/Makefile.in ../config.status
cd ..; sh config.status
realclean distclean: clean
$(RM) -f Makefile *.log
clean: FORCE
$(RM) -f *.elc
FORCE:
texinfo-3.7/emacs/detexinfo.el 100666 12120 13 22637 5771054222 14522 0 ustar rms user ;;; Here is a handy keybinding:
(global-set-key "\C-x\\" 'detexinfo)
;;;;;;;;;;;;;;;; detexinfo.el ;;;;;;;;;;;;;;;;
;;;
;;; Remove Texinfo commands from a Texinfo source file.
;;;
;;; Copyright (C) 1991, 1992 Free Software Foundation
;;; Robert J. Chassell
;;; bugs to bug-texinfo@prep.ai.mit.edu
;;;
;;; ==> test version <==
;;; Fails if Texinfo source file contains formatting errors.
;;;
;;; Version 0.05 - 3 Jun 1992
;;; Add to list of removed commands. Improve messages.
;;;
;;; Version 0.04 - 27 Jan 1992
;;; Rewrite to insert detexinfo'd text into a temporary buffer.
;;;
;;; Version 0.03 - 27 Dec 1991
;;; Improved messages.
;;;
;;; Version 0.02 - 13 Nov 1991
;;; detexinfo-remove-inline-cmd, detexinfo-syntax-table: Handle
;;; nested commands.
;;; detexinfo: Handle nested @'s, eg @samp{@}} and @samp{@@};
;;; replace @TeX{} with TeX.
;;;
;;; Version 0.01 - 13 Nov 1991
;;;
;;; Based on detex.el, by Bengt Martensson, 4 Oct 1987
;;;
;;;;;;;;;;;;;;;;
(defvar detexinfo-buffer-name "*detexinfo*"
"*Name of the temporary buffer used by \\[detexinfo].")
(defvar detexinfo-syntax-table nil)
(if detexinfo-syntax-table
nil
(setq detexinfo-syntax-table (make-syntax-table))
(modify-syntax-entry ?\[ "." detexinfo-syntax-table)
(modify-syntax-entry ?\] "." detexinfo-syntax-table)
(modify-syntax-entry ?\" "." detexinfo-syntax-table)
(modify-syntax-entry ?\\ "." detexinfo-syntax-table)
(modify-syntax-entry ?\( "." detexinfo-syntax-table)
(modify-syntax-entry ?\) "." detexinfo-syntax-table)
(modify-syntax-entry ?{ "(}" detexinfo-syntax-table)
(modify-syntax-entry ?} "){" detexinfo-syntax-table))
(defun detexinfo ()
"Remove Texinfo commands from current buffer, copying result to new buffer.
BUG: Fails if Texinfo source file contains formatting errors."
(interactive)
(let ((input-buffer (current-buffer)))
;; Find a buffer to use.
(switch-to-buffer (get-buffer-create detexinfo-buffer-name))
(setq major-mode 'detexinfo-mode)
(set-syntax-table detexinfo-syntax-table)
(erase-buffer)
(insert-buffer-substring input-buffer)
;; Replace @{ and @} with %#* and *#% temporarily, so @samp{@{} works.
;; What is a better way of doing this??
(goto-char (point-min))
(while (search-forward "@{" nil t) ; e.g., @samp{@{}
(replace-match "%#*"))
(goto-char (point-min))
(while (search-forward "@}" nil t)
(forward-char -3) ; e.g., @samp{@@}
(if (looking-at "@") ; Two @@ in a row
(progn
(delete-char 2)
(insert "%&%#"))
(forward-char 1)
(delete-char 2)
(insert "*#%")))
(goto-char (point-min))
;; Remove @refill, the only inline command without braces.
(while (search-forward "@refill" nil t)
(replace-match ""))
;; Replace @TeX{} with TeX
(goto-char (point-min))
(while (search-forward "@TeX{}" nil t) (replace-match "TeX" t t))
(detexinfo-remove-line-cmds-without-arg)
(detexinfo-remove-inline-cmds-without-arg)
(detexinfo-remove-inline-cmds-keep-arg)
(detexinfo-remove-line-cmds-deletable-arg)
(detexinfo-remove-line-cmds-maybe-delete-arg)
(detexinfo-remove-line-cmds-keep-arg)
;; Now replace %#*, *#%, and %&%# with {, }, and @@.
(goto-char (point-min))
(while (search-forward "%#*" nil t)
(replace-match "{"))
(goto-char (point-min))
(while (search-forward "*#%" nil t)
(replace-match "}"))
(goto-char (point-min))
(while (search-forward "%&%#" nil t)
(replace-match "@@"))
;; Scan for remaining two character @-commands
(goto-char (point-min))
(while (search-forward "@" nil t)
(cond ((looking-at "[*:]")
(delete-region (1- (point)) (1+ (point))))
((looking-at "[{}^@.'`]\"?!")
(delete-region (1- (point)) (point)))))
(goto-char (point-min))
(message "Done...removed Texinfo commands from buffer. You may save it.")))
(defun detexinfo-remove-whole-line (cmd)
"Delete Texinfo line command CMD at beginning of line and rest of line."
(goto-char (point-min))
(while
(re-search-forward
(concat "^@" cmd "[ \n]+") (point-max) t)
(goto-char (match-beginning 0))
(delete-region
(point) (save-excursion (end-of-line) (1+ (point))))))
(defun detexinfo-remove-inline-cmd (cmd)
"Delete Texinfo inline command CMD, eg. @point, @code."
(goto-char (point-min))
(while
(re-search-forward (concat "@" cmd "{") (point-max) t)
(save-excursion
(forward-char -1)
(forward-sexp 1)
(delete-char -1)) ; delete right brace
(delete-region (point) (match-beginning 0))))
;;;;;;;;;;;;;;;;
;;; 1. @setfilename and other line commands with args to delete
(defvar detexinfo-line-cmds-deletable-arg
'("enumerate" "ftable" "vtable" "itemize" "table"
"setfilename" "settitle" "setchapternewpage"
"footnotestyle" "paragraphindent"
"include" "need" "sp"
"clear" "ifclear" "ifset" "set"
"defcodeindex" "defindex" "syncodeindex" "synindex")
"List of Texinfo commands whose arguments should be deleted.")
(defun detexinfo-remove-line-cmds-deletable-arg ()
"Delete Texinfo line commands together with their args, eg @setfilename."
(message "Removing commands such as @enumerate...with their arguments...")
(mapcar 'detexinfo-remove-whole-line
detexinfo-line-cmds-deletable-arg))
;;; 2. @cindex and other cmds with args that may be deleted
;;; This list is here just to make it easier to revise the
;;; categories. In particular, you might want to keep the index entries.
(defvar detexinfo-line-cmds-maybe-delete-arg
'("cindex" "findex" "kindex" "pindex" "tindex" "vindex" "node"
"c" "comment" "end" "headings" "printindex" "vskip"
"evenfooting" "evenheading" "everyfooting" "everyheading"
"oddfooting" "oddheading")
"List of Texinfo commands whose arguments may possibly be deleted.")
(defun detexinfo-remove-line-cmds-maybe-delete-arg ()
"Delete Texinfo line commands together with their arguments, eg, @cindex."
(message "Removing commands such as @cindex...with their arguments...")
(mapcar 'detexinfo-remove-whole-line
detexinfo-line-cmds-maybe-delete-arg))
;;; 3. @chapter and other line cmds with args to keep.
(defvar detexinfo-line-cmds-keep-arg
'("top" "chapter" "section" "subsection" "subsubsection"
"unnumbered" "unnumberedsec" "unnumberedsubsec" "unnumberedsubsubsec"
"majorheading" "chapheading" "heading" "subheading" "subsubheading"
"appendix" "appendixsec" "appendixsubsec" "appendixsubsubsec"
"item" "itemx"
"title" "subtitle" "center" "author" "exdent"
"defcv" "deffn" "defivar" "defmac" "defmethod" "defop" "defopt"
"defspec" "deftp" "deftypefn" "deftypefun" "deftypvr"
"deftypevar" "defun" "defvar" "defvr")
"List of Texinfo line commands whose arguments should be kept.")
(defun detexinfo-remove-line-cmds-keep-arg ()
"Delete Texinfo line commands but keep their arguments, eg @chapter."
(message "Removing commands such as @chapter...but not their arguments...")
(mapcar 'detexinfo-remove-line-cmd-keep-arg
detexinfo-line-cmds-keep-arg))
(defun detexinfo-remove-line-cmd-keep-arg (cmd)
"Delete Texinfo line command CMD but keep its argument, eg @chapter."
(goto-char (point-min))
(while
(re-search-forward
(concat "^@" cmd "[ \n]+") (point-max) t)
(delete-region (match-beginning 0) (match-end 0))))
;;; 4. @bye and other line commands without args.
(defvar detexinfo-line-cmds-without-arg
'("bye" "contents" "display" "example" "finalout"
"flushleft" "flushright" "format" "group" "ifhtml" "ifinfo" "iftex"
"ignore" "lisp" "menu" "noindent" "page" "quotation"
"shortcontents" "smallbook" "smallexample" "smalllisp"
"summarycontents" "tex" "thischapter" "thischaptername"
"thisfile" "thispage" "thissection" "thistitle" "titlepage")
"List of Texinfo commands without arguments that should be deleted.")
(defun detexinfo-remove-line-cmds-without-arg ()
"Delete line Texinfo commands that lack args, eg. @example."
(message "Removing commands such as @example...that lack arguments...")
(mapcar 'detexinfo-remove-whole-line
detexinfo-line-cmds-without-arg))
;;; 5. @equiv and other inline cmds without args.
(defvar detexinfo-inline-cmds-without-arg
'("equiv" "error" "expansion" "point" "print" "result"
"asis" "br" "bullet" "dots" "minus" "today")
"List of Texinfo inline commands without arguments that should be deleted.")
(defun detexinfo-remove-inline-cmds-without-arg ()
"Delete Texinfo inline commands in that lack arguments."
(message "Removing within line commands such as @result...")
(mapcar 'detexinfo-remove-inline-cmd
detexinfo-inline-cmds-without-arg))
;;; 6. @code and other inline cmds with args to keep
(defvar detexinfo-inline-cmds-keep-arg
'("b" "cartouche" "cite" "code" "copyright" "ctrl" "dfn" "dmn"
"emph" "file" "footnote" "i" "inforef"
"kbd" "key" "pxref" "r" "ref" "samp" "sc" "titlefont"
"strong" "t" "var" "w" "xref")
"List of Texinfo inline commands with arguments that should be kept.")
(defun detexinfo-remove-inline-cmds-keep-arg ()
"Delete Texinfo inline commands but keep its arg, eg. @code."
(message
"Removing within line commands such as @code...but not their arguments...")
(mapcar 'detexinfo-remove-inline-cmd
detexinfo-inline-cmds-keep-arg))
;;;;;;;;;;;;;;;; end detexinfo.el ;;;;;;;;;;;;;;;;
texinfo-3.7/emacs/elisp-comp 100777 11732 13 227 5767640073 14317 0 ustar bfox user #!/bin/sh
setpath=/tmp/elc.$$
echo "(setq load-path (cons nil load-path))" > $setpath
emacs -batch -l $setpath -f batch-byte-compile $*
rm -f $setpath
texinfo-3.7/emacs/info.el 100444 11732 13 201040 6054440170 13626 0 ustar bfox user ;;; info.el --- info package for Emacs.
;; Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: help
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Commentary:
;;; Note that nowadays we expect info files to be made using makeinfo.
;;; Code:
(defvar Info-history nil
"List of info nodes user has visited.
Each element of list is a list (FILENAME NODENAME BUFFERPOS).")
(defvar Info-enable-edit nil
"*Non-nil means the \\\\[Info-edit] command in Info can edit the current node.
This is convenient if you want to write info files by hand.
However, we recommend that you not do this.
It is better to write a Texinfo file and generate the Info file from that,
because that gives you a printed manual as well.")
(defvar Info-enable-active-nodes t
"Non-nil allows Info to execute Lisp code associated with nodes.
The Lisp code is executed when the node is selected.")
(defvar Info-fontify t
"*Non-nil enables highlighting and fonts in Info nodes.")
(defvar Info-fontify-maximum-menu-size 30000
"*Maximum size of menu to fontify if `Info-fontify' is non-nil.")
(defvar Info-directory-list
(let ((path (getenv "INFOPATH"))
;; This is for older Emacs versions
;; which might get this info.el from the Texinfo distribution.
(path-separator (if (boundp 'path-separator) path-separator
(if (eq system-type 'ms-dos) ";" ":")))
(source (expand-file-name "info/" source-directory))
(sibling (if installation-directory
(expand-file-name "info/" installation-directory)))
alternative)
(if path
(let ((list nil)
idx)
(while (> (length path) 0)
(setq idx (or (string-match path-separator path) (length path))
list (cons (substring path 0 idx) list)
path (substring path (min (1+ idx)
(length path)))))
(nreverse list))
(if (and sibling (file-exists-p sibling))
(setq alternative sibling)
(setq alternative source))
(if (or (member alternative Info-default-directory-list)
(not (file-exists-p alternative))
;; On DOS/NT, we use movable executables always,
;; and we must always find the Info dir at run time.
(if (or (eq system-type 'ms-dos) (eq system-type 'windows-nt))
nil
;; Use invocation-directory for Info only if we used it for
;; exec-directory also.
(not (string= exec-directory
(expand-file-name "lib-src/"
installation-directory)))))
Info-default-directory-list
(reverse (cons alternative
(cdr (reverse Info-default-directory-list)))))))
"List of directories to search for Info documentation files.
nil means not yet initialized. In this case, Info uses the environment
variable INFOPATH to initialize it, or `Info-default-directory-list'
if there is no INFOPATH variable in the environment.
The last element of `Info-default-directory-list' is the directory
where Emacs installs the Info files that come with it.
If you run the Emacs executable from the `src' directory in the Emacs
source tree, the `info' directory in the source tree is used as the last
element, in place of the installation Info directory. This is useful
when you run a version of Emacs without installing it.")
(defvar Info-additional-directory-list nil
"List of additional directories to search for Info documentation files.
These directories are not searched for merging the `dir' file.")
(defvar Info-current-file nil
"Info file that Info is now looking at, or nil.
This is the name that was specified in Info, not the actual file name.
It doesn't contain directory names or file name extensions added by Info.")
(defvar Info-current-subfile nil
"Info subfile that is actually in the *info* buffer now,
or nil if current info file is not split into subfiles.")
(defvar Info-current-node nil
"Name of node that Info is now looking at, or nil.")
(defvar Info-tag-table-marker (make-marker)
"Marker pointing at beginning of current Info file's tag table.
Marker points nowhere if file has no tag table.")
(defvar Info-current-file-completions nil
"Cached completion list for current Info file.")
(defvar Info-index-alternatives nil
"List of possible matches for last Info-index command.")
(defvar Info-standalone nil
"Non-nil if Emacs was started solely as an Info browser.")
(defvar Info-suffix-list
(if (eq system-type 'ms-dos)
'( (".gz" . "gunzip")
(".z" . "gunzip")
(".inf" . nil)
("" . nil))
'( (".info.Z" . "uncompress")
(".info.Y" . "unyabba")
(".info.gz" . "gunzip")
(".info.z" . "gunzip")
(".info" . nil)
(".Z" . "uncompress")
(".Y" . "unyabba")
(".gz" . "gunzip")
(".z" . "gunzip")
("" . nil)))
"List of file name suffixes and associated decoding commands.
Each entry should be (SUFFIX . STRING); the file is given to
the command as standard input. If STRING is nil, no decoding is done.
Because the SUFFIXes are tried in order, the empty string should
be last in the list.")
;; Concatenate SUFFIX onto FILENAME. SUFFIX should start with a dot.
;; First, on ms-dos, delete some of the extension in FILENAME
;; to make room.
(defun info-insert-file-contents-1 (filename suffix)
(if (not (eq system-type 'ms-dos))
(concat filename suffix)
(let* ((sans-exts (file-name-sans-extension filename))
;; How long is the extension in FILENAME (not counting the dot).
(ext-len (max 0 (- (length filename) (length sans-exts) 1)))
ext-left)
;; SUFFIX starts with a dot. If FILENAME already has one,
;; get rid of the one in SUFFIX.
(or (and (<= ext-len 0)
(not (eq (aref filename (1- (length filename))) ?.)))
(setq suffix (substring suffix 1)))
;; How many chars of that extension should we keep?
(setq ext-left (min ext-len (max 0 (- 3 (length suffix)))))
;; Get rid of the rest of the extension, and add SUFFIX.
(concat (substring filename 0 (- (length filename)
(- ext-len ext-left)))
suffix))))
(defun info-insert-file-contents (filename &optional visit)
"Insert the contents of an info file in the current buffer.
Do the right thing if the file has been compressed or zipped."
(let ((tail Info-suffix-list)
fullname decoder)
(if (file-exists-p filename)
;; FILENAME exists--see if that name contains a suffix.
;; If so, set DECODE accordingly.
(progn
(while (and tail
(not (string-match
(concat (regexp-quote (car (car tail))) "$")
filename)))
(setq tail (cdr tail)))
(setq fullname filename
decoder (cdr (car tail))))
;; Try adding suffixes to FILENAME and see if we can find something.
(while (and tail
(not (file-exists-p (info-insert-file-contents-1
filename (car (car tail))))))
(setq tail (cdr tail)))
;; If we found a file with a suffix, set DECODER according to the suffix
;; and set FULLNAME to the file's actual name.
(setq fullname (info-insert-file-contents-1 filename (car (car tail)))
decoder (cdr (car tail)))
(or tail
(error "Can't find %s or any compressed version of it" filename)))
;; check for conflict with jka-compr
(if (and (featurep 'jka-compr)
(jka-compr-installed-p)
(jka-compr-get-compression-info fullname))
(setq decoder nil))
(insert-file-contents fullname visit)
(if decoder
(let ((buffer-read-only nil)
(default-directory (or (file-name-directory fullname)
default-directory)))
(call-process-region (point-min) (point-max) decoder t t)))))
;;;###autoload (add-hook 'same-window-buffer-names "*info*")
;;;###autoload
(defun info (&optional file)
"Enter Info, the documentation browser.
Optional argument FILE specifies the file to examine;
the default is the top-level directory of Info.
In interactive use, a prefix argument directs this command
to read a file name from the minibuffer."
(interactive (if current-prefix-arg
(list (read-file-name "Info file name: " nil nil t))))
(if file
(Info-goto-node (concat "(" file ")"))
(if (get-buffer "*info*")
(pop-to-buffer "*info*")
(Info-directory))))
;;;###autoload
(defun info-standalone ()
"Run Emacs as a standalone Info reader.
Usage: emacs -f info-standalone [filename]
In standalone mode, \\\\[Info-exit] exits Emacs itself."
(setq Info-standalone t)
(if (and command-line-args-left
(not (string-match "^-" (car command-line-args-left))))
(condition-case err
(progn
(info (car command-line-args-left))
(setq command-line-args-left (cdr command-line-args-left)))
(error (send-string-to-terminal
(format "%s\n" (if (eq (car-safe err) 'error)
(nth 1 err) err)))
(save-buffers-kill-emacs)))
(info)))
;; Go to an info node specified as separate filename and nodename.
;; no-going-back is non-nil if recovering from an error in this function;
;; it says do not attempt further (recursive) error recovery.
(defun Info-find-node (filename nodename &optional no-going-back)
;; Convert filename to lower case if not found as specified.
;; Expand it.
(if filename
(let (temp temp-downcase found)
(setq filename (substitute-in-file-name filename))
(if (string= (downcase (file-name-nondirectory filename)) "dir")
(setq found t)
(let ((dirs (if (string-match "^\\./" filename)
;; If specified name starts with `./'
;; then just try current directory.
'("./")
(if (file-name-absolute-p filename)
;; No point in searching for an
;; absolute file name
'(nil)
(if Info-additional-directory-list
(append Info-directory-list
Info-additional-directory-list)
Info-directory-list)))))
;; Search the directory list for file FILENAME.
(while (and dirs (not found))
(setq temp (expand-file-name filename (car dirs)))
(setq temp-downcase
(expand-file-name (downcase filename) (car dirs)))
;; Try several variants of specified name.
(let ((suffix-list Info-suffix-list))
(while (and suffix-list (not found))
(cond ((file-exists-p
(info-insert-file-contents-1
temp (car (car suffix-list))))
(setq found temp))
((file-exists-p
(info-insert-file-contents-1
temp-downcase (car (car suffix-list))))
(setq found temp-downcase)))
(setq suffix-list (cdr suffix-list))))
(setq dirs (cdr dirs)))))
(if found
(setq filename found)
(error "Info file %s does not exist" filename))))
;; Record the node we are leaving.
(if (and Info-current-file (not no-going-back))
(setq Info-history
(cons (list Info-current-file Info-current-node (point))
Info-history)))
;; Go into info buffer.
(switch-to-buffer "*info*")
(buffer-disable-undo (current-buffer))
(or (eq major-mode 'Info-mode)
(Info-mode))
(widen)
(setq Info-current-node nil)
(unwind-protect
(progn
;; Switch files if necessary
(or (null filename)
(equal Info-current-file filename)
(let ((buffer-read-only nil))
(setq Info-current-file nil
Info-current-subfile nil
Info-current-file-completions nil
Info-index-alternatives nil
buffer-file-name nil)
(erase-buffer)
(if (eq filename t)
(Info-insert-dir)
(info-insert-file-contents filename t)
(setq default-directory (file-name-directory filename)))
(set-buffer-modified-p nil)
;; See whether file has a tag table. Record the location if yes.
(set-marker Info-tag-table-marker nil)
(goto-char (point-max))
(forward-line -8)
;; Use string-equal, not equal, to ignore text props.
(or (string-equal nodename "*")
(not (search-forward "\^_\nEnd tag table\n" nil t))
(let (pos)
;; We have a tag table. Find its beginning.
;; Is this an indirect file?
(search-backward "\nTag table:\n")
(setq pos (point))
(if (save-excursion
(forward-line 2)
(looking-at "(Indirect)\n"))
;; It is indirect. Copy it to another buffer
;; and record that the tag table is in that buffer.
(save-excursion
(let ((buf (current-buffer)))
(set-buffer (get-buffer-create " *info tag table*"))
(buffer-disable-undo (current-buffer))
(setq case-fold-search t)
(erase-buffer)
(insert-buffer-substring buf)
(set-marker Info-tag-table-marker
(match-end 0))))
(set-marker Info-tag-table-marker pos))))
(setq Info-current-file
(if (eq filename t) "dir" filename))))
;; Use string-equal, not equal, to ignore text props.
(if (string-equal nodename "*")
(progn (setq Info-current-node nodename)
(Info-set-mode-line))
;; Search file for a suitable node.
(let ((guesspos (point-min))
(regexp (concat "Node: *" (regexp-quote nodename) " *[,\t\n\177]")))
;; First get advice from tag table if file has one.
;; Also, if this is an indirect info file,
;; read the proper subfile into this buffer.
(if (marker-position Info-tag-table-marker)
(save-excursion
(set-buffer (marker-buffer Info-tag-table-marker))
(goto-char Info-tag-table-marker)
(if (re-search-forward regexp nil t)
(progn
(setq guesspos (read (current-buffer)))
;; If this is an indirect file,
;; determine which file really holds this node
;; and read it in.
(if (not (eq (current-buffer) (get-buffer "*info*")))
(setq guesspos
(Info-read-subfile guesspos))))
(error "No such node: \"%s\"" nodename))))
(goto-char (max (point-min) (- guesspos 1000)))
;; Now search from our advised position (or from beg of buffer)
;; to find the actual node.
(catch 'foo
(while (search-forward "\n\^_" nil t)
(forward-line 1)
(let ((beg (point)))
(forward-line 1)
(if (re-search-backward regexp beg t)
(throw 'foo t))))
(error "No such node: %s" nodename)))
(Info-select-node)))
;; If we did not finish finding the specified node,
;; go back to the previous one.
(or Info-current-node no-going-back (null Info-history)
(let ((hist (car Info-history)))
(setq Info-history (cdr Info-history))
(Info-find-node (nth 0 hist) (nth 1 hist) t)
(goto-char (nth 2 hist)))))
(goto-char (point-min)))
;; Cache the contents of the (virtual) dir file, once we have merged
;; it for the first time, so we can save time subsequently.
(defvar Info-dir-contents nil)
;; Cache for the directory we decided to use for the default-directory
;; of the merged dir text.
(defvar Info-dir-contents-directory nil)
;; Record the file attributes of all the files from which we
;; constructed Info-dir-contents.
(defvar Info-dir-file-attributes nil)
;; Construct the Info directory node by merging the files named `dir'
;; from various directories. Set the *info* buffer's
;; default-directory to the first directory we actually get any text
;; from.
(defun Info-insert-dir ()
(if (and Info-dir-contents Info-dir-file-attributes
;; Verify that none of the files we used has changed
;; since we used it.
(eval (cons 'and
(mapcar '(lambda (elt)
(let ((curr (file-attributes (car elt))))
;; Don't compare the access time.
(if curr (setcar (nthcdr 4 curr) 0))
(setcar (nthcdr 4 (cdr elt)) 0)
(equal (cdr elt) curr)))
Info-dir-file-attributes))))
(insert Info-dir-contents)
(let ((dirs Info-directory-list)
buffers buffer others nodes dirs-done)
(setq Info-dir-file-attributes nil)
;; Search the directory list for the directory file.
(while dirs
(let ((truename (file-truename (expand-file-name (car dirs)))))
(or (member truename dirs-done)
(member (directory-file-name truename) dirs-done)
;; Try several variants of specified name.
;; Try upcasing, appending `.info', or both.
(let* (file
(attrs
(or
(progn (setq file (expand-file-name "dir" truename))
(file-attributes file))
(progn (setq file (expand-file-name "DIR" truename))
(file-attributes file))
(progn (setq file (expand-file-name "dir.info" truename))
(file-attributes file))
(progn (setq file (expand-file-name "DIR.INFO" truename))
(file-attributes file)))))
(setq dirs-done
(cons truename
(cons (directory-file-name truename)
dirs-done)))
(if attrs
(save-excursion
(or buffers
(message "Composing main Info directory..."))
(set-buffer (generate-new-buffer "info dir"))
(insert-file-contents file)
(setq buffers (cons (current-buffer) buffers)
Info-dir-file-attributes
(cons (cons file attrs)
Info-dir-file-attributes))))))
(setq dirs (cdr dirs))))
(or buffers
(error "Can't find the info directory node"))
;; Distinguish the dir file that comes with Emacs from all the
;; others. Yes, that is really what this is supposed to do.
;; If it doesn't work, fix it.
(setq buffer (car buffers)
others (cdr buffers))
;; Insert the entire original dir file as a start; use its
;; default directory as the default directory for the whole
;; concatenation.
(insert-buffer buffer)
(setq Info-dir-contents-directory (save-excursion
(set-buffer buffer)
default-directory))
;; Look at each of the other buffers one by one.
(while others
(let ((other (car others)))
;; In each, find all the menus.
(save-excursion
(set-buffer other)
(goto-char (point-min))
;; Find each menu, and add an elt to NODES for it.
(while (re-search-forward "^\\* Menu:" nil t)
(let (beg nodename end)
(forward-line 1)
(setq beg (point))
(search-backward "\n\^_")
(search-forward "Node: ")
(setq nodename (Info-following-node-name))
(search-forward "\n\^_" nil 'move)
(beginning-of-line)
(setq end (point))
(setq nodes (cons (list nodename other beg end) nodes))))))
(setq others (cdr others)))
;; Add to the main menu a menu item for each other node.
(re-search-forward "^\\* Menu:")
(forward-line 1)
(let ((menu-items '("top"))
(nodes nodes)
(case-fold-search t)
(end (save-excursion (search-forward "\^_" nil t) (point))))
(while nodes
(let ((nodename (car (car nodes))))
(save-excursion
(or (member (downcase nodename) menu-items)
(re-search-forward (concat "^\\* "
(regexp-quote nodename)
"::")
end t)
(progn
(insert "* " nodename "::" "\n")
(setq menu-items (cons nodename menu-items))))))
(setq nodes (cdr nodes))))
;; Now take each node of each of the other buffers
;; and merge it into the main buffer.
(while nodes
(let ((nodename (car (car nodes))))
(goto-char (point-min))
;; Find the like-named node in the main buffer.
(if (re-search-forward (concat "\n\^_.*\n.*Node: "
(regexp-quote nodename)
"[,\n\t]")
nil t)
(progn
(search-forward "\n\^_" nil 'move)
(beginning-of-line)
(insert "\n"))
;; If none exists, add one.
(goto-char (point-max))
(insert "\^_\nFile: dir\tNode: " nodename "\n\n* Menu:\n\n"))
;; Merge the text from the other buffer's menu
;; into the menu in the like-named node in the main buffer.
(apply 'insert-buffer-substring (cdr (car nodes))))
(setq nodes (cdr nodes)))
;; Kill all the buffers we just made.
(while buffers
(kill-buffer (car buffers))
(setq buffers (cdr buffers)))
(message "Composing main Info directory...done"))
(setq Info-dir-contents (buffer-string)))
(setq default-directory Info-dir-contents-directory))
(defun Info-read-subfile (nodepos)
(set-buffer (marker-buffer Info-tag-table-marker))
(goto-char (point-min))
(search-forward "\n\^_")
(let (lastfilepos
lastfilename)
(forward-line 2)
(catch 'foo
(while (not (looking-at "\^_"))
(if (not (eolp))
(let ((beg (point))
thisfilepos thisfilename)
(search-forward ": ")
(setq thisfilename (buffer-substring beg (- (point) 2)))
(setq thisfilepos (read (current-buffer)))
;; read in version 19 stops at the end of number.
;; Advance to the next line.
(forward-line 1)
(if (> thisfilepos nodepos)
(throw 'foo t))
(setq lastfilename thisfilename)
(setq lastfilepos thisfilepos))
(forward-line 1))))
(set-buffer (get-buffer "*info*"))
(or (equal Info-current-subfile lastfilename)
(let ((buffer-read-only nil))
(setq buffer-file-name nil)
(widen)
(erase-buffer)
(info-insert-file-contents lastfilename)
(set-buffer-modified-p nil)
(setq Info-current-subfile lastfilename)))
(goto-char (point-min))
(search-forward "\n\^_")
(+ (- nodepos lastfilepos) (point))))
;; Select the info node that point is in.
(defun Info-select-node ()
(save-excursion
;; Find beginning of node.
(search-backward "\n\^_")
(forward-line 2)
;; Get nodename spelled as it is in the node.
(re-search-forward "Node:[ \t]*")
(setq Info-current-node
(buffer-substring-no-properties (point)
(progn
(skip-chars-forward "^,\t\n")
(point))))
(Info-set-mode-line)
;; Find the end of it, and narrow.
(beginning-of-line)
(let (active-expression)
(narrow-to-region (point)
(if (re-search-forward "\n[\^_\f]" nil t)
(prog1
(1- (point))
(if (looking-at "[\n\^_\f]*execute: ")
(progn
(goto-char (match-end 0))
(setq active-expression
(read (current-buffer))))))
(point-max)))
(if Info-enable-active-nodes (eval active-expression))
(if Info-fontify (Info-fontify-node))
(run-hooks 'Info-selection-hook))))
(defun Info-set-mode-line ()
(setq mode-line-buffer-identification
(concat
"Info: ("
(if Info-current-file
(file-name-nondirectory Info-current-file)
"")
")"
(or Info-current-node ""))))
;; Go to an info node specified with a filename-and-nodename string
;; of the sort that is found in pointers in nodes.
(defun Info-goto-node (nodename)
"Go to info node named NAME. Give just NODENAME or (FILENAME)NODENAME."
(interactive (list (Info-read-node-name "Goto node: ")))
(let (filename)
(string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)"
nodename)
(setq filename (if (= (match-beginning 1) (match-end 1))
""
(substring nodename (match-beginning 2) (match-end 2)))
nodename (substring nodename (match-beginning 3) (match-end 3)))
(let ((trim (string-match "\\s *\\'" filename)))
(if trim (setq filename (substring filename 0 trim))))
(let ((trim (string-match "\\s *\\'" nodename)))
(if trim (setq nodename (substring nodename 0 trim))))
(if transient-mark-mode (deactivate-mark))
(Info-find-node (if (equal filename "") nil filename)
(if (equal nodename "") "Top" nodename))))
;; This function is used as the "completion table" while reading a node name.
;; It does completion using the alist in completion-table
;; unless STRING starts with an open-paren.
(defun Info-read-node-name-1 (string predicate code)
(let ((no-completion (and (> (length string) 0) (eq (aref string 0) ?\())))
(cond ((eq code nil)
(if no-completion
string
(try-completion string completion-table predicate)))
((eq code t)
(if no-completion
nil
(all-completions string completion-table predicate)))
((eq code 'lambda)
(if no-completion
t
(assoc string completion-table))))))
(defun Info-read-node-name (prompt &optional default)
(let* ((completion-ignore-case t)
(completion-table (Info-build-node-completions))
(nodename (completing-read prompt 'Info-read-node-name-1)))
(if (equal nodename "")
(or default
(Info-read-node-name prompt))
nodename)))
(defun Info-build-node-completions ()
(or Info-current-file-completions
(let ((compl nil))
(save-excursion
(save-restriction
(if (marker-buffer Info-tag-table-marker)
(progn
(set-buffer (marker-buffer Info-tag-table-marker))
(widen)
(goto-char Info-tag-table-marker)
(while (re-search-forward "\nNode: \\(.*\\)\177" nil t)
(setq compl
(cons (list (buffer-substring (match-beginning 1)
(match-end 1)))
compl))))
(widen)
(goto-char (point-min))
(while (search-forward "\n\^_" nil t)
(forward-line 1)
(let ((beg (point)))
(forward-line 1)
(if (re-search-backward "Node: *\\([^,\n]*\\) *[,\n\t]"
beg t)
(setq compl
(cons (list (buffer-substring (match-beginning 1)
(match-end 1)))
compl))))))))
(setq Info-current-file-completions compl))))
(defun Info-restore-point (hl)
"If this node has been visited, restore the point value when we left."
(while hl
(if (and (equal (nth 0 (car hl)) Info-current-file)
;; Use string-equal, not equal, to ignore text props.
(string-equal (nth 1 (car hl)) Info-current-node))
(progn
(goto-char (nth 2 (car hl)))
(setq hl nil)) ;terminate the while at next iter
(setq hl (cdr hl)))))
(defvar Info-last-search nil
"Default regexp for \\\\[Info-search] command to search for.")
(defun Info-search (regexp)
"Search for REGEXP, starting from point, and select node it's found in."
(interactive "sSearch (regexp): ")
(if transient-mark-mode (deactivate-mark))
(if (equal regexp "")
(setq regexp Info-last-search)
(setq Info-last-search regexp))
(let ((found ()) current
(onode Info-current-node)
(ofile Info-current-file)
(opoint (point))
(osubfile Info-current-subfile))
(save-excursion
(save-restriction
(widen)
(if (null Info-current-subfile)
(progn (re-search-forward regexp) (setq found (point)))
(condition-case err
(progn (re-search-forward regexp) (setq found (point)))
(search-failed nil)))))
(if (not found) ;can only happen in subfile case -- else would have erred
(unwind-protect
(let ((list ()))
(set-buffer (marker-buffer Info-tag-table-marker))
(goto-char (point-min))
(search-forward "\n\^_\nIndirect:")
(save-restriction
(narrow-to-region (point)
(progn (search-forward "\n\^_")
(1- (point))))
(goto-char (point-min))
(search-forward (concat "\n" osubfile ": "))
(beginning-of-line)
(while (not (eobp))
(re-search-forward "\\(^.*\\): [0-9]+$")
(goto-char (+ (match-end 1) 2))
(setq list (cons (cons (read (current-buffer))
(buffer-substring (match-beginning 1)
(match-end 1)))
list))
(goto-char (1+ (match-end 0))))
(setq list (nreverse list)
current (car (car list))
list (cdr list)))
(while list
(message "Searching subfile %s..." (cdr (car list)))
(Info-read-subfile (car (car list)))
(setq list (cdr list))
;; (goto-char (point-min))
(if (re-search-forward regexp nil t)
(setq found (point) list ())))
(if found
(message "")
(signal 'search-failed (list regexp))))
(if (not found)
(progn (Info-read-subfile opoint)
(goto-char opoint)
(Info-select-node)))))
(widen)
(goto-char found)
(Info-select-node)
;; Use string-equal, not equal, to ignore text props.
(or (and (string-equal onode Info-current-node)
(equal ofile Info-current-file))
(setq Info-history (cons (list ofile onode opoint)
Info-history)))))
;; Extract the value of the node-pointer named NAME.
;; If there is none, use ERRORNAME in the error message;
;; if ERRORNAME is nil, just return nil.
(defun Info-extract-pointer (name &optional errorname)
(save-excursion
(goto-char (point-min))
(forward-line 1)
(if (re-search-backward (concat name ":") nil t)
(progn
(goto-char (match-end 0))
(Info-following-node-name))
(if (eq errorname t)
nil
(error (concat "Node has no " (capitalize (or errorname name))))))))
;; Return the node name in the buffer following point.
;; ALLOWEDCHARS, if non-nil, goes within [...] to make a regexp
;; saying which chas may appear in the node name.
(defun Info-following-node-name (&optional allowedchars)
(skip-chars-forward " \t")
(buffer-substring-no-properties
(point)
(progn
(while (looking-at (concat "[" (or allowedchars "^,\t\n") "]"))
(skip-chars-forward (concat (or allowedchars "^,\t\n") "("))
(if (looking-at "(")
(skip-chars-forward "^)")))
(skip-chars-backward " ")
(point))))
(defun Info-next ()
"Go to the next node of this node."
(interactive)
(Info-goto-node (Info-extract-pointer "next")))
(defun Info-prev ()
"Go to the previous node of this node."
(interactive)
(Info-goto-node (Info-extract-pointer "prev[ious]*" "previous")))
(defun Info-up ()
"Go to the superior node of this node."
(interactive)
(Info-goto-node (Info-extract-pointer "up"))
(Info-restore-point Info-history))
(defun Info-last ()
"Go back to the last node visited."
(interactive)
(or Info-history
(error "This is the first Info node you looked at"))
(let (filename nodename opoint)
(setq filename (car (car Info-history)))
(setq nodename (car (cdr (car Info-history))))
(setq opoint (car (cdr (cdr (car Info-history)))))
(setq Info-history (cdr Info-history))
(Info-find-node filename nodename)
(setq Info-history (cdr Info-history))
(goto-char opoint)))
(defun Info-directory ()
"Go to the Info directory node."
(interactive)
(Info-find-node "dir" "top"))
(defun Info-follow-reference (footnotename)
"Follow cross reference named NAME to the node it refers to.
NAME may be an abbreviation of the reference name."
(interactive
(let ((completion-ignore-case t)
completions default alt-default (start-point (point)) str i bol eol)
(save-excursion
;; Store end and beginning of line.
(end-of-line)
(setq eol (point))
(beginning-of-line)
(setq bol (point))
(goto-char (point-min))
(while (re-search-forward "\\*note[ \n\t]*\\([^:]*\\):" nil t)
(setq str (buffer-substring
(match-beginning 1)
(1- (point))))
;; See if this one should be the default.
(and (null default)
(<= (match-beginning 0) start-point)
(<= start-point (point))
(setq default t))
;; See if this one should be the alternate default.
(and (null alt-default)
(and (<= bol (match-beginning 0))
(<= (point) eol))
(setq alt-default t))
(setq i 0)
(while (setq i (string-match "[ \n\t]+" str i))
(setq str (concat (substring str 0 i) " "
(substring str (match-end 0))))
(setq i (1+ i)))
;; Record as a completion and perhaps as default.
(if (eq default t) (setq default str))
(if (eq alt-default t) (setq alt-default str))
(setq completions
(cons (cons str nil)
completions))))
;; If no good default was found, try an alternate.
(or default
(setq default alt-default))
;; If only one cross-reference found, then make it default.
(if (eq (length completions) 1)
(setq default (car (car completions))))
(if completions
(let ((input (completing-read (if default
(concat "Follow reference named: ("
default ") ")
"Follow reference named: ")
completions nil t)))
(list (if (equal input "")
default input)))
(error "No cross-references in this node"))))
(let (target beg i (str (concat "\\*note " (regexp-quote footnotename))))
(while (setq i (string-match " " str i))
(setq str (concat (substring str 0 i) "[ \t\n]+" (substring str (1+ i))))
(setq i (+ i 6)))
(save-excursion
(goto-char (point-min))
(or (re-search-forward str nil t)
(error "No cross-reference named %s" footnotename))
(goto-char (+ (match-beginning 0) 5))
(setq target
(Info-extract-menu-node-name "Bad format cross reference" t)))
(while (setq i (string-match "[ \t\n]+" target i))
(setq target (concat (substring target 0 i) " "
(substring target (match-end 0))))
(setq i (+ i 1)))
(Info-goto-node target)))
(defun Info-extract-menu-node-name (&optional errmessage multi-line)
(skip-chars-forward " \t\n")
(let ((beg (point))
str i)
(skip-chars-forward "^:")
(forward-char 1)
(setq str
(if (looking-at ":")
(buffer-substring-no-properties beg (1- (point)))
(skip-chars-forward " \t\n")
(Info-following-node-name (if multi-line "^.,\t" "^.,\t\n"))))
(while (setq i (string-match "\n" str i))
(aset str i ?\ ))
;; Collapse multiple spaces.
(while (string-match " +" str)
(setq str (replace-match " " t t str)))
str))
;; No one calls this.
;;(defun Info-menu-item-sequence (list)
;; (while list
;; (Info-menu (car list))
;; (setq list (cdr list))))
(defun Info-complete-menu-item (string predicate action)
(let ((case-fold-search t))
(cond ((eq action nil)
(let (completions
(pattern (concat "\n\\* \\("
(regexp-quote string)
"[^:\t\n]*\\):")))
(save-excursion
(set-buffer Info-complete-menu-buffer)
(goto-char (point-min))
(search-forward "\n* Menu:")
(while (re-search-forward pattern nil t)
(setq completions (cons (cons (format "%s"
(buffer-substring
(match-beginning 1)
(match-end 1)))
(match-beginning 1))
completions))))
(try-completion string completions predicate)))
((eq action t)
(let (completions
(pattern (concat "\n\\* \\("
(regexp-quote string)
"[^:\t\n]*\\):")))
(save-excursion
(set-buffer Info-complete-menu-buffer)
(goto-char (point-min))
(search-forward "\n* Menu:")
(while (re-search-forward pattern nil t)
(setq completions (cons (cons (format "%s"
(buffer-substring
(match-beginning 1)
(match-end 1)))
(match-beginning 1))
completions))))
(all-completions string completions predicate)))
(t
(save-excursion
(set-buffer Info-complete-menu-buffer)
(goto-char (point-min))
(search-forward "\n* Menu:")
(re-search-forward (concat "\n\\* "
(regexp-quote string)
":")
nil t))))))
(defun Info-menu (menu-item)
"Go to node for menu item named (or abbreviated) NAME.
Completion is allowed, and the menu item point is on is the default."
(interactive
(let ((completions '())
;; If point is within a menu item, use that item as the default
(default nil)
(p (point))
beg
(last nil))
(save-excursion
(goto-char (point-min))
(if (not (search-forward "\n* menu:" nil t))
(error "No menu in this node"))
(setq beg (point))
(and (< (point) p)
(save-excursion
(goto-char p)
(end-of-line)
(re-search-backward "\n\\* \\([^:\t\n]*\\):" beg t)
(setq default (format "%s" (buffer-substring
(match-beginning 1)
(match-end 1)))))))
(let ((item nil))
(while (null item)
(setq item (let ((completion-ignore-case t)
(Info-complete-menu-buffer (current-buffer)))
(completing-read (if default
(format "Menu item (default %s): "
default)
"Menu item: ")
'Info-complete-menu-item nil t)))
;; we rely on the fact that completing-read accepts an input
;; of "" even when the require-match argument is true and ""
;; is not a valid possibility
(if (string= item "")
(if default
(setq item default)
;; ask again
(setq item nil))))
(list item))))
;; there is a problem here in that if several menu items have the same
;; name you can only go to the node of the first with this command.
(Info-goto-node (Info-extract-menu-item menu-item)))
(defun Info-extract-menu-item (menu-item)
(setq menu-item (regexp-quote menu-item))
(save-excursion
(goto-char (point-min))
(or (search-forward "\n* menu:" nil t)
(error "No menu in this node"))
(or (re-search-forward (concat "\n\\* " menu-item ":") nil t)
(re-search-forward (concat "\n\\* " menu-item) nil t)
(error "No such item in menu"))
(beginning-of-line)
(forward-char 2)
(Info-extract-menu-node-name)))
;; If COUNT is nil, use the last item in the menu.
(defun Info-extract-menu-counting (count)
(save-excursion
(goto-char (point-min))
(or (search-forward "\n* menu:" nil t)
(error "No menu in this node"))
(if count
(or (search-forward "\n* " nil t count)
(error "Too few items in menu"))
(while (search-forward "\n* " nil t)
nil))
(Info-extract-menu-node-name)))
(defun Info-nth-menu-item ()
"Go to the node of the Nth menu item.
N is the digit argument used to invoke this command."
(interactive)
(Info-goto-node
(Info-extract-menu-counting
(- (aref (this-command-keys) (1- (length (this-command-keys)))) ?0))))
(defun Info-top-node ()
"Go to the Top node of this file."
(interactive)
(Info-goto-node "Top"))
(defun Info-final-node ()
"Go to the final node in this file."
(interactive)
(Info-goto-node "Top")
(let (Info-history)
;; Go to the last node in the menu of Top.
(Info-goto-node (Info-extract-menu-counting nil))
;; If the last node in the menu is not last in pointer structure,
;; move forward until we can't go any farther.
(while (Info-forward-node t t) nil)
;; Then keep moving down to last subnode, unless we reach an index.
(while (and (not (string-match "\\" Info-current-node))
(save-excursion (search-forward "\n* Menu:" nil t)))
(Info-goto-node (Info-extract-menu-counting nil)))))
(defun Info-forward-node (&optional not-down no-error)
"Go forward one node, considering all nodes as forming one sequence."
(interactive)
(goto-char (point-min))
(forward-line 1)
;; three possibilities, in order of priority:
;; 1. next node is in a menu in this node (but not in an index)
;; 2. next node is next at same level
;; 3. next node is up and next
(cond ((and (not not-down)
(save-excursion (search-forward "\n* menu:" nil t))
(not (string-match "\\" Info-current-node)))
(Info-goto-node (Info-extract-menu-counting 1))
t)
((save-excursion (search-backward "next:" nil t))
(Info-next)
t)
((and (save-excursion (search-backward "up:" nil t))
;; Use string-equal, not equal, to ignore text props.
(not (string-equal (downcase (Info-extract-pointer "up"))
"top")))
(let ((old-node Info-current-node))
(Info-up)
(let (Info-history success)
(unwind-protect
(setq success (Info-forward-node t no-error))
(or success (Info-goto-node old-node))))))
(no-error nil)
(t (error "No pointer forward from this node"))))
(defun Info-backward-node ()
"Go backward one node, considering all nodes as forming one sequence."
(interactive)
(let ((prevnode (Info-extract-pointer "prev[ious]*" t))
(upnode (Info-extract-pointer "up" t)))
(cond ((and upnode (string-match "(" upnode))
(error "First node in file"))
((and upnode (or (null prevnode)
;; Use string-equal, not equal,
;; to ignore text properties.
(string-equal (downcase prevnode)
(downcase upnode))))
(Info-up))
(prevnode
;; If we move back at the same level,
;; go down to find the last subnode*.
(Info-prev)
(let (Info-history)
(while (and (not (string-match "\\" Info-current-node))
(save-excursion (search-forward "\n* Menu:" nil t)))
(Info-goto-node (Info-extract-menu-counting nil)))))
(t
(error "No pointer backward from this node")))))
(defun Info-exit ()
"Exit Info by selecting some other buffer."
(interactive)
(if Info-standalone
(save-buffers-kill-emacs)
(switch-to-buffer (prog1 (other-buffer (current-buffer))
(bury-buffer (current-buffer))))))
(defun Info-next-menu-item ()
(interactive)
(save-excursion
(forward-line -1)
(search-forward "\n* menu:" nil t)
(or (search-forward "\n* " nil t)
(error "No more items in menu"))
(Info-goto-node (Info-extract-menu-node-name))))
(defun Info-last-menu-item ()
(interactive)
(save-excursion
(forward-line 1)
(let ((beg (save-excursion
(and (search-backward "\n* menu:" nil t)
(point)))))
(or (and beg (search-backward "\n* " beg t))
(error "No previous items in menu")))
(Info-goto-node (save-excursion
(goto-char (match-end 0))
(Info-extract-menu-node-name)))))
(defmacro Info-no-error (&rest body)
(list 'condition-case nil (cons 'progn (append body '(t))) '(error nil)))
(defun Info-next-preorder ()
"Go to the next subnode or the next node, or go up a level."
(interactive)
(cond ((Info-no-error (Info-next-menu-item)))
((Info-no-error (Info-next)))
((Info-no-error (Info-up))
;; Since we have already gone thru all the items in this menu,
;; go up to the end of this node.
(goto-char (point-max)))
(t
(error "No more nodes"))))
(defun Info-last-preorder ()
"Go to the last node, popping up a level if there is none."
(interactive)
(cond ((Info-no-error
(Info-last-menu-item)
;; If we go down a menu item, go to the end of the node
;; so we can scroll back through it.
(goto-char (point-max)))
(recenter -1))
((Info-no-error (Info-prev))
(goto-char (point-max))
(recenter -1))
((Info-no-error (Info-up))
(goto-char (point-min))
(or (search-forward "\n* Menu:" nil t)
(goto-char (point-max))))
(t (error "No previous nodes"))))
(defun Info-scroll-up ()
"Scroll one screenful forward in Info, considering all nodes as one sequence.
Once you scroll far enough in a node that its menu appears on the screen,
the next scroll moves into its first subnode. When you scroll past
the end of a node, that goes to the next node or back up to the parent node."
(interactive)
(if (or (< (window-start) (point-min))
(> (window-start) (point-max)))
(set-window-start (selected-window) (point)))
(let ((virtual-end (save-excursion
(goto-char (point-min))
(if (search-forward "\n* Menu:" nil t)
(point)
(point-max)))))
(if (or (< virtual-end (window-start))
(pos-visible-in-window-p virtual-end))
(Info-next-preorder)
(scroll-up))))
(defun Info-scroll-down ()
"Scroll one screenful back in Info, considering all nodes as one sequence.
Within the menu of a node, this goes to its last subnode.
When you scroll past the beginning of a node, that goes to the
previous node or back up to the parent node."
(interactive)
(if (or (< (window-start) (point-min))
(> (window-start) (point-max)))
(set-window-start (selected-window) (point)))
(let ((virtual-end (save-excursion
(goto-char (point-min))
(search-forward "\n* Menu:" nil t))))
(if (or virtual-end (pos-visible-in-window-p (point-min)))
(Info-last-preorder)
(scroll-down))))
(defun Info-next-reference ()
"Move cursor to the next cross-reference or menu item in the node."
(interactive)
(let ((pat "\\*note[ \n\t]*\\([^:]*\\):\\|^\\* .*:")
(old-pt (point)))
(or (eobp) (forward-char 1))
(or (re-search-forward pat nil t)
(progn
(goto-char (point-min))
(or (re-search-forward pat nil t)
(progn
(goto-char old-pt)
(error "No cross references in this node")))))
(goto-char (match-beginning 0))
(if (looking-at "\\* Menu:")
(Info-next-reference))))
(defun Info-prev-reference ()
"Move cursor to the previous cross-reference or menu item in the node."
(interactive)
(let ((pat "\\*note[ \n\t]*\\([^:]*\\):\\|^\\* .*:")
(old-pt (point)))
(or (re-search-backward pat nil t)
(progn
(goto-char (point-max))
(or (re-search-backward pat nil t)
(progn
(goto-char old-pt)
(error "No cross references in this node")))))
(goto-char (match-beginning 0))
(if (looking-at "\\* Menu:")
(Info-prev-reference))))
(defun Info-index (topic)
"Look up a string in the index for this file.
The index is defined as the first node in the top-level menu whose
name contains the word \"Index\", plus any immediately following
nodes whose names also contain the word \"Index\".
If there are no exact matches to the specified topic, this chooses
the first match which is a case-insensitive substring of a topic.
Use the `,' command to see the other matches.
Give a blank topic name to go to the Index node itself."
(interactive "sIndex topic: ")
(let ((orignode Info-current-node)
(rnode nil)
(pattern (format "\n\\* \\([^\n:]*%s[^\n:]*\\):[ \t]*\\([^.\n]*\\)\\.[ \t]*\\([0-9]*\\)"
(regexp-quote topic)))
node)
(Info-goto-node "Top")
(or (search-forward "\n* menu:" nil t)
(error "No index"))
(or (re-search-forward "\n\\* \\(.*\\\\)" nil t)
(error "No index"))
(goto-char (match-beginning 1))
;; Here, and subsequently in this function,
;; we bind Info-history to nil for internal node-switches
;; so that we don't put junk in the history.
;; In the first Info-goto-node call, above, we do update the history
;; because that is what the user's previous node choice into it.
(let ((Info-history nil))
(Info-goto-node (Info-extract-menu-node-name)))
(or (equal topic "")
(let ((matches nil)
(exact nil)
(Info-history nil)
found)
(while
(progn
(goto-char (point-min))
(while (re-search-forward pattern nil t)
(setq matches
(cons (list (buffer-substring (match-beginning 1)
(match-end 1))
(buffer-substring (match-beginning 2)
(match-end 2))
Info-current-node
(string-to-int (concat "0"
(buffer-substring
(match-beginning 3)
(match-end 3)))))
matches)))
(and (setq node (Info-extract-pointer "next" t))
(string-match "\\" node)))
(Info-goto-node node))
(or matches
(progn
(Info-last)
(error "No \"%s\" in index" topic)))
;; Here it is a feature that assoc is case-sensitive.
(while (setq found (assoc topic matches))
(setq exact (cons found exact)
matches (delq found matches)))
(setq Info-index-alternatives (nconc exact (nreverse matches)))
(Info-index-next 0)))))
(defun Info-index-next (num)
"Go to the next matching index item from the last `i' command."
(interactive "p")
(or Info-index-alternatives
(error "No previous `i' command in this file"))
(while (< num 0)
(setq num (+ num (length Info-index-alternatives))))
(while (> num 0)
(setq Info-index-alternatives
(nconc (cdr Info-index-alternatives)
(list (car Info-index-alternatives)))
num (1- num)))
(Info-goto-node (nth 1 (car Info-index-alternatives)))
(if (> (nth 3 (car Info-index-alternatives)) 0)
(forward-line (nth 3 (car Info-index-alternatives)))
(forward-line 3) ; don't search in headers
(let ((name (car (car Info-index-alternatives))))
(if (or (re-search-forward (format
"\\(Function\\|Command\\): %s\\( \\|$\\)"
(regexp-quote name)) nil t)
(search-forward (format "`%s'" name) nil t)
(and (string-match "\\`.*\\( (.*)\\)\\'" name)
(search-forward
(format "`%s'" (substring name 0 (match-beginning 1)))
nil t))
(search-forward name nil t))
(beginning-of-line)
(goto-char (point-min)))))
(message "Found \"%s\" in %s. %s"
(car (car Info-index-alternatives))
(nth 2 (car Info-index-alternatives))
(if (cdr Info-index-alternatives)
"(Press `,' for more)"
"(Only match)")))
(defun Info-undefined ()
"Make command be undefined in Info."
(interactive)
(ding))
(defun Info-help ()
"Enter the Info tutorial."
(interactive)
(delete-other-windows)
(Info-find-node "info"
(if (< (window-height) 23)
"Help-Small-Screen"
"Help")))
(defun Info-summary ()
"Display a brief summary of all Info commands."
(interactive)
(save-window-excursion
(switch-to-buffer "*Help*")
(erase-buffer)
(insert (documentation 'Info-mode))
(help-mode)
(goto-char (point-min))
(let (ch flag)
(while (progn (setq flag (not (pos-visible-in-window-p (point-max))))
(message (if flag "Type Space to see more"
"Type Space to return to Info"))
(if (not (eq ?\ (setq ch (read-event))))
(progn (setq unread-command-events (list ch)) nil)
flag))
(scroll-up)))
(bury-buffer "*Help*")))
(defun Info-get-token (pos start all &optional errorstring)
"Return the token around POS,
POS must be somewhere inside the token
START is a regular expression which will match the
beginning of the tokens delimited string
ALL is a regular expression with a single
parenthized subpattern which is the token to be
returned. E.g. '{\(.*\)}' would return any string
enclosed in braces around POS.
SIG optional fourth argument, controls action on no match
nil: return nil
t: beep
a string: signal an error, using that string."
(save-excursion
(goto-char pos)
(re-search-backward start (max (point-min) (- pos 200)) 'yes)
(let (found)
(while (and (re-search-forward all (min (point-max) (+ pos 200)) 'yes)
(not (setq found (and (<= (match-beginning 0) pos)
(> (match-end 0) pos))))))
(if (and found (<= (match-beginning 0) pos)
(> (match-end 0) pos))
(buffer-substring (match-beginning 1) (match-end 1))
(cond ((null errorstring)
nil)
((eq errorstring t)
(beep)
nil)
(t
(error "No %s around position %d" errorstring pos)))))))
(defun Info-mouse-follow-nearest-node (click)
"\\Follow a node reference near point.
Like \\[Info-menu], \\[Info-follow-reference], \\[Info-next], \\[Info-prev] or \\[Info-up] command, depending on where you click.
At end of the node's text, moves to the next node, or up if none."
(interactive "e")
(let* ((start (event-start click))
(window (car start))
(pos (car (cdr start))))
(select-window window)
(goto-char pos))
(and (not (Info-try-follow-nearest-node))
(save-excursion (forward-line 1) (eobp))
(Info-next-preorder)))
(defun Info-follow-nearest-node ()
"\\Follow a node reference near point.
Like \\[Info-menu], \\[Info-follow-reference], \\[Info-next], \\[Info-prev] or \\[Info-up] command, depending on where point is.
If no reference to follow, moves to the next node, or up if none."
(interactive)
(or (Info-try-follow-nearest-node)
(Info-next-preorder)))
;; Common subroutine.
(defun Info-try-follow-nearest-node ()
"Follow a node reference near point. Return non-nil if successful."
(let (node)
(cond
((setq node (Info-get-token (point) "\\*note[ \n]"
"\\*note[ \n]\\([^:]*\\):"))
(Info-follow-reference node))
((setq node (Info-get-token (point) "\\* " "\\* \\([^:]*\\)::"))
(Info-goto-node node))
((setq node (Info-get-token (point) "\\* " "\\* \\([^:]*\\):"))
(Info-menu node))
((setq node (Info-get-token (point) "Up: " "Up: \\([^,\n\t]*\\)"))
(Info-goto-node node))
((setq node (Info-get-token (point) "Next: " "Next: \\([^,\n\t]*\\)"))
(Info-goto-node node))
((setq node (Info-get-token (point) "File: " "File: \\([^,\n\t]*\\)"))
(Info-goto-node "Top"))
((setq node (Info-get-token (point) "Prev: " "Prev: \\([^,\n\t]*\\)"))
(Info-goto-node node)))
node))
(defvar Info-mode-map nil
"Keymap containing Info commands.")
(if Info-mode-map
nil
(setq Info-mode-map (make-keymap))
(suppress-keymap Info-mode-map)
(define-key Info-mode-map "." 'beginning-of-buffer)
(define-key Info-mode-map " " 'Info-scroll-up)
(define-key Info-mode-map "\C-m" 'Info-follow-nearest-node)
(define-key Info-mode-map "\t" 'Info-next-reference)
(define-key Info-mode-map "\e\t" 'Info-prev-reference)
(define-key Info-mode-map "1" 'Info-nth-menu-item)
(define-key Info-mode-map "2" 'Info-nth-menu-item)
(define-key Info-mode-map "3" 'Info-nth-menu-item)
(define-key Info-mode-map "4" 'Info-nth-menu-item)
(define-key Info-mode-map "5" 'Info-nth-menu-item)
(define-key Info-mode-map "6" 'Info-nth-menu-item)
(define-key Info-mode-map "7" 'Info-nth-menu-item)
(define-key Info-mode-map "8" 'Info-nth-menu-item)
(define-key Info-mode-map "9" 'Info-nth-menu-item)
(define-key Info-mode-map "0" 'undefined)
(define-key Info-mode-map "?" 'Info-summary)
(define-key Info-mode-map "]" 'Info-forward-node)
(define-key Info-mode-map "[" 'Info-backward-node)
(define-key Info-mode-map "<" 'Info-top-node)
(define-key Info-mode-map ">" 'Info-final-node)
(define-key Info-mode-map "b" 'beginning-of-buffer)
(define-key Info-mode-map "d" 'Info-directory)
(define-key Info-mode-map "e" 'Info-edit)
(define-key Info-mode-map "f" 'Info-follow-reference)
(define-key Info-mode-map "g" 'Info-goto-node)
(define-key Info-mode-map "h" 'Info-help)
(define-key Info-mode-map "i" 'Info-index)
(define-key Info-mode-map "l" 'Info-last)
(define-key Info-mode-map "m" 'Info-menu)
(define-key Info-mode-map "n" 'Info-next)
(define-key Info-mode-map "p" 'Info-prev)
(define-key Info-mode-map "q" 'Info-exit)
(define-key Info-mode-map "s" 'Info-search)
;; For consistency with Rmail.
(define-key Info-mode-map "\M-s" 'Info-search)
(define-key Info-mode-map "t" 'Info-top-node)
(define-key Info-mode-map "u" 'Info-up)
(define-key Info-mode-map "," 'Info-index-next)
(define-key Info-mode-map "\177" 'Info-scroll-down)
(define-key Info-mode-map [mouse-2] 'Info-mouse-follow-nearest-node)
)
;; Info mode is suitable only for specially formatted data.
(put 'info-mode 'mode-class 'special)
(defun Info-mode ()
"\\
Info mode provides commands for browsing through the Info documentation tree.
Documentation in Info is divided into \"nodes\", each of which discusses
one topic and contains references to other nodes which discuss related
topics. Info has commands to follow the references and show you other nodes.
\\[Info-help] Invoke the Info tutorial.
Selecting other nodes:
\\[Info-mouse-follow-nearest-node]
Follow a node reference you click on.
This works with menu items, cross references, and
the \"next\", \"previous\" and \"up\", depending on where you click.
\\[Info-next] Move to the \"next\" node of this node.
\\[Info-prev] Move to the \"previous\" node of this node.
\\[Info-up] Move \"up\" from this node.
\\[Info-menu] Pick menu item specified by name (or abbreviation).
Picking a menu item causes another node to be selected.
\\[Info-directory] Go to the Info directory node.
\\[Info-follow-reference] Follow a cross reference. Reads name of reference.
\\[Info-last] Move to the last node you were at.
\\[Info-index] Look up a topic in this file's Index and move to that node.
\\[Info-index-next] (comma) Move to the next match from a previous `i' command.
Moving within a node:
\\[Info-scroll-up] Normally, scroll forward a full screen. If the end of the buffer is
already visible, try to go to the next menu entry, or up if there is none.
\\[Info-scroll-down] Normally, scroll backward. If the beginning of the buffer is
already visible, try to go to the previous menu entry, or up if there is none.
\\[beginning-of-buffer] Go to beginning of node.
Advanced commands:
\\[Info-exit] Quit Info: reselect previously selected buffer.
\\[Info-edit] Edit contents of selected node.
1 Pick first item in node's menu.
2, 3, 4, 5 Pick second ... fifth item in node's menu.
\\[Info-goto-node] Move to node specified by name.
You may include a filename as well, as (FILENAME)NODENAME.
\\[universal-argument] \\[info] Move to new Info file with completion.
\\[Info-search] Search through this Info file for specified regexp,
and select the node in which the next occurrence is found.
\\[Info-next-reference] Move cursor to next cross-reference or menu item.
\\[Info-prev-reference] Move cursor to previous cross-reference or menu item."
(kill-all-local-variables)
(setq major-mode 'Info-mode)
(setq mode-name "Info")
(use-local-map Info-mode-map)
(set-syntax-table text-mode-syntax-table)
(setq local-abbrev-table text-mode-abbrev-table)
(setq case-fold-search t)
(setq buffer-read-only t)
(make-local-variable 'Info-current-file)
(make-local-variable 'Info-current-subfile)
(make-local-variable 'Info-current-node)
(make-local-variable 'Info-tag-table-marker)
(make-local-variable 'Info-history)
(make-local-variable 'Info-index-alternatives)
(if (memq (framep (selected-frame)) '(x pc))
(progn
(make-face 'info-node)
(make-face 'info-menu-5)
(make-face 'info-xref)
(or (face-differs-from-default-p 'info-node)
(if (face-differs-from-default-p 'bold-italic)
(copy-face 'bold-italic 'info-node)
(copy-face 'bold 'info-node)))
(or (face-differs-from-default-p 'info-menu-5)
(set-face-underline-p 'info-menu-5 t))
(or (face-differs-from-default-p 'info-xref)
(copy-face 'bold 'info-xref)))
(setq Info-fontify nil))
(Info-set-mode-line)
(run-hooks 'Info-mode-hook))
(defvar Info-edit-map nil
"Local keymap used within `e' command of Info.")
(if Info-edit-map
nil
(setq Info-edit-map (nconc (make-sparse-keymap) text-mode-map))
(define-key Info-edit-map "\C-c\C-c" 'Info-cease-edit))
;; Info-edit mode is suitable only for specially formatted data.
(put 'info-edit-mode 'mode-class 'special)
(defun Info-edit-mode ()
"Major mode for editing the contents of an Info node.
Like text mode with the addition of `Info-cease-edit'
which returns to Info mode for browsing.
\\{Info-edit-map}"
(use-local-map Info-edit-map)
(setq major-mode 'Info-edit-mode)
(setq mode-name "Info Edit")
(kill-local-variable 'mode-line-buffer-identification)
(setq buffer-read-only nil)
(force-mode-line-update)
(buffer-enable-undo (current-buffer))
(run-hooks 'Info-edit-mode-hook))
(defun Info-edit ()
"Edit the contents of this Info node.
Allowed only if variable `Info-enable-edit' is non-nil."
(interactive)
(or Info-enable-edit
(error "Editing info nodes is not enabled"))
(Info-edit-mode)
(message (substitute-command-keys
"Editing: Type \\\\[Info-cease-edit] to return to info")))
(defun Info-cease-edit ()
"Finish editing Info node; switch back to Info proper."
(interactive)
;; Do this first, so nothing has changed if user C-g's at query.
(and (buffer-modified-p)
(y-or-n-p "Save the file? ")
(save-buffer))
(use-local-map Info-mode-map)
(setq major-mode 'Info-mode)
(setq mode-name "Info")
(Info-set-mode-line)
(setq buffer-read-only t)
(force-mode-line-update)
(and (marker-position Info-tag-table-marker)
(buffer-modified-p)
(message "Tags may have changed. Use Info-tagify if necessary")))
(defvar Info-file-list-for-emacs
'("ediff" "forms" "gnus" "info" ("mh" . "mh-e") "sc")
"List of Info files that describe Emacs commands.
An element can be a file name, or a list of the form (PREFIX . FILE)
where PREFIX is a name prefix and FILE is the file to look in.
If the element is just a file name, the file name also serves as the prefix.")
(defun Info-find-emacs-command-nodes (command)
"Return a list of locations documenting COMMAND.
The `info-file' property of COMMAND says which Info manual to search.
If COMMAND has no property, the variable `Info-file-list-for-emacs'
defines heuristics for which Info manual to try.
The locations are of the format used in Info-history, i.e.
\(FILENAME NODENAME BUFFERPOS\)."
(let ((where '())
(cmd-desc (concat "^\\* " (regexp-quote (symbol-name command))
":\\s *\\(.*\\)\\.$"))
(info-file "emacs")) ;default
;; Determine which info file this command is documented in.
(if (get command 'info-file)
(setq info-file (get command 'info-file))
;; If it doesn't say explicitly, test its name against
;; various prefixes that we know.
(let ((file-list Info-file-list-for-emacs))
(while file-list
(let* ((elt (car file-list))
(name (if (consp elt)
(car elt)
elt))
(file (if (consp elt) (cdr elt) elt))
(regexp (concat "\\`" (regexp-quote name)
"\\(\\'\\|-\\)")))
(if (string-match regexp (symbol-name command))
(setq info-file file file-list nil))
(setq file-list (cdr file-list))))))
(save-excursion
(condition-case nil
(Info-find-node info-file "Command Index")
;; Some manuals may not have a separate Command Index node,
;; so try just Index instead.
(error
(Info-find-node info-file "Index")))
;; Take the index node off the Info history.
(setq Info-history (cdr Info-history))
(goto-char (point-max))
(while (re-search-backward cmd-desc nil t)
(setq where (cons (list Info-current-file
(buffer-substring
(match-beginning 1)
(match-end 1))
0)
where)))
where)))
;;;###autoload
(defun Info-goto-emacs-command-node (command)
"Go to the Info node in the Emacs manual for command COMMAND.
The command is found by looking up in Emacs manual's Command Index
or in another manual found via COMMAND's `info-file' property or
the variable `Info-file-list-for-emacs'."
(interactive "CFind documentation for command: ")
(or (commandp command)
(signal 'wrong-type-argument (list 'commandp command)))
(let ((where (Info-find-emacs-command-nodes command)))
(if where
(let ((num-matches (length where)))
;; Get Info running, and pop to it in another window.
(save-window-excursion
(info))
(pop-to-buffer "*info*")
(Info-find-node (car (car where))
(car (cdr (car where))))
(if (> num-matches 1)
(progn
;; Info-find-node already pushed (car where) onto
;; Info-history. Put the other nodes that were found on
;; the history.
(setq Info-history (nconc (cdr where) Info-history))
(message (substitute-command-keys
"Found %d other entr%s. Use \\[Info-last] to see %s.")
(1- num-matches)
(if (> num-matches 2) "ies" "y")
(if (> num-matches 2) "them" "it")))))
(error "Couldn't find documentation for %s." command))))
;;;###autoload
(defun Info-goto-emacs-key-command-node (key)
"Go to the Info node in the Emacs manual the command bound to KEY, a string.
Interactively, if the binding is execute-extended-command, a command is read.
The command is found by looking up in Emacs manual's Command Index
or in another manual found via COMMAND's `info-file' property or
the variable `Info-file-list-for-emacs'."
(interactive "kFind documentation for key:")
(let ((command (key-binding key)))
(cond ((null command)
(message "%s is undefined" (key-description key)))
((and (interactive-p)
(eq command 'execute-extended-command))
(Info-goto-emacs-command-node
(read-command "Find documentation for command: ")))
(t
(Info-goto-emacs-command-node command)))))
(defvar Info-title-face-alist
'((?* bold underline)
(?= bold-italic underline)
(?- italic underline))
"*Alist of face or list of faces to use for pseudo-underlined titles.
The alist key is the character the title is underlined with (?*, ?= or ?-).")
(defun Info-fontify-node ()
(save-excursion
(let ((buffer-read-only nil))
(goto-char (point-min))
(if (looking-at "^File: [^,: \t]+,?[ \t]+")
(progn
(goto-char (match-end 0))
(while
(looking-at "[ \t]*[^:, \t\n]+:[ \t]+\\([^:,\t\n]+\\),?")
(goto-char (match-end 0))
(put-text-property (match-beginning 1) (match-end 1)
'face 'info-xref)
(put-text-property (match-beginning 1) (match-end 1)
'mouse-face 'highlight))))
(goto-char (point-min))
(while (re-search-forward "\n\\([^ \t\n].+\\)\n\\(\\*+\\|=+\\|-+\\)$"
nil t)
(put-text-property (match-beginning 1) (match-end 1)
'face
(cdr (assq (preceding-char) Info-title-face-alist)))
(put-text-property (match-end 1) (match-end 2)
'invisible t))
(goto-char (point-min))
(while (re-search-forward "\\*Note[ \n\t]+\\([^:]*\\):" nil t)
(if (= (char-after (1- (match-beginning 0))) ?\") ; hack
nil
(put-text-property (match-beginning 1) (match-end 1)
'face 'info-xref)
(put-text-property (match-beginning 1) (match-end 1)
'mouse-face 'highlight)))
(goto-char (point-min))
(if (and (search-forward "\n* Menu:" nil t)
(not (string-match "\\" Info-current-node))
;; Don't take time to annotate huge menus
(< (- (point-max) (point)) Info-fontify-maximum-menu-size))
(let ((n 0))
(while (re-search-forward "^\\* \\([^:\t\n]*\\):" nil t)
(setq n (1+ n))
(if (memq n '(5 9)) ; visual aids to help with 1-9 keys
(put-text-property (match-beginning 0)
(1+ (match-beginning 0))
'face 'info-menu-5))
(put-text-property (match-beginning 1) (match-end 1)
'face 'info-node)
(put-text-property (match-beginning 1) (match-end 1)
'mouse-face 'highlight))))
(set-buffer-modified-p nil))))
(provide 'info)
;;; info.el ends here
texinfo-3.7/emacs/informat.el 100444 11732 13 33467 6043213664 14516 0 ustar bfox user ;;; informat.el --- info support functions package for Emacs
;; Copyright (C) 1986 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: help
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Code:
(require 'info)
;;;###autoload
(defun Info-tagify ()
"Create or update Info-file tag table in current buffer."
(interactive)
;; Save and restore point and restrictions.
;; save-restrictions would not work
;; because it records the old max relative to the end.
;; We record it relative to the beginning.
(message "Tagifying %s ..." (file-name-nondirectory (buffer-file-name)))
(let ((omin (point-min))
(omax (point-max))
(nomax (= (point-max) (1+ (buffer-size))))
(opoint (point)))
(unwind-protect
(progn
(widen)
(goto-char (point-min))
(if (search-forward "\^_\nIndirect:\n" nil t)
(message "Cannot tagify split info file")
(let ((regexp "Node:[ \t]*\\([^,\n\t]*\\)[,\t\n]")
(case-fold-search t)
list)
(while (search-forward "\n\^_" nil t)
;; We want the 0-origin character position of the ^_.
;; That is the same as the Emacs (1-origin) position
;; of the newline before it.
(let ((beg (match-beginning 0)))
(forward-line 2)
(if (re-search-backward regexp beg t)
(setq list
(cons (list (buffer-substring-no-properties
(match-beginning 1)
(match-end 1))
beg)
list)))))
(goto-char (point-max))
(forward-line -8)
(let ((buffer-read-only nil))
(if (search-forward "\^_\nEnd tag table\n" nil t)
(let ((end (point)))
(search-backward "\nTag table:\n")
(beginning-of-line)
(delete-region (point) end)))
(goto-char (point-max))
(insert "\^_\f\nTag table:\n")
(move-marker Info-tag-table-marker (point))
(setq list (nreverse list))
(while list
(insert "Node: " (car (car list)) ?\177)
(princ (car (cdr (car list))) (current-buffer))
(insert ?\n)
(setq list (cdr list)))
(insert "\^_\nEnd tag table\n")))))
(goto-char opoint)
(narrow-to-region omin (if nomax (1+ (buffer-size))
(min omax (point-max))))))
(message "Tagifying %s ... done" (file-name-nondirectory (buffer-file-name))))
;;;###autoload
(defun Info-split ()
"Split an info file into an indirect file plus bounded-size subfiles.
Each subfile will be up to 50,000 characters plus one node.
To use this command, first visit a large Info file that has a tag
table. The buffer is modified into a (small) indirect info file which
should be saved in place of the original visited file.
The subfiles are written in the same directory the original file is
in, with names generated by appending `-' and a number to the original
file name. The indirect file still functions as an Info file, but it
contains just the tag table and a directory of subfiles."
(interactive)
(if (< (buffer-size) 70000)
(error "This is too small to be worth splitting"))
(goto-char (point-min))
(search-forward "\^_")
(forward-char -1)
(let ((start (point))
(chars-deleted 0)
subfiles
(subfile-number 1)
(case-fold-search t)
(filename (file-name-sans-versions buffer-file-name)))
(goto-char (point-max))
(forward-line -8)
(setq buffer-read-only nil)
(or (search-forward "\^_\nEnd tag table\n" nil t)
(error "Tag table required; use M-x Info-tagify"))
(search-backward "\nTag table:\n")
(if (looking-at "\nTag table:\n\^_")
(error "Tag table is just a skeleton; use M-x Info-tagify"))
(beginning-of-line)
(forward-char 1)
(save-restriction
(narrow-to-region (point-min) (point))
(goto-char (point-min))
(while (< (1+ (point)) (point-max))
(goto-char (min (+ (point) 50000) (point-max)))
(search-forward "\^_" nil 'move)
(setq subfiles
(cons (list (+ start chars-deleted)
(concat (file-name-nondirectory filename)
(format "-%d" subfile-number)))
subfiles))
;; Put a newline at end of split file, to make Unix happier.
(insert "\n")
(write-region (point-min) (point)
(concat filename (format "-%d" subfile-number)))
(delete-region (1- (point)) (point))
;; Back up over the final ^_.
(forward-char -1)
(setq chars-deleted (+ chars-deleted (- (point) start)))
(delete-region start (point))
(setq subfile-number (1+ subfile-number))))
(while subfiles
(goto-char start)
(insert (nth 1 (car subfiles))
(format ": %d" (1- (car (car subfiles))))
"\n")
(setq subfiles (cdr subfiles)))
(goto-char start)
(insert "\^_\nIndirect:\n")
(search-forward "\nTag Table:\n")
(insert "(Indirect)\n")))
;;;###autoload
(defun Info-validate ()
"Check current buffer for validity as an Info file.
Check that every node pointer points to an existing node."
(interactive)
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(if (search-forward "\nTag table:\n(Indirect)\n" nil t)
(error "Don't yet know how to validate indirect info files: \"%s\""
(buffer-name (current-buffer))))
(goto-char (point-min))
(let ((allnodes '(("*")))
(regexp "Node:[ \t]*\\([^,\n\t]*\\)[,\t\n]")
(case-fold-search t)
(tags-losing nil)
(lossages ()))
(while (search-forward "\n\^_" nil t)
(forward-line 1)
(let ((beg (point)))
(forward-line 1)
(if (re-search-backward regexp beg t)
(let ((name (downcase
(buffer-substring-no-properties
(match-beginning 1)
(progn
(goto-char (match-end 1))
(skip-chars-backward " \t")
(point))))))
(if (assoc name allnodes)
(setq lossages
(cons (list name "Duplicate node-name" nil)
lossages))
(setq allnodes
(cons (list name
(progn
(end-of-line)
(and (re-search-backward
"prev[ious]*:" beg t)
(progn
(goto-char (match-end 0))
(downcase
(Info-following-node-name)))))
beg)
allnodes)))))))
(goto-char (point-min))
(while (search-forward "\n\^_" nil t)
(forward-line 1)
(let ((beg (point))
thisnode next)
(forward-line 1)
(if (re-search-backward regexp beg t)
(save-restriction
(search-forward "\n\^_" nil 'move)
(narrow-to-region beg (point))
(setq thisnode (downcase
(buffer-substring-no-properties
(match-beginning 1)
(progn
(goto-char (match-end 1))
(skip-chars-backward " \t")
(point)))))
(end-of-line)
(and (search-backward "next:" nil t)
(setq next (Info-validate-node-name "invalid Next"))
(assoc next allnodes)
(if (equal (car (cdr (assoc next allnodes)))
thisnode)
;; allow multiple `next' pointers to one node
(let ((tem lossages))
(while tem
(if (and (equal (car (cdr (car tem)))
"should have Previous")
(equal (car (car tem))
next))
(setq lossages (delq (car tem) lossages)))
(setq tem (cdr tem))))
(setq lossages
(cons (list next
"should have Previous"
thisnode)
lossages))))
(end-of-line)
(if (re-search-backward "prev[ious]*:" nil t)
(Info-validate-node-name "invalid Previous"))
(end-of-line)
(if (search-backward "up:" nil t)
(Info-validate-node-name "invalid Up"))
(if (re-search-forward "\n* Menu:" nil t)
(while (re-search-forward "\n\\* " nil t)
(Info-validate-node-name
(concat "invalid menu item "
(buffer-substring (point)
(save-excursion
(skip-chars-forward "^:")
(point))))
(Info-extract-menu-node-name))))
(goto-char (point-min))
(while (re-search-forward "\\*note[ \n]*[^:\t]*:" nil t)
(goto-char (+ (match-beginning 0) 5))
(skip-chars-forward " \n")
(Info-validate-node-name
(concat "invalid reference "
(buffer-substring (point)
(save-excursion
(skip-chars-forward "^:")
(point))))
(Info-extract-menu-node-name "Bad format cross-reference")))))))
(setq tags-losing (not (Info-validate-tags-table)))
(if (or lossages tags-losing)
(with-output-to-temp-buffer " *problems in info file*"
(while lossages
(princ "In node \"")
(princ (car (car lossages)))
(princ "\", ")
(let ((tem (nth 1 (car lossages))))
(cond ((string-match "\n" tem)
(princ (substring tem 0 (match-beginning 0)))
(princ "..."))
(t
(princ tem))))
(if (nth 2 (car lossages))
(progn
(princ ": ")
(let ((tem (nth 2 (car lossages))))
(cond ((string-match "\n" tem)
(princ (substring tem 0 (match-beginning 0)))
(princ "..."))
(t
(princ tem))))))
(terpri)
(setq lossages (cdr lossages)))
(if tags-losing (princ "\nTags table must be recomputed\n")))
;; Here if info file is valid.
;; If we already made a list of problems, clear it out.
(save-excursion
(if (get-buffer " *problems in info file*")
(progn
(set-buffer " *problems in info file*")
(kill-buffer (current-buffer)))))
(message "File appears valid"))))))
(defun Info-validate-node-name (kind &optional name)
(if name
nil
(goto-char (match-end 0))
(skip-chars-forward " \t")
(if (= (following-char) ?\()
nil
(setq name
(buffer-substring-no-properties
(point)
(progn
(skip-chars-forward "^,\t\n")
(skip-chars-backward " ")
(point))))))
(if (null name)
nil
(setq name (downcase name))
(or (and (> (length name) 0) (= (aref name 0) ?\())
(assoc name allnodes)
(setq lossages
(cons (list thisnode kind name) lossages))))
name)
(defun Info-validate-tags-table ()
(goto-char (point-min))
(if (not (search-forward "\^_\nEnd tag table\n" nil t))
t
(not (catch 'losing
(let* ((end (match-beginning 0))
(start (progn (search-backward "\nTag table:\n")
(1- (match-end 0))))
tem)
(setq tem allnodes)
(while tem
(goto-char start)
(or (equal (car (car tem)) "*")
(search-forward (concat "Node: "
(car (car tem))
"\177")
end t)
(throw 'losing 'x))
(setq tem (cdr tem)))
(goto-char (1+ start))
(while (looking-at ".*Node: \\(.*\\)\177\\([0-9]+\\)$")
(setq tem (downcase (buffer-substring-no-properties
(match-beginning 1)
(match-end 1))))
(setq tem (assoc tem allnodes))
(if (or (not tem)
(< 1000 (progn
(goto-char (match-beginning 2))
(setq tem (- (car (cdr (cdr tem)))
(read (current-buffer))))
(if (> tem 0) tem (- tem)))))
(throw 'losing 'y))
(forward-line 1)))
(if (looking-at "\^_\n")
(forward-line 1))
(or (looking-at "End tag table\n")
(throw 'losing 'z))
nil))))
;;;###autoload
(defun batch-info-validate ()
"Runs `Info-validate' on the files remaining on the command line.
Must be used only with -batch, and kills Emacs on completion.
Each file will be processed even if an error occurred previously.
For example, invoke \"emacs -batch -f batch-info-validate $info/ ~/*.info\""
(if (not noninteractive)
(error "batch-info-validate may only be used -batch."))
(let ((version-control t)
(auto-save-default nil)
(find-file-run-dired nil)
(kept-old-versions 259259)
(kept-new-versions 259259))
(let ((error 0)
file
(files ()))
(while command-line-args-left
(setq file (expand-file-name (car command-line-args-left)))
(cond ((not (file-exists-p file))
(message ">> %s does not exist!" file)
(setq error 1
command-line-args-left (cdr command-line-args-left)))
((file-directory-p file)
(setq command-line-args-left (nconc (directory-files file)
(cdr command-line-args-left))))
(t
(setq files (cons file files)
command-line-args-left (cdr command-line-args-left)))))
(while files
(setq file (car files)
files (cdr files))
(let ((lose nil))
(condition-case err
(progn
(if buffer-file-name (kill-buffer (current-buffer)))
(find-file file)
(buffer-disable-undo (current-buffer))
(set-buffer-modified-p nil)
(fundamental-mode)
(let ((case-fold-search nil))
(goto-char (point-max))
(cond ((search-backward "\n\^_\^L\nTag table:\n" nil t)
(message "%s already tagified" file))
((< (point-max) 30000)
(message "%s too small to bother tagifying" file))
(t
(Info-tagify))))
(let ((loss-name " *problems in info file*"))
(message "Checking validity of info file %s..." file)
(if (get-buffer loss-name)
(kill-buffer loss-name))
(Info-validate)
(if (not (get-buffer loss-name))
nil ;(message "Checking validity of info file %s... OK" file)
(message "----------------------------------------------------------------------")
(message ">> PROBLEMS IN INFO FILE %s" file)
(save-excursion
(set-buffer loss-name)
(princ (buffer-substring-no-properties
(point-min) (point-max))))
(message "----------------------------------------------------------------------")
(setq error 1 lose t)))
(if (and (buffer-modified-p)
(not lose))
(progn (message "Saving modified %s" file)
(save-buffer))))
(error (message ">> Error: %s" (prin1-to-string err))))))
(kill-emacs error))))
;;; informat.el ends here
texinfo-3.7/emacs/makeinfo.el 100444 11732 13 21362 6045204205 14450 0 ustar bfox user ;;; makeinfo.el --- run makeinfo conveniently
;; Copyright (C) 1991, 1993 Free Software Foundation, Inc.
;; Author: Robert J. Chassell
;; Maintainer: FSF
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Commentary:
;;; The Texinfo mode `makeinfo' related commands are:
;; makeinfo-region to run makeinfo on the current region.
;; makeinfo-buffer to run makeinfo on the current buffer, or
;; with optional prefix arg, on current region
;; kill-compilation to kill currently running makeinfo job
;; makeinfo-recenter-makeinfo-buffer to redisplay *compilation* buffer
;;; Keybindings (defined in `texinfo.el')
;; makeinfo bindings
; (define-key texinfo-mode-map "\C-c\C-m\C-r" 'makeinfo-region)
; (define-key texinfo-mode-map "\C-c\C-m\C-b" 'makeinfo-buffer)
; (define-key texinfo-mode-map "\C-c\C-m\C-k" 'kill-compilation)
; (define-key texinfo-mode-map "\C-c\C-m\C-l"
; 'makeinfo-recenter-compilation-buffer)
;;; Code:
;;; Variables used by `makeinfo'
(require 'compile)
(defvar makeinfo-run-command "makeinfo"
"*Command used to run `makeinfo' subjob.
The name of the file is appended to this string, separated by a space.")
(defvar makeinfo-options "--fill-column=70"
"*String containing options for running `makeinfo'.
Do not include `--footnote-style' or `--paragraph-indent';
the proper way to specify those is with the Texinfo commands
`@footnotestyle` and `@paragraphindent'.")
(require 'texinfo)
(defvar makeinfo-compilation-process nil
"Process that runs `makeinfo'. Should start out nil.")
(defvar makeinfo-temp-file nil
"Temporary file name used for text being sent as input to `makeinfo'.")
(defvar makeinfo-output-file-name nil
"Info file name used for text output by `makeinfo'.")
;;; The `makeinfo' function definitions
(defun makeinfo-region (region-beginning region-end)
"Make Info file from region of current Texinfo file, and switch to it.
This command does not offer the `next-error' feature since it would
apply to a temporary file, not the original; use the `makeinfo-buffer'
command to gain use of `next-error'."
(interactive "r")
(let (filename-or-header
filename-or-header-beginning
filename-or-header-end)
;; Cannot use `let' for makeinfo-temp-file or
;; makeinfo-output-file-name since `makeinfo-compilation-sentinel'
;; needs them.
(setq makeinfo-temp-file
(concat
(make-temp-name
(substring (buffer-file-name)
0
(or (string-match "\\.tex" (buffer-file-name))
(length (buffer-file-name)))))
".texinfo"))
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(let ((search-end (save-excursion (forward-line 100) (point))))
;; Find and record the Info filename,
;; or else explain that a filename is needed.
(if (re-search-forward
"^@setfilename[ \t]+\\([^ \t\n]+\\)[ \t]*"
search-end t)
(setq makeinfo-output-file-name
(buffer-substring (match-beginning 1) (match-end 1)))
(error
"The texinfo file needs a line saying: @setfilename "))
;; Find header and specify its beginning and end.
(goto-char (point-min))
(if (and
(prog1
(search-forward tex-start-of-header search-end t)
(beginning-of-line)
;; Mark beginning of header.
(setq filename-or-header-beginning (point)))
(prog1
(search-forward tex-end-of-header nil t)
(beginning-of-line)
;; Mark end of header
(setq filename-or-header-end (point))))
;; Insert the header into the temporary file.
(write-region
(min filename-or-header-beginning region-beginning)
filename-or-header-end
makeinfo-temp-file nil nil)
;; Else no header; insert @filename line into temporary file.
(goto-char (point-min))
(search-forward "@setfilename" search-end t)
(beginning-of-line)
(setq filename-or-header-beginning (point))
(forward-line 1)
(setq filename-or-header-end (point))
(write-region
(min filename-or-header-beginning region-beginning)
filename-or-header-end
makeinfo-temp-file nil nil))
;; Insert the region into the file.
(write-region
(max region-beginning filename-or-header-end)
region-end
makeinfo-temp-file t nil)
;; Run the `makeinfo-compile' command in the *compilation* buffer
(save-excursion
(makeinfo-compile
(concat makeinfo-run-command
" "
makeinfo-options
" "
makeinfo-temp-file)
"Use `makeinfo-buffer' to gain use of the `next-error' command"
nil)))))))
;;; Actually run makeinfo. COMMAND is the command to run.
;;; ERROR-MESSAGE is what to say when next-error can't find another error.
;;; If PARSE-ERRORS is non-nil, do try to parse error messages.
(defun makeinfo-compile (command error-message parse-errors)
(let ((buffer
(compile-internal command error-message nil
(and (not parse-errors)
;; If we do want to parse errors, pass nil.
;; Otherwise, use this function, which won't
;; ever find any errors.
'(lambda (&rest ignore)
(setq compilation-error-list nil))))))
(set-process-sentinel (get-buffer-process buffer)
'makeinfo-compilation-sentinel)))
;; Delete makeinfo-temp-file after processing is finished,
;; and visit Info file.
;; This function is called when the compilation process changes state.
;; Based on `compilation-sentinel' in compile.el
(defun makeinfo-compilation-sentinel (proc msg)
(compilation-sentinel proc msg)
(if (and makeinfo-temp-file (file-exists-p makeinfo-temp-file))
(delete-file makeinfo-temp-file))
;; Always use the version on disk.
(if (get-file-buffer makeinfo-output-file-name)
(progn (set-buffer makeinfo-output-file-name)
(revert-buffer t t))
(find-file makeinfo-output-file-name))
(goto-char (point-min)))
(defun makeinfo-buffer ()
"Make Info file from current buffer.
Use the \\[next-error] command to move to the next error
\(if there are errors\)."
(interactive)
(cond ((null buffer-file-name)
(error "Buffer not visiting any file"))
((buffer-modified-p)
(if (y-or-n-p "Buffer modified; do you want to save it? ")
(save-buffer))))
;; Find and record the Info filename,
;; or else explain that a filename is needed.
(save-excursion
(goto-char (point-min))
(let ((search-end (save-excursion (forward-line 100) (point))))
(if (re-search-forward
"^@setfilename[ \t]+\\([^ \t\n]+\\)[ \t]*"
search-end t)
(setq makeinfo-output-file-name
(buffer-substring (match-beginning 1) (match-end 1)))
(error
"The texinfo file needs a line saying: @setfilename "))))
(save-excursion
(makeinfo-compile
(concat makeinfo-run-command " " makeinfo-options
" " buffer-file-name)
"No more errors."
t)))
(defun makeinfo-recenter-compilation-buffer (linenum)
"Redisplay `*compilation*' buffer so most recent output can be seen.
The last line of the buffer is displayed on
line LINE of the window, or centered if LINE is nil."
(interactive "P")
(let ((makeinfo-buffer (get-buffer "*compilation*"))
(old-buffer (current-buffer)))
(if (null makeinfo-buffer)
(message "No *compilation* buffer")
(pop-to-buffer makeinfo-buffer)
(bury-buffer makeinfo-buffer)
(goto-char (point-max))
(recenter (if linenum
(prefix-numeric-value linenum)
(/ (window-height) 2)))
(pop-to-buffer old-buffer)
)))
;;; Place `provide' at end of file.
(provide 'makeinfo)
;;; makeinfo.el ends here
texinfo-3.7/emacs/texinfmt.el 100444 11732 13 341537 6045205360 14551 0 ustar bfox user ;;; texinfmt.el --- format Texinfo files into Info files.
;; Copyright (C) 1985, 1986, 1988,
;; 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
;; Maintainer: Robert J. Chassell
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Code:
;;; Emacs lisp functions to convert Texinfo files to Info files.
(defvar texinfmt-version "2.32 of 19 November 1993")
;;; Variable definitions
(require 'texinfo) ; So `texinfo-footnote-style' is defined.
(require 'texnfo-upd) ; So `texinfo-section-types-regexp' is defined.
(defvar texinfo-format-syntax-table nil)
(defvar texinfo-vindex)
(defvar texinfo-findex)
(defvar texinfo-cindex)
(defvar texinfo-pindex)
(defvar texinfo-tindex)
(defvar texinfo-kindex)
(defvar texinfo-last-node)
(defvar texinfo-node-names)
(defvar texinfo-enclosure-list)
(defvar texinfo-alias-list)
(defvar texinfo-command-start)
(defvar texinfo-command-end)
(defvar texinfo-command-name)
(defvar texinfo-defun-type)
(defvar texinfo-last-node-pos)
(defvar texinfo-stack)
(defvar texinfo-short-index-cmds-alist)
(defvar texinfo-short-index-format-cmds-alist)
(defvar texinfo-format-filename)
(defvar texinfo-footnote-number)
(defvar texinfo-start-of-header)
(defvar texinfo-end-of-header)
(defvar texinfo-raisesections-alist)
(defvar texinfo-lowersections-alist)
;;; Syntax table
(if texinfo-format-syntax-table
nil
(setq texinfo-format-syntax-table (make-syntax-table))
(modify-syntax-entry ?\" " " texinfo-format-syntax-table)
(modify-syntax-entry ?\\ " " texinfo-format-syntax-table)
(modify-syntax-entry ?@ "\\" texinfo-format-syntax-table)
(modify-syntax-entry ?\^q "\\" texinfo-format-syntax-table)
(modify-syntax-entry ?\[ "." texinfo-format-syntax-table)
(modify-syntax-entry ?\] "." texinfo-format-syntax-table)
(modify-syntax-entry ?\( "." texinfo-format-syntax-table)
(modify-syntax-entry ?\) "." texinfo-format-syntax-table)
(modify-syntax-entry ?{ "(}" texinfo-format-syntax-table)
(modify-syntax-entry ?} "){" texinfo-format-syntax-table)
(modify-syntax-entry ?\' "." texinfo-format-syntax-table))
;;; Top level buffer and region formatting functions
;;;###autoload
(defun texinfo-format-buffer (&optional notagify)
"Process the current buffer as texinfo code, into an Info file.
The Info file output is generated in a buffer visiting the Info file
names specified in the @setfilename command.
Non-nil argument (prefix, if interactive) means don't make tag table
and don't split the file if large. You can use Info-tagify and
Info-split to do these manually."
(interactive "P")
(let ((lastmessage "Formatting Info file..."))
(message lastmessage)
(texinfo-format-buffer-1)
(if notagify
nil
(if (> (buffer-size) 30000)
(progn
(message (setq lastmessage "Making tags table for Info file..."))
(Info-tagify)))
(if (> (buffer-size) 100000)
(progn
(message (setq lastmessage "Splitting Info file..."))
(Info-split))))
(message (concat lastmessage
(if (interactive-p) "done. Now save it." "done.")))))
(defvar texinfo-region-buffer-name "*Info Region*"
"*Name of the temporary buffer used by \\[texinfo-format-region].")
;;;###autoload
(defun texinfo-format-region (region-beginning region-end)
"Convert the current region of the Texinfo file to Info format.
This lets you see what that part of the file will look like in Info.
The command is bound to \\[texinfo-format-region]. The text that is
converted to Info is stored in a temporary buffer."
(interactive "r")
(message "Converting region to Info format...")
(let (texinfo-command-start
texinfo-command-end
texinfo-command-name
texinfo-vindex
texinfo-findex
texinfo-cindex
texinfo-pindex
texinfo-tindex
texinfo-kindex
texinfo-stack
(texinfo-format-filename "")
texinfo-example-start
texinfo-last-node-pos
texinfo-last-node
texinfo-node-names
(texinfo-footnote-number 0)
last-input-buffer
(fill-column-for-info fill-column)
(input-buffer (current-buffer))
(input-directory default-directory)
(header-text "")
(header-beginning 1)
(header-end 1))
;;; Copy lines between beginning and end of header lines,
;;; if any, or else copy the `@setfilename' line, if any.
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(let ((search-end (save-excursion (forward-line 100) (point))))
(if (or
;; Either copy header text.
(and
(prog1
(search-forward tex-start-of-header search-end t)
(forward-line 1)
;; Mark beginning of header.
(setq header-beginning (point)))
(prog1
(search-forward tex-end-of-header nil t)
(beginning-of-line)
;; Mark end of header
(setq header-end (point))))
;; Or copy @filename line.
(prog2
(goto-char (point-min))
(search-forward "@setfilename" search-end t)
(beginning-of-line)
(setq header-beginning (point))
(forward-line 1)
(setq header-end (point))))
;; Copy header
(setq header-text
(buffer-substring
(min header-beginning region-beginning)
header-end))))))
;;; Find a buffer to use.
(switch-to-buffer (get-buffer-create texinfo-region-buffer-name))
(erase-buffer)
;; Insert the header into the buffer.
(insert header-text)
;; Insert the region into the buffer.
(insert-buffer-substring
input-buffer
(max region-beginning header-end)
region-end)
;; Make sure region ends in a newline.
(or (= (preceding-char) ?\n)
(insert "\n"))
(goto-char (point-min))
(texinfo-mode)
(message "Converting region to Info format...")
(setq fill-column fill-column-for-info)
;; Install a syntax table useful for scanning command operands.
(set-syntax-table texinfo-format-syntax-table)
;; Insert @include files so `texinfo-raise-lower-sections' can
;; work on them without losing track of multiple
;; @raise/@lowersections commands.
(while (re-search-forward "^@include" nil t)
(setq texinfo-command-end (point))
(let ((filename (concat input-directory
(texinfo-parse-line-arg))))
(re-search-backward "^@include")
(delete-region (point) (save-excursion (forward-line 1) (point)))
(message "Reading included file: %s" filename)
(save-excursion
(save-restriction
(narrow-to-region
(point)
(+ (point) (car (cdr (insert-file-contents filename)))))
(goto-char (point-min))
;; Remove `@setfilename' line from included file, if any,
;; so @setfilename command not duplicated.
(if (re-search-forward
"^@setfilename" (save-excursion (forward-line 100) (point)) t)
(progn
(beginning-of-line)
(delete-region
(point) (save-excursion (forward-line 1) (point)))))))))
;; Raise or lower level of each section, if necessary.
(goto-char (point-min))
(texinfo-raise-lower-sections)
;; Append @refill to appropriate paragraphs for filling.
(goto-char (point-min))
(texinfo-append-refill)
;; If the region includes the effective end of the data,
;; discard everything after that.
(goto-char (point-max))
(if (re-search-backward "^@bye" nil t)
(delete-region (point) (point-max)))
;; Make sure buffer ends in a newline.
(or (= (preceding-char) ?\n)
(insert "\n"))
;; Don't use a previous value of texinfo-enclosure-list.
(setq texinfo-enclosure-list nil)
(setq texinfo-alias-list nil)
(goto-char (point-min))
(if (looking-at "\\\\input[ \t]+texinfo")
(delete-region (point) (save-excursion (forward-line 1) (point))))
;; Insert Info region title text.
(goto-char (point-min))
(if (search-forward
"@setfilename" (save-excursion (forward-line 100) (point)) t)
(progn
(setq texinfo-command-end (point))
(beginning-of-line)
(setq texinfo-command-start (point))
(let ((arg (texinfo-parse-arg-discard)))
(insert " "
texinfo-region-buffer-name
" buffer for: `")
(insert (file-name-nondirectory (expand-file-name arg)))
(insert "', -*-Text-*-\n")))
;; Else no `@setfilename' line
(insert " "
texinfo-region-buffer-name
" buffer -*-Text-*-\n"))
(insert "produced by `texinfo-format-region'\n"
"from a region in: "
(if (buffer-file-name input-buffer)
(concat "`"
(file-name-sans-versions
(file-name-nondirectory
(buffer-file-name input-buffer)))
"'")
(concat "buffer `" (buffer-name input-buffer) "'"))
"\nusing `texinfmt.el' version "
texinfmt-version
".\n\n")
;; Now convert for real.
(goto-char (point-min))
(texinfo-format-scan)
(goto-char (point-min))
(message "Done.")))
;;; Primary internal formatting function for the whole buffer.
(defun texinfo-format-buffer-1 ()
(let (texinfo-format-filename
texinfo-example-start
texinfo-command-start
texinfo-command-end
texinfo-command-name
texinfo-last-node
texinfo-last-node-pos
texinfo-vindex
texinfo-findex
texinfo-cindex
texinfo-pindex
texinfo-tindex
texinfo-kindex
texinfo-stack
texinfo-node-names
(texinfo-footnote-number 0)
last-input-buffer
outfile
(fill-column-for-info fill-column)
(input-buffer (current-buffer))
(input-directory default-directory))
(setq texinfo-enclosure-list nil)
(setq texinfo-alias-list nil)
(save-excursion
(goto-char (point-min))
(or (search-forward "@setfilename" nil t)
(error "Texinfo file needs an `@setfilename FILENAME' line."))
(setq texinfo-command-end (point))
(setq outfile (texinfo-parse-line-arg)))
(find-file outfile)
(texinfo-mode)
(setq fill-column fill-column-for-info)
(set-syntax-table texinfo-format-syntax-table)
(erase-buffer)
(insert-buffer-substring input-buffer)
(message "Converting %s to Info format..." (buffer-name input-buffer))
;; Insert @include files so `texinfo-raise-lower-sections' can
;; work on them without losing track of multiple
;; @raise/@lowersections commands.
(goto-char (point-min))
(while (re-search-forward "^@include" nil t)
(setq texinfo-command-end (point))
(let ((filename (concat input-directory
(texinfo-parse-line-arg))))
(re-search-backward "^@include")
(delete-region (point) (save-excursion (forward-line 1) (point)))
(message "Reading included file: %s" filename)
(save-excursion
(save-restriction
(narrow-to-region
(point)
(+ (point) (car (cdr (insert-file-contents filename)))))
(goto-char (point-min))
;; Remove `@setfilename' line from included file, if any,
;; so @setfilename command not duplicated.
(if (re-search-forward
"^@setfilename"
(save-excursion (forward-line 100) (point)) t)
(progn
(beginning-of-line)
(delete-region
(point) (save-excursion (forward-line 1) (point)))))))))
;; Raise or lower level of each section, if necessary.
(goto-char (point-min))
(texinfo-raise-lower-sections)
;; Append @refill to appropriate paragraphs
(goto-char (point-min))
(texinfo-append-refill)
(goto-char (point-min))
(search-forward "@setfilename")
(beginning-of-line)
(delete-region (point-min) (point))
;; Remove @bye at end of file, if it is there.
(goto-char (point-max))
(if (search-backward "@bye" nil t)
(delete-region (point) (point-max)))
;; Make sure buffer ends in a newline.
(or (= (preceding-char) ?\n)
(insert "\n"))
;; Scan the whole buffer, converting to Info format.
(texinfo-format-scan)
;; Return data for indices.
(goto-char (point-min))
(list outfile
texinfo-vindex texinfo-findex texinfo-cindex
texinfo-pindex texinfo-tindex texinfo-kindex)))
;;; Perform non-@-command file conversions: quotes and hyphens
(defun texinfo-format-convert (min max)
;; Convert left and right quotes to typewriter font quotes.
(goto-char min)
(while (search-forward "``" max t)
(replace-match "\""))
(goto-char min)
(while (search-forward "''" max t)
(replace-match "\""))
;; Convert three hyphens in a row to two.
(goto-char min)
(while (re-search-forward "\\( \\|\\w\\)\\(---\\)\\( \\|\\w\\)" max t)
(delete-region (1+ (match-beginning 2)) (+ 2 (match-beginning
2)))))
;;; Handle paragraph filling
(defvar texinfo-no-refill-regexp
"^@\\(example\\|smallexample\\|lisp\\|smalllisp\\|display\\|format\\|flushleft\\|flushright\\|menu\\|titlepage\\|iftex\\|ifhtml\\|tex\\|html\\)"
"Regexp specifying environments in which paragraphs are not filled.")
(defvar texinfo-part-of-para-regexp
"^@\\(b{\\|bullet{\\|cite{\\|code{\\|emph{\\|equiv{\\|error{\\|expansion{\\|file{\\|i{\\|inforef{\\|kbd{\\|key{\\|lisp{\\|minus{\\|point{\\|print{\\|pxref{\\|r{\\|ref{\\|result{\\|samp{\\|sc{\\|t{\\|TeX{\\|today{\\|var{\\|w{\\|xref{\\)"
"Regexp specifying @-commands found within paragraphs.")
(defun texinfo-append-refill ()
"Append @refill at end of each paragraph that should be filled.
Do not append @refill to paragraphs within @example and similar environments.
Do not append @refill to paragraphs containing @w{TEXT} or @*."
;; It is necessary to append @refill before other processing because
;; the other processing removes information that tells Texinfo
;; whether the text should or should not be filled.
(while (< (point) (point-max))
(let ((refill-blank-lines "^[ \t\n]*$")
(case-fold-search nil)) ; Don't confuse @TeX and @tex....
(beginning-of-line)
;; 1. Skip over blank lines;
;; skip over lines beginning with @-commands,
;; but do not skip over lines
;; that are no-refill environments such as @example or
;; that begin with within-paragraph @-commands such as @code.
(while (and (looking-at (concat "^@\\|^\\\\\\|" refill-blank-lines))
(not (looking-at
(concat
"\\("
texinfo-no-refill-regexp
"\\|"
texinfo-part-of-para-regexp
"\\)")))
(< (point) (point-max)))
(forward-line 1))
;; 2. Skip over @example and similar no-refill environments.
(if (looking-at texinfo-no-refill-regexp)
(let ((environment
(buffer-substring (match-beginning 1) (match-end 1))))
(progn (re-search-forward (concat "^@end " environment) nil t)
(forward-line 1)))
;; 3. Do not refill a paragraph containing @w or @*
(if (or
(>= (point) (point-max))
(re-search-forward
"@w{\\|@\\*" (save-excursion (forward-paragraph) (point)) t))
;; Go to end of paragraph and do nothing.
(forward-paragraph)
;; 4. Else go to end of paragraph and insert @refill
(forward-paragraph)
(forward-line -1)
(end-of-line)
(delete-region
(point)
(save-excursion (skip-chars-backward " \t") (point)))
;; `looking-at-backward' not available in v. 18.57
;; (if (not (looking-at-backward "@refill\\|@bye")) ;)
(if (not (re-search-backward
"@refill\\|@bye"
(save-excursion (beginning-of-line) (point))
t))
(insert "@refill"))
(forward-line 1))))))
;;; Handle `@raisesections' and `@lowersections' commands
;; These commands change the hierarchical level of chapter structuring
;; commands.
;;
;; @raisesections changes @subsection to @section,
;; @section to @chapter,
;; etc.
;;
;; @lowersections changes @chapter to @section
;; @subsection to @subsubsection,
;; etc.
;;
;; An @raisesections/@lowersections command changes only those
;; structuring commands that follow the @raisesections/@lowersections
;; command.
;;
;; Repeated @raisesections/@lowersections continue to raise or lower
;; the heading level.
;;
;; An @lowersections command cancels an @raisesections command, and
;; vice versa.
;;
;; You cannot raise or lower "beyond" chapters or subsubsections, but
;; trying to do so does not elicit an error---you just get more
;; headings that mean the same thing as you keep raising or lowering
;; (for example, after a single @raisesections, both @chapter and
;; @section produce chapter headings).
(defun texinfo-raise-lower-sections ()
"Raise or lower the hierarchical level of chapters, sections, etc.
This function acts according to `@raisesections' and `@lowersections'
commands in the Texinfo file.
For example, an `@lowersections' command is useful if you wish to
include what is written as an outer or standalone Texinfo file in
another Texinfo file as an inner, included file. The `@lowersections'
command changes chapters to sections, sections to subsections and so
on.
@raisesections changes @subsection to @section,
@section to @chapter,
@heading to @chapheading,
etc.
@lowersections changes @chapter to @section,
@subsection to @subsubsection,
@heading to @subheading,
etc.
An `@raisesections' or `@lowersections' command changes only those
structuring commands that follow the `@raisesections' or
`@lowersections' command.
An `@lowersections' command cancels an `@raisesections' command, and
vice versa.
Repeated use of the commands continue to raise or lower the hierarchical
level a step at a time.
An attempt to raise above `chapters' reproduces chapter commands; an
attempt to lower below subsubsections reproduces subsubsection
commands."
;; `texinfo-section-types-regexp' is defined in `texnfo-upd.el';
;; it is a regexp matching chapter, section, other headings
;; (but not the top node).
(let (type (level 0))
(while
(re-search-forward
(concat
"\\(\\(^@\\(raise\\|lower\\)sections\\)\\|\\("
texinfo-section-types-regexp
"\\)\\)")
nil t)
(beginning-of-line)
(save-excursion (setq type (read (current-buffer))))
(cond
;; 1. Increment level
((eq type '@raisesections)
(setq level (1+ level))
(delete-region
(point) (save-excursion (forward-line 1) (point))))
;; 2. Decrement level
((eq type '@lowersections)
(setq level (1- level))
(delete-region
(point) (save-excursion (forward-line 1) (point))))
;; Now handle structuring commands
((cond
;; 3. Raise level when positive
((> level 0)
(let ((count level)
(new-level type))
(while (> count 0)
(setq new-level
(cdr (assq new-level texinfo-raisesections-alist)))
(setq count (1- count)))
(kill-word 1)
(insert (symbol-name new-level))))
;; 4. Do nothing except move point when level is zero
((= level 0) (forward-line 1))
;; 5. Lower level when positive
((< level 0)
(let ((count level)
(new-level type))
(while (< count 0)
(setq new-level
(cdr (assq new-level texinfo-lowersections-alist)))
(setq count (1+ count)))
(kill-word 1)
(insert (symbol-name new-level))))))))))
(defvar texinfo-raisesections-alist
'((@chapter . @chapter) ; Cannot go higher
(@unnumbered . @unnumbered)
(@majorheading . @majorheading)
(@chapheading . @chapheading)
(@appendix . @appendix)
(@section . @chapter)
(@unnumberedsec . @unnumbered)
(@heading . @chapheading)
(@appendixsec . @appendix)
(@subsection . @section)
(@unnumberedsubsec . @unnumberedsec)
(@subheading . @heading)
(@appendixsubsec . @appendixsec)
(@subsubsection . @subsection)
(@unnumberedsubsubsec . @unnumberedsubsec)
(@subsubheading . @subheading)
(@appendixsubsubsec . @appendixsubsec))
"*An alist of next higher levels for chapters, sections. etc.
For example, section to chapter, subsection to section.
Used by `texinfo-raise-lower-sections'.
The keys specify types of section; the values correspond to the next
higher types.")
(defvar texinfo-lowersections-alist
'((@chapter . @section)
(@unnumbered . @unnumberedsec)
(@majorheading . @heading)
(@chapheading . @heading)
(@appendix . @appendixsec)
(@section . @subsection)
(@unnumberedsec . @unnumberedsubsec)
(@heading . @subheading)
(@appendixsec . @appendixsubsec)
(@subsection . @subsubsection)
(@unnumberedsubsec . @unnumberedsubsubsec)
(@subheading . @subsubheading)
(@appendixsubsec . @appendixsubsubsec)
(@subsubsection . @subsubsection) ; Cannot go lower.
(@unnumberedsubsubsec . @unnumberedsubsubsec)
(@subsubheading . @subsubheading)
(@appendixsubsubsec . @appendixsubsubsec))
"*An alist of next lower levels for chapters, sections. etc.
For example, chapter to section, section to subsection.
Used by `texinfo-raise-lower-sections'.
The keys specify types of section; the values correspond to the next
lower types.")
;;; Perform those texinfo-to-info conversions that apply to the whole input
;;; uniformly.
(defun texinfo-format-scan ()
(texinfo-format-convert (point-min) (point-max))
;; Scan for @-commands.
(goto-char (point-min))
(while (search-forward "@" nil t)
(if (looking-at "[@{}^'` *\"?!]")
;; Handle a few special @-followed-by-one-char commands.
(if (= (following-char) ?*)
(progn
;; remove command
(delete-region (1- (point)) (1+ (point)))
;; insert return if not at end of line;
;; else line is already broken.
(if (not (= (following-char) ?\n))
(insert ?\n)))
;; The other characters are simply quoted. Delete the @.
(delete-char -1)
(forward-char 1))
;; @ is followed by a command-word; find the end of the word.
(setq texinfo-command-start (1- (point)))
(if (= (char-syntax (following-char)) ?w)
(forward-word 1)
(forward-char 1))
(setq texinfo-command-end (point))
;; Handle let aliasing
(setq texinfo-command-name
(let (trial
(cmdname
(buffer-substring
(1+ texinfo-command-start) texinfo-command-end)))
(while (setq trial (assoc cmdname texinfo-alias-list))
(setq cmdname (cdr trial)))
(intern cmdname)))
;; Call the handler for this command.
(let ((enclosure-type
(assoc
(symbol-name texinfo-command-name)
texinfo-enclosure-list)))
(if enclosure-type
(progn
(insert
(car (car (cdr enclosure-type)))
(texinfo-parse-arg-discard)
(car (cdr (car (cdr enclosure-type)))))
(goto-char texinfo-command-start))
(let ((cmd (get texinfo-command-name 'texinfo-format)))
(if cmd (funcall cmd) (texinfo-unsupported)))))))
(cond (texinfo-stack
(goto-char (nth 2 (car texinfo-stack)))
(error "Unterminated @%s" (car (car texinfo-stack))))))
(put 'begin 'texinfo-format 'texinfo-format-begin)
(defun texinfo-format-begin ()
(texinfo-format-begin-end 'texinfo-format))
(put 'end 'texinfo-format 'texinfo-format-end)
(defun texinfo-format-end ()
(texinfo-format-begin-end 'texinfo-end))
(defun texinfo-format-begin-end (prop)
(setq texinfo-command-name (intern (texinfo-parse-line-arg)))
(let ((cmd (get texinfo-command-name prop)))
(if cmd (funcall cmd)
(texinfo-unsupported))))
;;; Parsing functions
(defun texinfo-parse-line-arg ()
(goto-char texinfo-command-end)
(let ((start (point)))
(cond ((looking-at " ")
(skip-chars-forward " ")
(setq start (point))
(end-of-line)
(skip-chars-backward " ")
(delete-region (point) (progn (end-of-line) (point)))
(setq texinfo-command-end (1+ (point))))
((looking-at "{")
(setq start (1+ (point)))
(forward-list 1)
(setq texinfo-command-end (point))
(forward-char -1))
(t
(error "Invalid texinfo command arg format")))
(prog1 (buffer-substring start (point))
(if (eolp) (forward-char 1)))))
(defun texinfo-parse-expanded-arg ()
(goto-char texinfo-command-end)
(let ((start (point))
marker)
(cond ((looking-at " ")
(skip-chars-forward " ")
(setq start (point))
(end-of-line)
(setq texinfo-command-end (1+ (point))))
((looking-at "{")
(setq start (1+ (point)))
(forward-list 1)
(setq texinfo-command-end (point))
(forward-char -1))
(t
(error "Invalid texinfo command arg format")))
(setq marker (move-marker (make-marker) texinfo-command-end))
(texinfo-format-expand-region start (point))
(setq texinfo-command-end (marker-position marker))
(move-marker marker nil)
(prog1 (buffer-substring start (point))
(if (eolp) (forward-char 1)))))
(defun texinfo-format-expand-region (start end)
(save-restriction
(narrow-to-region start end)
(let (texinfo-command-start
texinfo-command-end
texinfo-command-name
texinfo-stack)
(texinfo-format-scan))
(goto-char (point-max))))
(defun texinfo-parse-arg-discard ()
(prog1 (texinfo-parse-line-arg)
(texinfo-discard-command)))
(defun texinfo-discard-command ()
(delete-region texinfo-command-start texinfo-command-end))
(defun texinfo-optional-braces-discard ()
"Discard braces following command, if any."
(goto-char texinfo-command-end)
(let ((start (point)))
(cond ((looking-at "[ \t]*\n")) ; do nothing
((looking-at "{") ; remove braces, if any
(forward-list 1)
(setq texinfo-command-end (point)))
(t
(error
"Invalid `texinfo-optional-braces-discard' format \(need braces?\)")))
(delete-region texinfo-command-start texinfo-command-end)))
(defun texinfo-format-parse-line-args ()
(let ((start (1- (point)))
next beg end
args)
(skip-chars-forward " ")
(while (not (eolp))
(setq beg (point))
(re-search-forward "[\n,]")
(setq next (point))
(if (bolp) (setq next (1- next)))
(forward-char -1)
(skip-chars-backward " ")
(setq end (point))
(setq args (cons (if (> end beg) (buffer-substring beg end))
args))
(goto-char next)
(skip-chars-forward " "))
(if (eolp) (forward-char 1))
(setq texinfo-command-end (point))
(nreverse args)))
(defun texinfo-format-parse-args ()
(let ((start (1- (point)))
next beg end
args)
(search-forward "{")
(save-excursion
(texinfo-format-expand-region
(point)
(save-excursion (up-list 1) (1- (point)))))
;; The following does not handle cross references of the form:
;; `@xref{bullet, , @code{@@bullet}@{@}}.' because the
;; re-search-forward finds the first right brace after the second
;; comma.
(while (/= (preceding-char) ?\})
(skip-chars-forward " \t\n")
(setq beg (point))
(re-search-forward "[},]")
(setq next (point))
(forward-char -1)
(skip-chars-backward " \t\n")
(setq end (point))
(cond ((< beg end)
(goto-char beg)
(while (search-forward "\n" end t)
(replace-match " "))))
(setq args (cons (if (> end beg) (buffer-substring beg end))
args))
(goto-char next))
(if (eolp) (forward-char 1))
(setq texinfo-command-end (point))
(nreverse args)))
(defun texinfo-format-parse-defun-args ()
(goto-char texinfo-command-end)
(let ((start (point)))
(end-of-line)
(setq texinfo-command-end (1+ (point)))
(let ((marker (move-marker (make-marker) texinfo-command-end)))
(texinfo-format-expand-region start (point))
(setq texinfo-command-end (marker-position marker))
(move-marker marker nil))
(goto-char start)
(let ((args '())
beg end)
(skip-chars-forward " ")
(while (not (eolp))
(cond ((looking-at "{")
(setq beg (1+ (point)))
(forward-list 1)
(setq end (1- (point))))
(t
(setq beg (point))
(re-search-forward "[\n ]")
(forward-char -1)
(setq end (point))))
(setq args (cons (buffer-substring beg end) args))
(skip-chars-forward " "))
(forward-char 1)
(nreverse args))))
(defun texinfo-discard-line ()
(goto-char texinfo-command-end)
(skip-chars-forward " \t")
(or (eolp)
(error "Extraneous text at end of command line."))
(goto-char texinfo-command-start)
(or (bolp)
(error "Extraneous text at beginning of command line."))
(delete-region (point) (progn (forward-line 1) (point))))
(defun texinfo-discard-line-with-args ()
(goto-char texinfo-command-start)
(delete-region (point) (progn (forward-line 1) (point))))
;;; @setfilename
;; Only `texinfo-format-buffer' handles @setfilename with this
;; definition; `texinfo-format-region' handles @setfilename, if any,
;; specially.
(put 'setfilename 'texinfo-format 'texinfo-format-setfilename)
(defun texinfo-format-setfilename ()
(let ((arg (texinfo-parse-arg-discard)))
(message "Formatting Info file: %s" arg)
(setq texinfo-format-filename
(file-name-nondirectory (expand-file-name arg)))
(insert "Info file: "
texinfo-format-filename ", -*-Text-*-\n"
;; Date string removed so that regression testing is easier.
;; "produced on "
;; (substring (current-time-string) 8 10) " "
;; (substring (current-time-string) 4 7) " "
;; (substring (current-time-string) -4) " "
"produced by `texinfo-format-buffer'\n"
"from file"
(if (buffer-file-name input-buffer)
(concat " `"
(file-name-sans-versions
(file-name-nondirectory
(buffer-file-name input-buffer)))
"'")
(concat "buffer `" (buffer-name input-buffer) "'"))
"\nusing `texinfmt.el' version "
texinfmt-version
".\n\n")))
;;; @node, @menu
(put 'node 'texinfo-format 'texinfo-format-node)
(put 'nwnode 'texinfo-format 'texinfo-format-node)
(defun texinfo-format-node ()
(let* ((args (texinfo-format-parse-line-args))
(name (nth 0 args))
(next (nth 1 args))
(prev (nth 2 args))
(up (nth 3 args)))
(texinfo-discard-command)
(setq texinfo-last-node name)
(let ((tem (downcase name)))
(if (assoc tem texinfo-node-names)
(error "Duplicate node name: %s" name)
(setq texinfo-node-names (cons (list tem) texinfo-node-names))))
(setq texinfo-footnote-number 0)
;; insert "\n\^_" unconditionally since this is what info is looking for
(insert "\n\^_\nFile: " texinfo-format-filename
", Node: " name)
(if next
(insert ", Next: " next))
(if prev
(insert ", Prev: " prev))
(if up
(insert ", Up: " up))
(insert ?\n)
(setq texinfo-last-node-pos (point))))
(put 'menu 'texinfo-format 'texinfo-format-menu)
(defun texinfo-format-menu ()
(texinfo-discard-line)
(insert "* Menu:\n\n"))
(put 'menu 'texinfo-end 'texinfo-discard-command)
;;; Cross references
; @xref {NODE, FNAME, NAME, FILE, DOCUMENT}
; -> *Note FNAME: (FILE)NODE
; If FILE is missing,
; *Note FNAME: NODE
; If FNAME is empty and NAME is present
; *Note NAME: Node
; If both NAME and FNAME are missing
; *Note NODE::
; texinfo ignores the DOCUMENT argument.
; -> See section [NAME, else NODE], page
; If FILE is specified, (FILE)NODE is used for xrefs.
; If fifth argument DOCUMENT is specified, produces
; See section [NAME, else NODE], page
; of DOCUMENT
; @ref a reference that does not put `See' or `see' in
; the hardcopy and is the same as @xref in Info
(put 'ref 'texinfo-format 'texinfo-format-xref)
(put 'xref 'texinfo-format 'texinfo-format-xref)
(defun texinfo-format-xref ()
(let ((args (texinfo-format-parse-args)))
(texinfo-discard-command)
(insert "*Note ")
(let ((fname (or (nth 1 args) (nth 2 args))))
(if (null (or fname (nth 3 args)))
(insert (car args) "::")
(insert (or fname (car args)) ": ")
(if (nth 3 args)
(insert "(" (nth 3 args) ")"))
(insert (car args))))))
(put 'pxref 'texinfo-format 'texinfo-format-pxref)
(defun texinfo-format-pxref ()
(texinfo-format-xref)
(or (save-excursion
(forward-char -2)
(looking-at "::"))
(insert ".")))
;@inforef{NODE, FNAME, FILE}
;Like @xref{NODE, FNAME,,FILE} in texinfo.
;In Tex, generates "See Info file FILE, node NODE"
(put 'inforef 'texinfo-format 'texinfo-format-inforef)
(defun texinfo-format-inforef ()
(let ((args (texinfo-format-parse-args)))
(texinfo-discard-command)
(if (nth 1 args)
(insert "*Note " (nth 1 args) ": (" (nth 2 args) ")" (car args))
(insert "*Note " "(" (nth 2 args) ")" (car args) "::"))))
;;; Section headings
(put 'majorheading 'texinfo-format 'texinfo-format-chapter)
(put 'chapheading 'texinfo-format 'texinfo-format-chapter)
(put 'ichapter 'texinfo-format 'texinfo-format-chapter)
(put 'chapter 'texinfo-format 'texinfo-format-chapter)
(put 'iappendix 'texinfo-format 'texinfo-format-chapter)
(put 'appendix 'texinfo-format 'texinfo-format-chapter)
(put 'iunnumbered 'texinfo-format 'texinfo-format-chapter)
(put 'top 'texinfo-format 'texinfo-format-chapter)
(put 'unnumbered 'texinfo-format 'texinfo-format-chapter)
(defun texinfo-format-chapter ()
(texinfo-format-chapter-1 ?*))
(put 'heading 'texinfo-format 'texinfo-format-section)
(put 'isection 'texinfo-format 'texinfo-format-section)
(put 'section 'texinfo-format 'texinfo-format-section)
(put 'iappendixsection 'texinfo-format 'texinfo-format-section)
(put 'appendixsection 'texinfo-format 'texinfo-format-section)
(put 'iappendixsec 'texinfo-format 'texinfo-format-section)
(put 'appendixsec 'texinfo-format 'texinfo-format-section)
(put 'iunnumberedsec 'texinfo-format 'texinfo-format-section)
(put 'unnumberedsec 'texinfo-format 'texinfo-format-section)
(defun texinfo-format-section ()
(texinfo-format-chapter-1 ?=))
(put 'subheading 'texinfo-format 'texinfo-format-subsection)
(put 'isubsection 'texinfo-format 'texinfo-format-subsection)
(put 'subsection 'texinfo-format 'texinfo-format-subsection)
(put 'iappendixsubsec 'texinfo-format 'texinfo-format-subsection)
(put 'appendixsubsec 'texinfo-format 'texinfo-format-subsection)
(put 'iunnumberedsubsec 'texinfo-format 'texinfo-format-subsection)
(put 'unnumberedsubsec 'texinfo-format 'texinfo-format-subsection)
(defun texinfo-format-subsection ()
(texinfo-format-chapter-1 ?-))
(put 'subsubheading 'texinfo-format 'texinfo-format-subsubsection)
(put 'isubsubsection 'texinfo-format 'texinfo-format-subsubsection)
(put 'subsubsection 'texinfo-format 'texinfo-format-subsubsection)
(put 'iappendixsubsubsec 'texinfo-format 'texinfo-format-subsubsection)
(put 'appendixsubsubsec 'texinfo-format 'texinfo-format-subsubsection)
(put 'iunnumberedsubsubsec 'texinfo-format 'texinfo-format-subsubsection)
(put 'unnumberedsubsubsec 'texinfo-format 'texinfo-format-subsubsection)
(defun texinfo-format-subsubsection ()
(texinfo-format-chapter-1 ?.))
(defun texinfo-format-chapter-1 (belowchar)
(let ((arg (texinfo-parse-arg-discard)))
(message "Formatting: %s ... " arg) ; So we can see where we are.
(insert ?\n arg ?\n "@SectionPAD " belowchar ?\n)
(forward-line -2)))
(put 'SectionPAD 'texinfo-format 'texinfo-format-sectionpad)
(defun texinfo-format-sectionpad ()
(let ((str (texinfo-parse-arg-discard)))
(forward-char -1)
(let ((column (current-column)))
(forward-char 1)
(while (> column 0)
(insert str)
(setq column (1- column))))
(insert ?\n)))
;;; Space controlling commands: @. and @:, and the soft hyphen.
(put '\. 'texinfo-format 'texinfo-format-\.)
(defun texinfo-format-\. ()
(texinfo-discard-command)
(insert "."))
(put '\: 'texinfo-format 'texinfo-format-\:)
(defun texinfo-format-\: ()
(texinfo-discard-command))
(put '\- 'texinfo-format 'texinfo-format-soft-hyphen)
(defun texinfo-format-soft-hyphen ()
(texinfo-discard-command))
;;; @center, @sp, and @br
(put 'center 'texinfo-format 'texinfo-format-center)
(defun texinfo-format-center ()
(let ((arg (texinfo-parse-expanded-arg)))
(texinfo-discard-command)
(insert arg)
(insert ?\n)
(save-restriction
(goto-char (1- (point)))
(let ((indent-tabs-mode nil))
(center-line)))))
(put 'sp 'texinfo-format 'texinfo-format-sp)
(defun texinfo-format-sp ()
(let* ((arg (texinfo-parse-arg-discard))
(num (read arg)))
(insert-char ?\n num)))
(put 'br 'texinfo-format 'texinfo-format-paragraph-break)
(defun texinfo-format-paragraph-break ()
"Force a paragraph break.
If used within a line, follow `@br' with braces."
(texinfo-optional-braces-discard)
;; insert one return if at end of line;
;; else insert two returns, to generate a blank line.
(if (= (following-char) ?\n)
(insert ?\n)
(insert-char ?\n 2)))
;;; @footnote and @footnotestyle
; In Texinfo, footnotes are created with the `@footnote' command.
; This command is followed immediately by a left brace, then by the text of
; the footnote, and then by a terminating right brace. The
; template for a footnote is:
;
; @footnote{TEXT}
;
; Info has two footnote styles:
;
; * In the End of node style, all the footnotes for a single node
; are placed at the end of that node. The footnotes are
; separated from the rest of the node by a line of dashes with
; the word `Footnotes' within it.
;
; * In the Separate node style, all the footnotes for a single node
; are placed in an automatically constructed node of their own.
; Footnote style is specified by the @footnotestyle command, either
; @footnotestyle separate
; or
; @footnotestyle end
;
; The default is separate
(defvar texinfo-footnote-style "separate"
"Footnote style, either separate or end.")
(put 'footnotestyle 'texinfo-format 'texinfo-footnotestyle)
(defun texinfo-footnotestyle ()
"Specify whether footnotes are at end of node or in separate nodes.
Argument is either end or separate."
(setq texinfo-footnote-style (texinfo-parse-arg-discard)))
(defvar texinfo-footnote-number)
(put 'footnote 'texinfo-format 'texinfo-format-footnote)
(defun texinfo-format-footnote ()
"Format a footnote in either end of node or separate node style.
The texinfo-footnote-style variable controls which style is used."
(setq texinfo-footnote-number (1+ texinfo-footnote-number))
(cond ((string= texinfo-footnote-style "end")
(texinfo-format-end-node))
((string= texinfo-footnote-style "separate")
(texinfo-format-separate-node))))
(defun texinfo-format-separate-node ()
"Format footnote in Separate node style, with notes in own node.
The node is constructed automatically."
(let* (start
(arg (texinfo-parse-line-arg))
(node-name-beginning
(save-excursion
(re-search-backward
"^File: \\w+\\(\\w\\|\\s_\\|\\.\\|,\\)*[ \t]+Node:")
(match-end 0)))
(node-name
(save-excursion
(buffer-substring
(progn (goto-char node-name-beginning) ; skip over node command
(skip-chars-forward " \t") ; and over spaces
(point))
(if (search-forward
","
(save-excursion (end-of-line) (point)) t) ; bound search
(1- (point))
(end-of-line) (point))))))
(texinfo-discard-command) ; remove or insert whitespace, as needed
(delete-region (save-excursion (skip-chars-backward " \t\n") (point))
(point))
(insert (format " (%d) (*Note %s-Footnotes::)"
texinfo-footnote-number node-name))
(fill-paragraph nil)
(save-excursion
(if (re-search-forward "^@node" nil 'move)
(forward-line -1))
;; two cases: for the first footnote, we must insert a node header;
;; for the second and subsequent footnotes, we need only insert
;; the text of the footnote.
(if (save-excursion
(re-search-backward
(concat node-name "-Footnotes, Up: ")
node-name-beginning
t))
(progn ; already at least one footnote
(setq start (point))
(insert (format "\n(%d) %s\n" texinfo-footnote-number arg))
(fill-region start (point)))
;; else not yet a footnote
(insert "\n\^_\nFile: " texinfo-format-filename
" Node: " node-name "-Footnotes, Up: " node-name "\n")
(setq start (point))
(insert (format "\n(%d) %s\n" texinfo-footnote-number arg))
(fill-region start (point))))))
(defun texinfo-format-end-node ()
"Format footnote in the End of node style, with notes at end of node."
(let (start
(arg (texinfo-parse-line-arg)))
(texinfo-discard-command) ; remove or insert whitespace, as needed
(delete-region (save-excursion (skip-chars-backward " \t\n") (point))
(point))
(insert (format " (%d) " texinfo-footnote-number))
(fill-paragraph nil)
(save-excursion
(if (search-forward "\n--------- Footnotes ---------\n" nil t)
(progn ; already have footnote, put new one before end of node
(if (re-search-forward "^@node" nil 'move)
(forward-line -1))
(setq start (point))
(insert (format "\n(%d) %s\n" texinfo-footnote-number arg))
(fill-region start (point)))
;; else no prior footnote
(if (re-search-forward "^@node" nil 'move)
(forward-line -1))
(insert "\n--------- Footnotes ---------\n")
(setq start (point))
(insert (format "\n(%d) %s\n" texinfo-footnote-number arg))))))
;;; @itemize, @enumerate, and similar commands
;; @itemize pushes (itemize "COMMANDS" STARTPOS) on texinfo-stack.
;; @enumerate pushes (enumerate 0 STARTPOS).
;; @item dispatches to the texinfo-item prop of the first elt of the list.
;; For itemize, this puts in and rescans the COMMANDS.
;; For enumerate, this increments the number and puts it in.
;; In either case, it puts a Backspace at the front of the line
;; which marks it not to be indented later.
;; All other lines get indented by 5 when the @end is reached.
(defvar texinfo-stack-depth 0
"Count of number of unpopped texinfo-push-stack calls.
Used by @refill indenting command to avoid indenting within lists, etc.")
(defun texinfo-push-stack (check arg)
(setq texinfo-stack-depth (1+ texinfo-stack-depth))
(setq texinfo-stack
(cons (list check arg texinfo-command-start)
texinfo-stack)))
(defun texinfo-pop-stack (check)
(setq texinfo-stack-depth (1- texinfo-stack-depth))
(if (null texinfo-stack)
(error "Unmatched @end %s" check))
(if (not (eq (car (car texinfo-stack)) check))
(error "@end %s matches @%s"
check (car (car texinfo-stack))))
(prog1 (cdr (car texinfo-stack))
(setq texinfo-stack (cdr texinfo-stack))))
(put 'itemize 'texinfo-format 'texinfo-itemize)
(defun texinfo-itemize ()
(texinfo-push-stack
'itemize
(progn (skip-chars-forward " \t")
(if (eolp)
"@bullet"
(texinfo-parse-line-arg))))
(texinfo-discard-line-with-args)
(setq fill-column (- fill-column 5)))
(put 'itemize 'texinfo-end 'texinfo-end-itemize)
(defun texinfo-end-itemize ()
(setq fill-column (+ fill-column 5))
(texinfo-discard-command)
(let ((stacktop
(texinfo-pop-stack 'itemize)))
(texinfo-do-itemize (nth 1 stacktop))))
(put 'enumerate 'texinfo-format 'texinfo-enumerate)
(defun texinfo-enumerate ()
(texinfo-push-stack
'enumerate
(progn (skip-chars-forward " \t")
(if (eolp)
1
(read (current-buffer)))))
(if (and (symbolp (car (cdr (car texinfo-stack))))
(> 1 (length (symbol-name (car (cdr (car texinfo-stack)))))))
(error
"@enumerate: Use a number or letter, eg: 1, A, a, 3, B, or d." ))
(texinfo-discard-line-with-args)
(setq fill-column (- fill-column 5)))
(put 'enumerate 'texinfo-end 'texinfo-end-enumerate)
(defun texinfo-end-enumerate ()
(setq fill-column (+ fill-column 5))
(texinfo-discard-command)
(let ((stacktop
(texinfo-pop-stack 'enumerate)))
(texinfo-do-itemize (nth 1 stacktop))))
;; @alphaenumerate never became a standard part of Texinfo
(put 'alphaenumerate 'texinfo-format 'texinfo-alphaenumerate)
(defun texinfo-alphaenumerate ()
(texinfo-push-stack 'alphaenumerate (1- ?a))
(setq fill-column (- fill-column 5))
(texinfo-discard-line))
(put 'alphaenumerate 'texinfo-end 'texinfo-end-alphaenumerate)
(defun texinfo-end-alphaenumerate ()
(setq fill-column (+ fill-column 5))
(texinfo-discard-command)
(let ((stacktop
(texinfo-pop-stack 'alphaenumerate)))
(texinfo-do-itemize (nth 1 stacktop))))
;; @capsenumerate never became a standard part of Texinfo
(put 'capsenumerate 'texinfo-format 'texinfo-capsenumerate)
(defun texinfo-capsenumerate ()
(texinfo-push-stack 'capsenumerate (1- ?A))
(setq fill-column (- fill-column 5))
(texinfo-discard-line))
(put 'capsenumerate 'texinfo-end 'texinfo-end-capsenumerate)
(defun texinfo-end-capsenumerate ()
(setq fill-column (+ fill-column 5))
(texinfo-discard-command)
(let ((stacktop
(texinfo-pop-stack 'capsenumerate)))
(texinfo-do-itemize (nth 1 stacktop))))
;; At the @end, indent all the lines within the construct
;; except those marked with backspace. FROM says where
;; construct started.
(defun texinfo-do-itemize (from)
(save-excursion
(while (progn (forward-line -1)
(>= (point) from))
(if (= (following-char) ?\b)
(save-excursion
(delete-char 1)
(end-of-line)
(delete-char 6))
(if (not (looking-at "[ \t]*$"))
(save-excursion (insert " ")))))))
(put 'item 'texinfo-format 'texinfo-item)
(put 'itemx 'texinfo-format 'texinfo-item)
(defun texinfo-item ()
(funcall (get (car (car texinfo-stack)) 'texinfo-item)))
(put 'itemize 'texinfo-item 'texinfo-itemize-item)
(defun texinfo-itemize-item ()
;; (texinfo-discard-line) ; Did not handle text on same line as @item.
(delete-region (1+ (point)) (save-excursion (beginning-of-line) (point)))
(if (looking-at "[ \t]*[^ \t\n]+")
;; Text on same line as @item command.
(insert "\b " (nth 1 (car texinfo-stack)) " \n")
;; Else text on next line.
(insert "\b " (nth 1 (car texinfo-stack)) " "))
(forward-line -1))
(put 'enumerate 'texinfo-item 'texinfo-enumerate-item)
(defun texinfo-enumerate-item ()
(texinfo-discard-line)
(let (enumerating-symbol)
(cond ((integerp (car (cdr (car texinfo-stack))))
(setq enumerating-symbol (car (cdr (car texinfo-stack))))
(insert ?\b (format "%3d. " enumerating-symbol) ?\n)
(setcar (cdr (car texinfo-stack)) (1+ enumerating-symbol)))
((symbolp (car (cdr (car texinfo-stack))))
(setq enumerating-symbol
(symbol-name (car (cdr (car texinfo-stack)))))
(if (or (equal ?\[ (string-to-char enumerating-symbol))
(equal ?\{ (string-to-char enumerating-symbol)))
(error
"Too many items in enumerated list; alphabet ends at Z."))
(insert ?\b (format "%3s. " enumerating-symbol) ?\n)
(setcar (cdr (car texinfo-stack))
(make-symbol
(char-to-string
(1+
(string-to-char enumerating-symbol))))))
(t
(error
"@enumerate: Use a number or letter, eg: 1, A, a, 3, B or d." )))
(forward-line -1)))
(put 'alphaenumerate 'texinfo-item 'texinfo-alphaenumerate-item)
(defun texinfo-alphaenumerate-item ()
(texinfo-discard-line)
(let ((next (1+ (car (cdr (car texinfo-stack))))))
(if (> next ?z)
(error "More than 26 items in @alphaenumerate; get a bigger alphabet."))
(setcar (cdr (car texinfo-stack)) next)
(insert "\b " next ". \n"))
(forward-line -1))
(put 'capsenumerate 'texinfo-item 'texinfo-capsenumerate-item)
(defun texinfo-capsenumerate-item ()
(texinfo-discard-line)
(let ((next (1+ (car (cdr (car texinfo-stack))))))
(if (> next ?Z)
(error "More than 26 items in @capsenumerate; get a bigger alphabet."))
(setcar (cdr (car texinfo-stack)) next)
(insert "\b " next ". \n"))
(forward-line -1))
;;; @table
; The `@table' command produces two-column tables.
(put 'table 'texinfo-format 'texinfo-table)
(defun texinfo-table ()
(texinfo-push-stack
'table
(progn (skip-chars-forward " \t")
(if (eolp)
"@asis"
(texinfo-parse-line-arg))))
(texinfo-discard-line-with-args)
(setq fill-column (- fill-column 5)))
(put 'table 'texinfo-item 'texinfo-table-item)
(defun texinfo-table-item ()
(let ((arg (texinfo-parse-arg-discard))
(itemfont (car (cdr (car texinfo-stack)))))
(insert ?\b itemfont ?\{ arg "}\n \n"))
(forward-line -2))
(put 'table 'texinfo-end 'texinfo-end-table)
(defun texinfo-end-table ()
(setq fill-column (+ fill-column 5))
(texinfo-discard-command)
(let ((stacktop
(texinfo-pop-stack 'table)))
(texinfo-do-itemize (nth 1 stacktop))))
;; @description appears to be an undocumented variant on @table that
;; does not require an arg. It fails in texinfo.tex 2.58 and is not
;; part of makeinfo.c The command appears to be a relic of the past.
(put 'description 'texinfo-end 'texinfo-end-table)
(put 'description 'texinfo-format 'texinfo-description)
(defun texinfo-description ()
(texinfo-push-stack 'table "@asis")
(setq fill-column (- fill-column 5))
(texinfo-discard-line))
;;; @ftable, @vtable
; The `@ftable' and `@vtable' commands are like the `@table' command
; but they also insert each entry in the first column of the table
; into the function or variable index.
;; Handle the @ftable and @vtable commands:
(put 'ftable 'texinfo-format 'texinfo-ftable)
(put 'vtable 'texinfo-format 'texinfo-vtable)
(defun texinfo-ftable () (texinfo-indextable 'ftable))
(defun texinfo-vtable () (texinfo-indextable 'vtable))
(defun texinfo-indextable (table-type)
(texinfo-push-stack table-type (texinfo-parse-arg-discard))
(setq fill-column (- fill-column 5)))
;; Handle the @item commands within ftable and vtable:
(put 'ftable 'texinfo-item 'texinfo-ftable-item)
(put 'vtable 'texinfo-item 'texinfo-vtable-item)
(defun texinfo-ftable-item () (texinfo-indextable-item 'texinfo-findex))
(defun texinfo-vtable-item () (texinfo-indextable-item 'texinfo-vindex))
(defun texinfo-indextable-item (index-type)
(let ((item (texinfo-parse-arg-discard))
(itemfont (car (cdr (car texinfo-stack))))
(indexvar index-type))
(insert ?\b itemfont ?\{ item "}\n \n")
(set indexvar
(cons
(list item texinfo-last-node)
(symbol-value indexvar)))
(forward-line -2)))
;; Handle @end ftable, @end vtable
(put 'ftable 'texinfo-end 'texinfo-end-ftable)
(put 'vtable 'texinfo-end 'texinfo-end-vtable)
(defun texinfo-end-ftable () (texinfo-end-indextable 'ftable))
(defun texinfo-end-vtable () (texinfo-end-indextable 'vtable))
(defun texinfo-end-indextable (table-type)
(setq fill-column (+ fill-column 5))
(texinfo-discard-command)
(let ((stacktop
(texinfo-pop-stack table-type)))
(texinfo-do-itemize (nth 1 stacktop))))
;;; @ifinfo, @iftex, @tex, @ifhtml, @html
(put 'ifinfo 'texinfo-format 'texinfo-discard-line)
(put 'ifinfo 'texinfo-end 'texinfo-discard-command)
(put 'iftex 'texinfo-format 'texinfo-format-iftex)
(defun texinfo-format-iftex ()
(delete-region texinfo-command-start
(progn (re-search-forward "@end iftex[ \t]*\n")
(point))))
(put 'ifhtml 'texinfo-format 'texinfo-format-ifhtml)
(defun texinfo-format-ifhtml ()
(delete-region texinfo-command-start
(progn (re-search-forward "@end ifhtml[ \t]*\n")
(point))))
(put 'tex 'texinfo-format 'texinfo-format-tex)
(defun texinfo-format-tex ()
(delete-region texinfo-command-start
(progn (re-search-forward "@end tex[ \t]*\n")
(point))))
(put 'html 'texinfo-format 'texinfo-format-html)
(defun texinfo-format-html ()
(delete-region texinfo-command-start
(progn (re-search-forward "@end html[ \t]*\n")
(point))))
;;; @titlepage
(put 'titlepage 'texinfo-format 'texinfo-format-titlepage)
(defun texinfo-format-titlepage ()
(delete-region texinfo-command-start
(progn (re-search-forward "@end titlepage[ \t]*\n")
(point))))
(put 'endtitlepage 'texinfo-format 'texinfo-discard-line)
; @titlespec an alternative titling command; ignored by Info
(put 'titlespec 'texinfo-format 'texinfo-format-titlespec)
(defun texinfo-format-titlespec ()
(delete-region texinfo-command-start
(progn (re-search-forward "@end titlespec[ \t]*\n")
(point))))
(put 'endtitlespec 'texinfo-format 'texinfo-discard-line)
;;; @today
(put 'today 'texinfo-format 'texinfo-format-today)
; Produces Day Month Year style of output. eg `1 Jan 1900'
; The `@today{}' command requires a pair of braces, like `@dots{}'.
(defun texinfo-format-today ()
(texinfo-parse-arg-discard)
(insert (format "%s %s %s"
(substring (current-time-string) 8 10)
(substring (current-time-string) 4 7)
(substring (current-time-string) -4))))
;;; @ignore
(put 'ignore 'texinfo-format 'texinfo-format-ignore)
(defun texinfo-format-ignore ()
(delete-region texinfo-command-start
(progn (re-search-forward "@end ignore[ \t]*\n")
(point))))
(put 'endignore 'texinfo-format 'texinfo-discard-line)
;;; Define the Info enclosure command: @definfoenclose
; A `@definfoenclose' command may be used to define a highlighting
; command for Info, but not for TeX. A command defined using
; `@definfoenclose' marks text by enclosing it in strings that precede
; and follow the text.
;
; Presumably, if you define a command with `@definfoenclose` for Info,
; you will also define the same command in the TeX definitions file,
; `texinfo.tex' in a manner appropriate for typesetting.
;
; Write a `@definfoenclose' command on a line and follow it with three
; arguments separated by commas (commas are used as separators in an
; `@node' line in the same way). The first argument to
; `@definfoenclose' is the @-command name \(without the `@'\); the
; second argument is the Info start delimiter string; and the third
; argument is the Info end delimiter string. The latter two arguments
; enclose the highlighted text in the Info file. A delimiter string
; may contain spaces. Neither the start nor end delimiter is
; required. However, if you do not provide a start delimiter, you
; must follow the command name with two commas in a row; otherwise,
; the Info formatting commands will misinterpret the end delimiter
; string as a start delimiter string.
;
; If you do a @definfoenclose{} on the name of a pre-defined macro (such
; as @emph{}, @strong{}, @tt{}, or @i{}) the enclosure definition will
; override the built-in definition.
;
; An enclosure command defined this way takes one argument in braces.
;
; For example, you can write:
;
; @ifinfo
; @definfoenclose phoo, //, \\
; @end ifinfo
;
; near the beginning of a Texinfo file at the beginning of the lines
; to define `@phoo' as an Info formatting command that inserts `//'
; before and `\\' after the argument to `@phoo'. You can then write
; `@phoo{bar}' wherever you want `//bar\\' highlighted in Info.
;
; Also, for TeX formatting, you could write
;
; @iftex
; @global@let@phoo=@i
; @end iftex
;
; to define `@phoo' as a command that causes TeX to typeset
; the argument to `@phoo' in italics.
;
; Note that each definition applies to its own formatter: one for TeX,
; the other for texinfo-format-buffer or texinfo-format-region.
;
; Here is another example: write
;
; @definfoenclose headword, , :
;
; near the beginning of the file, to define `@headword' as an Info
; formatting command that inserts nothing before and a colon after the
; argument to `@headword'.
(put 'definfoenclose 'texinfo-format 'texinfo-define-info-enclosure)
(defun texinfo-define-info-enclosure ()
(let* ((args (texinfo-format-parse-line-args))
(command-name (nth 0 args))
(beginning-delimiter (or (nth 1 args) ""))
(end-delimiter (or (nth 2 args) "")))
(texinfo-discard-command)
(setq texinfo-enclosure-list
(cons
(list command-name
(list
beginning-delimiter
end-delimiter))
texinfo-enclosure-list))))
;;; @var, @code and the like
(put 'var 'texinfo-format 'texinfo-format-var)
; @sc a small caps font for TeX; formatted as `var' in Info
(put 'sc 'texinfo-format 'texinfo-format-var)
(defun texinfo-format-var ()
(insert (upcase (texinfo-parse-arg-discard)))
(goto-char texinfo-command-start))
; various noops
(put 'b 'texinfo-format 'texinfo-format-noop)
(put 'i 'texinfo-format 'texinfo-format-noop)
(put 'r 'texinfo-format 'texinfo-format-noop)
(put 't 'texinfo-format 'texinfo-format-noop)
(put 'w 'texinfo-format 'texinfo-format-noop)
(put 'asis 'texinfo-format 'texinfo-format-noop)
(put 'dmn 'texinfo-format 'texinfo-format-noop)
(put 'key 'texinfo-format 'texinfo-format-noop)
(put 'math 'texinfo-format 'texinfo-format-noop)
(put 'titlefont 'texinfo-format 'texinfo-format-noop)
(defun texinfo-format-noop ()
(insert (texinfo-parse-arg-discard))
(goto-char texinfo-command-start))
(put 'cite 'texinfo-format 'texinfo-format-code)
(put 'code 'texinfo-format 'texinfo-format-code)
(put 'file 'texinfo-format 'texinfo-format-code)
(put 'kbd 'texinfo-format 'texinfo-format-code)
(put 'samp 'texinfo-format 'texinfo-format-code)
(defun texinfo-format-code ()
(insert "`" (texinfo-parse-arg-discard) "'")
(goto-char texinfo-command-start))
(put 'emph 'texinfo-format 'texinfo-format-emph)
(put 'strong 'texinfo-format 'texinfo-format-emph)
(defun texinfo-format-emph ()
(insert "*" (texinfo-parse-arg-discard) "*")
(goto-char texinfo-command-start))
(put 'dfn 'texinfo-format 'texinfo-format-defn)
(put 'defn 'texinfo-format 'texinfo-format-defn)
(defun texinfo-format-defn ()
(insert "\"" (texinfo-parse-arg-discard) "\"")
(goto-char texinfo-command-start))
(put 'bullet 'texinfo-format 'texinfo-format-bullet)
(defun texinfo-format-bullet ()
"Insert an asterisk.
If used within a line, follow `@bullet' with braces."
(texinfo-optional-braces-discard)
(insert "*"))
;;; @example, @lisp, @quotation, @display, @smalllisp, @smallexample
(put 'display 'texinfo-format 'texinfo-format-example)
(put 'example 'texinfo-format 'texinfo-format-example)
(put 'lisp 'texinfo-format 'texinfo-format-example)
(put 'quotation 'texinfo-format 'texinfo-format-example)
(put 'smallexample 'texinfo-format 'texinfo-format-example)
(put 'smalllisp 'texinfo-format 'texinfo-format-example)
(defun texinfo-format-example ()
(texinfo-push-stack 'example nil)
(setq fill-column (- fill-column 5))
(texinfo-discard-line))
(put 'example 'texinfo-end 'texinfo-end-example)
(put 'display 'texinfo-end 'texinfo-end-example)
(put 'lisp 'texinfo-end 'texinfo-end-example)
(put 'quotation 'texinfo-end 'texinfo-end-example)
(put 'smallexample 'texinfo-end 'texinfo-end-example)
(put 'smalllisp 'texinfo-end 'texinfo-end-example)
(defun texinfo-end-example ()
(setq fill-column (+ fill-column 5))
(texinfo-discard-command)
(let ((stacktop
(texinfo-pop-stack 'example)))
(texinfo-do-itemize (nth 1 stacktop))))
(put 'exdent 'texinfo-format 'texinfo-format-exdent)
(defun texinfo-format-exdent ()
(texinfo-discard-command)
(delete-region (point)
(progn
(skip-chars-forward " ")
(point)))
(insert ?\b)
;; Cancel out the deletion that texinfo-do-itemize
;; is going to do at the end of this line.
(save-excursion
(end-of-line)
(insert "\n ")))
;;; @cartouche
; The @cartouche command is a noop in Info; in a printed manual,
; it makes a box with rounded corners.
(put 'cartouche 'texinfo-format 'texinfo-discard-line)
(put 'cartouche 'texinfo-end 'texinfo-discard-command)
;;; @flushleft and @format
; The @flushleft command left justifies every line but leaves the
; right end ragged. As far as Info is concerned, @flushleft is a
; `do-nothing' command
; The @format command is similar to @example except that it does not
; indent; this means that in Info, @format is similar to @flushleft.
(put 'format 'texinfo-format 'texinfo-format-flushleft)
(put 'flushleft 'texinfo-format 'texinfo-format-flushleft)
(defun texinfo-format-flushleft ()
(texinfo-discard-line))
(put 'format 'texinfo-end 'texinfo-end-flushleft)
(put 'flushleft 'texinfo-end 'texinfo-end-flushleft)
(defun texinfo-end-flushleft ()
(texinfo-discard-command))
;;; @flushright
; The @flushright command right justifies every line but leaves the
; left end ragged. Spaces and tabs at the right ends of lines are
; removed so that visible text lines up on the right side.
(put 'flushright 'texinfo-format 'texinfo-format-flushright)
(defun texinfo-format-flushright ()
(texinfo-push-stack 'flushright nil)
(texinfo-discard-line))
(put 'flushright 'texinfo-end 'texinfo-end-flushright)
(defun texinfo-end-flushright ()
(texinfo-discard-command)
(let ((stacktop
(texinfo-pop-stack 'flushright)))
(texinfo-do-flushright (nth 1 stacktop))))
(defun texinfo-do-flushright (from)
(save-excursion
(while (progn (forward-line -1)
(>= (point) from))
(beginning-of-line)
(insert
(make-string
(- fill-column
(save-excursion
(end-of-line)
(skip-chars-backward " \t")
(delete-region (point) (progn (end-of-line) (point)))
(current-column)))
? )))))
;;; @ctrl, @TeX, @copyright, @minus, @dots
(put 'ctrl 'texinfo-format 'texinfo-format-ctrl)
(defun texinfo-format-ctrl ()
(let ((str (texinfo-parse-arg-discard)))
(insert (logand 31 (aref str 0)))))
(put 'TeX 'texinfo-format 'texinfo-format-TeX)
(defun texinfo-format-TeX ()
(texinfo-parse-arg-discard)
(insert "TeX"))
(put 'copyright 'texinfo-format 'texinfo-format-copyright)
(defun texinfo-format-copyright ()
(texinfo-parse-arg-discard)
(insert "(C)"))
(put 'minus 'texinfo-format 'texinfo-format-minus)
(defun texinfo-format-minus ()
"Insert a minus sign.
If used within a line, follow `@minus' with braces."
(texinfo-optional-braces-discard)
(insert "-"))
(put 'dots 'texinfo-format 'texinfo-format-dots)
(defun texinfo-format-dots ()
(texinfo-parse-arg-discard)
(insert "..."))
(put 'enddots 'texinfo-format 'texinfo-format-enddots)
(defun texinfo-format-enddots ()
(texinfo-parse-arg-discard)
(insert "...."))
;;; Refilling and indenting: @refill, @paragraphindent, @noindent
;;; Indent only those paragraphs that are refilled as a result of an
;;; @refill command.
; * If the value is `asis', do not change the existing indentation at
; the starts of paragraphs.
; * If the value zero, delete any existing indentation.
; * If the value is greater than zero, indent each paragraph by that
; number of spaces.
;;; But do not refill paragraphs with an @refill command that are
;;; preceded by @noindent or are part of a table, list, or deffn.
(defvar texinfo-paragraph-indent "asis"
"Number of spaces for @refill to indent a paragraph; else to leave as is.")
(put 'paragraphindent 'texinfo-format 'texinfo-paragraphindent)
(defun texinfo-paragraphindent ()
"Specify the number of spaces for @refill to indent a paragraph.
Default is to leave the number of spaces as is."
(let ((arg (texinfo-parse-arg-discard)))
(if (string= "asis" arg)
(setq texinfo-paragraph-indent "asis")
(setq texinfo-paragraph-indent (string-to-int arg)))))
(put 'refill 'texinfo-format 'texinfo-format-refill)
(defun texinfo-format-refill ()
"Refill paragraph. Also, indent first line as set by @paragraphindent.
Default is to leave paragraph indentation as is."
(texinfo-discard-command)
(forward-paragraph -1)
(if (looking-at "[ \t\n]*$") (forward-line 1))
;; Do not indent if an entry in a list, table, or deffn,
;; or if paragraph is preceded by @noindent.
;; Otherwise, indent
(cond
;; delete a @noindent line and do not indent paragraph
((save-excursion (forward-line -1)
(looking-at "^@noindent"))
(forward-line -1)
(delete-region (point) (progn (forward-line 1) (point))))
;; do nothing if "asis"
((equal texinfo-paragraph-indent "asis"))
;; do no indenting in list, etc.
((> texinfo-stack-depth 0))
;; otherwise delete existing whitespace and indent
(t
(delete-region (point) (progn (skip-chars-forward " \t") (point)))
(insert (make-string texinfo-paragraph-indent ? ))))
(forward-paragraph 1)
(forward-line -1)
(end-of-line)
;; Do not fill a section title line with asterisks, hyphens, etc. that
;; are used to underline it. This could occur if the line following
;; the underlining is not an index entry and has text within it.
(let* ((previous-paragraph-separate paragraph-separate)
(paragraph-separate (concat paragraph-separate "\\|[-=*.]+"))
(previous-paragraph-start paragraph-start)
(paragraph-start (concat paragraph-start "\\|[-=*.]+")))
(unwind-protect
(fill-paragraph nil)
(setq paragraph-separate previous-paragraph-separate)
(setq paragraph-start previous-paragraph-start))))
(put 'noindent 'texinfo-format 'texinfo-noindent)
(defun texinfo-noindent ()
(save-excursion
(forward-paragraph 1)
(if (search-backward "@refill"
(save-excursion (forward-line -1) (point)) t)
() ; leave @noindent command so @refill command knows not to indent
;; else
(texinfo-discard-line))))
;;; Index generation
(put 'vindex 'texinfo-format 'texinfo-format-vindex)
(defun texinfo-format-vindex ()
(texinfo-index 'texinfo-vindex))
(put 'cindex 'texinfo-format 'texinfo-format-cindex)
(defun texinfo-format-cindex ()
(texinfo-index 'texinfo-cindex))
(put 'findex 'texinfo-format 'texinfo-format-findex)
(defun texinfo-format-findex ()
(texinfo-index 'texinfo-findex))
(put 'pindex 'texinfo-format 'texinfo-format-pindex)
(defun texinfo-format-pindex ()
(texinfo-index 'texinfo-pindex))
(put 'tindex 'texinfo-format 'texinfo-format-tindex)
(defun texinfo-format-tindex ()
(texinfo-index 'texinfo-tindex))
(put 'kindex 'texinfo-format 'texinfo-format-kindex)
(defun texinfo-format-kindex ()
(texinfo-index 'texinfo-kindex))
(defun texinfo-index (indexvar)
(let ((arg (texinfo-parse-expanded-arg)))
(texinfo-discard-command)
(set indexvar
(cons (list arg
texinfo-last-node
;; Region formatting may not provide last node position.
(if texinfo-last-node-pos
(1+ (count-lines texinfo-last-node-pos (point)))
1))
(symbol-value indexvar)))))
(defconst texinfo-indexvar-alist
'(("cp" . texinfo-cindex)
("fn" . texinfo-findex)
("vr" . texinfo-vindex)
("tp" . texinfo-tindex)
("pg" . texinfo-pindex)
("ky" . texinfo-kindex)))
;;; @defindex @defcodeindex
(put 'defindex 'texinfo-format 'texinfo-format-defindex)
(put 'defcodeindex 'texinfo-format 'texinfo-format-defindex)
(defun texinfo-format-defindex ()
(let* ((index-name (texinfo-parse-arg-discard)) ; eg: `aa'
(indexing-command (intern (concat index-name "index")))
(index-formatting-command ; eg: `texinfo-format-aaindex'
(intern (concat "texinfo-format-" index-name "index")))
(index-alist-name ; eg: `texinfo-aaindex'
(intern (concat "texinfo-" index-name "index"))))
(set index-alist-name nil)
(put indexing-command ; eg, aaindex
'texinfo-format
index-formatting-command) ; eg, texinfo-format-aaindex
;; eg: "aa" . texinfo-aaindex
(or (assoc index-name texinfo-indexvar-alist)
(setq texinfo-indexvar-alist
(cons
(cons index-name
index-alist-name)
texinfo-indexvar-alist)))
(fset index-formatting-command
(list 'lambda 'nil
(list 'texinfo-index
(list 'quote index-alist-name))))))
;;; @synindex @syncodeindex
(put 'synindex 'texinfo-format 'texinfo-format-synindex)
(put 'syncodeindex 'texinfo-format 'texinfo-format-synindex)
(defun texinfo-format-synindex ()
(let* ((args (texinfo-parse-arg-discard))
(second (cdr (read-from-string args)))
(joiner (symbol-name (car (read-from-string args))))
(joined (symbol-name (car (read-from-string args second)))))
(if (assoc joiner texinfo-short-index-cmds-alist)
(put
(cdr (assoc joiner texinfo-short-index-cmds-alist))
'texinfo-format
(or (cdr (assoc joined texinfo-short-index-format-cmds-alist))
(intern (concat "texinfo-format-" joined "index"))))
(put
(intern (concat joiner "index"))
'texinfo-format
(or (cdr(assoc joined texinfo-short-index-format-cmds-alist))
(intern (concat "texinfo-format-" joined "index")))))))
(defconst texinfo-short-index-cmds-alist
'(("cp" . cindex)
("fn" . findex)
("vr" . vindex)
("tp" . tindex)
("pg" . pindex)
("ky" . kindex)))
(defconst texinfo-short-index-format-cmds-alist
'(("cp" . texinfo-format-cindex)
("fn" . texinfo-format-findex)
("vr" . texinfo-format-vindex)
("tp" . texinfo-format-tindex)
("pg" . texinfo-format-pindex)
("ky" . texinfo-format-kindex)))
;;; Sort and index (for VMS)
;; Sort an index which is in the current buffer between START and END.
;; Used on VMS, where the `sort' utility is not available.
(defun texinfo-sort-region (start end)
(require 'sort)
(save-restriction
(narrow-to-region start end)
(sort-subr nil 'forward-line 'end-of-line 'texinfo-sort-startkeyfun)))
;; Subroutine for sorting an index.
;; At start of a line, return a string to sort the line under.
(defun texinfo-sort-startkeyfun ()
(let ((line
(buffer-substring (point) (save-excursion (end-of-line) (point)))))
;; Canonicalize whitespace and eliminate funny chars.
(while (string-match "[ \t][ \t]+\\|[^a-z0-9 ]+" line)
(setq line (concat (substring line 0 (match-beginning 0))
" "
(substring line (match-end 0) (length line)))))
line))
;;; @printindex
(put 'printindex 'texinfo-format 'texinfo-format-printindex)
(defun texinfo-format-printindex ()
(let ((indexelts (symbol-value
(cdr (assoc (texinfo-parse-arg-discard)
texinfo-indexvar-alist))))
opoint)
(insert "\n* Menu:\n\n")
(setq opoint (point))
(texinfo-print-index nil indexelts)
(if (eq system-type 'vax-vms)
(texinfo-sort-region opoint (point))
(shell-command-on-region opoint (point) "sort -fd" 1))))
(defun texinfo-print-index (file indexelts)
(while indexelts
(if (stringp (car (car indexelts)))
(progn
(insert "* " (car (car indexelts)) ": " )
(indent-to 32)
(insert
(if file (concat "(" file ")") "")
(nth 1 (car indexelts)) ".")
(indent-to 54)
(insert
(if (nth 2 (car indexelts))
(format " %d." (nth 2 (car indexelts)))
"")
"\n"))
;; index entries from @include'd file
(texinfo-print-index (nth 1 (car indexelts))
(nth 2 (car indexelts))))
(setq indexelts (cdr indexelts))))
;;; Glyphs: @equiv, @error, etc
;; @equiv to show that two expressions are equivalent
;; @error to show an error message
;; @expansion to show what a macro expands to
;; @point to show the location of point in an example
;; @print to show what an evaluated expression prints
;; @result to indicate the value returned by an expression
(put 'equiv 'texinfo-format 'texinfo-format-equiv)
(defun texinfo-format-equiv ()
(texinfo-parse-arg-discard)
(insert "=="))
(put 'error 'texinfo-format 'texinfo-format-error)
(defun texinfo-format-error ()
(texinfo-parse-arg-discard)
(insert "error-->"))
(put 'expansion 'texinfo-format 'texinfo-format-expansion)
(defun texinfo-format-expansion ()
(texinfo-parse-arg-discard)
(insert "==>"))
(put 'point 'texinfo-format 'texinfo-format-point)
(defun texinfo-format-point ()
(texinfo-parse-arg-discard)
(insert "-!-"))
(put 'print 'texinfo-format 'texinfo-format-print)
(defun texinfo-format-print ()
(texinfo-parse-arg-discard)
(insert "-|"))
(put 'result 'texinfo-format 'texinfo-format-result)
(defun texinfo-format-result ()
(texinfo-parse-arg-discard)
(insert "=>"))
;;; Definition formatting: @deffn, @defun, etc
;; What definition formatting produces:
;;
;; @deffn category name args...
;; In Info, `Category: name ARGS'
;; In index: name: node. line#.
;;
;; @defvr category name
;; In Info, `Category: name'
;; In index: name: node. line#.
;;
;; @deftp category name attributes...
;; `category name attributes...' Note: @deftp args in lower case.
;; In index: name: node. line#.
;;
;; Specialized function-like or variable-like entity:
;;
;; @defun, @defmac, @defspec, @defvar, @defopt
;;
;; @defun name args In Info, `Function: name ARGS'
;; @defmac name args In Info, `Macro: name ARGS'
;; @defvar name In Info, `Variable: name'
;; etc.
;; In index: name: node. line#.
;;
;; Generalized typed-function-like or typed-variable-like entity:
;; @deftypefn category data-type name args...
;; In Info, `Category: data-type name args...'
;; @deftypevr category data-type name
;; In Info, `Category: data-type name'
;; In index: name: node. line#.
;;
;; Specialized typed-function-like or typed-variable-like entity:
;; @deftypefun data-type name args...
;; In Info, `Function: data-type name ARGS'
;; In index: name: node. line#.
;;
;; @deftypevar data-type name
;; In Info, `Variable: data-type name'
;; In index: name: node. line#. but include args after name!?
;;
;; Generalized object oriented entity:
;; @defop category class name args...
;; In Info, `Category on class: name ARG'
;; In index: name on class: node. line#.
;;
;; @defcv category class name
;; In Info, `Category of class: name'
;; In index: name of class: node. line#.
;;
;; Specialized object oriented entity:
;; @defmethod class name args...
;; In Info, `Method on class: name ARGS'
;; In index: name on class: node. line#.
;;
;; @defivar class name
;; In Info, `Instance variable of class: name'
;; In index: name of class: node. line#.
;;; The definition formatting functions
(defun texinfo-format-defun ()
(texinfo-push-stack 'defun nil)
(setq fill-column (- fill-column 5))
(texinfo-format-defun-1 t))
(defun texinfo-end-defun ()
(setq fill-column (+ fill-column 5))
(texinfo-discard-command)
(let ((start (nth 1 (texinfo-pop-stack 'defun))))
(texinfo-do-itemize start)
;; Delete extra newline inserted after header.
(save-excursion
(goto-char start)
(delete-char -1))))
(defun texinfo-format-defunx ()
(texinfo-format-defun-1 nil))
(defun texinfo-format-defun-1 (first-p)
(let ((parse-args (texinfo-format-parse-defun-args))
(texinfo-defun-type (get texinfo-command-name 'texinfo-defun-type)))
(texinfo-discard-command)
;; Delete extra newline inserted after previous header line.
(if (not first-p)
(delete-char -1))
(funcall
(get texinfo-command-name 'texinfo-deffn-formatting-property) parse-args)
;; Insert extra newline so that paragraph filling does not mess
;; with header line.
(insert "\n\n")
(rplaca (cdr (cdr (car texinfo-stack))) (point))
(funcall
(get texinfo-command-name 'texinfo-defun-indexing-property) parse-args)))
;;; Formatting the first line of a definition
;; @deffn, @defvr, @deftp
(put 'deffn 'texinfo-deffn-formatting-property 'texinfo-format-deffn)
(put 'deffnx 'texinfo-deffn-formatting-property 'texinfo-format-deffn)
(put 'defvr 'texinfo-deffn-formatting-property 'texinfo-format-deffn)
(put 'defvrx 'texinfo-deffn-formatting-property 'texinfo-format-deffn)
(put 'deftp 'texinfo-deffn-formatting-property 'texinfo-format-deffn)
(put 'deftpx 'texinfo-deffn-formatting-property 'texinfo-format-deffn)
(defun texinfo-format-deffn (parsed-args)
;; Generalized function-like, variable-like, or generic data-type entity:
;; @deffn category name args...
;; In Info, `Category: name ARGS'
;; @deftp category name attributes...
;; `category name attributes...' Note: @deftp args in lower case.
(let ((category (car parsed-args))
(name (car (cdr parsed-args)))
(args (cdr (cdr parsed-args))))
(insert " -- " category ": " name)
(while args
(insert " "
(if (or (= ?& (aref (car args) 0))
(eq (eval (car texinfo-defun-type)) 'deftp-type))
(car args)
(upcase (car args))))
(setq args (cdr args)))))
;; @defun, @defmac, @defspec, @defvar, @defopt: Specialized, simple
(put 'defun 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(put 'defunx 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(put 'defmac 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(put 'defmacx 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(put 'defspec 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(put 'defspecx 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(put 'defvar 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(put 'defvarx 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(put 'defopt 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(put 'defoptx 'texinfo-deffn-formatting-property
'texinfo-format-specialized-defun)
(defun texinfo-format-specialized-defun (parsed-args)
;; Specialized function-like or variable-like entity:
;; @defun name args In Info, `Function: Name ARGS'
;; @defmac name args In Info, `Macro: Name ARGS'
;; @defvar name In Info, `Variable: Name'
;; Use cdr of texinfo-defun-type to determine category:
(let ((category (car (cdr texinfo-defun-type)))
(name (car parsed-args))
(args (cdr parsed-args)))
(insert " -- " category ": " name)
(while args
(insert " "
(if (= ?& (aref (car args) 0))
(car args)
(upcase (car args))))
(setq args (cdr args)))))
;; @deftypefn, @deftypevr: Generalized typed
(put 'deftypefn 'texinfo-deffn-formatting-property 'texinfo-format-deftypefn)
(put 'deftypefnx 'texinfo-deffn-formatting-property 'texinfo-format-deftypefn)
(put 'deftypevr 'texinfo-deffn-formatting-property 'texinfo-format-deftypefn)
(put 'deftypevrx 'texinfo-deffn-formatting-property 'texinfo-format-deftypefn)
(defun texinfo-format-deftypefn (parsed-args)
;; Generalized typed-function-like or typed-variable-like entity:
;; @deftypefn category data-type name args...
;; In Info, `Category: data-type name args...'
;; @deftypevr category data-type name
;; In Info, `Category: data-type name'
;; Note: args in lower case, unless modified in command line.
(let ((category (car parsed-args))
(data-type (car (cdr parsed-args)))
(name (car (cdr (cdr parsed-args))))
(args (cdr (cdr (cdr parsed-args)))))
(insert " -- " category ": " data-type " " name)
(while args
(insert " " (car args))
(setq args (cdr args)))))
;; @deftypefun, @deftypevar: Specialized typed
(put 'deftypefun 'texinfo-deffn-formatting-property 'texinfo-format-deftypefun)
(put 'deftypefunx 'texinfo-deffn-formatting-property
'texinfo-format-deftypefun)
(put 'deftypevar 'texinfo-deffn-formatting-property 'texinfo-format-deftypefun)
(put 'deftypevarx 'texinfo-deffn-formatting-property
'texinfo-format-deftypefun)
(defun texinfo-format-deftypefun (parsed-args)
;; Specialized typed-function-like or typed-variable-like entity:
;; @deftypefun data-type name args...
;; In Info, `Function: data-type name ARGS'
;; @deftypevar data-type name
;; In Info, `Variable: data-type name'
;; Note: args in lower case, unless modified in command line.
;; Use cdr of texinfo-defun-type to determine category:
(let ((category (car (cdr texinfo-defun-type)))
(data-type (car parsed-args))
(name (car (cdr parsed-args)))
(args (cdr (cdr parsed-args))))
(insert " -- " category ": " data-type " " name)
(while args
(insert " " (car args))
(setq args (cdr args)))))
;; @defop: Generalized object-oriented
(put 'defop 'texinfo-deffn-formatting-property 'texinfo-format-defop)
(put 'defopx 'texinfo-deffn-formatting-property 'texinfo-format-defop)
(defun texinfo-format-defop (parsed-args)
;; Generalized object oriented entity:
;; @defop category class name args...
;; In Info, `Category on class: name ARG'
;; Note: args in upper case; use of `on'
(let ((category (car parsed-args))
(class (car (cdr parsed-args)))
(name (car (cdr (cdr parsed-args))))
(args (cdr (cdr (cdr parsed-args)))))
(insert " -- " category " on " class ": " name)
(while args
(insert " " (upcase (car args)))
(setq args (cdr args)))))
;; @defcv: Generalized object-oriented
(put 'defcv 'texinfo-deffn-formatting-property 'texinfo-format-defcv)
(put 'defcvx 'texinfo-deffn-formatting-property 'texinfo-format-defcv)
(defun texinfo-format-defcv (parsed-args)
;; Generalized object oriented entity:
;; @defcv category class name
;; In Info, `Category of class: name'
;; Note: args in upper case; use of `of'
(let ((category (car parsed-args))
(class (car (cdr parsed-args)))
(name (car (cdr (cdr parsed-args))))
(args (cdr (cdr (cdr parsed-args)))))
(insert " -- " category " of " class ": " name)
(while args
(insert " " (upcase (car args)))
(setq args (cdr args)))))
;; @defmethod: Specialized object-oriented
(put 'defmethod 'texinfo-deffn-formatting-property 'texinfo-format-defmethod)
(put 'defmethodx 'texinfo-deffn-formatting-property 'texinfo-format-defmethod)
(defun texinfo-format-defmethod (parsed-args)
;; Specialized object oriented entity:
;; @defmethod class name args...
;; In Info, `Method on class: name ARGS'
;; Note: args in upper case; use of `on'
;; Use cdr of texinfo-defun-type to determine category:
(let ((category (car (cdr texinfo-defun-type)))
(class (car parsed-args))
(name (car (cdr parsed-args)))
(args (cdr (cdr parsed-args))))
(insert " -- " category " on " class ": " name)
(while args
(insert " " (upcase (car args)))
(setq args (cdr args)))))
;; @defivar: Specialized object-oriented
(put 'defivar 'texinfo-deffn-formatting-property 'texinfo-format-defivar)
(put 'defivarx 'texinfo-deffn-formatting-property 'texinfo-format-defivar)
(defun texinfo-format-defivar (parsed-args)
;; Specialized object oriented entity:
;; @defivar class name
;; In Info, `Instance variable of class: name'
;; Note: args in upper case; use of `of'
;; Use cdr of texinfo-defun-type to determine category:
(let ((category (car (cdr texinfo-defun-type)))
(class (car parsed-args))
(name (car (cdr parsed-args)))
(args (cdr (cdr parsed-args))))
(insert " -- " category " of " class ": " name)
(while args
(insert " " (upcase (car args)))
(setq args (cdr args)))))
;;; Indexing for definitions
;; An index entry has three parts: the `entry proper', the node name, and the
;; line number. Depending on the which command is used, the entry is
;; formatted differently:
;;
;; @defun,
;; @defmac,
;; @defspec,
;; @defvar,
;; @defopt all use their 1st argument as the entry-proper
;;
;; @deffn,
;; @defvr,
;; @deftp
;; @deftypefun
;; @deftypevar all use their 2nd argument as the entry-proper
;;
;; @deftypefn,
;; @deftypevr both use their 3rd argument as the entry-proper
;;
;; @defmethod uses its 2nd and 1st arguments as an entry-proper
;; formatted: NAME on CLASS
;; @defop uses its 3rd and 2nd arguments as an entry-proper
;; formatted: NAME on CLASS
;;
;; @defivar uses its 2nd and 1st arguments as an entry-proper
;; formatted: NAME of CLASS
;;
;; @defcv uses its 3rd and 2nd argument as an entry-proper
;; formatted: NAME of CLASS
(put 'defun 'texinfo-defun-indexing-property 'texinfo-index-defun)
(put 'defunx 'texinfo-defun-indexing-property 'texinfo-index-defun)
(put 'defmac 'texinfo-defun-indexing-property 'texinfo-index-defun)
(put 'defmacx 'texinfo-defun-indexing-property 'texinfo-index-defun)
(put 'defspec 'texinfo-defun-indexing-property 'texinfo-index-defun)
(put 'defspecx 'texinfo-defun-indexing-property 'texinfo-index-defun)
(put 'defvar 'texinfo-defun-indexing-property 'texinfo-index-defun)
(put 'defvarx 'texinfo-defun-indexing-property 'texinfo-index-defun)
(put 'defopt 'texinfo-defun-indexing-property 'texinfo-index-defun)
(put 'defoptx 'texinfo-defun-indexing-property 'texinfo-index-defun)
(defun texinfo-index-defun (parsed-args)
;; use 1st parsed-arg as entry-proper
;; `index-list' will be texinfo-findex or the like
(let ((index-list (get texinfo-command-name 'texinfo-defun-index)))
(set index-list
(cons
;; Three elements: entry-proper, node-name, line-number
(list
(car parsed-args)
texinfo-last-node
;; Region formatting may not provide last node position.
(if texinfo-last-node-pos
(1+ (count-lines texinfo-last-node-pos (point)))
1))
(symbol-value index-list)))))
(put 'deffn 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(put 'deffnx 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(put 'defvr 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(put 'defvrx 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(put 'deftp 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(put 'deftpx 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(put 'deftypefun 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(put 'deftypefunx 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(put 'deftypevar 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(put 'deftypevarx 'texinfo-defun-indexing-property 'texinfo-index-deffn)
(defun texinfo-index-deffn (parsed-args)
;; use 2nd parsed-arg as entry-proper
;; `index-list' will be texinfo-findex or the like
(let ((index-list (get texinfo-command-name 'texinfo-defun-index)))
(set index-list
(cons
;; Three elements: entry-proper, node-name, line-number
(list
(car (cdr parsed-args))
texinfo-last-node
;; Region formatting may not provide last node position.
(if texinfo-last-node-pos
(1+ (count-lines texinfo-last-node-pos (point)))
1))
(symbol-value index-list)))))
(put 'deftypefn 'texinfo-defun-indexing-property 'texinfo-index-deftypefn)
(put 'deftypefnx 'texinfo-defun-indexing-property 'texinfo-index-deftypefn)
(put 'deftypevr 'texinfo-defun-indexing-property 'texinfo-index-deftypefn)
(put 'deftypevrx 'texinfo-defun-indexing-property 'texinfo-index-deftypefn)
(defun texinfo-index-deftypefn (parsed-args)
;; use 3rd parsed-arg as entry-proper
;; `index-list' will be texinfo-findex or the like
(let ((index-list (get texinfo-command-name 'texinfo-defun-index)))
(set index-list
(cons
;; Three elements: entry-proper, node-name, line-number
(list
(car (cdr (cdr parsed-args)))
texinfo-last-node
;; Region formatting may not provide last node position.
(if texinfo-last-node-pos
(1+ (count-lines texinfo-last-node-pos (point)))
1))
(symbol-value index-list)))))
(put 'defmethod 'texinfo-defun-indexing-property 'texinfo-index-defmethod)
(put 'defmethodx 'texinfo-defun-indexing-property 'texinfo-index-defmethod)
(defun texinfo-index-defmethod (parsed-args)
;; use 2nd on 1st parsed-arg as entry-proper
;; `index-list' will be texinfo-findex or the like
(let ((index-list (get texinfo-command-name 'texinfo-defun-index)))
(set index-list
(cons
;; Three elements: entry-proper, node-name, line-number
(list
(format "%s on %s"
(car (cdr parsed-args))
(car parsed-args))
texinfo-last-node
;; Region formatting may not provide last node position.
(if texinfo-last-node-pos
(1+ (count-lines texinfo-last-node-pos (point)))
1))
(symbol-value index-list)))))
(put 'defop 'texinfo-defun-indexing-property 'texinfo-index-defop)
(put 'defopx 'texinfo-defun-indexing-property 'texinfo-index-defop)
(defun texinfo-index-defop (parsed-args)
;; use 3rd on 2nd parsed-arg as entry-proper
;; `index-list' will be texinfo-findex or the like
(let ((index-list (get texinfo-command-name 'texinfo-defun-index)))
(set index-list
(cons
;; Three elements: entry-proper, node-name, line-number
(list
(format "%s on %s"
(car (cdr (cdr parsed-args)))
(car (cdr parsed-args)))
texinfo-last-node
;; Region formatting may not provide last node position.
(if texinfo-last-node-pos
(1+ (count-lines texinfo-last-node-pos (point)))
1))
(symbol-value index-list)))))
(put 'defivar 'texinfo-defun-indexing-property 'texinfo-index-defivar)
(put 'defivarx 'texinfo-defun-indexing-property 'texinfo-index-defivar)
(defun texinfo-index-defivar (parsed-args)
;; use 2nd of 1st parsed-arg as entry-proper
;; `index-list' will be texinfo-findex or the like
(let ((index-list (get texinfo-command-name 'texinfo-defun-index)))
(set index-list
(cons
;; Three elements: entry-proper, node-name, line-number
(list
(format "%s of %s"
(car (cdr parsed-args))
(car parsed-args))
texinfo-last-node
;; Region formatting may not provide last node position.
(if texinfo-last-node-pos
(1+ (count-lines texinfo-last-node-pos (point)))
1))
(symbol-value index-list)))))
(put 'defcv 'texinfo-defun-indexing-property 'texinfo-index-defcv)
(put 'defcvx 'texinfo-defun-indexing-property 'texinfo-index-defcv)
(defun texinfo-index-defcv (parsed-args)
;; use 3rd of 2nd parsed-arg as entry-proper
;; `index-list' will be texinfo-findex or the like
(let ((index-list (get texinfo-command-name 'texinfo-defun-index)))
(set index-list
(cons
;; Three elements: entry-proper, node-name, line-number
(list
(format "%s of %s"
(car (cdr (cdr parsed-args)))
(car (cdr parsed-args)))
texinfo-last-node
;; Region formatting may not provide last node position.
(if texinfo-last-node-pos
(1+ (count-lines texinfo-last-node-pos (point)))
1))
(symbol-value index-list)))))
;;; Properties for definitions
;; Each definition command has six properties:
;;
;; 1. texinfo-deffn-formatting-property to format definition line
;; 2. texinfo-defun-indexing-property to create index entry
;; 3. texinfo-format formatting command
;; 4. texinfo-end end formatting command
;; 5. texinfo-defun-type type of deffn to format
;; 6. texinfo-defun-index type of index to use
;;
;; The `x' forms of each definition command are used for the second
;; and subsequent header lines.
;; The texinfo-deffn-formatting-property and texinfo-defun-indexing-property
;; are listed just before the appropriate formatting and indexing commands.
(put 'deffn 'texinfo-format 'texinfo-format-defun)
(put 'deffnx 'texinfo-format 'texinfo-format-defunx)
(put 'deffn 'texinfo-end 'texinfo-end-defun)
(put 'deffn 'texinfo-defun-type '('deffn-type nil))
(put 'deffnx 'texinfo-defun-type '('deffn-type nil))
(put 'deffn 'texinfo-defun-index 'texinfo-findex)
(put 'deffnx 'texinfo-defun-index 'texinfo-findex)
(put 'defun 'texinfo-format 'texinfo-format-defun)
(put 'defunx 'texinfo-format 'texinfo-format-defunx)
(put 'defun 'texinfo-end 'texinfo-end-defun)
(put 'defun 'texinfo-defun-type '('defun-type "Function"))
(put 'defunx 'texinfo-defun-type '('defun-type "Function"))
(put 'defun 'texinfo-defun-index 'texinfo-findex)
(put 'defunx 'texinfo-defun-index 'texinfo-findex)
(put 'defmac 'texinfo-format 'texinfo-format-defun)
(put 'defmacx 'texinfo-format 'texinfo-format-defunx)
(put 'defmac 'texinfo-end 'texinfo-end-defun)
(put 'defmac 'texinfo-defun-type '('defun-type "Macro"))
(put 'defmacx 'texinfo-defun-type '('defun-type "Macro"))
(put 'defmac 'texinfo-defun-index 'texinfo-findex)
(put 'defmacx 'texinfo-defun-index 'texinfo-findex)
(put 'defspec 'texinfo-format 'texinfo-format-defun)
(put 'defspecx 'texinfo-format 'texinfo-format-defunx)
(put 'defspec 'texinfo-end 'texinfo-end-defun)
(put 'defspec 'texinfo-defun-type '('defun-type "Special form"))
(put 'defspecx 'texinfo-defun-type '('defun-type "Special form"))
(put 'defspec 'texinfo-defun-index 'texinfo-findex)
(put 'defspecx 'texinfo-defun-index 'texinfo-findex)
(put 'defvr 'texinfo-format 'texinfo-format-defun)
(put 'defvrx 'texinfo-format 'texinfo-format-defunx)
(put 'defvr 'texinfo-end 'texinfo-end-defun)
(put 'defvr 'texinfo-defun-type '('deffn-type nil))
(put 'defvrx 'texinfo-defun-type '('deffn-type nil))
(put 'defvr 'texinfo-defun-index 'texinfo-vindex)
(put 'defvrx 'texinfo-defun-index 'texinfo-vindex)
(put 'defvar 'texinfo-format 'texinfo-format-defun)
(put 'defvarx 'texinfo-format 'texinfo-format-defunx)
(put 'defvar 'texinfo-end 'texinfo-end-defun)
(put 'defvar 'texinfo-defun-type '('defun-type "Variable"))
(put 'defvarx 'texinfo-defun-type '('defun-type "Variable"))
(put 'defvar 'texinfo-defun-index 'texinfo-vindex)
(put 'defvarx 'texinfo-defun-index 'texinfo-vindex)
(put 'defconst 'texinfo-format 'texinfo-format-defun)
(put 'defconstx 'texinfo-format 'texinfo-format-defunx)
(put 'defconst 'texinfo-end 'texinfo-end-defun)
(put 'defconst 'texinfo-defun-type '('defun-type "Constant"))
(put 'defconstx 'texinfo-defun-type '('defun-type "Constant"))
(put 'defconst 'texinfo-defun-index 'texinfo-vindex)
(put 'defconstx 'texinfo-defun-index 'texinfo-vindex)
(put 'defcmd 'texinfo-format 'texinfo-format-defun)
(put 'defcmdx 'texinfo-format 'texinfo-format-defunx)
(put 'defcmd 'texinfo-end 'texinfo-end-defun)
(put 'defcmd 'texinfo-defun-type '('defun-type "Command"))
(put 'defcmdx 'texinfo-defun-type '('defun-type "Command"))
(put 'defcmd 'texinfo-defun-index 'texinfo-findex)
(put 'defcmdx 'texinfo-defun-index 'texinfo-findex)
(put 'defopt 'texinfo-format 'texinfo-format-defun)
(put 'defoptx 'texinfo-format 'texinfo-format-defunx)
(put 'defopt 'texinfo-end 'texinfo-end-defun)
(put 'defopt 'texinfo-defun-type '('defun-type "User Option"))
(put 'defoptx 'texinfo-defun-type '('defun-type "User Option"))
(put 'defopt 'texinfo-defun-index 'texinfo-vindex)
(put 'defoptx 'texinfo-defun-index 'texinfo-vindex)
(put 'deftp 'texinfo-format 'texinfo-format-defun)
(put 'deftpx 'texinfo-format 'texinfo-format-defunx)
(put 'deftp 'texinfo-end 'texinfo-end-defun)
(put 'deftp 'texinfo-defun-type '('deftp-type nil))
(put 'deftpx 'texinfo-defun-type '('deftp-type nil))
(put 'deftp 'texinfo-defun-index 'texinfo-tindex)
(put 'deftpx 'texinfo-defun-index 'texinfo-tindex)
;;; Object-oriented stuff is a little hairier.
(put 'defop 'texinfo-format 'texinfo-format-defun)
(put 'defopx 'texinfo-format 'texinfo-format-defunx)
(put 'defop 'texinfo-end 'texinfo-end-defun)
(put 'defop 'texinfo-defun-type '('defop-type nil))
(put 'defopx 'texinfo-defun-type '('defop-type nil))
(put 'defop 'texinfo-defun-index 'texinfo-findex)
(put 'defopx 'texinfo-defun-index 'texinfo-findex)
(put 'defmethod 'texinfo-format 'texinfo-format-defun)
(put 'defmethodx 'texinfo-format 'texinfo-format-defunx)
(put 'defmethod 'texinfo-end 'texinfo-end-defun)
(put 'defmethod 'texinfo-defun-type '('defmethod-type "Method"))
(put 'defmethodx 'texinfo-defun-type '('defmethod-type "Method"))
(put 'defmethod 'texinfo-defun-index 'texinfo-findex)
(put 'defmethodx 'texinfo-defun-index 'texinfo-findex)
(put 'defcv 'texinfo-format 'texinfo-format-defun)
(put 'defcvx 'texinfo-format 'texinfo-format-defunx)
(put 'defcv 'texinfo-end 'texinfo-end-defun)
(put 'defcv 'texinfo-defun-type '('defop-type nil))
(put 'defcvx 'texinfo-defun-type '('defop-type nil))
(put 'defcv 'texinfo-defun-index 'texinfo-vindex)
(put 'defcvx 'texinfo-defun-index 'texinfo-vindex)
(put 'defivar 'texinfo-format 'texinfo-format-defun)
(put 'defivarx 'texinfo-format 'texinfo-format-defunx)
(put 'defivar 'texinfo-end 'texinfo-end-defun)
(put 'defivar 'texinfo-defun-type '('defmethod-type "Instance variable"))
(put 'defivarx 'texinfo-defun-type '('defmethod-type "Instance variable"))
(put 'defivar 'texinfo-defun-index 'texinfo-vindex)
(put 'defivarx 'texinfo-defun-index 'texinfo-vindex)
;;; Typed functions and variables
(put 'deftypefn 'texinfo-format 'texinfo-format-defun)
(put 'deftypefnx 'texinfo-format 'texinfo-format-defunx)
(put 'deftypefn 'texinfo-end 'texinfo-end-defun)
(put 'deftypefn 'texinfo-defun-type '('deftypefn-type nil))
(put 'deftypefnx 'texinfo-defun-type '('deftypefn-type nil))
(put 'deftypefn 'texinfo-defun-index 'texinfo-findex)
(put 'deftypefnx 'texinfo-defun-index 'texinfo-findex)
(put 'deftypefun 'texinfo-format 'texinfo-format-defun)
(put 'deftypefunx 'texinfo-format 'texinfo-format-defunx)
(put 'deftypefun 'texinfo-end 'texinfo-end-defun)
(put 'deftypefun 'texinfo-defun-type '('deftypefun-type "Function"))
(put 'deftypefunx 'texinfo-defun-type '('deftypefun-type "Function"))
(put 'deftypefun 'texinfo-defun-index 'texinfo-findex)
(put 'deftypefunx 'texinfo-defun-index 'texinfo-findex)
(put 'deftypevr 'texinfo-format 'texinfo-format-defun)
(put 'deftypevrx 'texinfo-format 'texinfo-format-defunx)
(put 'deftypevr 'texinfo-end 'texinfo-end-defun)
(put 'deftypevr 'texinfo-defun-type '('deftypefn-type nil))
(put 'deftypevrx 'texinfo-defun-type '('deftypefn-type nil))
(put 'deftypevr 'texinfo-defun-index 'texinfo-vindex)
(put 'deftypevrx 'texinfo-defun-index 'texinfo-vindex)
(put 'deftypevar 'texinfo-format 'texinfo-format-defun)
(put 'deftypevarx 'texinfo-format 'texinfo-format-defunx)
(put 'deftypevar 'texinfo-end 'texinfo-end-defun)
(put 'deftypevar 'texinfo-defun-type '('deftypevar-type "Variable"))
(put 'deftypevarx 'texinfo-defun-type '('deftypevar-type "Variable"))
(put 'deftypevar 'texinfo-defun-index 'texinfo-vindex)
(put 'deftypevarx 'texinfo-defun-index 'texinfo-vindex)
;;; @set, @clear, @ifset, @ifclear
;; If a flag is set with @set FLAG, then text between @ifset and @end
;; ifset is formatted normally, but if the flag is is cleared with
;; @clear FLAG, then the text is not formatted; it is ignored.
;; If a flag is cleared with @clear FLAG, then text between @ifclear
;; and @end ifclear is formatted normally, but if the flag is is set with
;; @set FLAG, then the text is not formatted; it is ignored. @ifclear
;; is the opposite of @ifset.
;; If a flag is set to a string with @set FLAG,
;; replace @value{FLAG} with the string.
;; If a flag with a value is cleared,
;; @value{FLAG} is invalid,
;; as if there had never been any @set FLAG previously.
(put 'clear 'texinfo-format 'texinfo-clear)
(defun texinfo-clear ()
"Clear the value of the flag."
(let* ((arg (texinfo-parse-arg-discard))
(flag (car (read-from-string arg)))
(value (substring arg (cdr (read-from-string arg)))))
(put flag 'texinfo-whether-setp 'flag-cleared)
(put flag 'texinfo-set-value "")))
(put 'set 'texinfo-format 'texinfo-set)
(defun texinfo-set ()
"Set the value of the flag, optionally to a string.
The command `@set foo This is a string.'
sets flag foo to the value: `This is a string.'
The command `@value{foo}' expands to the value."
(let* ((arg (texinfo-parse-arg-discard))
(flag (car (read-from-string arg)))
(value (substring arg (cdr (read-from-string arg)))))
(put flag 'texinfo-whether-setp 'flag-set)
(put flag 'texinfo-set-value value)))
(put 'value 'texinfo-format 'texinfo-value)
(defun texinfo-value ()
"Insert the string to which the flag is set.
The command `@set foo This is a string.'
sets flag foo to the value: `This is a string.'
The command `@value{foo}' expands to the value."
(let ((arg (texinfo-parse-arg-discard)))
(cond ((and
(eq (get (car (read-from-string arg)) 'texinfo-whether-setp)
'flag-set)
(get (car (read-from-string arg)) 'texinfo-set-value))
(insert (get (car (read-from-string arg)) 'texinfo-set-value)))
((eq (get (car (read-from-string arg)) 'texinfo-whether-setp)
'flag-cleared)
(insert (format "{No value for \"%s\"}" arg)))
((eq (get (car (read-from-string arg)) 'texinfo-whether-setp) nil)
(insert (format "{No value for \"%s\"}" arg))))))
(put 'ifset 'texinfo-end 'texinfo-discard-command)
(put 'ifset 'texinfo-format 'texinfo-if-set)
(defun texinfo-if-set ()
"If set, continue formatting; else do not format region up to @end ifset"
(let ((arg (texinfo-parse-arg-discard)))
(cond
((eq (get (car (read-from-string arg)) 'texinfo-whether-setp)
'flag-set)
;; Format the text (i.e., do not remove it); do nothing here.
())
((eq (get (car (read-from-string arg)) 'texinfo-whether-setp)
'flag-cleared)
;; Clear region (i.e., cause the text to be ignored).
(delete-region texinfo-command-start
(progn (re-search-forward "@end ifset[ \t]*\n")
(point))))
((eq (get (car (read-from-string arg)) 'texinfo-whether-setp)
nil)
;; In this case flag is neither set nor cleared.
;; Act as if set, i.e. do nothing.
()))))
(put 'ifclear 'texinfo-end 'texinfo-discard-command)
(put 'ifclear 'texinfo-format 'texinfo-if-clear)
(defun texinfo-if-clear ()
"If clear, continue formatting; if set, do not format up to @end ifset"
(let ((arg (texinfo-parse-arg-discard)))
(cond
((eq (get (car (read-from-string arg)) 'texinfo-whether-setp)
'flag-set)
;; Clear region (i.e., cause the text to be ignored).
(delete-region texinfo-command-start
(progn (re-search-forward "@end ifclear[ \t]*\n")
(point))))
((eq (get (car (read-from-string arg)) 'texinfo-whether-setp)
'flag-cleared)
;; Format the text (i.e., do not remove it); do nothing here.
())
((eq (get (car (read-from-string arg)) 'texinfo-whether-setp)
nil)
;; In this case flag is neither set nor cleared.
;; Act as if clear, i.e. do nothing.
()))))
;;; Process included files: `@include' command
;; Updated 19 October 1990
;; In the original version, include files were ignored by Info but
;; incorporated in to the printed manual. To make references to the
;; included file, the Texinfo source file has to refer to the included
;; files using the `(filename)nodename' format for refering to other
;; Info files. Also, the included files had to be formatted on their
;; own. It was just like they were another file.
;; Currently, include files are inserted into the buffer that is
;; formatted for Info. If large, the resulting info file is split and
;; tagified. For current include files to work, the master menu must
;; refer to all the nodes, and the highest level nodes in the include
;; files must have the correct next, prev, and up pointers.
;; The included file may have an @setfilename and even an @settitle,
;; but not an `\input texinfo' line.
;; Updated 24 March 1993
;; In order for @raisesections and @lowersections to work, included
;; files must be inserted into the buffer holding the outer file
;; before other Info formatting takes place. So @include is no longer
;; is treated like other @-commands.
(put 'include 'texinfo-format 'texinfo-format-noop)
; Original definition:
; (defun texinfo-format-include ()
; (let ((filename (texinfo-parse-arg-discard))
; (default-directory input-directory)
; subindex)
; (setq subindex
; (save-excursion
; (progn (find-file
; (cond ((file-readable-p (concat filename ".texinfo"))
; (concat filename ".texinfo"))
; ((file-readable-p (concat filename ".texi"))
; (concat filename ".texi"))
; ((file-readable-p (concat filename ".tex"))
; (concat filename ".tex"))
; ((file-readable-p filename)
; filename)
; (t (error "@include'd file %s not found"
; filename))))
; (texinfo-format-buffer-1))))
; (texinfo-subindex 'texinfo-vindex (car subindex) (nth 1 subindex))
; (texinfo-subindex 'texinfo-findex (car subindex) (nth 2 subindex))
; (texinfo-subindex 'texinfo-cindex (car subindex) (nth 3 subindex))
; (texinfo-subindex 'texinfo-pindex (car subindex) (nth 4 subindex))
; (texinfo-subindex 'texinfo-tindex (car subindex) (nth 5 subindex))
; (texinfo-subindex 'texinfo-kindex (car subindex) (nth 6 subindex))))
;
;(defun texinfo-subindex (indexvar file content)
; (set indexvar (cons (list 'recurse file content)
; (symbol-value indexvar))))
; Second definition:
; (put 'include 'texinfo-format 'texinfo-format-include)
; (defun texinfo-format-include ()
; (let ((filename (concat input-directory
; (texinfo-parse-arg-discard)))
; (default-directory input-directory))
; (message "Reading: %s" filename)
; (save-excursion
; (save-restriction
; (narrow-to-region
; (point)
; (+ (point) (car (cdr (insert-file-contents filename)))))
; (goto-char (point-min))
; (texinfo-append-refill)
; (texinfo-format-convert (point-min) (point-max))))
; (setq last-input-buffer input-buffer) ; to bypass setfilename
; ))
;;; Numerous commands do nothing in Texinfo
;; These commands are defined in texinfo.tex for printed output.
(put 'bye 'texinfo-format 'texinfo-discard-line)
(put 'c 'texinfo-format 'texinfo-discard-line-with-args)
(put 'comment 'texinfo-format 'texinfo-discard-line-with-args)
(put 'contents 'texinfo-format 'texinfo-discard-line-with-args)
(put 'finalout 'texinfo-format 'texinfo-discard-line)
(put 'group 'texinfo-end 'texinfo-discard-line-with-args)
(put 'group 'texinfo-format 'texinfo-discard-line-with-args)
(put 'headings 'texinfo-format 'texinfo-discard-line-with-args)
(put 'hsize 'texinfo-format 'texinfo-discard-line-with-args)
(put 'itemindent 'texinfo-format 'texinfo-discard-line-with-args)
(put 'lispnarrowing 'texinfo-format 'texinfo-discard-line-with-args)
(put 'need 'texinfo-format 'texinfo-discard-line-with-args)
(put 'nopara 'texinfo-format 'texinfo-discard-line-with-args)
(put 'page 'texinfo-format 'texinfo-discard-line-with-args)
(put 'parindent 'texinfo-format 'texinfo-discard-line-with-args)
(put 'setchapternewpage 'texinfo-format 'texinfo-discard-line-with-args)
(put 'setq 'texinfo-format 'texinfo-discard-line-with-args)
(put 'settitle 'texinfo-format 'texinfo-discard-line-with-args)
(put 'setx 'texinfo-format 'texinfo-discard-line-with-args)
(put 'shortcontents 'texinfo-format 'texinfo-discard-line-with-args)
(put 'smallbook 'texinfo-format 'texinfo-discard-line)
(put 'summarycontents 'texinfo-format 'texinfo-discard-line-with-args)
;;; Some commands cannot be handled
(defun texinfo-unsupported ()
(error "%s is not handled by texinfo"
(buffer-substring texinfo-command-start texinfo-command-end)))
;;; Batch formatting
(defun batch-texinfo-format ()
"Runs texinfo-format-buffer on the files remaining on the command line.
Must be used only with -batch, and kills emacs on completion.
Each file will be processed even if an error occurred previously.
For example, invoke
\"emacs -batch -funcall batch-texinfo-format $docs/ ~/*.texinfo\"."
(if (not noninteractive)
(error "batch-texinfo-format may only be used -batch."))
(let ((version-control t)
(auto-save-default nil)
(find-file-run-dired nil)
(kept-old-versions 259259)
(kept-new-versions 259259))
(let ((error 0)
file
(files ()))
(while command-line-args-left
(setq file (expand-file-name (car command-line-args-left)))
(cond ((not (file-exists-p file))
(message ">> %s does not exist!" file)
(setq error 1
command-line-args-left (cdr command-line-args-left)))
((file-directory-p file)
(setq command-line-args-left
(nconc (directory-files file)
(cdr command-line-args-left))))
(t
(setq files (cons file files)
command-line-args-left (cdr command-line-args-left)))))
(while files
(setq file (car files)
files (cdr files))
(condition-case err
(progn
(if buffer-file-name (kill-buffer (current-buffer)))
(find-file file)
(buffer-disable-undo (current-buffer))
(set-buffer-modified-p nil)
(texinfo-mode)
(message "texinfo formatting %s..." file)
(texinfo-format-buffer nil)
(if (buffer-modified-p)
(progn (message "Saving modified %s" (buffer-file-name))
(save-buffer))))
(error
(message ">> Error: %s" (prin1-to-string err))
(message ">> point at")
(let ((s (buffer-substring (point)
(min (+ (point) 100)
(point-max))))
(tem 0))
(while (setq tem (string-match "\n+" s tem))
(setq s (concat (substring s 0 (match-beginning 0))
"\n>> "
(substring s (match-end 0)))
tem (1+ tem)))
(message ">> %s" s))
(setq error 1))))
(kill-emacs error))))
;;; Place `provide' at end of file.
(provide 'texinfmt)
;;; texinfmt.el ends here.
texinfo-3.7/emacs/texinfo.el 100444 11732 13 72417 6045205454 14351 0 ustar bfox user ;;; texinfo.el --- major mode for editing Texinfo files
;; Copyright (C) 1985, '88, '89,
;; '90, '91, '92, '93 Free Software Foundation, Inc.
;; Author: Robert J. Chassell
;; Maintainer: FSF
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Autoloads:
(autoload 'makeinfo-region
"makeinfo"
"Make Info file from region of current Texinfo file, and switch to it.
This command does not offer the `next-error' feature since it would
apply to a temporary file, not the original; use the `makeinfo-buffer'
command to gain use of `next-error'."
t nil)
(autoload 'makeinfo-buffer
"makeinfo"
"Make Info file from current buffer.
Use the \\[next-error] command to move to the next error
\(if there are errors\)."
t nil)
(autoload 'kill-compilation
"compile"
"Kill the process made by the \\[compile] command."
t nil)
(autoload 'makeinfo-recenter-compilation-buffer
"makeinfo"
"Redisplay `*compilation*' buffer so most recent output can be seen.
The last line of the buffer is displayed on
line LINE of the window, or centered if LINE is nil."
t nil)
(autoload 'texinfo-make-menu
"texnfo-upd"
"Without any prefix argument, make or update a menu.
Make the menu for the section enclosing the node found following point.
Non-nil argument (prefix, if interactive) means make or update menus
for nodes within or part of the marked region.
Whenever a menu exists, and is being updated, the descriptions that
are associated with node names in the pre-existing menu are
incorporated into the new menu. Otherwise, the nodes' section titles
are inserted as descriptions."
t nil)
(autoload 'texinfo-all-menus-update
"texnfo-upd"
"Update every regular menu in a Texinfo file.
Remove pre-existing master menu, if there is one.
If called with a non-nil argument, this function first updates all the
nodes in the buffer before updating the menus."
t nil)
(autoload 'texinfo-master-menu
"texnfo-upd"
"Make a master menu for a whole Texinfo file.
Non-nil argument (prefix, if interactive) means first update all
existing nodes and menus. Remove pre-existing master menu, if there is one.
This function creates a master menu that follows the top node. The
master menu includes every entry from all the other menus. It
replaces any existing ordinary menu that follows the top node.
If called with a non-nil argument, this function first updates all the
menus in the buffer (incorporating descriptions from pre-existing
menus) before it constructs the master menu.
The function removes the detailed part of an already existing master
menu. This action depends on the pre-exisitng master menu using the
standard `texinfo-master-menu-header'.
The master menu has the following format, which is adapted from the
recommendation in the Texinfo Manual:
* The first part contains the major nodes in the Texinfo file: the
nodes for the chapters, chapter-like sections, and the major
appendices. This includes the indices, so long as they are in
chapter-like sections, such as unnumbered sections.
* The second and subsequent parts contain a listing of the other,
lower level menus, in order. This way, an inquirer can go
directly to a particular node if he or she is searching for
specific information.
Each of the menus in the detailed node listing is introduced by the
title of the section containing the menu."
t nil)
(autoload 'texinfo-indent-menu-description
"texnfo-upd"
"Indent every description in menu following point to COLUMN.
Non-nil argument (prefix, if interactive) means indent every
description in every menu in the region. Does not indent second and
subsequent lines of a multi-line description."
t nil)
(autoload 'texinfo-insert-node-lines
"texnfo-upd"
"Insert missing `@node' lines in region of Texinfo file.
Non-nil argument (prefix, if interactive) means also to insert the
section titles as node names; and also to insert the section titles as
node names in pre-existing @node lines that lack names."
t nil)
(autoload 'texinfo-start-menu-description
"texnfo-upd"
"In this menu entry, insert the node's section title as a description.
Position point at beginning of description ready for editing.
Do not insert a title if the line contains an existing description.
You will need to edit the inserted text since a useful description
complements the node name rather than repeats it as a title does."
t nil)
(autoload 'texinfo-multiple-files-update
"texnfo-upd"
"Update first node pointers in each file included in OUTER-FILE;
create or update main menu in the outer file that refers to such nodes.
This does not create or update menus or pointers within the included files.
With optional MAKE-MASTER-MENU argument (prefix arg, if interactive),
insert a master menu in OUTER-FILE. This does not create or update
menus or pointers within the included files.
With optional UPDATE-EVERYTHING argument (numeric prefix arg, if
interactive), update all the menus and all the `Next', `Previous', and
`Up' pointers of all the files included in OUTER-FILE before inserting
a master menu in OUTER-FILE.
The command also updates the `Top' level node pointers of OUTER-FILE.
Notes:
* this command does NOT save any files--you must save the
outer file and any modified, included files.
* except for the `Top' node, this command does NOT handle any
pre-existing nodes in the outer file; hence, indices must be
enclosed in an included file.
Requirements:
* each of the included files must contain exactly one highest
hierarchical level node,
* this highest node must be the first node in the included file,
* each highest hierarchical level node must be of the same type.
Thus, normally, each included file contains one, and only one,
chapter."
t nil)
;;; Code:
;;; Don't you dare insert any `require' calls at top level in this file--rms.
;;; Syntax table
(defvar texinfo-mode-syntax-table nil)
(if texinfo-mode-syntax-table
nil
(setq texinfo-mode-syntax-table (make-syntax-table))
(modify-syntax-entry ?\" " " texinfo-mode-syntax-table)
(modify-syntax-entry ?\\ " " texinfo-mode-syntax-table)
(modify-syntax-entry ?@ "\\" texinfo-mode-syntax-table)
(modify-syntax-entry ?\^q "\\" texinfo-mode-syntax-table)
(modify-syntax-entry ?\[ "(]" texinfo-mode-syntax-table)
(modify-syntax-entry ?\] ")[" texinfo-mode-syntax-table)
(modify-syntax-entry ?{ "(}" texinfo-mode-syntax-table)
(modify-syntax-entry ?} "){" texinfo-mode-syntax-table)
(modify-syntax-entry ?\' "w" texinfo-mode-syntax-table))
;; Written by Wolfgang Bangerth
;; To overide this example, set either `imenu-generic-expression'
;; or `imenu-create-index-function'.
(defvar texinfo-imenu-generic-expression
'((nil "^@node[ \t]+\\([^,\n]*\\)" 1)
("Chapters" "^@chapter[ \t]+\\(.*\\)$" 1))
"Imenu generic expression for TexInfo mode. See `imenu-generic-expression'.")
(defvar texinfo-font-lock-keywords
(list
;; All but the first 2 had an OVERRIDE of t.
;; It didn't seem to be any better, and it's slower--simon.
'("^\\(@c\\|@comment\\)\\>.*" . font-lock-comment-face) ;comments
;; Robert J. Chassell says remove this line.
;'("\\$\\([^$]*\\)\\$" 1 font-lock-string-face t)
"@\\(@\\|[^}\t \n{]+\\)" ;commands
'("^\\(*.*\\)[\t ]*$" 1 font-lock-function-name-face t) ;menu items
'("@\\(emph\\|strong\\|b\\|i\\){\\([^}]+\\)" 2 font-lock-comment-face)
'("@\\(file\\|kbd\\|key\\){\\([^}]+\\)" 2 font-lock-string-face)
'("@\\(samp\\|code\\|var\\|math\\){\\([^}]+\\)"
2 font-lock-variable-name-face)
'("@\\(cite\\|xref\\|pxref\\){\\([^}]+\\)" 2 font-lock-reference-face)
'("@\\(end\\|item\\) *\\(.+\\)" 2 font-lock-function-name-face keep)
)
"Additional expressions to highlight in TeXinfo mode.")
;;; Keybindings
(defvar texinfo-mode-map nil)
;;; Keys common both to Texinfo mode and to TeX shell.
(defun texinfo-define-common-keys (keymap)
"Define the keys both in Texinfo mode and in the texinfo-tex-shell."
(define-key keymap "\C-c\C-t\C-k" 'tex-kill-job)
(define-key keymap "\C-c\C-t\C-x" 'texinfo-quit-job)
(define-key keymap "\C-c\C-t\C-l" 'tex-recenter-output-buffer)
(define-key keymap "\C-c\C-t\C-d" 'texinfo-delete-from-print-queue)
(define-key keymap "\C-c\C-t\C-q" 'tex-show-print-queue)
(define-key keymap "\C-c\C-t\C-p" 'texinfo-tex-print)
(define-key keymap "\C-c\C-t\C-i" 'texinfo-texindex)
(define-key keymap "\C-c\C-t\C-r" 'texinfo-tex-region)
(define-key keymap "\C-c\C-t\C-b" 'texinfo-tex-buffer))
;; Mode documentation displays commands in reverse order
;; from how they are listed in the texinfo-mode-map.
(if texinfo-mode-map
nil
(setq texinfo-mode-map (make-sparse-keymap))
;; bindings for `texnfo-tex.el'
(texinfo-define-common-keys texinfo-mode-map)
;; bindings for `makeinfo.el'
(define-key texinfo-mode-map "\C-c\C-m\C-k" 'kill-compilation)
(define-key texinfo-mode-map "\C-c\C-m\C-l"
'makeinfo-recenter-compilation-buffer)
(define-key texinfo-mode-map "\C-c\C-m\C-r" 'makeinfo-region)
(define-key texinfo-mode-map "\C-c\C-m\C-b" 'makeinfo-buffer)
; Bindings for texinfmt.el.
(define-key texinfo-mode-map "\C-c\C-e\C-r" 'texinfo-format-region)
(define-key texinfo-mode-map "\C-c\C-e\C-b" 'texinfo-format-buffer)
;; bindings for updating nodes and menus
(define-key texinfo-mode-map "\C-c\C-um" 'texinfo-master-menu)
(define-key texinfo-mode-map "\C-c\C-u\C-m" 'texinfo-make-menu)
(define-key texinfo-mode-map "\C-c\C-u\C-n" 'texinfo-update-node)
(define-key texinfo-mode-map "\C-c\C-u\C-e" 'texinfo-every-node-update)
(define-key texinfo-mode-map "\C-c\C-u\C-a" 'texinfo-all-menus-update)
(define-key texinfo-mode-map "\C-c\C-s" 'texinfo-show-structure)
(define-key texinfo-mode-map "\C-c}" 'up-list)
(define-key texinfo-mode-map "\C-c{" 'texinfo-insert-braces)
;; bindings for inserting strings
(define-key texinfo-mode-map "\C-c\C-c\C-d" 'texinfo-start-menu-description)
(define-key texinfo-mode-map "\C-c\C-cv" 'texinfo-insert-@var)
(define-key texinfo-mode-map "\C-c\C-ct" 'texinfo-insert-@table)
(define-key texinfo-mode-map "\C-c\C-cs" 'texinfo-insert-@samp)
(define-key texinfo-mode-map "\C-c\C-co" 'texinfo-insert-@noindent)
(define-key texinfo-mode-map "\C-c\C-cn" 'texinfo-insert-@node)
(define-key texinfo-mode-map "\C-c\C-ck" 'texinfo-insert-@kbd)
(define-key texinfo-mode-map "\C-c\C-ci" 'texinfo-insert-@item)
(define-key texinfo-mode-map "\C-c\C-cf" 'texinfo-insert-@file)
(define-key texinfo-mode-map "\C-c\C-cx" 'texinfo-insert-@example)
(define-key texinfo-mode-map "\C-c\C-ce" 'texinfo-insert-@end)
(define-key texinfo-mode-map "\C-c\C-cd" 'texinfo-insert-@dfn)
(define-key texinfo-mode-map "\C-c\C-cc" 'texinfo-insert-@code))
;;; Texinfo mode
(defvar texinfo-chapter-level-regexp
"chapter\\|unnumbered \\|appendix \\|majorheading\\|chapheading"
"Regular expression matching Texinfo chapter-level headings.
This does not match `@node' and does not match the `@top' command.")
;;;###autoload
(defun texinfo-mode ()
"Major mode for editing Texinfo files.
It has these extra commands:
\\{texinfo-mode-map}
These are files that are used as input for TeX to make printed manuals
and also to be turned into Info files with \\[makeinfo-buffer] or
the `makeinfo' program. These files must be written in a very restricted and
modified version of TeX input format.
Editing commands are like text-mode except that the syntax table is
set up so expression commands skip Texinfo bracket groups. To see
what the Info version of a region of the Texinfo file will look like,
use \\[makeinfo-region], which runs `makeinfo' on the current region.
You can show the structure of a Texinfo file with \\[texinfo-show-structure].
This command shows the structure of a Texinfo file by listing the
lines with the @-sign commands for @chapter, @section, and the like.
These lines are displayed in another window called the *Occur* window.
In that window, you can position the cursor over one of the lines and
use \\[occur-mode-goto-occurrence], to jump to the corresponding spot
in the Texinfo file.
In addition, Texinfo mode provides commands that insert various
frequently used @-sign commands into the buffer. You can use these
commands to save keystrokes. And you can insert balanced braces with
\\[texinfo-insert-braces] and later use the command \\[up-list] to
move forward past the closing brace.
Also, Texinfo mode provides functions for automatically creating or
updating menus and node pointers. These functions
* insert the `Next', `Previous' and `Up' pointers of a node,
* insert or update the menu for a section, and
* create a master menu for a Texinfo source file.
Here are the functions:
texinfo-update-node \\[texinfo-update-node]
texinfo-every-node-update \\[texinfo-every-node-update]
texinfo-sequential-node-update
texinfo-make-menu \\[texinfo-make-menu]
texinfo-all-menus-update \\[texinfo-all-menus-update]
texinfo-master-menu
texinfo-indent-menu-description (column &optional region-p)
The `texinfo-column-for-description' variable specifies the column to
which menu descriptions are indented.
Passed an argument (a prefix argument, if interactive), the
`texinfo-update-node' and `texinfo-make-menu' functions do their jobs
in the region.
To use the updating commands, you must structure your Texinfo file
hierarchically, such that each `@node' line, with the exception of the
Top node, is accompanied by some kind of section line, such as an
`@chapter' or `@section' line.
If the file has a `top' node, it must be called `top' or `Top' and
be the first node in the file.
Entering Texinfo mode calls the value of text-mode-hook, and then the
value of texinfo-mode-hook."
(interactive)
(text-mode)
(setq mode-name "Texinfo")
(setq major-mode 'texinfo-mode)
(use-local-map texinfo-mode-map)
(set-syntax-table texinfo-mode-syntax-table)
(make-local-variable 'page-delimiter)
(setq page-delimiter
(concat
"^@node [ \t]*[Tt]op\\|^@\\("
texinfo-chapter-level-regexp
"\\)"))
(make-local-variable 'require-final-newline)
(setq require-final-newline t)
(make-local-variable 'indent-tabs-mode)
(setq indent-tabs-mode nil)
(make-local-variable 'paragraph-separate)
(setq paragraph-separate (concat "\b\\|@[a-zA-Z]*[ \n]\\|" paragraph-separate))
(make-local-variable 'paragraph-start)
(setq paragraph-start (concat "\b\\|@[a-zA-Z]*[ \n]\\|" paragraph-start))
(make-local-variable 'fill-column)
(setq fill-column 72)
(make-local-variable 'comment-start)
(setq comment-start "@c ")
(make-local-variable 'comment-start-skip)
(setq comment-start-skip "@c +")
(make-local-variable 'words-include-escapes)
(setq words-include-escapes t)
(make-local-variable 'imenu-generic-expression)
(setq imenu-generic-expression texinfo-imenu-generic-expression)
(make-local-variable 'font-lock-defaults)
(setq font-lock-defaults '(texinfo-font-lock-keywords t))
(make-local-variable 'tex-start-of-header)
(setq tex-start-of-header "%**start")
(make-local-variable 'tex-end-of-header)
(setq tex-end-of-header "%**end")
(run-hooks 'text-mode-hook 'texinfo-mode-hook))
;;; Insert string commands
(defconst texinfo-environment-regexp
"^[ \t]*@\\(f?table\\|enumerate\\|itemize\
\\|ifhtml\\|ifinfo\\|iftex\\|ifset\\|ifclear\
\\|example\\|quotation\\|lisp\\|smallexample\\|smalllisp\\|display\\|format\
\\|flushleft\\|flushright\\|ignore\\|group\\|tex\\|html\\|cartouche\\|menu\
\\|titlepage\\|end\\|def[a-z]*[a-wyz]\\>\\)"
"Regexp for environment-like Texinfo list commands.
Subexpression 1 is what goes into the corresponding `@end' statement.")
(defun texinfo-insert-@end ()
"Insert the matching `@end' for the last Texinfo command that needs one."
(interactive)
(let ((depth 1) string)
(save-excursion
(while (and (> depth 0)
(re-search-backward texinfo-environment-regexp nil t)
(if (looking-at "@end")
(setq depth (1+ depth))
(setq depth (1- depth)))))
(looking-at texinfo-environment-regexp)
(if (zerop depth)
(setq string
(buffer-substring (match-beginning 1)
(match-end 1)))))
(insert "@end ")
(if string (insert string "\n"))))
;; The following insert commands accept a prefix arg N, which is the
;; number of words (actually s-exprs) that should be surrounded by
;; braces. Thus you can first paste a variable name into a .texinfo
;; buffer, then say C-u 1 C-c C-c v at the beginning of the just
;; pasted variable name to put @var{...} *around* the variable name.
;; Operate on previous word or words with negative arg.
;; These commands use texinfo-insert-@-with-arg
(defun texinfo-insert-@-with-arg (string &optional arg)
(if arg
(progn
(setq arg (prefix-numeric-value arg))
(if (< arg 0)
(progn
(skip-chars-backward " \t\n\r\f")
(save-excursion
(forward-sexp arg)
(insert "@" string "{"))
(insert "}"))
(skip-chars-forward " \t\n\r\f")
(insert "@" string "{")
(forward-sexp arg)
(insert "}")))
(insert "@" string "{}")
(backward-char)))
(defun texinfo-insert-braces ()
"Make a pair of braces and be poised to type inside of them.
Use \\[up-list] to move forward out of the braces."
(interactive)
(insert "{}")
(backward-char))
(defun texinfo-insert-@code (&optional arg)
"Insert a `@code{...}' command in a Texinfo buffer.
A numeric argument says how many words the braces should surround.
The default is not to surround any existing words with the braces."
(interactive "P")
(texinfo-insert-@-with-arg "code" arg))
(defun texinfo-insert-@dfn (&optional arg)
"Insert a `@dfn{...}' command in a Texinfo buffer.
A numeric argument says how many words the braces should surround.
The default is not to surround any existing words with the braces."
(interactive "P")
(texinfo-insert-@-with-arg "dfn" arg))
(defun texinfo-insert-@example ()
"Insert the string `@example' in a Texinfo buffer."
(interactive)
(insert "@example\n"))
(defun texinfo-insert-@file (&optional arg)
"Insert a `@file{...}' command in a Texinfo buffer.
A numeric argument says how many words the braces should surround.
The default is not to surround any existing words with the braces."
(interactive "P")
(texinfo-insert-@-with-arg "file" arg))
(defun texinfo-insert-@item ()
"Insert the string `@item' in a Texinfo buffer."
(interactive)
(insert "@item")
(newline))
(defun texinfo-insert-@kbd (&optional arg)
"Insert a `@kbd{...}' command in a Texinfo buffer.
A numeric argument says how many words the braces should surround.
The default is not to surround any existing words with the braces."
(interactive "P")
(texinfo-insert-@-with-arg "kbd" arg))
(defun texinfo-insert-@node ()
"Insert the string `@node' in a Texinfo buffer.
This also inserts on the following line a comment indicating
the order of arguments to @node."
(interactive)
(insert "@node \n@comment node-name, next, previous, up")
(forward-line -1)
(forward-char 6))
(defun texinfo-insert-@noindent ()
"Insert the string `@noindent' in a Texinfo buffer."
(interactive)
(insert "@noindent\n"))
(defun texinfo-insert-@samp (&optional arg)
"Insert a `@samp{...}' command in a Texinfo buffer.
A numeric argument says how many words the braces should surround.
The default is not to surround any existing words with the braces."
(interactive "P")
(texinfo-insert-@-with-arg "samp" arg))
(defun texinfo-insert-@table (&optional arg)
"Insert the string `@table' in a Texinfo buffer."
(interactive "P")
(insert "@table "))
(defun texinfo-insert-@var (&optional arg)
"Insert a `@var{}' command in a Texinfo buffer.
A numeric argument says how many words the braces should surround.
The default is not to surround any existing words with the braces."
(interactive "P")
(texinfo-insert-@-with-arg "var" arg))
;;; Texinfo file structure
(defun texinfo-show-structure (&optional nodes-too)
"Show the structure of a Texinfo file.
List the lines in the file that begin with the @-sign commands for
@chapter, @section, and the like.
With optional argument (prefix if interactive), list both the lines
with @-sign commands for @chapter, @section, and the like, and list
@node lines.
Lines with structuring commands beginning in them are displayed in
another buffer named `*Occur*'. In that buffer, you can move point to
one of those lines and then use \\\\[occur-mode-goto-occurrence],
to jump to the corresponding spot in the Texinfo source file."
(interactive "P")
(require 'texnfo-upd)
(save-excursion
(goto-char (point-min))
(if nodes-too
(occur (concat "\\(^@node\\)\\|" texinfo-section-types-regexp))
(occur texinfo-section-types-regexp)))
(pop-to-buffer "*Occur*")
(goto-char (point-min))
(flush-lines "-----")
;; Now format the "*Occur*" buffer to show the structure.
;; Thanks to ceder@signum.se (Per Cederqvist)
(goto-char (point-max))
(let ((margin 5))
(while (re-search-backward "^ *[0-9]*:" nil 0)
(re-search-forward ":")
(setq margin
(cond
((looking-at
(concat "@\\(" texinfo-chapter-level-regexp "\\)")) 5)
;; ((looking-at "@chapter ") 5)
;; ((looking-at "@unnumbered ") 5)
;; ((looking-at "@appendix ") 5)
;; ((looking-at "@majorheading ") 5)
;; ((looking-at "@chapheading ") 5)
((looking-at
(concat "@\\(" texinfo-section-level-regexp "\\)")) 9)
;; ((looking-at "@section ") 9)
;; ((looking-at "@unnumberedsec ") 9)
;; ((looking-at "@appendixsec ") 9)
;; ((looking-at "@heading ") 9)
((looking-at
(concat "@\\(" texinfo-subsection-level-regexp "\\)")) 13)
;; ((looking-at "@subsection ") 13)
;; ((looking-at "@unnumberedsubsec ") 13)
;; ((looking-at "@appendixsubsec ") 13)
;; ((looking-at "@subheading ") 13)
((looking-at
(concat "@\\(" texinfo-subsubsection-level-regexp "\\)")) 17)
;; ((looking-at "@subsubsection ") 17)
;; ((looking-at "@unnumberedsubsubsec ") 17)
;; ((looking-at "@appendixsubsubsec ") 17)
;; ((looking-at "@subsubheading ") 17)
(t margin)))
(indent-to-column margin)
(beginning-of-line))))
;;; The tex and print function definitions:
(defvar texinfo-texi2dvi-command "texi2dvi"
"*Command used by `texinfo-tex-buffer' to run TeX and texindex on a buffer.")
(defvar texinfo-tex-command "tex"
"*Command used by `texinfo-tex-region' to run TeX on a region.")
(defvar texinfo-texindex-command "texindex"
"*Command used by `texinfo-texindex' to sort unsorted index files.")
(defvar texinfo-delete-from-print-queue-command "lprm"
"*Command string used to delete a job from the line printer queue.
Command is used by \\[texinfo-delete-from-print-queue] based on
number provided by a previous \\[tex-show-print-queue]
command.")
(defvar texinfo-tex-trailer "@bye"
"String appended after a region sent to TeX by `texinfo-tex-region'.")
(defun texinfo-tex-region (beg end)
"Run TeX on the current region.
This works by writing a temporary file (`tex-zap-file') in the directory
that is the value of `tex-directory', then running TeX on that file.
The first line of the buffer is copied to the
temporary file; and if the buffer has a header, it is written to the
temporary file before the region itself. The buffer's header is all lines
between the strings defined by `tex-start-of-header' and `tex-end-of-header'
inclusive. The header must start in the first 100 lines.
The value of `texinfo-tex-trailer' is appended to the temporary file after the region."
(interactive "r")
(require 'tex-mode)
(if (get-buffer "*tex-shell*")
(tex-kill-job)
(tex-start-shell))
(or tex-zap-file (setq tex-zap-file (make-temp-name "#tz")))
(let ((tex-out-file (concat tex-zap-file ".tex"))
(temp-buffer (get-buffer-create " tex-Output-Buffer"))
(zap-directory
(file-name-as-directory (expand-file-name tex-directory))))
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(forward-line 100)
(let ((search-end (point))
(hbeg (point-min)) (hend (point-min))
(default-directory zap-directory))
(goto-char (point-min))
;; Copy first line, the `\input texinfo' line, to temp file
(write-region (point)
(save-excursion (end-of-line) (point))
tex-out-file nil nil)
;; Don't copy first line twice if region includes it.
(forward-line 1)
(if (< beg (point)) (setq beg (point)))
;; Initialize the temp file with either the header or nothing
(if (search-forward tex-start-of-header search-end t)
(progn
(beginning-of-line)
(setq hbeg (point)) ; Mark beginning of header.
(if (search-forward tex-end-of-header nil t)
(progn (beginning-of-line)
(setq hend (point))) ; Mark end of header.
(setq hbeg (point-min))))) ; Else no header.
;; Copy header to temp file.
(write-region (min hbeg beg) hend tex-out-file t nil)
;; Copy region to temp file.
(write-region (max beg hend) end tex-out-file t nil))
;; This is a kludge to insert the tex-trailer into the tex-out-file.
;; We have to create a special buffer in which to insert
;; the tex-trailer first because there is no function with
;; which to append a literal string directly to a file.
(let ((local-tex-trailer texinfo-tex-trailer))
(set-buffer temp-buffer)
(erase-buffer)
;; make sure trailer isn't hidden by a comment
(insert-string "\n")
(if local-tex-trailer (insert-string local-tex-trailer))
(tex-set-buffer-directory temp-buffer zap-directory)
(write-region (point-min) (point-max) tex-out-file t nil))
;;; The following is sufficient in Emacs 19.
;;; (write-region (concat "\n" texinfo-tex-trailer) nil
;;; tex-out-file t nil)
))
(tex-set-buffer-directory "*tex-shell*" zap-directory)
(tex-send-command tex-shell-cd-command zap-directory)
(tex-send-command texinfo-tex-command tex-out-file))
(tex-recenter-output-buffer 0))
(defun texinfo-tex-buffer ()
"Run TeX on visited file, once or twice, to make a correct `.dvi' file."
(interactive)
;; Make sure TeX shell is running.
(require 'tex-mode)
(if (get-buffer "*tex-shell*")
(quit-process (get-process "tex-shell") t)
(tex-start-shell))
(cond ((null buffer-file-name)
(error "Buffer not visiting any file!"))
((buffer-modified-p)
(error "Buffer has been modified since last saved!")))
(setq tex-zap-file buffer-file-name)
(tex-send-command tex-shell-cd-command (file-name-directory tex-zap-file))
(tex-send-command texinfo-texi2dvi-command tex-zap-file)
(tex-recenter-output-buffer 0))
(defun texinfo-texindex ()
"Run `texindex' on unsorted index files.
The index files are made by \\[texinfo-tex-region] or \\[texinfo-tex-buffer].
This runs the shell command defined by `texinfo-texindex-command'."
(interactive)
(require 'tex-mode)
(tex-send-command texinfo-texindex-command (concat tex-zap-file ".??"))
(tex-recenter-output-buffer nil))
(defun texinfo-tex-print ()
"Print `.dvi' file made by \\[texinfo-tex-region] or \\[texinfo-tex-buffer].
This runs the shell command defined by `tex-dvi-print-command'."
(interactive)
(require 'tex-mode)
(tex-send-command tex-dvi-print-command (concat tex-zap-file ".dvi"))
(tex-recenter-output-buffer nil))
(defun texinfo-quit-job ()
"Quit currently running TeX job, by sending an `x' to it."
(interactive)
(if (not (get-process "tex-shell"))
(error "No TeX shell running"))
(tex-send-command "x"))
(defun texinfo-delete-from-print-queue (job-number)
"Delete job from the line printer spooling queue.
You are prompted for the job number (use a number shown by a previous
\\[texinfo-show-print-queue] command)."
(interactive "nPrinter job number for deletion: ")
(require 'tex-mode)
(if (tex-shell-running)
(tex-kill-job)
(tex-start-shell))
(tex-send-command texinfo-delete-from-print-queue-command job-number)
(tex-recenter-output-buffer nil))
(provide 'texinfo)
;;; texinfo.el ends here
texinfo-3.7/emacs/texnfo-tex.el 100666 21641 13 33127 5354447751 15640 0 ustar friedman user ;;;; texnfo-tex.el
;;; Texinfo mode TeX and hardcopy printing commands.
;; These commands are for running TeX on a region of a Texinfo file in
;; GNU Emacs, or on the whole buffer, and for printing the resulting
;; DVI file.
;;; Version 2.07 22 October 1991
;;; Robert J. Chassell
;;; Please send bug reports to: bug-texinfo@prep.ai.mit.edu
;;; Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
;;; This file is part of GNU Emacs.
;; GNU Emacs 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 1, or (at your option)
;; any later version.
;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; The Texinfo mode TeX related commands are:
; texinfo-tex-region to run tex on the current region.
; texinfo-tex-buffer to run tex on the current buffer.
; texinfo-texindex to sort unsorted index files.
; texinfo-tex-print to print the .dvi file made by tex.
; texinfo-kill-tex-job to kill the currently running tex job.
; texinfo-recenter-tex-output-buffer to redisplay tex output buffer.
; texinfo-show-tex-print-queue to show the print queue.
;;; Keys common both to Texinfo mode and to TeX shell.
;; Defined in `texinfo.el'
; (defun texinfo-define-common-keys (keymap)
; "Define the keys both in Texinfo mode and in the texinfo-tex-shell."
; (define-key keymap "\C-c\C-t\C-k" 'texinfo-kill-tex-job)
; (define-key keymap "\C-c\C-t\C-x" 'texinfo-quit-tex-job)
; (define-key keymap "\C-c\C-t\C-l" 'texinfo-recenter-tex-output-buffer)
; (define-key keymap "\C-c\C-t\C-d" 'texinfo-delete-from-tex-print-queue)
; (define-key keymap "\C-c\C-t\C-q" 'texinfo-show-tex-print-queue)
; (define-key keymap "\C-c\C-t\C-p" 'texinfo-tex-print)
; (define-key keymap "\C-c\C-t\C-i" 'texinfo-texindex)
; (define-key keymap "\C-c\C-t\C-r" 'texinfo-tex-region)
; (define-key keymap "\C-c\C-t\C-b" 'texinfo-tex-buffer))
;; See also texinfo-tex-start-shell.
;; The following is executed in the `texinfo.el' file
;(texinfo-define-common-keys texinfo-mode-map)
;;; Variable definitions:
(require 'shell)
(defvar texinfo-tex-shell-cd-command "cd"
"Command to give to shell running TeX to change directory.")
(defvar texinfo-tex-command "tex"
"*Command used by texinfo-tex-region to run tex on a region.")
(defvar texinfo-texindex-command "texindex"
"*Command used by texinfo-texindex to sort unsorted index files.")
(defvar texinfo-tex-dvi-print-command "lpr -d"
"*Command string used by \\[tex-print] to print a .dvi file.")
(defvar texinfo-show-tex-queue-command "lpq"
"*Command string used to show the Texinfo TeX print queue.
Command is used by \\[texinfo-show-tex-print-queue] and it
should show the queue that \\[texinfo-tex-print] puts jobs on.")
(defvar texinfo-delete-from-print-queue-command "lprm"
"*Command string used to delete a job from the line printer queue.
Command is used by \\[texinfo-delete-from-tex-print-queue] based on
number provided by a previous \\[texinfo-show-tex-print-queue]
command.")
(defvar texinfo-tex-trailer "@bye"
"String appended after a region sent to TeX by texinfo-tex-region.")
(defvar texinfo-tex-original-file ""
"Original name of file on which to run TeX.")
(defvar texinfo-tex-temp-file nil
"Temporary file name used for text being sent as input to TeX.")
(defvar texinfo-tex-root-temp-file nil
"Temporary file name used for text being sent as input to TeX.")
;;; Texinfo TeX main functions
(defun texinfo-tex-region (beginning end)
"Run tex on the current region.
A temporary file is written in the default directory, and tex is run
in that directory. The first line of the file is copied to the
temporary file; and if the buffer has a header, it is written to the
temporary file before the region itself. The buffer's header is all
lines between the strings defined by texinfo-start-of-header and
texinfo-end-of-header inclusive. The header must start in the first 100
lines. The value of texinfo-tex-trailer is appended to the temporary file
after the region."
(interactive "r")
(if (get-buffer "*texinfo-tex-shell*")
(quit-process (get-process "texinfo-tex-shell") t)
(texinfo-tex-start-shell))
(setq texinfo-tex-root-temp-file
(expand-file-name
(make-temp-name
(prin1-to-string (read (buffer-name))))))
(let ((texinfo-tex-temp-file (concat texinfo-tex-root-temp-file ".tex")))
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(forward-line 100)
(let ((search-end (point))
(header-beginning (point-min)) (header-end (point-min)))
(goto-char (point-min))
;; Copy first line, the `\input texinfo' line, to temp file
(write-region (point)
(save-excursion (forward-line 1) (point))
texinfo-tex-temp-file nil nil)
;; Don't copy first line twice if region includes it.
(forward-line 1)
(if (< beginning (point)) (setq beginning (point)))
;; Initialize the temp file with either the header or nothing
(if (search-forward texinfo-start-of-header search-end t)
(progn
(beginning-of-line)
(setq header-beginning (point)) ; Mark beginning of header.
(if (search-forward texinfo-end-of-header nil t)
(progn (beginning-of-line)
(setq header-end (point))) ; Mark end of header.
(setq header-beginning (point-min))))) ; Else no header.
;; Copy header to temp file.
(write-region
(min header-beginning beginning )
header-end
texinfo-tex-temp-file t nil)
;; Copy region to temp file.
(write-region
(max beginning header-end)
end
texinfo-tex-temp-file t nil)
;; This is a kludge to insert the texinfo-tex-trailer into the
;; texinfo-tex-temp-file. We have to create a special buffer
;; in which to insert the texinfo-tex-trailer first because there is
;; no function with which to append a literal string directly
;; to a file.
(let ((local-tex-trailer texinfo-tex-trailer)
(temp-buffer (get-buffer-create " texinfo-trailer-buffer")))
(set-buffer temp-buffer)
(erase-buffer)
;; make sure trailer isn't hidden by a comment
(insert-string "\n")
(if local-tex-trailer (insert local-tex-trailer))
(write-region (point-min) (point-max)
texinfo-tex-temp-file t nil)))
(set-process-sentinel (get-process "texinfo-tex-shell")
'texinfo-tex-shell-sentinel)
(send-string "texinfo-tex-shell"
(concat texinfo-tex-shell-cd-command " "
default-directory "\n"))
(send-string "texinfo-tex-shell"
(concat texinfo-tex-command " "
texinfo-tex-temp-file "\n "))
(texinfo-recenter-tex-output-buffer 0)))))
(defun texinfo-tex-buffer (buffer)
"Run TeX on current buffer.
After running TeX the first time, you may have to run \\[texinfo-texindex]
and then \\[texinfo-tex-buffer] again."
(interactive
(list
;; Sometimes you put point into *texinfo-tex-shell*; this prompts
;; you for the correct file regardless.
(if (and
(string= (buffer-name (current-buffer)) "*texinfo-tex-shell*")
texinfo-tex-root-temp-file)
(read-string (format "Run TeX on: ")
texinfo-tex-original-file)
(read-string (format "Run TeX on: ") (buffer-name (current-buffer))))))
;; Set to original buffer if in *texinfo-tex-shell*; otherwise,
;; record name of current buffer.
(if (string= (buffer-name (current-buffer)) "*texinfo-tex-shell*")
(set-buffer buffer)
(setq texinfo-tex-original-file
(buffer-name (current-buffer))))
(if (get-buffer "*texinfo-tex-shell*")
(quit-process (get-process "texinfo-tex-shell") t)
(texinfo-tex-start-shell))
(cond ((null buffer-file-name)
(error "Buffer not visiting any file!"))
((buffer-modified-p)
(error "Buffer has been modified since last saved!"))
(t (set-process-sentinel (get-process "texinfo-tex-shell")
'texinfo-tex-shell-sentinel)
(send-string "texinfo-tex-shell"
(concat texinfo-tex-shell-cd-command
" "
(file-name-directory
(buffer-file-name
(get-buffer buffer)))
"\n"))
(send-string "texinfo-tex-shell"
(concat texinfo-tex-command " " buffer "\n "))
;; so the texinfo-tex-print command works
(setq texinfo-tex-root-temp-file
(substring buffer 0
(or (string-match "\\.tex" buffer)
(length buffer))))
(texinfo-recenter-tex-output-buffer 0))))
(defun texinfo-texindex ()
"Run texindex on unsorted index files.
The index files are made by \\[texinfo-tex-region] or \\[texinfo-tex-buffer].
Runs the shell command defined by texinfo-texindex-command."
(interactive)
(send-string "texinfo-tex-shell"
(concat texinfo-texindex-command
" " texinfo-tex-root-temp-file ".??" "\n"))
(texinfo-recenter-tex-output-buffer nil))
(defun texinfo-tex-print ()
"Print .dvi file made by \\[texinfo-tex-region] or \\[texinfo-tex-buffer].
Runs the shell command defined by texinfo-tex-dvi-print-command."
(interactive)
(send-string "texinfo-tex-shell"
(concat texinfo-tex-dvi-print-command
" " texinfo-tex-root-temp-file ".dvi" "\n"))
(texinfo-recenter-tex-output-buffer nil))
;;; Texinfo TeX utility functions
(defun texinfo-tex-start-shell ()
(save-excursion
(require 'texinfo)
(set-buffer (make-shell "texinfo-tex-shell" "/bin/sh" nil "-v"))
(setq texinfo-tex-shell-map (copy-keymap shell-mode-map))
(texinfo-define-common-keys texinfo-tex-shell-map)
(use-local-map texinfo-tex-shell-map)
(run-hooks 'texinfo-tex-shell-hook)
(if (zerop (buffer-size))
(sleep-for 1))))
(defun texinfo-quit-tex-job ()
"Quit currently running TeX job, by sending an `x' to it."
(interactive)
(if (not (get-process "texinfo-tex-shell"))
(error "No TeX shell running."))
(save-excursion
(set-buffer (get-buffer "*texinfo-tex-shell*"))
(goto-char (point-max))
(insert "x")
(shell-send-input)))
(defun texinfo-kill-tex-job ()
"Kill the currently running TeX job."
(interactive)
(if (get-process "texinfo-tex-shell")
;; Use `texinfo-tex-shell-sentinel' to restart
;; texinfo-tex-shell after it is killed.
(kill-process (get-process "texinfo-tex-shell"))))
(defun texinfo-tex-shell-sentinel (process event)
"Restart texinfo-tex-shell after it is killed."
(if (equal event "killed\n")
(save-excursion
(set-buffer "*texinfo-tex-shell*")
(insert "\n")
(texinfo-tex-start-shell))))
(defun texinfo-recenter-tex-output-buffer (linenum)
"Redisplay buffer of TeX job output so that most recent output can be seen.
The last line of the buffer is displayed on
line LINE of the window, or centered if LINE is nil."
(interactive "P")
(let ((texinfo-tex-shell (get-buffer "*texinfo-tex-shell*"))
(old-buffer (current-buffer)))
(if (null texinfo-tex-shell)
(message "No TeX output buffer")
(pop-to-buffer texinfo-tex-shell)
(bury-buffer texinfo-tex-shell)
(goto-char (point-max))
(recenter (if linenum
(prefix-numeric-value linenum)
(/ (window-height) 2)))
(pop-to-buffer old-buffer)
)))
(defun texinfo-show-tex-print-queue ()
"Show the print queue that \\[texinfo-tex-print] put your job on.
Runs the shell command defined by texinfo-show-tex-queue-command."
(interactive)
(if (not (texinfo-tex-shell-running-p))
(texinfo-tex-start-shell))
(send-string "texinfo-tex-shell"
(concat texinfo-show-tex-queue-command "\n"))
(texinfo-recenter-tex-output-buffer nil))
(defun texinfo-delete-from-tex-print-queue (job-number)
"Delete job from the line printer spooling queue.
You are prompted for the job number (shown by a previous
\\[texinfo-show-tex-print-queue] command."
(interactive "nPrinter job number for deletion: ")
(if (texinfo-tex-shell-running-p)
(texinfo-kill-tex-job)
(texinfo-tex-start-shell))
(send-string "texinfo-tex-shell"
(concat
texinfo-delete-from-print-queue-command
" "
job-number"\n"))
(texinfo-recenter-tex-output-buffer nil))
(defun texinfo-tex-shell-running-p ()
(and (get-process "texinfo-tex-shell")
(eq (process-status (get-process "texinfo-tex-shell")) 'run)))
;;; Place `provide' at end of file.
(provide 'texnfo-tex)
;;;;;;;;;;;;;;;; end texnfo-tex.el ;;;;;;;;;;;;;;;;
texinfo-3.7/emacs/texnfo-upd.el 100444 11732 13 232235 6045247020 14775 0 ustar bfox user ;;; texnfo-upd.el --- utilities for updating nodes and menus in Texinfo files
;; Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
;; Author: Robert J. Chassell
;; Maintainer: bug-texinfo@prep.ai.mit.edu
;; Keywords: maint, tex, docs
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Commentary:
;;; Known bug: update commands fail to ignore @ignore.
;;; Summary: how to use the updating commands
; The node and menu updating functions automatically
; * insert missing `@node' lines,
; * insert the `Next', `Previous' and `Up' pointers of a node,
; * insert or update the menu for a section,
; * create a master menu for a Texinfo source file.
;
; Passed an argument, the `texinfo-update-node' and
; `texinfo-make-menu' functions do their jobs in the region.
;
; In brief, the functions for creating or updating nodes and menus, are:
;
; texinfo-update-node (&optional region-p)
; texinfo-every-node-update ()
; texinfo-sequential-node-update (&optional region-p)
;
; texinfo-make-menu (&optional region-p)
; texinfo-all-menus-update ()
; texinfo-master-menu ()
;
; texinfo-insert-node-lines (&optional title-p)
;
; texinfo-indent-menu-description (column &optional region-p)
; The `texinfo-column-for-description' variable specifies the column to
; which menu descriptions are indented.
; Texinfo file structure
; ----------------------
; To use the updating commands, you must structure your Texinfo file
; hierarchically. Each `@node' line, with the exception of the top
; node, must be accompanied by some kind of section line, such as an
; `@chapter' or `@section' line. Each node-line/section-line
; combination must look like this:
; @node Lists and Tables, Cross References, Structuring, Top
; @comment node-name, next, previous, up
; @chapter Making Lists and Tables
; or like this (without the `@comment' line):
; @node Lists and Tables, Cross References, Structuring, Top
; @chapter Making Lists and Tables
; If the file has a `top' node, it must be called `top' or `Top' and
; be the first node in the file.
;;; The update node functions described in detail
; The `texinfo-update-node' function without an argument inserts
; the correct next, previous and up pointers for the node in which
; point is located (i.e., for the node preceding point).
; With an argument, the `texinfo-update-node' function inserts the
; correct next, previous and up pointers for the nodes inside the
; region.
; It does not matter whether the `@node' line has pre-existing
; `Next', `Previous', or `Up' pointers in it. They are removed.
; The `texinfo-every-node-update' function runs `texinfo-update-node'
; on the whole buffer.
; The `texinfo-sequential-node-update' function inserts the
; immediately following and preceding node into the `Next' or
; `Previous' pointers regardless of their hierarchical level. This is
; only useful for certain kinds of text, like a novel, which you go
; through sequentially.
;;; The menu making functions described in detail
; The `texinfo-make-menu' function without an argument creates or
; updates a menu for the section encompassing the node that follows
; point. With an argument, it makes or updates menus for the nodes
; within or part of the marked region.
; Whenever an existing menu is updated, the descriptions from
; that menu are incorporated into the new menu. This is done by copying
; descriptions from the existing menu to the entries in the new menu
; that have the same node names. If the node names are different, the
; descriptions are not copied to the new menu.
; Menu entries that refer to other Info files are removed since they
; are not a node within current buffer. This is a deficiency.
; The `texinfo-all-menus-update' function runs `texinfo-make-menu'
; on the whole buffer.
; The `texinfo-master-menu' function creates an extended menu located
; after the top node. (The file must have a top node.) The function
; first updates all the regular menus in the buffer (incorporating the
; descriptions from pre-existing menus), and then constructs a master
; menu that includes every entry from every other menu. (However, the
; function cannot update an already existing master menu; if one
; exists, it must be removed before calling the function.)
; The `texinfo-indent-menu-description' function indents every
; description in the menu following point, to the specified column.
; Non-nil argument (prefix, if interactive) means indent every
; description in every menu in the region. This function does not
; indent second and subsequent lines of a multi-line description.
; The `texinfo-insert-node-lines' function inserts `@node' before the
; `@chapter', `@section', and such like lines of a region in a Texinfo
; file where the `@node' lines are missing.
;
; With a non-nil argument (prefix, if interactive), the function not
; only inserts `@node' lines but also inserts the chapter or section
; titles as the names of the corresponding nodes; and inserts titles
; as node names in pre-existing `@node' lines that lack names.
;
; Since node names should be more concise than section or chapter
; titles, node names so inserted will need to be edited manually.
;;; Code:
;;; The menu making functions
(defun texinfo-make-menu (&optional region-p)
"Without any prefix argument, make or update a menu.
Make the menu for the section enclosing the node found following point.
Non-nil argument (prefix, if interactive) means make or update menus
for nodes within or part of the marked region.
Whenever a menu exists, and is being updated, the descriptions that
are associated with node names in the pre-existing menu are
incorporated into the new menu. Otherwise, the nodes' section titles
are inserted as descriptions."
(interactive "P")
(if (not region-p)
(let ((level (texinfo-hierarchic-level)))
(texinfo-make-one-menu level)
(message "Done...updated the menu. You may save the buffer."))
;; else
(message "Making or updating menus in %s... " (buffer-name))
(let ((beginning (region-beginning))
(region-end (region-end))
(level (progn ; find section type following point
(goto-char (region-beginning))
(texinfo-hierarchic-level))))
(if (= region-end beginning)
(error "Please mark a region!"))
(save-excursion
(save-restriction
(widen)
(while (texinfo-find-lower-level-node level region-end)
(setq level (texinfo-hierarchic-level)) ; new, lower level
(texinfo-make-one-menu level))
(while (and (< (point) region-end)
(texinfo-find-higher-level-node level region-end))
(setq level (texinfo-hierarchic-level))
(while (texinfo-find-lower-level-node level region-end)
(setq level (texinfo-hierarchic-level)) ; new, lower level
(texinfo-make-one-menu level))))))
(message "Done...updated menus. You may save the buffer.")))
(defun texinfo-make-one-menu (level)
"Make a menu of all the appropriate nodes in this section.
`Appropriate nodes' are those associated with sections that are
at the level specified by LEVEL. Point is left at the end of menu."
(let*
((case-fold-search t)
(beginning
(save-excursion
(goto-char (texinfo-update-menu-region-beginning level))
(end-of-line)
(point)))
(end (texinfo-update-menu-region-end level))
(first (texinfo-menu-first-node beginning end))
(node-name (progn
(goto-char beginning)
(beginning-of-line)
(texinfo-copy-node-name)))
(new-menu-list (texinfo-make-menu-list beginning end level)))
(if (texinfo-old-menu-p beginning first)
(progn
(texinfo-incorporate-descriptions new-menu-list)
(texinfo-incorporate-menu-entry-names new-menu-list)
(texinfo-delete-old-menu beginning first)))
(texinfo-insert-menu new-menu-list node-name)))
(defun texinfo-all-menus-update (&optional update-all-nodes-p)
"Update every regular menu in a Texinfo file.
Update pre-existing master menu, if there is one.
If called with a non-nil argument, this function first updates all the
nodes in the buffer before updating the menus."
(interactive "P")
(let ((case-fold-search t)
master-menu-p)
(save-excursion
(push-mark (point-max) t)
(goto-char (point-min))
(message "Checking for a master menu in %s ... "(buffer-name))
(save-excursion
(if (re-search-forward texinfo-master-menu-header nil t)
;; Remove detailed master menu listing
(progn
(setq master-menu-p t)
(goto-char (match-beginning 0))
(let ((end-of-detailed-menu-descriptions
(save-excursion ; beginning of end menu line
(goto-char (texinfo-menu-end))
(beginning-of-line) (forward-char -1)
(point))))
(delete-region (point) end-of-detailed-menu-descriptions)))))
(if update-all-nodes-p
(progn
(message "Updating all nodes in %s ... " (buffer-name))
(sleep-for 2)
(push-mark (point-max) t)
(goto-char (point-min))
;; Using the mark to pass bounds this way
;; is kludgy, but it's not worth fixing. -- rms.
(let ((mark-active t))
(texinfo-update-node t))))
(message "Updating all menus in %s ... " (buffer-name))
(sleep-for 2)
(push-mark (point-max) t)
(goto-char (point-min))
;; Using the mark to pass bounds this way
;; is kludgy, but it's not worth fixing. -- rms.
(let ((mark-active t))
(texinfo-make-menu t))
(if master-menu-p
(progn
(message "Updating the master menu in %s... " (buffer-name))
(sleep-for 2)
(texinfo-master-menu nil))))
(message "Done...updated all the menus. You may save the buffer.")))
(defun texinfo-find-lower-level-node (level region-end)
"Search forward from point for node at any level lower than LEVEL.
Search is limited to the end of the marked region, REGION-END,
and to the end of the menu region for the level.
Return t if the node is found, else nil. Leave point at the beginning
of the node if one is found; else do not move point."
(let ((case-fold-search t))
(if (and (< (point) region-end)
(re-search-forward
(concat
"\\(^@node\\).*\n" ; match node line
"\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
"\\|" ; or
"\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
(eval (cdr (assoc level texinfo-update-menu-lower-regexps))))
;; the next higher level node marks the end of this
;; section, and no lower level node will be found beyond
;; this position even if region-end is farther off
(texinfo-update-menu-region-end level)
t))
(goto-char (match-beginning 1)))))
(defun texinfo-find-higher-level-node (level region-end)
"Search forward from point for node at any higher level than argument LEVEL.
Search is limited to the end of the marked region, REGION-END.
Return t if the node is found, else nil. Leave point at the beginning
of the node if one is found; else do not move point."
(let ((case-fold-search t))
(cond
((or (string-equal "top" level) (string-equal "chapter" level))
(if (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" region-end t)
(progn (beginning-of-line) t)))
(t
(if (re-search-forward
(concat
"\\(^@node\\).*\n" ; match node line
"\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
"\\|" ; or
"\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
(eval (cdr (assoc level texinfo-update-menu-higher-regexps))))
region-end t)
(progn (beginning-of-line) t))))))
;;; Making the list of new menu entries
(defun texinfo-make-menu-list (beginning end level)
"Make a list of node names and their descriptions.
Point is left at the end of the menu region, but the menu is not inserted.
First argument is position from which to start making menu list;
second argument is end of region in which to try to locate entries;
third argument is the level of the nodes that are the entries.
Node names and descriptions are dotted pairs of strings. Each pair is
an element of the list. If the description does not exist, the
element consists only of the node name."
(goto-char beginning)
(let (new-menu-list)
(while (texinfo-menu-locate-entry-p level end)
(setq new-menu-list
(cons (cons
(texinfo-copy-node-name)
(prog1 "" (forward-line 1)))
;; Use following to insert section titles automatically.
;; (texinfo-copy-section-title))
new-menu-list)))
(reverse new-menu-list)))
(defun texinfo-menu-locate-entry-p (level search-end)
"Find a node that will be part of menu for this section.
First argument is a string such as \"section\" specifying the general
hierarchical level of the menu; second argument is a position
specifying the end of the search.
The function returns t if the node is found, else nil. It searches
forward from point, and leaves point at the beginning of the node.
The function finds entries of the same type. Thus `subsections' and
`unnumberedsubsecs' will appear in the same menu."
(let ((case-fold-search t))
(if (re-search-forward
(concat
"\\(^@node\\).*\n" ; match node line
"\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
"\\|" ; or
"\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
(eval
(cdr (assoc level texinfo-update-menu-same-level-regexps))))
search-end
t)
(goto-char (match-beginning 1)))))
(defun texinfo-copy-node-name ()
"Return the node name as a string.
Start with point at the beginning of the node line; copy the text
after the node command up to the first comma on the line, if any, and
return the text as a string. Leaves point at the beginning of the
line. If there is no node name, returns an empty string."
(save-excursion
(buffer-substring
(progn (forward-word 1) ; skip over node command
(skip-chars-forward " \t") ; and over spaces
(point))
(if (search-forward
","
(save-excursion (end-of-line) (point)) t) ; bound search
(1- (point))
(end-of-line) (point)))))
(defun texinfo-copy-section-title ()
"Return the title of the section as a string.
The title is used as a description line in the menu when one does not
already exist.
Move point to the beginning of the appropriate section line by going
to the start of the text matched by last regexp searched for, which
must have been done by `texinfo-menu-locate-entry-p'."
;; could use the same re-search as in `texinfo-menu-locate-entry-p'
;; instead of using `match-beginning'; such a variation would be
;; more general, but would waste information already collected
(goto-char (match-beginning 7)) ; match section name
(buffer-substring
(progn (forward-word 1) ; skip over section type
(skip-chars-forward " \t") ; and over spaces
(point))
(progn (end-of-line) (point))))
;;; Handling the old menu
(defun texinfo-old-menu-p (beginning first)
"Move point to the beginning of the menu for this section, if any.
Otherwise move point to the end of the first node of this section.
Return t if a menu is found, nil otherwise.
First argument is the position of the beginning of the section in which
the menu will be located; second argument is the position of the first
node within the section.
If no menu is found, the function inserts two newlines just before the
end of the section, and leaves point there where a menu ought to be."
(goto-char beginning)
(if (not (re-search-forward "^@menu" first 'goto-end))
(progn (insert "\n\n") (forward-line -2) nil)
t))
(defun texinfo-incorporate-descriptions (new-menu-list)
"Copy the old menu line descriptions that exist to the new menu.
Point must be at beginning of old menu.
If the node-name of the new menu is found in the old menu, insert the
old description into the new entry.
For this function, the new menu is a list made up of lists of dotted
pairs in which the first element of the pair is the node name and the
second element the description. The new menu is changed destructively.
The old menu is the menu as it appears in the texinfo file."
(let ((new-menu-list-pointer new-menu-list)
(end-of-menu (texinfo-menu-end)))
(while new-menu-list
(save-excursion ; keep point at beginning of menu
(if (re-search-forward
;; Existing nodes can have the form
;; * NODE NAME:: DESCRIPTION
;; or
;; * MENU ITEM: NODE NAME. DESCRIPTION.
;;
;; Recognize both when looking for the description.
(concat "\\* \\(" ; so only menu entries are found
(car (car new-menu-list)) "::"
"\\|"
".*: " (car (car new-menu-list)) "[.,\t\n]"
"\\)"
) ; so only complete entries are found
end-of-menu
t)
(setcdr (car new-menu-list)
(texinfo-menu-copy-old-description end-of-menu))))
(setq new-menu-list (cdr new-menu-list)))
(setq new-menu-list new-menu-list-pointer)))
(defun texinfo-incorporate-menu-entry-names (new-menu-list)
"Copy any old menu entry names to the new menu.
Point must be at beginning of old menu.
If the node-name of the new menu entry cannot be found in the old
menu, do nothing.
For this function, the new menu is a list made up of lists of dotted
pairs in which the first element of the pair is the node name and the
second element is the description (or nil).
If we find an existing menu entry name, we change the first element of
the pair to be another dotted pair in which the car is the menu entry
name and the cdr is the node name.
NEW-MENU-LIST is changed destructively. The old menu is the menu as it
appears in the texinfo file."
(let ((new-menu-list-pointer new-menu-list)
(end-of-menu (texinfo-menu-end)))
(while new-menu-list
(save-excursion ; keep point at beginning of menu
(if (re-search-forward
;; Existing nodes can have the form
;; * NODE NAME:: DESCRIPTION
;; or
;; * MENU ITEM: NODE NAME. DESCRIPTION.
;;
;; We're interested in the second case.
(concat "\\* " ; so only menu entries are found
"\\(.*\\): " (car (car new-menu-list)) "[.,\t\n]")
end-of-menu
t)
(setcar
(car new-menu-list) ; replace the node name
(cons (buffer-substring (match-beginning 1) (match-end 1))
(car (car new-menu-list)))))
(setq new-menu-list (cdr new-menu-list))))
(setq new-menu-list new-menu-list-pointer)))
(defun texinfo-menu-copy-old-description (end-of-menu)
"Return description field of old menu line as string.
Point must be located just after the node name. Point left before description.
Single argument, END-OF-MENU, is position limiting search."
(skip-chars-forward "[:.,\t\n ]+")
;; don't copy a carriage return at line beginning with asterisk!
;; do copy a description that begins with an `@'!
;; !! Known bug: does not copy descriptions starting with ^|\{?* etc.
(if (and (looking-at "\\(\\w+\\|@\\)")
(not (looking-at "\\(^\\* \\|^@end menu\\)")))
(buffer-substring
(point)
(save-excursion
(re-search-forward "\\(^\\* \\|^@end menu\\)" end-of-menu t)
(forward-line -1)
(end-of-line) ; go to end of last description line
(point)))
""))
(defun texinfo-menu-end ()
"Return position of end of menu. Does not change location of point.
Signal an error if not end of menu."
(save-excursion
(if (re-search-forward "^@end menu" nil t)
(point)
(error "Menu does not have an end."))))
(defun texinfo-delete-old-menu (beginning first)
"Delete the old menu. Point must be in or after menu.
First argument is position of the beginning of the section in which
the menu will be located; second argument is the position of the first
node within the section."
;; No third arg to search, so error if search fails.
(re-search-backward "^@menu" beginning)
(delete-region (point)
(save-excursion
(re-search-forward "^@end menu" first)
(point))))
;;; Inserting new menu
;; try 32, but perhaps 24 is better
(defvar texinfo-column-for-description 32
"*Column at which descriptions start in a Texinfo menu.")
(defun texinfo-insert-menu (menu-list node-name)
"Insert formatted menu at point.
Indents the first line of the description, if any, to the value of
texinfo-column-for-description.
MENU-LIST has form:
\(\(\"node-name1\" . \"description\"\)
\(\"node-name2\" . \"description\"\) ... \)
However, the description field might be nil.
Also, the node-name field might itself be a dotted pair (call it P) of
strings instead of just a string. In that case, the car of P
is the menu entry name, and the cdr of P is the node name."
(insert "@menu\n")
(while menu-list
;; Every menu entry starts with a star and a space.
(insert "* ")
;; Insert the node name (and menu entry name, if present).
(let ((node-part (car (car menu-list))))
(if (stringp node-part)
;; "Double colon" entry line; menu entry and node name are the same,
(insert (format "%s::" node-part))
;; "Single colon" entry line; menu entry and node name are different.
(insert (format "%s: %s." (car node-part) (cdr node-part)))))
;; Insert the description, if present.
(if (cdr (car menu-list))
(progn
;; Move to right place.
(indent-to texinfo-column-for-description 2)
;; Insert description.
(insert (format "%s" (cdr (car menu-list))))))
(insert "\n") ; end this menu entry
(setq menu-list (cdr menu-list)))
(insert "@end menu")
(message
"Updated \"%s\" level menu following node: %s ... " level node-name))
;;; Starting menu descriptions by inserting titles
(defun texinfo-start-menu-description ()
"In this menu entry, insert the node's section title as a description.
Position point at beginning of description ready for editing.
Do not insert a title if the line contains an existing description.
You will need to edit the inserted text since a useful description
complements the node name rather than repeats it as a title does."
(interactive)
(let (beginning end node-name title)
(save-excursion
(beginning-of-line)
(if (search-forward "* " (save-excursion (end-of-line) (point)) t)
(progn (skip-chars-forward " \t")
(setq beginning (point)))
(error "This is not a line in a menu!"))
(cond
;; "Double colon" entry line; menu entry and node name are the same,
((search-forward "::" (save-excursion (end-of-line) (point)) t)
(if (looking-at "[ \t]*[^ \t\n]+")
(error "Descriptive text already exists."))
(skip-chars-backward ": \t")
(setq node-name (buffer-substring beginning (point))))
;; "Single colon" entry line; menu entry and node name are different.
((search-forward ":" (save-excursion (end-of-line) (point)) t)
(skip-chars-forward " \t")
(setq beginning (point))
;; Menu entry line ends in a period, comma, or tab.
(if (re-search-forward "[.,\t]"
(save-excursion (forward-line 1) (point)) t)
(progn
(if (looking-at "[ \t]*[^ \t\n]+")
(error "Descriptive text already exists."))
(skip-chars-backward "., \t")
(setq node-name (buffer-substring beginning (point))))
;; Menu entry line ends in a return.
(re-search-forward ".*\n"
(save-excursion (forward-line 1) (point)) t)
(skip-chars-backward " \t\n")
(setq node-name (buffer-substring beginning (point)))
(if (= 0 (length node-name))
(error "No node name on this line.")
(insert "."))))
(t (error "No node name on this line.")))
;; Search for node that matches node name, and copy the section title.
(if (re-search-forward
(concat
"^@node[ \t]+"
node-name
".*\n" ; match node line
"\\("
"\\(\\(^@c \\|^@comment\\).*\n\\)" ; match comment line, if any
"\\|" ; or
"\\(^@ifinfo[ ]*\n\\)" ; ifinfo line, if any
"\\)?")
nil t)
(progn
(setq title
(buffer-substring
;; skip over section type
(progn (forward-word 1)
;; and over spaces
(skip-chars-forward " \t")
(point))
(progn (end-of-line)
(skip-chars-backward " \t")
(point)))))
(error "Cannot find node to match node name in menu entry.")))
;; Return point to the menu and insert the title.
(end-of-line)
(delete-region
(point)
(save-excursion (skip-chars-backward " \t") (point)))
(indent-to texinfo-column-for-description 2)
(save-excursion (insert title))))
;;; Handling description indentation
; Since the make-menu functions indent descriptions, these functions
; are useful primarily for indenting a single menu specially.
(defun texinfo-indent-menu-description (column &optional region-p)
"Indent every description in menu following point to COLUMN.
Non-nil argument (prefix, if interactive) means indent every
description in every menu in the region. Does not indent second and
subsequent lines of a multi-line description."
(interactive
"nIndent menu descriptions to (column number): \nP")
(save-excursion
(save-restriction
(widen)
(if (not region-p)
(progn
(re-search-forward "^@menu")
(texinfo-menu-indent-description column)
(message
"Indented descriptions in menu. You may save the buffer."))
;;else
(message "Indenting every menu description in region... ")
(goto-char (region-beginning))
(while (and (< (point) (region-end))
(texinfo-locate-menu-p))
(forward-line 1)
(texinfo-menu-indent-description column))
(message "Indenting done. You may save the buffer.")))))
(defun texinfo-menu-indent-description (to-column-number)
"Indent the Texinfo file menu description to TO-COLUMN-NUMBER.
Start with point just after the word `menu' in the `@menu' line and
leave point on the line before the `@end menu' line. Does not indent
second and subsequent lines of a multi-line description."
(let* ((beginning-of-next-line (point)))
(while (< beginning-of-next-line
(save-excursion ; beginning of end menu line
(goto-char (texinfo-menu-end))
(beginning-of-line)
(point)))
(if (re-search-forward "\\* \\(.*::\\|.*: [^.,\t\n]+[.,\t]\\)"
(texinfo-menu-end)
t)
(progn
(let ((beginning-white-space (point)))
(skip-chars-forward " \t") ; skip over spaces
(if (looking-at "\\(@\\|\\w\\)+") ; if there is text
(progn
;; remove pre-existing indentation
(delete-region beginning-white-space (point))
(indent-to-column to-column-number))))))
;; position point at beginning of next line
(forward-line 1)
(setq beginning-of-next-line (point)))))
;;; Making the master menu
(defun texinfo-master-menu (update-all-nodes-menus-p)
"Make a master menu for a whole Texinfo file.
Non-nil argument (prefix, if interactive) means first update all
existing nodes and menus. Remove pre-existing master menu, if there is one.
This function creates a master menu that follows the top node. The
master menu includes every entry from all the other menus. It
replaces any existing ordinary menu that follows the top node.
If called with a non-nil argument, this function first updates all the
menus in the buffer (incorporating descriptions from pre-existing
menus) before it constructs the master menu.
The function removes the detailed part of an already existing master
menu. This action depends on the pre-exisitng master menu using the
standard `texinfo-master-menu-header'.
The master menu has the following format, which is adapted from the
recommendation in the Texinfo Manual:
* The first part contains the major nodes in the Texinfo file: the
nodes for the chapters, chapter-like sections, and the major
appendices. This includes the indices, so long as they are in
chapter-like sections, such as unnumbered sections.
* The second and subsequent parts contain a listing of the other,
lower level menus, in order. This way, an inquirer can go
directly to a particular node if he or she is searching for
specific information.
Each of the menus in the detailed node listing is introduced by the
title of the section containing the menu."
(interactive "P")
(let ((case-fold-search t))
(widen)
(goto-char (point-min))
;; Move point to location after `top'.
(if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
(error "This buffer needs a Top node!"))
(let ((first-chapter
(save-excursion
(or (re-search-forward "^@node" nil t)
(error "Too few nodes for a master menu!"))
(point))))
(if (re-search-forward texinfo-master-menu-header first-chapter t)
;; Remove detailed master menu listing
(progn
(goto-char (match-beginning 0))
(let ((end-of-detailed-menu-descriptions
(save-excursion ; beginning of end menu line
(goto-char (texinfo-menu-end))
(beginning-of-line) (forward-char -1)
(point))))
(delete-region (point) end-of-detailed-menu-descriptions)))))
(if update-all-nodes-menus-p
(progn
(message "Making a master menu in %s ...first updating all nodes... "
(buffer-name))
(sleep-for 2)
(push-mark (point-max) t)
(goto-char (point-min))
(texinfo-update-node t)
(message "Updating all menus in %s ... " (buffer-name))
(sleep-for 2)
(push-mark (point-max) t)
(goto-char (point-min))
(texinfo-make-menu t)))
(message "Now making the master menu in %s... " (buffer-name))
(sleep-for 2)
(goto-char (point-min))
(texinfo-insert-master-menu-list
(texinfo-master-menu-list))
;; Remove extra newlines that texinfo-insert-master-menu-list
;; may have inserted.
(save-excursion
(goto-char (point-min))
(if (re-search-forward texinfo-master-menu-header nil t)
(progn
(goto-char (match-beginning 0))
(insert "\n")
(delete-blank-lines)
(goto-char (point-min))))
(re-search-forward "^@menu")
(forward-line -1)
(delete-blank-lines)
(re-search-forward "^@end menu")
(forward-line 1)
(delete-blank-lines))
(message
"Done...completed making master menu. You may save the buffer.")))
(defun texinfo-master-menu-list ()
"Return a list of menu entries and header lines for the master menu.
Start with the menu for chapters and indices and then find each
following menu and the title of the node preceding that menu.
The master menu list has this form:
\(\(\(... \"entry-1-2\" \"entry-1\"\) \"title-1\"\)
\(\(... \"entry-2-2\" \"entry-2-1\"\) \"title-2\"\)
...\)
However, there does not need to be a title field."
(let (master-menu-list)
(while (texinfo-locate-menu-p)
(setq master-menu-list
(cons (list
(texinfo-copy-menu)
(texinfo-copy-menu-title))
master-menu-list)))
(reverse master-menu-list)))
(defun texinfo-insert-master-menu-list (master-menu-list)
"Format and insert the master menu in the current buffer."
(goto-char (point-min))
;; Insert a master menu only after `Top' node and before next node
;; \(or include file if there is no next node\).
(if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
(error "This buffer needs a Top node!"))
(let ((first-chapter
(save-excursion (re-search-forward "^@node\\|^@include") (point))))
(if (not (re-search-forward "^@menu" first-chapter t))
(error
"Buffer lacks ordinary `Top' menu in which to insert master.")))
(beginning-of-line)
(delete-region ; buffer must have ordinary top menu
(point)
(save-excursion (re-search-forward "^@end menu") (point)))
(save-excursion ; leave point at beginning of menu
;; Handle top of menu
(insert "\n@menu\n")
;; Insert chapter menu entries
(setq this-very-menu-list (reverse (car (car master-menu-list))))
;; Tell user what is going on.
(message "Inserting chapter menu entry: %s ... " this-very-menu-list)
(while this-very-menu-list
(insert "* " (car this-very-menu-list) "\n")
(setq this-very-menu-list (cdr this-very-menu-list)))
(setq master-menu-list (cdr master-menu-list))
;; Only insert detailed master menu if there is one....
(if (car (car master-menu-list))
(insert texinfo-master-menu-header))
;; Now, insert all the other menus
;; The menu master-menu-list has a form like this:
;; ((("beta" "alpha") "title-A")
;; (("delta" "gamma") "title-B"))
(while master-menu-list
(message
"Inserting menu for %s .... " (car (cdr (car master-menu-list))))
;; insert title of menu section
(insert "\n" (car (cdr (car master-menu-list))) "\n\n")
;; insert each menu entry
(setq this-very-menu-list (reverse (car (car master-menu-list))))
(while this-very-menu-list
(insert "* " (car this-very-menu-list) "\n")
(setq this-very-menu-list (cdr this-very-menu-list)))
(setq master-menu-list (cdr master-menu-list)))
;; Finish menu
(insert "@end menu\n\n")))
(defvar texinfo-master-menu-header
"\n --- The Detailed Node Listing ---\n"
"String inserted before lower level entries in Texinfo master menu.
It comes after the chapter-level menu entries.")
(defun texinfo-locate-menu-p ()
"Find the next menu in the texinfo file.
If found, leave point after word `menu' on the `@menu' line, and return t.
If a menu is not found, do not move point and return nil."
(re-search-forward "\\(^@menu\\)" nil t))
(defun texinfo-copy-menu-title ()
"Return the title of the section preceding the menu as a string.
If such a title cannot be found, return an empty string. Do not move
point."
(let ((case-fold-search t))
(save-excursion
(if (re-search-backward
(concat
"\\(^@top"
"\\|" ; or
texinfo-section-types-regexp ; all other section types
"\\)")
nil
t)
(progn
(beginning-of-line)
(forward-word 1) ; skip over section type
(skip-chars-forward " \t") ; and over spaces
(buffer-substring
(point)
(progn (end-of-line) (point))))
""))))
(defun texinfo-copy-menu ()
"Return the entries of an existing menu as a list.
Start with point just after the word `menu' in the `@menu' line
and leave point on the line before the `@end menu' line."
(let* (this-menu-list
(end-of-menu (texinfo-menu-end)) ; position of end of `@end menu'
(last-entry (save-excursion ; position of beginning of
; last `* ' entry
(goto-char end-of-menu)
;; handle multi-line description
(if (not (re-search-backward "^\* " nil t))
(error "No entries in menu."))
(point))))
(while (< (point) last-entry)
(if (re-search-forward "^\* " end-of-menu t)
(progn
(setq this-menu-list
(cons
(buffer-substring
(point)
;; copy multi-line descriptions
(save-excursion
(re-search-forward "\\(^\* \\|^@e\\)" nil t)
(- (point) 3)))
this-menu-list)))))
this-menu-list))
;;; Determining the hierarchical level in the texinfo file
(defun texinfo-specific-section-type ()
"Return the specific type of next section, as a string.
For example, \"unnumberedsubsec\". Return \"top\" for top node.
Searches forward for a section. Hence, point must be before the
section whose type will be found. Does not move point. Signal an
error if the node is not the top node and a section is not found."
(let ((case-fold-search t))
(save-excursion
(cond
((re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)"
;;; Following search limit by cph but causes a bug
;;; (save-excursion
;;; (end-of-line)
;;; (point))
nil
t)
"top")
((re-search-forward texinfo-section-types-regexp nil t)
(buffer-substring-no-properties
(progn (beginning-of-line) ; copy its name
(1+ (point)))
(progn (forward-word 1)
(point))))
(t
(error
"texinfo-specific-section-type: Chapter or section not found."))))))
(defun texinfo-hierarchic-level ()
"Return the general hierarchal level of the next node in a texinfo file.
Thus, a subheading or appendixsubsec is of type subsection."
(let ((case-fold-search t))
(cdr (assoc
(texinfo-specific-section-type)
texinfo-section-to-generic-alist))))
;;; Locating the major positions
(defun texinfo-update-menu-region-beginning (level)
"Locate beginning of higher level section this section is within.
Return position of the beginning of the node line; do not move point.
Thus, if this level is subsection, searches backwards for section node.
Only argument is a string of the general type of section."
(let ((case-fold-search t))
;; !! Known bug: if section immediately follows top node, this
;; returns the beginning of the buffer as the beginning of the
;; higher level section.
(cond
((or (string-equal "top" level)
(string-equal "chapter" level))
(save-excursion
(goto-char (point-min))
(re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t)
(beginning-of-line)
(point)))
(t
(save-excursion
(re-search-backward
(concat
"\\(^@node\\).*\n" ; match node line
"\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
"\\|" ; or
"\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
(eval
(cdr (assoc level texinfo-update-menu-higher-regexps))))
nil
'goto-beginning)
(point))))))
(defun texinfo-update-menu-region-end (level)
"Locate end of higher level section this section is within.
Return position; do not move point. Thus, if this level is a
subsection, find the node for the section this subsection is within.
If level is top or chapter, returns end of file. Only argument is a
string of the general type of section."
(let ((case-fold-search t))
(save-excursion
(if (re-search-forward
(concat
"\\(^@node\\).*\n" ; match node line
"\\(\\(\\(^@c\\).*\n\\)" ; match comment line, if any
"\\|" ; or
"\\(^@ifinfo[ ]*\n\\)\\)?" ; ifinfo line, if any
(eval
;; Never finds end of level above chapter so goes to end.
(cdr (assoc level texinfo-update-menu-higher-regexps))))
nil
'goto-end)
(match-beginning 1)
(point-max)))))
(defun texinfo-menu-first-node (beginning end)
"Locate first node of the section the menu will be placed in.
Return position; do not move point.
The menu will be located just before this position.
First argument is the position of the beginning of the section in
which the menu will be located; second argument is the position of the
end of that region; it limits the search."
(save-excursion
(goto-char beginning)
(forward-line 1)
(re-search-forward "^@node" end t)
(beginning-of-line)
(point)))
;;; Alists and regular expressions for defining hierarchical levels
(defvar texinfo-section-to-generic-alist
'(("top" . "top")
("chapter" . "chapter")
("unnumbered" . "chapter")
("majorheading" . "chapter")
("chapheading" . "chapter")
("appendix" . "chapter")
("section" . "section")
("unnumberedsec" . "section")
("heading" . "section")
("appendixsec" . "section")
("subsection" . "subsection")
("unnumberedsubsec" . "subsection")
("subheading" . "subsection")
("appendixsubsec" . "subsection")
("subsubsection" . "subsubsection")
("unnumberedsubsubsec" . "subsubsection")
("subsubheading" . "subsubsection")
("appendixsubsubsec" . "subsubsection"))
"*An alist of specific and corresponding generic Texinfo section types.
The keys are strings specifying specific types of section; the values
are strings of their corresponding general types.")
;; We used to look for just sub, but that found @subtitle.
(defvar texinfo-section-types-regexp
"^@\\(chapter \\|sect\\|subs\\|subh\\|unnum\\|major\\|chapheading \\|heading \\|appendix\\)"
"Regexp matching chapter, section, other headings (but not the top node).")
(defvar texinfo-chapter-level-regexp
"chapter\\|unnumbered \\|appendix \\|majorheading\\|chapheading"
"Regular expression matching just the Texinfo chapter level headings.")
(defvar texinfo-section-level-regexp
"section\\|unnumberedsec\\|heading \\|appendixsec"
"Regular expression matching just the Texinfo section level headings.")
(defvar texinfo-subsection-level-regexp
"subsection\\|unnumberedsubsec\\|subheading\\|appendixsubsec"
"Regular expression matching just the Texinfo subsection level headings.")
(defvar texinfo-subsubsection-level-regexp
"subsubsection\\|unnumberedsubsubsec\\|subsubheading\\|appendixsubsubsec"
"Regular expression matching just the Texinfo subsubsection level headings.")
(defvar texinfo-update-menu-same-level-regexps
'(("top" . "top[ \t]+")
("chapter" .
(concat "\\(^@\\)\\(" texinfo-chapter-level-regexp "\\)[ \t]*"))
("section" .
(concat "\\(^@\\)\\(" texinfo-section-level-regexp "\\)[ \t]*"))
("subsection" .
(concat "\\(^@\\)\\(" texinfo-subsection-level-regexp "\\)[ \t]+"))
("subsubsection" .
(concat "\\(^@\\)\\(" texinfo-subsubsection-level-regexp "\\)[ \t]+")))
"*Regexps for searching for same level sections in a Texinfo file.
The keys are strings specifying the general hierarchical level in the
document; the values are regular expressions.")
(defvar texinfo-update-menu-higher-regexps
'(("top" . "^@node [ \t]*DIR")
("chapter" . "^@node [ \t]*top[ \t]*\\(,\\|$\\)")
("section" .
(concat
"\\(^@\\("
texinfo-chapter-level-regexp
"\\)[ \t]*\\)"))
("subsection" .
(concat
"\\(^@\\("
texinfo-section-level-regexp
"\\|"
texinfo-chapter-level-regexp
"\\)[ \t]*\\)"))
("subsubsection" .
(concat
"\\(^@\\("
texinfo-subsection-level-regexp
"\\|"
texinfo-section-level-regexp
"\\|"
texinfo-chapter-level-regexp
"\\)[ \t]*\\)")))
"*Regexps for searching for higher level sections in a Texinfo file.
The keys are strings specifying the general hierarchical level in the
document; the values are regular expressions.")
(defvar texinfo-update-menu-lower-regexps
'(("top" .
(concat
"\\(^@\\("
texinfo-chapter-level-regexp
"\\|"
texinfo-section-level-regexp
"\\|"
texinfo-subsection-level-regexp
"\\|"
texinfo-subsubsection-level-regexp
"\\)[ \t]*\\)"))
("chapter" .
(concat
"\\(^@\\("
texinfo-section-level-regexp
"\\|"
texinfo-subsection-level-regexp
"\\|"
texinfo-subsubsection-level-regexp
"\\)[ \t]*\\)"))
("section" .
(concat
"\\(^@\\("
texinfo-subsection-level-regexp
"\\|"
texinfo-subsubsection-level-regexp
"\\)[ \t]+\\)"))
("subsection" .
(concat
"\\(^@\\("
texinfo-subsubsection-level-regexp
"\\)[ \t]+\\)"))
("subsubsection" . "nothing lower"))
"*Regexps for searching for lower level sections in a Texinfo file.
The keys are strings specifying the general hierarchical level in the
document; the values are regular expressions.")
;;; Updating a node
;;;###autoload
(defun texinfo-update-node (&optional region-p)
"Without any prefix argument, update the node in which point is located.
Non-nil argument (prefix, if interactive) means update the nodes in the
marked region.
The functions for creating or updating nodes and menus, and their
keybindings, are:
texinfo-update-node (&optional region-p) \\[texinfo-update-node]
texinfo-every-node-update () \\[texinfo-every-node-update]
texinfo-sequential-node-update (&optional region-p)
texinfo-make-menu (&optional region-p) \\[texinfo-make-menu]
texinfo-all-menus-update () \\[texinfo-all-menus-update]
texinfo-master-menu ()
texinfo-indent-menu-description (column &optional region-p)
The `texinfo-column-for-description' variable specifies the column to
which menu descriptions are indented. Its default value is 32."
(interactive "P")
(if (not region-p)
;; update a single node
(let ((auto-fill-function nil) (auto-fill-hook nil))
(if (not (re-search-backward "^@node" (point-min) t))
(error "Node line not found before this position."))
(texinfo-update-the-node)
(message "Done...updated the node. You may save the buffer."))
;; else
(let ((auto-fill-function nil)
(auto-fill-hook nil)
(beginning (region-beginning))
(end (region-end)))
(if (= end beginning)
(error "Please mark a region!"))
(save-restriction
(narrow-to-region beginning end)
(goto-char beginning)
(push-mark (point) t)
(while (re-search-forward "^@node" (point-max) t)
(beginning-of-line)
(texinfo-update-the-node))
(message "Done...updated nodes in region. You may save the buffer.")))))
;;;###autoload
(defun texinfo-every-node-update ()
"Update every node in a Texinfo file."
(interactive)
(save-excursion
(push-mark (point-max) t)
(goto-char (point-min))
;; Using the mark to pass bounds this way
;; is kludgy, but it's not worth fixing. -- rms.
(let ((mark-active t))
(texinfo-update-node t))
(message "Done...updated every node. You may save the buffer.")))
(defun texinfo-update-the-node ()
"Update one node. Point must be at the beginning of node line.
Leave point at the end of the node line."
(texinfo-check-for-node-name)
(texinfo-delete-existing-pointers)
(message "Updating node: %s ... " (texinfo-copy-node-name))
(save-restriction
(widen)
(let*
((case-fold-search t)
(level (texinfo-hierarchic-level))
(beginning (texinfo-update-menu-region-beginning level))
(end (texinfo-update-menu-region-end level)))
(if (string-equal level "top")
(texinfo-top-pointer-case)
;; else
(texinfo-insert-pointer beginning end level 'next)
(texinfo-insert-pointer beginning end level 'previous)
(texinfo-insert-pointer beginning end level 'up)
(texinfo-clean-up-node-line)))))
(defun texinfo-top-pointer-case ()
"Insert pointers in the Top node. This is a special case.
The `Next' pointer is a pointer to a chapter or section at a lower
hierarchical level in the file. The `Previous' and `Up' pointers are
to `(dir)'. Point must be at the beginning of the node line, and is
left at the end of the node line."
(texinfo-clean-up-node-line)
(insert ", "
(save-excursion
;; There may be an @chapter or other such command between
;; the top node line and the next node line, as a title
;; for an `ifinfo' section. This @chapter command must
;; must be skipped. So the procedure is to search for
;; the next `@node' line, and then copy its name.
(if (re-search-forward "^@node" nil t)
(progn
(beginning-of-line)
(texinfo-copy-node-name))
" "))
", (dir), (dir)"))
(defun texinfo-check-for-node-name ()
"Determine whether the node has a node name. Prompt for one if not.
Point must be at beginning of node line. Does not move point."
(save-excursion
(let ((initial (texinfo-copy-next-section-title)))
;; This is not clean. Use `interactive' to read the arg.
(forward-word 1) ; skip over node command
(skip-chars-forward " \t") ; and over spaces
(if (not (looking-at "[^,\t\n ]+")) ; regexp based on what Info looks for
; alternatively, use "[a-zA-Z]+"
(let ((node-name
(read-from-minibuffer
"Node name (use no @, commas, colons, or apostrophes): "
initial)))
(insert " " node-name))))))
(defun texinfo-delete-existing-pointers ()
"Delete `Next', `Previous', and `Up' pointers.
Starts from the current position of the cursor, and searches forward
on the line for a comma and if one is found, deletes the rest of the
line, including the comma. Leaves point at beginning of line."
(let ((eol-point (save-excursion (end-of-line) (point))))
(if (search-forward "," eol-point t)
(delete-region (1- (point)) eol-point)))
(beginning-of-line))
(defun texinfo-find-pointer (beginning end level direction)
"Move point to section associated with next, previous, or up pointer.
Return type of pointer (either 'normal or 'no-pointer).
The first and second arguments bound the search for a pointer to the
beginning and end, respectively, of the enclosing higher level
section. The third argument is a string specifying the general kind
of section such as \"chapter\ or \"section\". When looking for the
`Next' pointer, the section found will be at the same hierarchical
level in the Texinfo file; when looking for the `Previous' pointer,
the section found will be at the same or higher hierarchical level in
the Texinfo file; when looking for the `Up' pointer, the section found
will be at some level higher in the Texinfo file. The fourth argument
\(one of 'next, 'previous, or 'up\) specifies whether to find the
`Next', `Previous', or `Up' pointer."
(let ((case-fold-search t))
(cond ((eq direction 'next)
(forward-line 3) ; skip over current node
;; Search for section commands accompanied by node lines;
;; ignore section commands in the middle of nodes.
(if (re-search-forward
;; A `Top' node is never a next pointer, so won't find it.
(concat
;; Match node line.
"\\(^@node\\).*\n"
;; Match comment or ifinfo line, if any
"\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
(eval
(cdr (assoc level texinfo-update-menu-same-level-regexps))))
end
t)
'normal
'no-pointer))
((eq direction 'previous)
(if (re-search-backward
(concat
"\\("
;; Match node line.
"\\(^@node\\).*\n"
;; Match comment or ifinfo line, if any
"\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
(eval
(cdr (assoc level texinfo-update-menu-same-level-regexps)))
"\\|"
;; Match node line.
"\\(^@node\\).*\n"
;; Match comment or ifinfo line, if any
"\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
(eval
(cdr (assoc level texinfo-update-menu-higher-regexps)))
"\\|"
;; Handle `Top' node specially.
"^@node [ \t]*top[ \t]*\\(,\\|$\\)"
"\\)")
beginning
t)
'normal
'no-pointer))
((eq direction 'up)
(if (re-search-backward
(concat
"\\("
;; Match node line.
"\\(^@node\\).*\n"
;; Match comment or ifinfo line, if any
"\\(\\(\\(^@c\\).*\n\\)\\|\\(^@ifinfo[ ]*\n\\)\\)?"
(eval (cdr (assoc level texinfo-update-menu-higher-regexps)))
"\\|"
;; Handle `Top' node specially.
"^@node [ \t]*top[ \t]*\\(,\\|$\\)"
"\\)")
(save-excursion
(goto-char beginning)
(beginning-of-line)
(point))
t)
'normal
'no-pointer))
(t
(error "texinfo-find-pointer: lack proper arguments")))))
(defun texinfo-pointer-name (kind)
"Return the node name preceding the section command.
The argument is the kind of section, either normal or no-pointer."
(let (name)
(cond ((eq kind 'normal)
(end-of-line) ; this handles prev node top case
(re-search-backward ; when point is already
"^@node" ; at the beginning of @node line
(save-excursion (forward-line -3))
t)
(setq name (texinfo-copy-node-name)))
((eq kind 'no-pointer)
(setq name " "))) ; put a blank in the pointer slot
name))
(defun texinfo-insert-pointer (beginning end level direction)
"Insert the `Next', `Previous' or `Up' node name at point.
Move point forward.
The first and second arguments bound the search for a pointer to the
beginning and end, respectively, of the enclosing higher level
section. The third argument is the hierarchical level of the Texinfo
file, a string such as \"section\". The fourth argument is direction
towards which the pointer is directed, one of `next, `previous, or
'up."
(end-of-line)
(insert
", "
(save-excursion
(texinfo-pointer-name
(texinfo-find-pointer beginning end level direction)))))
(defun texinfo-clean-up-node-line ()
"Remove extra commas, if any, at end of node line."
(end-of-line)
(skip-chars-backward ", ")
(delete-region (point) (save-excursion (end-of-line) (point))))
;;; Updating nodes sequentially
; These sequential update functions insert `Next' or `Previous'
; pointers that point to the following or preceding nodes even if they
; are at higher or lower hierarchical levels. This means that if a
; section contains one or more subsections, the section's `Next'
; pointer will point to the subsection and not the following section.
; (The subsection to which `Next' points will most likely be the first
; item on the section's menu.)
;;;###autoload
(defun texinfo-sequential-node-update (&optional region-p)
"Update one node (or many) in a Texinfo file with sequential pointers.
This function causes the `Next' or `Previous' pointer to point to the
immediately preceding or following node, even if it is at a higher or
lower hierarchical level in the document. Continually pressing `n' or
`p' takes you straight through the file.
Without any prefix argument, update the node in which point is located.
Non-nil argument (prefix, if interactive) means update the nodes in the
marked region.
This command makes it awkward to navigate among sections and
subsections; it should be used only for those documents that are meant
to be read like a novel rather than a reference, and for which the
Info `g*' command is inadequate."
(interactive "P")
(if (not region-p)
;; update a single node
(let ((auto-fill-function nil) (auto-fill-hook nil))
(if (not (re-search-backward "^@node" (point-min) t))
(error "Node line not found before this position."))
(texinfo-sequentially-update-the-node)
(message
"Done...sequentially updated the node . You may save the buffer."))
;; else
(let ((auto-fill-function nil)
(auto-fill-hook nil)
(beginning (region-beginning))
(end (region-end)))
(if (= end beginning)
(error "Please mark a region!"))
(save-restriction
(narrow-to-region beginning end)
(goto-char beginning)
(push-mark (point) t)
(while (re-search-forward "^@node" (point-max) t)
(beginning-of-line)
(texinfo-sequentially-update-the-node))
(message
"Done...updated the nodes in sequence. You may save the buffer.")))))
(defun texinfo-sequentially-update-the-node ()
"Update one node such that the pointers are sequential.
A `Next' or `Previous' pointer points to any preceding or following node,
regardless of its hierarchical level."
(texinfo-check-for-node-name)
(texinfo-delete-existing-pointers)
(message
"Sequentially updating node: %s ... " (texinfo-copy-node-name))
(save-restriction
(widen)
(let*
((case-fold-search t)
(level (texinfo-hierarchic-level)))
(if (string-equal level "top")
(texinfo-top-pointer-case)
;; else
(texinfo-sequentially-insert-pointer level 'next)
(texinfo-sequentially-insert-pointer level 'previous)
(texinfo-sequentially-insert-pointer level 'up)
(texinfo-clean-up-node-line)))))
(defun texinfo-sequentially-find-pointer (level direction)
"Find next or previous pointer sequentially in Texinfo file, or up pointer.
Move point to section associated with the pointer. Find point even if
it is in a different section.
Return type of pointer (either 'normal or 'no-pointer).
The first argument is a string specifying the general kind of section
such as \"chapter\ or \"section\". The section found will be at the
same hierarchical level in the Texinfo file, or, in the case of the up
pointer, some level higher. The second argument (one of 'next,
'previous, or 'up) specifies whether to find the `Next', `Previous',
or `Up' pointer."
(let ((case-fold-search t))
(cond ((eq direction 'next)
(forward-line 3) ; skip over current node
(if (re-search-forward
texinfo-section-types-regexp
(point-max)
t)
'normal
'no-pointer))
((eq direction 'previous)
(if (re-search-backward
texinfo-section-types-regexp
(point-min)
t)
'normal
'no-pointer))
((eq direction 'up)
(if (re-search-backward
(eval (cdr (assoc level texinfo-update-menu-higher-regexps)))
beginning
t)
'normal
'no-pointer))
(t
(error "texinfo-sequential-find-pointer: lack proper arguments")))))
(defun texinfo-sequentially-insert-pointer (level direction)
"Insert the `Next', `Previous' or `Up' node name at point.
Move point forward.
The first argument is the hierarchical level of the Texinfo file, a
string such as \"section\". The second argument is direction, one of
`next, `previous, or 'up."
(end-of-line)
(insert
", "
(save-excursion
(texinfo-pointer-name
(texinfo-sequentially-find-pointer level direction)))))
;;; Inserting `@node' lines
; The `texinfo-insert-node-lines' function inserts `@node' lines as needed
; before the `@chapter', `@section', and such like lines of a region
; in a Texinfo file.
(defun texinfo-insert-node-lines (beginning end &optional title-p)
"Insert missing `@node' lines in region of Texinfo file.
Non-nil argument (prefix, if interactive) means also to insert the
section titles as node names; and also to insert the section titles as
node names in pre-existing @node lines that lack names."
(interactive "r\nP")
;; Use marker; after inserting node lines, leave point at end of
;; region and mark at beginning.
(let (beginning-marker end-marker title last-section-position)
;; Save current position on mark ring and set mark to end.
(push-mark end t)
(setq end-marker (mark-marker))
(goto-char beginning)
(while (re-search-forward
texinfo-section-types-regexp
end-marker
'end)
;; Copy title if desired.
(if title-p
(progn
(beginning-of-line)
(forward-word 1)
(skip-chars-forward " \t")
(setq title (buffer-substring
(point)
(save-excursion (end-of-line) (point))))))
;; Insert node line if necessary.
(if (re-search-backward
"^@node"
;; Avoid finding previous node line if node lines are close.
(or last-section-position
(save-excursion (forward-line -2) (point))) t)
;; @node is present, and point at beginning of that line
(forward-word 1) ; Leave point just after @node.
;; Else @node missing; insert one.
(beginning-of-line) ; Beginning of `@section' line.
(insert "@node\n")
(backward-char 1)) ; Leave point just after `@node'.
;; Insert title if desired.
(if title-p
(progn
(skip-chars-forward " \t")
;; Use regexp based on what info looks for
;; (alternatively, use "[a-zA-Z]+");
;; this means we only insert a title if none exists.
(if (not (looking-at "[^,\t\n ]+"))
(progn
(beginning-of-line)
(forward-word 1)
(insert " " title)
(message "Inserted title %s ... " title)))))
;; Go forward beyond current section title.
(re-search-forward texinfo-section-types-regexp
(save-excursion (forward-line 3) (point)) t)
(setq last-section-position (point))
(forward-line 1))
;; Leave point at end of region, mark at beginning.
(set-mark beginning)
(if title-p
(message
"Done inserting node lines and titles. You may save the buffer.")
(message "Done inserting node lines. You may save the buffer."))))
;;; Update and create menus for multi-file Texinfo sources
;; 1. M-x texinfo-multiple-files-update
;;
;; Read the include file list of an outer Texinfo file and
;; update all highest level nodes in the files listed and insert a
;; main menu in the outer file after its top node.
;; 2. C-u M-x texinfo-multiple-files-update
;;
;; Same as 1, but insert a master menu. (Saves reupdating lower
;; level menus and nodes.) This command simply reads every menu,
;; so if the menus are wrong, the master menu will be wrong.
;; Similarly, if the lower level node pointers are wrong, they
;; will stay wrong.
;; 3. C-u 2 M-x texinfo-multiple-files-update
;;
;; Read the include file list of an outer Texinfo file and
;; update all nodes and menus in the files listed and insert a
;; master menu in the outer file after its top node.
;;; Note: these functions:
;;;
;;; * Do not save or delete any buffers. You may fill up your memory.
;;; * Do not handle any pre-existing nodes in outer file.
;;; Hence, you may need a file for indices.
;;; Auxiliary functions for multiple file updating
(defun texinfo-multi-file-included-list (outer-file)
"Return a list of the included files in OUTER-FILE."
(let ((included-file-list (list outer-file))
start)
(save-excursion
(switch-to-buffer (find-file-noselect outer-file))
(widen)
(goto-char (point-min))
(while (re-search-forward "^@include" nil t)
(skip-chars-forward " \t")
(setq start (point))
(end-of-line)
(skip-chars-backward " \t")
(setq included-file-list
(cons (buffer-substring start (point))
included-file-list)))
(nreverse included-file-list))))
(defun texinfo-copy-next-section-title ()
"Return the name of the immediately following section as a string.
Start with point at the beginning of the node line. Leave point at the
same place. If there is no title, returns an empty string."
(save-excursion
(end-of-line)
(let ((node-end (or
(save-excursion
(if (re-search-forward "\\(^@node\\)" nil t)
(match-beginning 0)))
(point-max))))
(if (re-search-forward texinfo-section-types-regexp node-end t)
(progn
(beginning-of-line)
;; copy title
(let ((title
(buffer-substring
(progn (forward-word 1) ; skip over section type
(skip-chars-forward " \t") ; and over spaces
(point))
(progn (end-of-line) (point)))))
title))
""))))
(defun texinfo-multi-file-update (files &optional update-everything)
"Update first node pointers in each file in FILES.
Return a list of the node names.
The first file in the list is an outer file; the remaining are
files included in the outer file with `@include' commands.
If optional arg UPDATE-EVERYTHING non-nil, update every menu and
pointer in each of the included files.
Also update the `Top' level node pointers of the outer file.
Requirements:
* the first file in the FILES list must be the outer file,
* each of the included files must contain exactly one highest
hierarchical level node,
* this node must be the first node in the included file,
* each highest hierarchical level node must be of the same type.
Thus, normally, each included file contains one, and only one,
chapter."
; The menu-list has the form:
;
; \(\(\"node-name1\" . \"title1\"\)
; \(\"node-name2\" . \"title2\"\) ... \)
;
; However, there does not need to be a title field and this function
; does not fill it; however a comment tells you how to do so.
; You would use the title field if you wanted to insert titles in the
; description slot of a menu as a description.
(let ((case-fold-search t)
menu-list)
;; Find the name of the first node of the first included file.
(switch-to-buffer (find-file-noselect (car (cdr files))))
(widen)
(goto-char (point-min))
(if (not (re-search-forward "^@node" nil t))
(error "No `@node' line found in %s !" (buffer-name)))
(beginning-of-line)
(texinfo-check-for-node-name)
(setq next-node-name (texinfo-copy-node-name))
(setq menu-list
(cons (cons
next-node-name
(prog1 "" (forward-line 1)))
;; Use following to insert section titles automatically.
;; (texinfo-copy-next-section-title)
menu-list))
;; Go to outer file
(switch-to-buffer (find-file-noselect (car files)))
(goto-char (point-min))
(if (not (re-search-forward "^@node [ \t]*top[ \t]*\\(,\\|$\\)" nil t))
(error "This buffer needs a Top node!"))
(beginning-of-line)
(texinfo-delete-existing-pointers)
(end-of-line)
(insert ", " next-node-name ", (dir), (dir)")
(beginning-of-line)
(setq previous-node-name "Top")
(setq files (cdr files))
(while files
(if (not (cdr files))
;; No next file
(setq next-node-name "")
;; Else,
;; find the name of the first node in the next file.
(switch-to-buffer (find-file-noselect (car (cdr files))))
(widen)
(goto-char (point-min))
(if (not (re-search-forward "^@node" nil t))
(error "No `@node' line found in %s !" (buffer-name)))
(beginning-of-line)
(texinfo-check-for-node-name)
(setq next-node-name (texinfo-copy-node-name))
(setq menu-list
(cons (cons
next-node-name
(prog1 "" (forward-line 1)))
;; Use following to insert section titles automatically.
;; (texinfo-copy-next-section-title)
menu-list)))
;; Go to node to be updated.
(switch-to-buffer (find-file-noselect (car files)))
(goto-char (point-min))
(if (not (re-search-forward "^@node" nil t))
(error "No `@node' line found in %s !" (buffer-name)))
(beginning-of-line)
;; Update other menus and nodes if requested.
(if update-everything (texinfo-all-menus-update t))
(beginning-of-line)
(texinfo-delete-existing-pointers)
(end-of-line)
(insert ", " next-node-name ", " previous-node-name ", " up-node-name)
(beginning-of-line)
(setq previous-node-name (texinfo-copy-node-name))
(setq files (cdr files)))
(nreverse menu-list)))
(defun texinfo-multi-files-insert-main-menu (menu-list)
"Insert formatted main menu at point.
Indents the first line of the description, if any, to the value of
texinfo-column-for-description."
(insert "@menu\n")
(while menu-list
;; Every menu entry starts with a star and a space.
(insert "* ")
;; Insert the node name (and menu entry name, if present).
(let ((node-part (car (car menu-list))))
(if (stringp node-part)
;; "Double colon" entry line; menu entry and node name are the same,
(insert (format "%s::" node-part))
;; "Single colon" entry line; menu entry and node name are different.
(insert (format "%s: %s." (car node-part) (cdr node-part)))))
;; Insert the description, if present.
(if (cdr (car menu-list))
(progn
;; Move to right place.
(indent-to texinfo-column-for-description 2)
;; Insert description.
(insert (format "%s" (cdr (car menu-list))))))
(insert "\n") ; end this menu entry
(setq menu-list (cdr menu-list)))
(insert "@end menu"))
(defun texinfo-multi-file-master-menu-list (files-list)
"Return master menu list from files in FILES-LIST.
Menu entries in each file collected using `texinfo-master-menu-list'.
The first file in FILES-LIST must be the outer file; the others must
be the files included within it. A main menu must already exist."
(save-excursion
(let (master-menu-list)
(while files-list
(switch-to-buffer (find-file-noselect (car files-list)))
(message "Working on: %s " (current-buffer))
(goto-char (point-min))
(setq master-menu-list
(append master-menu-list (texinfo-master-menu-list)))
(setq files-list (cdr files-list)))
master-menu-list)))
;;; The multiple-file update function
(defun texinfo-multiple-files-update
(outer-file &optional update-everything make-master-menu)
"Update first node pointers in each file included in OUTER-FILE;
create or update the `Top' level node pointers and the main menu in
the outer file that refers to such nodes. This does not create or
update menus or pointers within the included files.
With optional MAKE-MASTER-MENU argument (prefix arg, if interactive),
insert a master menu in OUTER-FILE in addition to creating or updating
pointers in the first @node line in each included file and creating or
updating the `Top' level node pointers of the outer file. This does
not create or update other menus and pointers within the included
files.
With optional UPDATE-EVERYTHING argument (numeric prefix arg, if
interactive), update all the menus and all the `Next', `Previous', and
`Up' pointers of all the files included in OUTER-FILE before inserting
a master menu in OUTER-FILE. Also, update the `Top' level node
pointers of OUTER-FILE.
Notes:
* this command does NOT save any files--you must save the
outer file and any modified, included files.
* except for the `Top' node, this command does NOT handle any
pre-existing nodes in the outer file; hence, indices must be
enclosed in an included file.
Requirements:
* each of the included files must contain exactly one highest
hierarchical level node,
* this highest node must be the first node in the included file,
* each highest hierarchical level node must be of the same type.
Thus, normally, each included file contains one, and only one,
chapter."
(interactive (cons
(read-string
"Name of outer `include' file: "
(buffer-file-name))
(cond ((not current-prefix-arg)
'(nil nil))
((listp current-prefix-arg)
'(t nil)) ; make-master-menu
((numberp current-prefix-arg)
'(t t)) ; update-everything
)))
(let* ((included-file-list (texinfo-multi-file-included-list outer-file))
(files included-file-list)
main-menu-list
next-node-name
previous-node-name
(up-node-name "Top"))
;;; Update the pointers
;;; and collect the names of the nodes and titles
(setq main-menu-list (texinfo-multi-file-update files update-everything))
;;; Insert main menu
;; Go to outer file
(switch-to-buffer (find-file-noselect (car included-file-list)))
(if (texinfo-old-menu-p
(point-min)
(save-excursion
(re-search-forward "^@include")
(beginning-of-line)
(point)))
;; If found, leave point after word `menu' on the `@menu' line.
(progn
(texinfo-incorporate-descriptions main-menu-list)
;; Delete existing menu.
(beginning-of-line)
(delete-region
(point)
(save-excursion (re-search-forward "^@end menu") (point)))
;; Insert main menu
(texinfo-multi-files-insert-main-menu main-menu-list))
;; Else no current menu; insert it before `@include'
(texinfo-multi-files-insert-main-menu main-menu-list))
;;; Insert master menu
(if make-master-menu
(progn
;; First, removing detailed part of any pre-existing master menu
(goto-char (point-min))
(if (re-search-forward texinfo-master-menu-header nil t)
;; Remove detailed master menu listing
(progn
(goto-char (match-beginning 0))
(let ((end-of-detailed-menu-descriptions
(save-excursion ; beginning of end menu line
(goto-char (texinfo-menu-end))
(beginning-of-line) (forward-char -1)
(point))))
(delete-region (point) end-of-detailed-menu-descriptions))))
;; Create a master menu and insert it
(texinfo-insert-master-menu-list
(texinfo-multi-file-master-menu-list
included-file-list)))))
;; Remove unwanted extra lines.
(save-excursion
(goto-char (point-min))
(re-search-forward "^@menu")
(forward-line -1)
(insert "\n") ; Ensure at least one blank line.
(delete-blank-lines)
(re-search-forward "^@end menu")
(forward-line 1)
(insert "\n") ; Ensure at least one blank line.
(delete-blank-lines))
(message "Multiple files updated."))
;;; Place `provide' at end of file.
(provide 'texnfo-upd)
;;; texnfo-upd.el ends here
texinfo-3.7/COPYING 100444 11732 13 43076 5022247405 12311 0 ustar bfox user GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C) 19yy
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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
texinfo-3.7/ChangeLog 100666 11732 13 205375 6067076374 13077 0 ustar bfox user Sat Dec 23 11:48:43 1995 Brian J. Fox
* info/man.c: (clean_manpage) Remove ^L's from page.
* makeinfo/makeinfo.c (get_brace_args): Change some memcpy's to
memmoves.
* info/info.c (main): Prefer caseless matches over partial
matches.
* Makefile.in (All Subdir Targets): Change suggested by Debian
people which allows errors in recursive makes to kill the
top-level make.
* makeinfo/Makefile.in (makeinfo.dvi): New target.
* info/info.c (main): Print version of containing texinfo package.
* makeinfo/makeinfo.c (flush_output): Don't strip high-bit from
sentence_enders.
Print the version number of the containing texinfo package.
* info/man.c (locate_manpage_xref): Count the 0th entry.
* makeinfo/makeinfo.c (cm_menu): If a menu is seen before a node
has been defined, warn, and create the node `Top'.
Wed Jun 21 03:19:39 1995 Brian Fox
* makeinfo/makeinfo.c (cm_infoinclude): Clean up after printing
error if the file couldn't be included.
(discard_braces): Print errors only for those unmatched open
braces that belong to a texinfo command.
* */Makefile.in: Use @CFLAGS@ and @LDFLAGS@.
* makeinfo/makeinfo.c: End `node_search_string' and friends with a
terminating null character.
Wed Jun 21 01:23:49 1995 Jim Meyering (meyering@comco.com)
* makeinfo/makeinfo.c: Close comment after #endif.
Tue Jun 20 04:58:26 1995 Brian Fox
* emacs/Makefile.in (install): Fix typo: "fle" -> "file".
* Makefile.in (VERSION): Bump to 3.6
* info/clib.c: Include general.h for `info_toupper' and friends.
* info/clib.h: strncmp and strncascmp return an int. What kind of
drugs was I on?
Mon Jun 19 23:34:47 1995 Brian Fox
* makeinfo/makeinfo.c (make_index_entries_unique): Copy the last
index entry.
Mon Jun 19 21:55:49 1995 Noah Friedman
* util/texi2dvi (--version): New option.
Cosmetic changes.
Mon Jun 19 16:06:40 1995 Brian Fox
* makeinfo/makeinfo.c (cm_macro): Fix typo. `x != y' is not the
same as `x |= y'.
* info/Makefile.in (exec_prefix): Use @exec_prefix@ not $(prefix).
* makeinfo/Makefile.in (exec_prefix): Use @exec_prefix@ not $(prefix).
* util/Makefile.in (exec_prefix): Use @exec_prefix@ not $(prefix).
* libtxi/Makefile.in (exec_prefix): Use @exec_prefix@ not $(prefix).
* emacs/Makefile.in (uninstall): New target.
(install): Use the definition of $(lispdir), don't dynamically
find it. Use INSTALL_DATA not cp.
(exec_prefix): use @exec_prefix@ not $(prefix).
* makeinfo/makeinfo.c (apply): If there isn't an actual argument
for a named argument, default it to "".
* Makefile.in (VERSION): Now at 3.5.
(texinfo): Make ./makeinfo/makeinfo depend on sub-all for parallel
makes.
* emacs/Makefile.in (ELISP_OBJS): Explictly declare .el and .elc
in the SUFFIXES list.
* makeinfo/makeinfo.c (cm_today): Special case for losing alpha.
* (minor_version): Increase to 63.
* info/info.c (version_string): Now at 2.14.
* info/tilde.c: Declare getenv to return (char *).
* info/window.c (build_message_buffer): Jump through hoops to keep
DEC Alpha's happy.
* info/xmalloc.c: Declare malloc and realloc as (void *) returning
functions.
Sun Jun 18 12:47:21 1995 Richard Stallman
* emacs/detexinfo.el (detexinfo-line-cmds-without-arg):
Handle ifhtml.
Fri Jun 16 13:48:14 1995 Brian Fox
* util/texindex.c: Update TEXINDEX_VERSION_STRING for texinfo 3.4
* (All *.c *.h *.in): Change FSF old address to new.
* texinfo.texi (Obtaining TeX): Change FSF old address to new
address. Change Old phone numbers to new phone numbers.
* Makefile.in (VERSION): Change to 3.4.
Thu Jun 15 22:49:07 1995 Robert J. Chassell
* texinfo.texi, emacs/=development/cover.texi: update
Texinfo distribution package version number
Thu Jun 15 09:23:02 1995 Brian J. Fox
* info/info.c: (minor_version): Set to 13.
* info/clib.c,h: New files gather together replacement functions
for those POSIX-style C library functions that are not present on
the target system.
* info/Makefile.in (SRCS): Add clib.c and clib.h. makedoc now
needs clib.o to build on systems missing various string.h stuff.
* info/variables.c (whole file): Call strdup, not savestring.
* info/tilde.c (whole file): Call strdup, not savestring.
* info/search.c (whole file): Call strdup, not savestring.
* info/nodes.c (whole file): Call strdup, not savestring.
* info/nodemenu.c (whole file): Call strdup, not savestring.
* info/man.c (whole file): Call strdup, not savestring.
* info/makedoc.c (whole file): Call strdup, not savestring.
* info/m-x.c (whole file): Call strdup, not savestring.
* info/info.c (whole file): Call strdup, not savestring.
* info/indices.c (whole file): Call strdup, not savestring.
* info/echo_area.c (whole file): Call strdup, not savestring.
* info/session.c (whole file): Call strdup, not savestring.
* info/filesys.c (whole file): Call strdup, not savestring.
* makeinfo/makeinfo.c (minor_version): Change to 1.62.
* makeinfo/makeinfo.c (get_execution_string): Initialize `i' to 0
in case there are no execution_strings.
Wed Jun 14 17:48:06 1995 Brian J. Fox
* texinfo.texi: include "texinfo.tex", not "texinfo".
* info/session.c (forget_window_and_nodes): Place a sequence point
in between "info_windows[i] = info_windows[++i];" as per various
compiler experts.
* makeinfo/makeinfo.c (strdup): Create this function if the system
doesn't have it.
(discard_insertions): Use the insertion's filename, not the
current input file.
(push_insertion): Remember the current input file with each
insertion.
(pop_insertion): Free storage used by remembered input file.
* makeinfo/makeinfo.c (whole file): Use `strdup' instead of
`savestring'.
* configure.in: Check for `strdup'.
Wed Jun 14 15:58:51 1995 Brian Fox
* libtxi/Makefile.in (prefix): Use @prefix@, not /usr/local/
Wed Jun 14 10:50:57 1995 Brian J. Fox
* Makefile.in (DISTFILES): Don't include *.elc files in the list
of files to distribute.
(installdirs): Include `emacs' in the list of sub-dirs with
Makefile.in's.
* emacs/elisp-comp: Shell script which batch compiles the *.el files.
* emacs/Makefile.in: New file contains targets to build the elc files.
* configure.in: Add `emacs/Makefile' to the list of created makefiles.
* makeinfo/makeinfo.c (whole file): Give every function a return
type. All cm_xxx functions are now void. Add declarations for
functions to top of file.
Mon Jun 12 12:00:57 1995 Brian J. Fox
* info/man.c (reference_section_starters): Add versions of "SEE
ALSO" and "RELATED INFORMATION" with tabs instead of spaces as
well.
* util/texindex.c: Back out changes for OFF_T. Explicity coerce
the result of lseek to a long, and use longs everywhere.
* texinfo.texi: Change "@end shorttitlepage" to "@end titlepage".
* makeinfo/makeinfo.c: Make @shorttitlepage ignore the rest of the
line.
* util/texindex.c (strrchr): Create if not present.
Test for HAVE_STRCHR and HAVE_STRING_H.
(main): Make PROGRAM_NAME be just the last path componenet of argv[0].
(decode_command): Rewrite.
(usage): Rewrite. Now texindex handles --version.
* makeinfo/makeinfo.c (make_index_entries_unique): Rewrite from
scratch.
* Don't distribute created info files with texinfo. After all,
the user will have the tools necessary to create them, yes?
* Makefile.in (distclean): Remove *.log
* info/man.c (read_from_fd): Change timeout value for select to 15
seconds. Some systems (e.g., albert.ai.mit.edu) actually need
more than 10 seconds to format a man page.
* info/tilde.c: Fix typo in declaration for
`tilde_expansion_failure_hook'.
Wed Jun 7 13:36:53 1995 Brian Fox
* info/tilde.h: Change type of tilde_expansion_failure_hook to
a pointer to a function returning a (char *).
* info/tilde.c: Change type of tilde_expansion_failure_hook to a
pointer to function returning a (char *).
* makeinfo/makeinfo.c (get_execution_string): Don't use `i' in the
latter assignment, use `execution_strings_index' instead.
* info/man.c (read_from_fd): Change logic to avoid using FIONREAD.
* info/xmalloc.c (xrealloc): Use (void *), not (caddr_t *).
* info/xmalloc.c (xmalloc): Use (void *), not (caddr_t *).
* Makefile.in (DISTFILES): Don't find RCS no "=" directories.
* util/Makefile.in (prefix): Use @prefix@ as the value.
* info/Makefile.in (prefix): Use @prefix@ as the value.
* makeinfo/Makefile.in (prefix): Use @prefix@ as the value.
Wed Jun 7 12:29:28 1995 Robert J. Chassell
* texinfo.texi: Correct minor typos.
* emacs/texinfmt.el: Don't require @shorttitlepage to be inside
of @iftex ... @end iftex
Mon May 8 18:33:52 1995 Brian J. Fox
* info/nodes.c: #include "man.h" if HANDLE_MAN_PAGES.
(info_get_node_of_file_buffer): If the file buffer is one
associated with manpages, call the manpage node finding
function instead.
(info_find_file_internal): If the file buffer is one associated
with manpages, avoid doing any file I/O.
(info_reload_file_buffer_contents): Ditto.
(info_find_file_internal): Call create_manpage_file_buffer instead
of info_load_file_internal.
* info/info.c: #include "man.h" if HANDLE_MAN_PAGES.
(main): If the initial node cannot be found, perhaps find it as a
manpage.
* info/info-utils.c: #include "man.h" if HANDLE_MAN_PAGES.
(info_xrefs_of_node): If handling man pages, and this is a manpage
node, use xrefs_of_manpage.
* info/session.c (info_set_input_from_file): Only fclose (stream)
if it is non-null and not stdin.
#include "man.h" if HANDLE_MAN_PAGES.
(info_menu_or_ref_item): If handling man pages, and this is a
manpage node, get the xrefs from manpage_xrefs_in_binding.
(info_man): Compile in for M-x man if handling man pages.
(info_move_to_xref): If handling man pages, and the current node
is a manpage node, use locate_manpage_xref to get xrefs.
Thu May 4 08:55:23 1995 Brian J. Fox
* info/info.c (main): If the output device is not a terminal, and
no output filename has been specified, make user_output_filename
be "-", so that the info is written to stdout, and turn on the
dumping of subnodes.
Thu Apr 13 18:05:06 1995 Daniel Hagerty
* texinfo.texi: Fixed @end titlepage/@end shorttitlepage
Sat Apr 8 12:51:49 1995 Roland McGrath
* makeinfo/makeinfo.c [! HAVE_STRERROR] (strerror): New function,
snarfed from ../info/filesys.c.
(cm_infoinclude): Use strerror instead of sys_errlist.
Tue Apr 4 18:44:00 1995 Brian J. Fox
* util/texindex.c (sort_offline): Change TOTAL to be an off_t.
* util/texindex.c (sort_in_core): Change TOTAL to be an off_t.
* util/texindex.c (MAX_IN_CORE_SORT): Cast to off_t.
Sun Apr 2 16:20:13 1995 Brian J. Fox
* info/Makefile.in: Define DEFAULT_INFOPATH in case we are
compiling in the current directory.
* info/Makefile.in (info.o): Add filesys.h because of DEFAULT_INFOPATH.
* info/(search.c,h, nodes.c info-utils.c) Use strcasecmp and
strncasecmp instead of stricmp and strnicmp. Define strcasecmp
and strncasecmp in search.c if !HAVE_STRCASECMP.
* info/search.c: If HAVE_STRING_H include it.
* info/nodes.c: If HAVE_STRING_H include it.
* info/info-utils.c: If HAVE_STRING_H include it.
* info/info.h: If HAVE_STRING_H include it.
* configure.in (AC_HAVE_FUNCS): Check for strcasecmp.
* makeinfo/makeinfo.c (strcasecmp): Define if !HAVE_STRCASECMP.
* makeinfo/makeinfo.c (entire file): Use `strcasecmp' instead of
`stricmp'.
* makeinfo/makeinfo.c (cm_ifeq): New command takes three args.
Compares first two, executes remainder if the first two are
string-wise eq.
* makeinfo/makeinfo.c (ifhtml): Add to command list. Shouldn't be
used, but it is by people who don't want to hack macros.
Sat Apr 1 09:20:14 1995 Brian J. Fox
* makeinfo/makeinfo.c (begin_insertion): Fix reversed arguments to
line_error.
* info/info-stnd.texi: Use "end" footnote style instead of "separate".
* info/Makefile.in: Change "rm -f" to $(RM).
* info/general.h: Define zero_mem in terms of memset if we have
it, else in terms of bzero if we have that, else as inline code.
* info/NEWS: Updated to reflect changes in 2.11.
Fri Mar 31 22:38:31 1995 Brian J. Fox
* Makefile (DISTFILES): Don't include *.a, *orig, nor *.e
files.
(DISTFILES):
Sat Mar 4 12:16:29 1995 Brian J. Fox
* Makefile.in: Use @prefix@ instead of hardwired `/usr/local'.
Clean up makefile rules which make in subdirs.
(ALL_SUBDIRS): Add makeinfo/macros to list of subdirectories.
* configure.in (AC_CHECK_FUNCS): Add `bcopy' to list of things to
check for.
Fri Mar 3 13:54:10 1995 Robert J. Chassell
* texinfo.texi: Minor changes for incremental new edition 2.20.
Fri Mar 3 19:01:36 1995 Brian J. Fox
* filesys.c (filesys_read_info_file): Local variable ST_SIZE is a
long which has the value of finfo->st_size casted to it.
* nodes.c (whole file): Similar changes.
These changes and the following for makedoc.c were required for
proper operation on HPm68k NetBSD.
Mon Feb 27 15:16:27 1995 Brian J. Fox
* makedoc.c (process_one_file): Local variable FILE_SIZE is a long
which has the value of finfo.st_size casted to it.
Fri Mar 3 18:58:38 1995 Brian J. Fox
* makeinfo.c (find_and_load): Cast fileinfo.st_size to a long for
internal use. This makes things work on NetBSD.
Fri Mar 3 13:54:10 1995 Robert J. Chassell
* texinfo.texi: Minor changes for incremental new edition 2.20.
Fri Mar 3 09:41:39 1995 Brian J. Fox
* configure.in (TERMLIBS): Use AC_CHECK_LIB instead of
AC_HAVE_LIBRARY.
Mon Jan 9 16:55:31 1995 Brian Fox
* Makefile.in (DISTFILES): Add the directory EMACS-BACKUPS to the
list of things to avoid distributing.
Tue Nov 29 17:48:37 1994 David J. MacKenzie
* configure.in: Check for off_t.
* util/texindex.c (main): Use it.
Fri Nov 11 14:46:28 1994 David J. MacKenzie
* configure.in: Update for Autoconf v2.
Thu Oct 13 02:17:38 1994 Richard Stallman
* emacs/detexinfo.el (detexinfo): Handle @!, @?, @^, @".
Mon Aug 1 03:26:13 1994 Richard Stallman
* texindex.c: Move the memset define down past string.h include.
Tue Jun 28 14:21:43 1994 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
* makeinfo/makeinfo.c: Add --help option.
(usage): Take args for stream and error code.
Change callers.
(print_version_info): Write to stdout, not stderr.
Wed May 18 18:55:24 1994 Brian J. Fox (bfox@ai.mit.edu)
* info/session.c (forget_window_and_nodes): Negate test for
internal_info_node_p. We only want to free the text if it is
not an internal node.
Thu Mar 10 03:07:18 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu)
* texindex.c (memset): Fix invalid parm name (was 0).
Thu Feb 10 12:56:52 1994 Noah Friedman (friedman@prep.ai.mit.edu)
* makeinfo/makeinfo.c (current_item_function): Don't loop if elt
is NULL.
Wed Feb 9 12:21:09 1994 Brian J. Fox (bfox@ai.mit.edu)
* makeinfo/makeinfo.c (minor_version): Release now at 1.60.
* makeinfo/makeinfo.c (expand_filename): Additional fixes. Now
when called with NULL filename, makes an output filename from the
input filename.
(convert_from_loaded_file): If REQUIRE_SETFILENAME is #defined (no
longer the default case) then error if no @setfilename was found
in the file. If REQUIRE_SETFILENAME is not #defined, the input
file starts either at the first line, or at the second line if the
first line contains the text "\input", and the output filename is
the input file name without directory and with ".info" replacing
any extension found.
(convert_from_loaded_file): Fixed bug in search for first
occurence of "@setfilename".
Tue Feb 8 14:16:58 1994 Noah Friedman (friedman@prep.ai.mit.edu)
* configure.in: Check for sys/file.h.
info/dir.c, info/filesys.c, info/makedoc.c, info/nodes.c,
info/session.c, info/termdep.h, makeinfo/makeinfo.c
[HAVE_SYS_FILE_H]: Include .
* makeinfo/makeinfo.c (convert_from_loaded_file): Print
real_output_filename instead of output_filename, so user knows
exactly where output file is going.
Fri Jun 11 14:34:30 1993 Ian Lance Taylor (ian@cygnus.com)
* configure.in: Check for sigprocmask and sigsetmask.
* info/signals.h (HAVE_SIGSETMASK): Don't define.
(HAVE_SIGPROCMASK): Use instead of _POSIX_VERSION.
(BLOCK_SIGNAL, UNBLOCK_SIGNAL): If neither HAVE_SIGPROCMASK nor
HAVE_SIGSETMASK is defined, define these to do nothing.
* info/signals.c (sigprocmask): Don't compile if HAVE_SIGSETMASK
is not defined.
* info/terminal.c (terminal_prep_terminal): Don't clobber VINTR
and VQUIT in conditionals.
Mon Feb 7 18:10:22 1994 Brian J. Fox (bfox@ai.mit.edu)
* makeinfo/makeinfo.c (full_pathname): Correct to really return
the full pathname of the input argument. Now makeinfo
/foo/bar.texi, where /foo/bar.texi contains "@setfilename
bar.info", correctly leaves the output file in "./bar.info".
Note that "@setfilename ../bar.info" still works; this is already
an absolute pathname.
Sat Feb 5 13:04:05 1994 Brian J. Fox (bfox@ai.mit.edu)
* makeinfo/makeinfo.c: Version 1.59 released.
* makeinfo/makeinfo.c (whole file): Large number of changes allow
the "-E filename" option to be used to write a macro expanded
output file. On a file which contains no @include's and no
@macro's, the output file is identical to the input file.
* makeinfo/makeinfo.c (declarations): Remove cm_tex (). It is
never used since it is implemented with `command_name_condition'.
* makeinfo/makeinfo.c (add_char): Shift braces following the
current break point if we have deleted any characters.
(adjust_braces_following): New function adjusts all of the markers
in the brace stack which follow HERE by AMOUNT. This fixes a bug
where (for example) @var{} immediately following a line break
which is the end of a sentence modified the output incorrectly.
Wed Feb 2 14:14:03 1994 Brian J. Fox (bfox@ai.mit.edu)
* makeinfo: Version 1.58.
* makeinfo/makeinfo.c (cm_node): Add extra hair to allow
backtracking through execution strings. Add extra hair to allow
the first node seen after a @top node is seen to adjust the
sectioning level of the @top node and associated menus.
Fix a few typos.
Add facility for macros to invoke the original definition. This
works by not allowing a single macro to recurse. Mutual recursion
is also disallowed with this plan.
* makeinfo/macros: New directory contains shippable macros.
* makeinfo/macros/simpledoc.texi: Macros which simplify the most
common uses of TeXinfo. See the example file.
Macros are now a reasonable way to get people started using
TeXinfo.
Mon Jan 31 12:54:36 1994 Brian J. Fox (bfox@ai.mit.edu)
* makeinfo/makeinfo.c (minor_version): Increase to 57.
* makeinfo/makeinfo.c (cm_node): Call execute_string on the node,
next, prev, and up pointers.
(reader_loop): Change logic for `@bye'. No longer required at the
ends of executed strings.
(execute_string): Do not append `@bye' to the string to execute.
* makeinfo/makeinfo.c (whole file): Use COMMAND_PREFIX instead of
hardcoding `@' character in strings and searches.
* makeinfo/makeinfo.c (read_command): If HAVE_MACROS is defined,
then recognize and execute macros here.
(CommandTable): Add "macro" and "unmacro" to table if HAVE_MACROS
is defined.
* makeinfo/makeinfo.c (cm_macro, cm_unmacro, execute_macro)
makeinfo/makeinfo.c (get_macro_args, find_macro, add_macro)
makeinfo/makeinfo.c (delete_macro, array_len, apply):
New functions implement macro facility if HAVE_MACROS is
defined.
* makeinfo/macro.texi (new file): Examples of using the new macro
facility.
Mon Jan 31 10:24:52 1994 Noah Friedman (friedman@prep.ai.mit.edu)
* makeinfo/makeinfo.c (executing_string): Restore global
declaration.
Mon Jan 24 23:48:26 1994 Noah Friedman (friedman@prep.ai.mit.edu)
* texinfo.texi: Various typo fixes from Bob Chassell
.
Thu Jan 6 13:34:21 1994 Noah Friedman (friedman@prep.ai.mit.edu)
* texinfo.texi: Turned on smallbook format and @set smallbook.
Wed Dec 15 20:08:43 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* info/filesys.h (DEFAULT_INFOPATH): Added /usr/local/info,
/opt/gnu/info, /usr/share/info, and /usr/local/share/info.
Tue Dec 14 19:10:20 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* libtxi/Makefile.in (ALLOCA): Define from configure.
Fri Dec 10 04:33:12 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* util/texi2dvi: Put under RCS control.
Sun Dec 26 11:55:46 1993 Brian J. Fox (bfox@ai.mit.edu)
* info/session.c (info_numeric_digit_arg_loop): Fix doc string.
* info/infodoc.c (create_internal_info_help_node): Print out list
of functions which have to keystroke equivalent if we support
NAMED_FUNCTIONS.
* info/filesys.c (compress_suffixes): Add ".gz" for "gunzip" to
alist.
* info/footnotes.c (make_footnotes_node): If refs[i] doesn't have
a nodename, then it couldn't be a reference to a footnote.
* info/nodemenu.c (get_visited_nodes): Handle the case where
filter_func has left no possible buffers to select.
Sat Dec 25 10:35:56 1993 Brian J. Fox (bfox@ai.mit.edu)
* info/infodoc.c (create_internal_info_help_node): Conditionalize
generation of the help node based on the #define
HELP_NODE_GETS_REGENERATED. When this is not set (the default)
the help node is generated exactly once, and is not gc'able.
Otherwise, a new node is always created for the help window, and
the old node gets garbage collected by the gc system.
(info_find_or_create_help_window): Conditionalize window node
selected based on the #define HELP_NODE_GETS_REGENERATED.
* info/dir.c (add_menu_to_file_buffer): Place exactly one blank
line between directory entries.
* info/info.c (version_string): Update minor version to "11".
* info/info.h: Update comment to "2.11".
* info/dir.c (maybe_build_dir_node): Only add the contents of a
new file if it is not identical to the file of the DIR buffer.
* info/nodes.c (info_get_node): Call `maybe_build_dir_node' on
"dir" as well as "localdir" to mimic emacs-19.22 "dir" merging
behaviour.
Fri Dec 3 13:41:44 1993 Brian J. Fox (bfox@ai.mit.edu)
* info/info-utils.c (canonicalize_whitespace): Suppress whitespace
found at the start of STRING.
Sat Nov 20 14:00:50 1993 Brian J. Fox (bfox@hippie)
* info/indices.c (DECLARE_INFO_COMMAND): Fix typo in assignment to
`old_offset' (= instead of ==).
Tue Nov 2 12:22:40 1993 Brian J. Fox (bfox@ai.mit.edu)
* makeinfo/makeinfo.c (make_index_entries_unique): New function
makes a sorted array have all unique entries by appending numbers
to the ends of strings.
(sort_index): Call `make_index_entries_unique'.
Mon Sep 20 12:04:05 1993 Brian J. Fox (bfox@ai.mit.edu)
* makeinfo/makeinfo.c (get_execution_string): New Function returns
a pointer to an EXECUTION_STRING structure.
(execute_string): No longer uses a static string; call
`get_execution_string' instead in order to get a free buffer for
consing.
Sun May 23 07:00:20 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* Texinfo 3.1 released.
Sat May 22 18:21:27 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* info/info.c (info_patch_level): Increment constant to 1.
* info/Makefile.in (DEFAULT_INFOPATH): Default definition deleted.
Makefile.in: Put it here instead.
* Makefile.in (MDEFINES): Add DEFAULT_INFOPATH.
* configure.in: check for vfprintf and vsprintf.
* makeinfo/makeinfo.c: Version 1.55.
* makeinfo/makeinfo.c (add_word_args, execute_string) [HAVE_VARARGS_H]:
Don't use this definition unless HAVE_VSPRINTF is also defined.
(error, line_error, warning) [HAVE_VARARGS_H]: Don't use this
definition unless HAVE_VFPRINTF is also defined.
Remove indentation of all cpp directives, except for #pragma.
Fri May 21 14:34:24 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* texinfo.texi: Rename to texi.texi.
Change @setfilenname and START-INFO-DIR-ENTRY to `texi.info'.
* Makefile.in (MDEFINES): Pass LDFLAGS to sub-makes.
(realclean): Delete `configure'.
Changed all references to texinfo.info to texi.info
* configure.in: Add AC_PROG_RANLIB, and AC_CONST.
Check for `rindex' function.
Check for varargs.h.
Clean up symbol names for header files so a single AC_HAVE_HEADERS
can be used.
(AC_INIT): Use texi.texi instead of makeinfo/makeinfo.c
* info/info-utils.h: Copy definitions of bcopy, index, and rindex
(with appropriate #ifdef wrappers) from termdep.h. These are
included by a mutually exclusive set of files.
* info/termdep.h [HAVE_SYS_PTEM]: Use HAVE_SYS_PTEM_H instead.
* info/terminal.c, info/termdep.h [HAVE_TERMIO]: Use HAVE_TERMIO_H
instead.
* info/makedoc.c, info/filesys.c [!O_RDONLY]: Include fcntl.h or
sys/fnctl.h, depending on whether HAVE_SYS_FCNTL_H is set.
* info/termdep.h: Remove all indentation in #-exprs.
Remove old assumptions about bcopy, index, and rindex.
[HAVE_BCOPY]: Define bcopy.
[HAVE_RINDEX]: Define index and rindex.
* info/nodes.c (info_get_node): Don't call stricmp if nodename is
NULL. Remove indentation in #-exprs.
* info/echo_area.c (echo_area_stack_depth): Declare static.
* info/Makefile.in (DEFAULT_INFOPATH): Make separate Makefile
variable so it can be overridden more easily by the user. Add `.'
to beginning of path.
(clean): Delete core.* (386bsd core files).
(MAKEDOC): Variable removed. Refer to `makedoc' explicitly.
(funs.h): Add `:' commands after if, to avoid spurious nonzero
exit statuses.
* info/userdoc.texi: Improved comments explaining its purpose.
* makeinfo/makeinfo.c [HAVE_VARARGS_H]: Include varargs.h.
(error, line_error, warning, add_word_args,
execute_string)[HAVE_VARARGS_H]: New versions that
use varargs. From bfox.
* makeinfo/Makefile.in (clean): Delete core.* (386bsd core files).
* util/Makefile.in (clean): Remove core.* (386bsd core files).
* libtxi/Makefile.in: Remove all references to $(common).
(RANLIB): New variable, set from autoconf.
(libtxi.a): Use $(RANLIB) instead of `ranlib' in target rules.
(clean): Delete core.* (386bsd core files).
Tue May 18 12:08:24 1993 Robert J. Chassell (bob at grackle.stockbridge.ma.us)
* emacs/texinfmt.el (texinfo-format-refill): Do not fill a section
title line with the asterisks, hyphens, etc. that underline
it in any circumstance.
Sun May 16 13:53:43 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* util/mkinstalldirs: handle relative pathnames.
Fri May 14 20:18:49 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* util/mkinstalldirs: initialize IFS if unset.
Tue May 11 06:33:14 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* makeinfo/makeinfo.c (cm_item): don't dereference item_func if NULL.
Mon May 10 14:50:31 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* Texinfo 3.0 released.
* Makefile.in (ALLOCA): Provide for substitution.
Mon May 10 10:12:53 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* emacs/texinfmt.el (texinfmt-version): Updated year.
Fri Apr 16 04:48:03 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* makeinfo/makeinfo.c: Version 1.54 from bfox.
* util/fixfonts: Replace instances of `[..]' with `test'.
Use more portable `test' arguments: `z$foo = z' instead of `! $foo'.
Robustify quoting in eval assignments.
(textfmdir, texpkdir, texgfdir): Don't override definition from
environment, if any.
Trap EXIT, SIGHUP, SIGINT, SIGQUIT, SIGTERM to delete temp files
instead of trying to remove them explicitly before calling exit.
When changing cwd, do so in subshell, in case various tex*dir
variables are relative.
Don't use `head', `dirname', or `basename'. These don't behave
consistently and/or don't even exist on some systems. They can
all be emulated with `sed' anyway.
(tempfile2_line1): New variable. Use it instead of running
process to extract first line out of tempfile2 multiple times.
Eliminate some gratuitous uses of $tempfile2, such as in for loops.
Fri Mar 26 23:25:13 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* texinfo.texi: @setfilename texinfo.info.
* makeinfo/makeinfo.c (reader_loop, end_insertion): Fix typos in
comments.
(handle_variable_internal): Handle the case that there further
menu text after a false ifset/ifclear.
* util/texi2dvi: Version 0.4
Replace all instances of `[ ... ]' with `test'.
Updated bug-reporting address.
Thu Mar 25 12:31:30 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* info/Makefile.in (install): Install info.1 man page.
(uninstall): Remove installed info.1 man page.
* info/infoman.texi: Standalone manual renamed to info-stnd.texi.
Makefile.in: Targets updated appropriately.
* info/Makefile.in (LDEFS): New variable. Use it for info-local
macros, since DEFS will be inherited from parent make and any
local definitions will get clobbered.
* info/RELEASE: Renamed to info/NEWS.
* README: New file.
* Makefile.in (topclean): New target.
* Getting-started: Renamed to INTRODUCTION. Former name is too
long (over 14 chars).
* New-features: Renamed to NEWS.
* Makefile.in (MDEFINES): Set it.
* Makefile.in (dist): Use --gzip option to tar to make sure
resulting file is compressed with gzip. Change tar file
extension from `.Z' to `.z'.
* Makefile.in (DISTFILES): Filter out any file or directory names
starting with `='.
* fixfonts: Moved to util/fixfonts.
* RELEASE: Deleted.
* makeinfo/Makefile.in (VPATH): Use $(srcdir), not @srcdir@.
(common): Use ../libtxi, not ../common.
(makeinfo.in): Run makeinfo with --no-split.
* makeinfo/makeinfo.texi: Changes from bob.
* util/Makefile.in (VPATH): Use $(srcdir), not @srcdir@.
(common): Use ../libtxi, not ../common.
* util/fixfonts: Moved from top-level directory.
Wed Mar 24 10:21:31 1993 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-format-region): Do not require
`@setfilename' line; delete `\input texinfo' line if part of
region.
* emacs/texinfmt.el (texinfo-raise-lower-sections): Raise or lower the
hierarchical level of chapters, sections, etc. according to
`@raisesections' and `@lowersections' commands.
Thu Mar 18 16:02:27 1993 Robert J. Chassell (bob at grackle)
* emacs/texinfo.el (texinfo-show-structure): Indent *Occur* buffer
according to the structure of the file.
Sat Mar 6 05:16:44 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* util/texi2dvi: use ${1+"$@"}, not just "$@".
Tue Feb 2 08:38:06 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* info/Makefile.in: Replace all "--nosplit" arguments to makeinfo
with "--no-split"
Sun Jan 31 18:16:58 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* util/texi2dvi: Don't put .dvi and related auxillary files in same
directory as source files. Put them in current directory instead.
(TEXINPUTS_orig): New variable.
(file_texi): Variable removed.
(filename_texi): New variable.
(command_line_filename): Use this wherever references to file_texi
occured except in setting filename_noext.
(TEXINPUTS): Current directory and source directory where input
file resides prepended to standard path before invoking TeX.
Wed Jan 27 16:24:37 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* util/Makefile.in: overhauled.
Tue Jan 26 21:04:23 1993 Noah Friedman (friedman@prep.ai.mit.edu)
* Makefile.in, info/Makefile.in, makeinfo/Makefile.in: Overhauled.
* configure.in: Renamed from texinfo.in.
Incorporated makeinfo/makeinfo.in, info/info.in, and
util/util.in. Create all child Makefiles.
* makeinfo/makeinfo.in, info/info.in: Deleted (incorporated into
top configure.in).
* util/util.in: Deleted (incorporated into ../configure.in).
Mon Jan 25 10:59:49 1993 Brian Fox (bfox@cubit)
* info/info.c: New version 2.9; new variable INFO_PATCH_LEVEL
appears in the version string if it is non-zero. New function
version_string () produces the current version string, as in 2.8-p1.
* info/dir.c: New file implements Gillespies `localdir' hacks.
* info/nodes.c (info_get_node): Now calls maybe_build_dir_node ()
if the file name to look for is "dir".
* info/nodes.h: New flag N_CannotGC unconditionally prevents garbage
collection of a file buffer's contents. Used when "dir" is made
from at least one "localdir".
Fri Jan 22 11:36:42 1993 Brian Fox (bfox@cubit)
* info/footnotes.c: Do not declare auto_footnotes_p as "extern" in
this file.
Thu Jan 21 08:57:08 1993 Brian Fox (bfox@cubit)
* info/info.c: New version 2.8.
* info/userdoc.texi, info/infoman.texi, info/info.texi: Fully
document Info; create both online and printed manual versions.
"userdoc.texi" contains exactly the documentation for GNU Info 2.x.
"infoman.texi" is a wrapper for that file; it is meant to produce
printed documentation. "info.texi" has the user documentation as a
complete chapter within itself, but continues to contain the Info
tutorial.
* info/makedoc.c: Convert "ea_" into "echo_area_" when creating the
command name.
Fri Jan 15 16:50:35 1993 Brian Fox (bfox@cubit)
* info/search.c (skip_node_characters): New argument NEWLINES_OKAY if
non-zero says that newlines should be skipped over during parsing.
* info/info-utils.c (info_parse_node): New argument NEWLINES_OKAY if
non-zero says that newlines should be skipped while parsing out
the nodename specification.
Wed Jan 13 14:42:33 1993 Brian Fox (bfox@cubit)
* info/makedoc.c: Remove "info_" from the front of the command name
before installing it.
* info/session.c (info_menu_or_ref_item): A label of "Menu" is okay if
the builder is not info_menu_of_node ();
* info/m-x.c: New function replace_in_documentation () replaces \\[foo]
with the keystrokes you type to get that command. Now used in
indices.c, info.c, infodoc.c.
Mon Jan 11 10:27:41 1993 Brian Fox (bfox@cubit)
* info/variables.c, h: New files contain describe-variable and stuff
moved out of m-x.c.
* info/m-x.c: Move VARIABLE_ALIST and variable functions into
variables.c. Add documentation string to variable definition.
* info/echo_area.c (push_echo_area): Zero the contents of
echo_area_completion_items after pushing the vars.
Sat Jan 9 11:59:47 1993 Brian Fox (bfox@cubit)
* info/Makefile.in: Add footnotes.c,h,o to the appropriate Makefile
variables.
* info/window.c (window_tile_windows): New function divides the
available space among the visible windows.
* info/session.c (info_tile_windows): New function calls
window_tile_windows.
* info/footnotes.c, footnotes.h: New file implements functions for
aiding automatic footnote display when entering a node which has
footnotes.
* info/m-x.c: New user-variable "automatic-footnotes".
* info/window.c (window_physical_lines) New function counts the
carriage returns found in NODE.
Wed Jan 6 11:24:19 1993 Brian Fox (bfox@cubit)
* info/general.h: #include if we have it.
Tue Jan 5 11:12:33 1993 Brian Fox (bfox@cubit)
* info/info-utils.c (info_concatenate_references): If either arg is
NULL, return the other arg.
* info/indices.c (info_indices_of_file_buffer): Simplified and
corrected loop through tags/nodes of file buffer looking for
indices.
* info/search.c (skip_node_characters): Rewrite "if" statement for
clarification and conciseness.
Fri Jan 1 03:18:26 1993 Brian Fox (bfox@cubit)
* info/info.in: Check for setvbuf (), and check to see whether the args
are reversed.
* info/dribble.c (open_dribble_file) Check HAVE_SETVBUF and
SETVBUF_REVERSED when setting the buffering on info_dribble_file.
Thu Dec 31 20:14:13 1992 Brian Fox (bfox@cubit)
* info/session.c (info_select_reference) If the node couldn't be found,
look for the label as a filename (i.e., "(LABEL)Top").
Wed Dec 30 01:57:50 1992 Brian Fox (bfox@cubit)
* New Version 2.7 Beta.
* info/echo_area.c: Numerous functions now do something with the
numeric argument. Kill ring implemented, as well as yank and
yank_pop. Also transpose-chars.
* info/window.c (window_make_modeline): Check node->flags for
N_IsCompressed and display "zz" in the modeline if the node comes
from a file which is compressed on disk.
Mon Dec 28 17:33:12 1992 Brian Fox (bfox@cubit)
* info/filesys.c, info/nodes.c: New member of FILE_BUFFER "FILESIZE"
contains the size of file_buffer->contents. finfo.st_size is no
longer relied upon to read the contents of files, since the new
function (filesys_read_info_file) can read compressed files.
* info/filesys.c (info_find_fullpath) If a file starts with a slash (or
tilde expansion causes it to start with a slash) still call
info_find_file_in_path () on it so that we can find files with
compression suffixes.
* info/m-x.c: New variable "gc-compressed-files".
Tue Dec 22 03:45:28 1992 Brian Fox (bfox@cubit)
* info/info.c: Version 2.6 Beta.
* info/indices.c (info_index_next): Improve the final search for the
matched index entry.
* info/session.c (move_to_screen_line): New function implements `M-r'.
Given a numeric argument, move point to the start of that line in
the current window; without an arg, move to the center line.
* infomap.c: Put move_to_screen_line () on `M-r'.
* info/nodes.c (adjust_nodestart): Don't set N_UpdateTags unless the
node came from a tags table.
* info/nodes.c (info_find_file_internal): If the filename being looked
for doesn't start with a `/', then additionally compare the
filename against the fullpath of the file buffer sans the
directory name. This can happen when selecting nodemenu items.
Mon Dec 21 10:07:18 1992 Brian Fox (bfox@cubit)
* info/session.c, info/display.c: Remove all references to
active_window_ch, active_window_cv, cursor_h, and cursor_v. The
single function display_cursor_at_point () is used for all cursor
movement, and to place the terminal's cursor at the right location
on the screen.
Sat Dec 19 12:01:33 1992 Brian Fox (bfox@cubit)
* info/nodemenu.c: New file implements a few functions for manipulating
previously visited nodes. `list-visited-nodes' produces a menu of
the nodes that could be reached by info_history_node () in some
window. `select-visited-node' is similar to `list-visited-node'
followed by `info-menu-item', but doesn't display a window with
the visited nodes menu.
* info/session.c (info_numeric_arg_digit_loop): If redisplay had been
interrupted, then redisplay all of the windows while waiting for
input.
* info/display.c (display_was_interrupted_p): New variable keeps track
of interrupted display. Used in
info/session.c:info_numeric_arg_digit_loop ().
* info/session.c (info_global_next, info_global_prev): Use the numeric
argument passed to determine how many nodes to move.
* info/session.c (info_scroll_forward, info_scroll_backward): If the
invoking key is not SPC or DEL only do Page Only scrolling.
Thu Dec 17 01:34:22 1992 Brian Fox (bfox@cubit)
* info/display.c (display_update_one_window): Allow W_NoWrap to affect
window display.
* info/window.c (calculate_line_starts): Now takes a WINDOW * as an
argument, and simply does the calculation, placing the results
into window->line_starts and window->line_count. It also handles
W_NoWrap in window->flags.
Mon Dec 14 02:18:55 1992 Brian Fox (bfox@cubit)
* info/session.c (info_backward_scroll): Don't try to get previous node
if the top of the node isn't currently being displayed.
* info/window.c (window_adjust_pagetop) Use new variable
"window_scroll_step" to attempt to control the amount which the
window scrolls.
* info/m-x.c (info_variables) Add "scroll-step" to the list.
Thu Dec 10 08:52:10 1992 Brian Fox (bfox@cubit)
* info/m-x.c: New variable entry show-index-matches. When set to
non-zero the matched portion of the search string is indicated
with ` and '. Perhaps I should use `|' inst|ea|d?
* info/echo_area.c (ea_possible_completions): Always build completions
before checking to see how many there were.
* info/info-utils.c: (info_concatenate_references): New utility
function concatenates references.
* info/Makefile.in: Add indices.c and indices.h to SRCS and HDRS.
Add indices.c to CMDFILES.
* info/indices.c, info/indices.h: New file implements `i' and `,'
commands of info, and provides index searching capabilities.
* info/echo_area.c (info_read_completing_in_echo_area): Split off into
separate callable function info_read_completing_internal ().
* info/echo_area.c (info_read_maybe_completing): New function calls
info_read_completing_internal () with non-forcing argument.
* info/session.c: Rename down_next_upnext_or_error () and
prev_up_or_error () to forward_move_node_structure (), and
backward_move_node_structure (). Implement new commands
info_global_next () and info_global_prev ().
* info/infomap.c (initialize_info_keymaps): Bind `[' and `]' to
backward_, forward_move_node_structure () respectively.
* info/session.c (info_menu_digit): Called with "0" as arg, select the
last menu item.
* info/infomap.c (initialize_info_keymaps): "0" calls
info_menu_digit ().
* info/session.c (info_move_to_xref): Take dir into account when there
are xrefs and menu items in the node and we are wrapping
backwards.
Tue Dec 8 09:57:58 1992 Brian Fox (bfox@cubit)
* info/info.c: Version 2.5 Beta.
* info/terminal.c (terminal_insert_lines, terminal_delete_lines) Do not
expect tgoto to return a new string; it returns the address of a
static buffer.
* info/infodoc.c (info_find_or_create_help_window) Correct check for
prior existing help node.
* info/m-x.c (set_variable): Allow variables to have a list of choices.
Add new variable scroll-behaviour.
* info/session.c (down_next_upnext_or_error, prev_up_or_error) New
functions implement user-controlled behaviour when attempting to
scroll past the bottom or top of a node. New variable
info_scroll_behaviour is user visible as "scroll-behaviour".
* info/session.c (info_scroll_forward, info_scroll_backward) Call new
functions for user-controlled scroll behaviour.
* info/terminal.c (terminal_initialize_terminal) Set PC from BC not
from BUFFER.
Mon Dec 7 11:26:12 1992 Brian Fox (bfox@cubit)
* util/texindex.c: Change EXIT_SUCCESS and EXIT_FATAL to TI_NO_ERROR
and TI_FATAL_ERROR respectively. This avoids namespace conflicts
on NeXT 2.0.
Sat Dec 5 00:07:59 1992 Brian Fox (bfox@cubit)
* info/info.c: New option "--subnodes" says to recursively dump the
menus of the nodes that you wish to dump. Menu items which point
to external nodes are not dumped, and no node is dumped twice.
Thu Dec 3 16:11:02 1992 Brian Fox (bfox@cubit)
* info/session.c (info_error) Don't ring the bell if
info_error_rings_bell_p is zero. (info_abort_key) Ring the bell
if printing "Quit" in the echo area wouldn't do it.
* info/m-x.c (set_variable) New functions allows setting of
variables in the echo area. Currently, only visilble-bell and
errors-ring-bell are implemented.
Wed Dec 2 13:11:37 1992 Brian Fox (bfox@cubit)
* info/nodes.c, info/makedoc.c: If O_RDONLY is not defined by
sys/file.h, include sys/fcntl.h.
* info/filesys.c (info_file_in_path): Expand leading tildes found
within directory names.
* info/terminal.c (terminal_initialize_terminal) Set ospeed to 13 if
not settable any other way. It is an index into an array of
output speeds.
* info/display.c (free_display) Do not free a NULL display.
* info/display.c (string_width): New functions returns the width of
STRING when printed at HPOS.
Sun Nov 29 01:24:42 1992 Brian Fox (bfox@cubit)
* info/info.c: New version 2.4 beta.
* info/general.h: #define info_toupper and info_tolower which check
their arguments before performing any conversion.
* info/search.c, info/echo_area.c: Use info_toupper.
Sat Nov 28 14:23:24 1992 Brian Fox (bfox@cubit)
* info/session.c (info_scroll_forward, info_scroll_backward) If at
last/first page of the node, and the last command was
forward/backward, do info_next/prev/_node.
* info/session.c: New function info_select_reference_this_line gets
menu or cross reference immediately.
* info/infomap.c (initialize_info_keymaps): Add info_keymap[LFD] to
invoke info_select_reference_this_line ().
* info/session.c (info_last_reference) Rename to
info_history_reference. Wrote info_last_reference, and
info_first_reference which go to the last or first node of an info
file.
Fri Nov 27 00:59:02 1992 Brian Fox (bfox@cubit)
* info/info.c: New version 2.3. Completed implementing contents of
TODO file.
* info/session.c (info_redraw_display): Fix C-l with numeric arg.
Thu Nov 26 20:14:18 1992 Brian Fox (bfox@cubit)
* info/m-x.c: New file implements reading named commands in the echo
area, along with a new function "info-set-screen-height".
Compilation of this file and some code in others controlled by the
Makefile variable NAMED_COMMANDS (set to -DNAMED_COMMANDS).
* info/window.c (window_new_screen_size) Rewrite from scratch, allowing
clean growth and shrinkage of the screen. New variable
window_deletion_notifier is a pointer to a function to call when
the screen changes size, and some windows have to get deleted.
The function is called with the window to be deleted as an
argument, and it should clean up dangling references to that
window.
* info/session.c (initialize_info_session): Set
window_deletion_function to forget_window_and_nodes.
* info/display.c (display_update_one_window): If the first row of the
window to display wouldn't appear in the_screen, don't try to
display it. This happens when the screen has been made
unreasonably small, and we attempt to display the echo area.
Tue Nov 24 00:47:20 1992 Brian Fox (bfox@cubit)
* Release Info 2.2.
* info/session.c: New functions implement reading typeahead and
implement C-g flushing typed ahead characters.
(info_search_internal): allows C-g to exit multi-file searches.
Mon Nov 23 01:53:35 1992 Brian Fox (bfox@cubit)
* info/nodes.c: Remove calls to sscanf (), replacing them with calls to
atol (), since that is much faster.
(get_nodes_of_tags_table) Only check for "(Indirect)" if we
haven't parsed any nodes out of the tags table. Increase the
amount that file_buffer->nodes grows to 100 from 50. These two
together sufficiently speed up the parsing process.
* info/nodes.c: info_get_node_of_file_buffer_tags (),
info_get_node_of_file_buffer_nodes (): Search the appropriate list
and return a node. This was simply a cut and paste edit to
functionalize the code.
* info/TODO: Remove suggestion for partial tag parsing, since tag
parsing is much faster now.
Sat Nov 21 02:48:23 1992 Brian Fox (bfox@cubit)
* info/makedoc.c: New File replaces makedoc.sh shell script.
* info/infomap.c: Install info_isearch (on C-s) and
info_reverse_isearch (on C-r) for Info windows.
* info/session.c (incremental_search, info_isearch,
info_reverse_isearch) New functions implement incremental
searching.
Fri Nov 20 00:01:35 1992 Brian Fox (bfox@cubit)
* info/terminal.c (terminal_initialize_terminal): Declare and set up
`ospeed'. Turn off C-s and C-q processing.
* info/session.c (info_show_point) When this function is called, the
desired result is to show the point immediately. So now it calls
set_window_pagetop () if the new pagetop is not the same as the
old one. This means that info_prev_line (), info_next_line (),
info_forward_word (), and info_backward_word () can all scroll the
window if they have to.
Thu Nov 19 12:27:07 1992 Brian Fox (bfox@cubit)
* info/session.c (set_window_pagetop): Add scrolling to make this
faster.
* info/echo_area.c (push/pop_echo_area): Remember the list of items to
complete over.
* info/session.c (info_forward_char): Don't let point get equal to
nodelen, only to nodelen - 1.
* info/display.c: New function display_scroll_display () scrolls the
rmembered display as well as the text on the actual display.
* info/terminal.c: New functions terminal_scroll_terminal (),
terminal_scroll_down (), and terminal_scroll_up (). All
implemented using "al" and "dl" termcap capabilities. (i.e.,
insert and delete line).
Wed Nov 18 15:05:14 1992 Brian Fox (bfox@cubit)
* info/termdep.h: Only define HAVE_FCNTL_H if !aix and !ultrix.
Tue Nov 17 20:35:08 1992 Brian Fox (bfox@cubit)
* First Beta Release of Info 2.0.
Sun Nov 1 02:21:05 1992 Noah Friedman (friedman@prep.ai.mit.edu)
* util/texi2dvi (--force): Option removed. Always run tex at least
once, don't bother checking if .dvi file is newer than source.
Fri Oct 30 02:16:28 1992 Noah Friedman (friedman@prep.ai.mit.edu)
* util/texi2dvi (-D): debugging option renamed from '-d'.
Made check to enable debugging more terse.
When checking if index files have changed, use
variable $this_file instead of $file in for loop.
(file_texi): wherever the variable $file was used to reference
the texinfo file, substituted $file_texi.
Sat Oct 17 07:30:34 1992 Brian J. Fox (bfox@helios)
* util/texindex.c: Remove references to USG replacing them with a
define declaring the actual feature required or missing.
Thu Oct 15 16:17:47 1992 Robert J. Chassell (bob@nutrimat.gnu.ai.mit.edu)
* emacs/texinfmt.el (texinfo-format-setfilename): Remove date from
Info file header so regression testing is easier.
Tue Sep 15 16:28:35 1992 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfmt-version): New variable.
(texinfo-format-setfilename): Include date and
version in Info file header.
Better documentation for @definfoenclose
Handle whitespace after @end iftex, etc.
Thu Sep 3 09:25:37 1992 Robert J. Chassell (bob at grackle)
* emacs/texnfo-upd.el: Fix typo re `texinfo-sequential-node-update.'
Tue Aug 18 08:56:24 1992 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-value): Revise syntax.
* emacs/texnfo-upd.el (texinfo-start-menu-description):
New function to insert title as description in a menu.
(texinfo-make-menu-list): Remove automatic title insertion.
* emacs/texinfo.el (texinfo-mode-map): Add keybinding for
texinfo-start-menu-description.
Wed Jul 29 11:58:53 1992 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-set): Revise to set a string to the flag.
(texinfo-value): @value{flag}: New command which inserts the
string to which the flag is set.
Tue Jul 7 15:10:52 1992 Robert J. Chassell (bob at grackle)
* emacs/texnfo-upd.el (texinfo-master-menu): Error message if file
contains too few nodes for a master menu.
(texinfo-insert-master-menu-list): Only attempt to insert detailed
master menu if there is one.
Wed Jun 10 15:26:18 1992 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-append-refill): Refill properly when lines
begin with within-paragraph @-commands.
Tue Jun 9 12:28:11 1992 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el: Add `texinfo-deffn-formatting-property' and
`texinfo-defun-indexing-property' to @deffn commands.
Mon Jun 8 11:52:01 1992 Robert J. Chassell (bob at grackle)
* emacs/texnfo-upd.el: Replace `(mark-whole-buffer)' with
`(push-mark (point-max) t) (goto-char (point-min))'
to avoid `Mark set' messages.
Fri Jun 5 15:15:16 1992 Robert J. Chassell (bob@kropotkin.gnu.ai.mit.edu)
* emacs/texnfo-upd.el (texinfo-check-for-node-name): Offer section
title as prompt.
(texinfo-copy-next-section-title): Copy title correctly.
Thu May 28 20:34:17 1992 Robert J. Chassell (bob@hill.gnu.ai.mit.edu)
* emacs/texinfmt.el: @vtable defined, parallel to @ftable, for
variables.
(texinfo-append-refill): set case-fold-search nil so @TeX is not
confused with @tex.
Thu Mar 26 21:36:41 1992 Robert J. Chassell (bob@kropotkin.gnu.ai.mit.edu)
* emacs/makeinfo.el: Rename temp buffer from `*Makeinfo*' back to
`*compilation*' so `next-error' works; unfortunately,
`*compilation*' is written into the code as the name
`next-error' needs.
Rename `makeinfo-recenter-makeinfo-buffer' back to
`makeinfo-recenter-makeinfo-buffer'
Thu May 14 21:14:25 1992 Noah Friedman (friedman@prep.ai.mit.edu)
* util/fixfonts: Enclosed most variable references with "" to prevent
potential globbing and other weirdness. Eliminated uses of
${var-value}, which unfortunately isn't portable.
* util/texi2dvi: rewritten from scratch.
Sat Apr 18 23:46:25 1992 Charles Hannum (mycroft@hal.gnu.ai.mit.edu)
* util/fixfonts: Re-evaluate prefix and libdir if inherited (to resolve
variable references from make).
(texlibdir): Don't add '/tex', since it's already there.
Fri Apr 10 14:51:23 1992 Noah Friedman (friedman@prep.ai.mit.edu)
* util/fixfonts: set prefix and libdir only if they are not already
defined (i.e. not inherited from the environment).
Changed default path for libdir to be consistent with Makefile.
Tue Mar 3 13:17:42 1992 Robert J. Chassell (bob at grackle)
* emacs/texnfo-upd.el (texinfo-insert-master-menu-list): Insert a
master menu only after `Top' node and before next node.
(texinfo-copy-menu): Error message if menu empty.
Mon Feb 24 15:47:49 1992 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-format-region): Make sure region ends in a
newline.
(texinfo-itemize-item): Recognize all non-whitespace on same line
as @item command.
Sat Feb 22 02:15:00 1992 Brian Fox (bfox at gnuwest.fsf.org)
* util/texindex.c: New version 1.45 has cleanups, should compile under
VMS quietly.
Wed Feb 12 10:50:51 1992 Robert J. Chassell (bob at grackle)
* emacs/makeinfo.el: Rename temp buffer as *Makeinfo*.
Rename `makeinfo-recenter-compilation-buffer'.
(makeinfo-buffer): Offer to save buffer if it is modified.
(makeinfo-compile): Do not offer to save other buffers.
(makeinfo-compilation-sentinel): Switch to Info file.
Tue Feb 4 13:07:39 1992 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-print-index): Format so that node names in
the index are lined up.
Mon Feb 3 09:08:14 1992 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-itemize-item): Format entry when text
is on the same line as @item command. Also, handle @-commands.
(texinfo-format-region, texinfo-format-buffer-1): Set fill column
to local value of Texinfo buffer.
* emacs/texnfo-upd.el (texinfo-pointer-name): Find only those
section commands that are accompanied by `@node' lines.
Tue Jan 14 16:10:16 1992 Robert J. Chassell (bob at grackle)
* emacs/texnfo-upd.el: Ensure that no commands depend on the value of
case-fold-search.
Fri Jan 10 15:13:55 1992 Robert J. Chassell (bob at kropotkin)
* emacs/texinfmt.el (texinfo-append-refill): Replace use of
unsupported function `looking-at-backward' with
`re-search-backward'.
Mon Dec 23 23:46:42 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* util/texindex.c: Change POSIX ifdefs to HAVE_UNISTD_H and
_POSIX_VERSION.
Mon Dec 16 15:01:36 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-append-refill): New function appends
@refill to all appropriate paragraphs so you no longer need to
append @refill command yourself.
(texinfo-format-region, texinfo-format-buffer-1,
texinfo-format-include): Call `texinfo-append-refill'.
Fri Dec 6 01:25:09 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* util/texindex.c: Conditionalize on _AIX (which is predefined) instead
of AIX, just like makeinfo does.
Tue Nov 26 10:21:04 1991 Robert J. Chassell (bob at grackle)
* emacs/texnfo-upd.el (texinfo-section-types-regexp): `@subtitle' no
longer treated as subsection.
Sat Nov 16 08:27:42 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu)
* util/fixfonts: New file, from Karl Berry.
Tue Nov 12 16:13:24 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el: Create @end smalllisp.
Mon Nov 11 16:50:13 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfo.el (texinfo-environment-regexp): Add all other block
enclosing Texinfo commands.
Thu Nov 7 10:23:51 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfo.el (texinfo-insert-@end): Attempt to insert correct end
command statement, eg, @end table. Fails with nested lists.
(texinfo-insert-*): Accept prefix arg to surround following N
words with braces for command.
Thu Oct 31 21:31:41 1991 Robert J. Chassell (bob at kropotki)
* emacs/texinfmt.el (texinfo-clear): Clear flag even if flag not
previously set.
Wed Oct 23 11:15:58 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfo.el (texinfo-mode): page-delimiter now finds top node as
well as chapters.
Tue Oct 22 11:46:12 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-do-flushright): Test whether a line is too
long for the flush right command (line length must be less than
the value of fill column).
* emacs/texnfo-tex.el (texinfo-tex-buffer): Prompt for original file
even if point moved to *texinfo-tex-shell*.
texinfo-tex-original-file: variable to hold file name.
Wed Oct 16 08:32:05 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-format-center): Expand string before
centering so @-commands not included.
Thu Oct 10 22:01:47 1991 Robert J. Chassell (bob at kropotki)
* emacs/texnfo-tex.el (texinfo-show-tex-print-queue): Do not kill a
running process; do start a process none exists.
Thu Sep 26 21:58:47 1991 Robert J. Chassell (bob at kropotki)
* util/texi2dvi: Misc. bugs fixed.
* emacs/texinfo.el: Remove extraneous references to TeX.
Thu Sep 19 20:45:29 1991 Robert J. Chassell (bob at kropotki)
* emacs/texinfmt.el: add @cartouche as a noop (makes box with rounded
corners in TeX)
Tue Sep 10 20:44:57 1991 Robert J. Chassell (bob at grackle)
* emacs/texnfo-upd.el (texinfo-make-one-menu): Copy node-name correctly
for message.
Thu Aug 29 17:54:07 1991 Robert J. Chassell (bob at kropotki)
* emacs/texnfo-tex.el (texinfo-quit-tex-job): Do not set mark.
Wed Aug 21 10:36:21 1991 Robert J. Chassell (bob at grackle)
* emacs/texnfo-upd.el: (texinfo-copy-menu-title): Copy title as it
should rather than node line.
Mon Aug 5 15:27:12 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el (texinfo-format-convert): Changed regexp that
looks for three hyphens in a row to find those between word
constituent characters, as now, for Oxford Univ. style dashes and
also between spaces, for Cambridge Univ. Press style dashes.
* emacs/texnfo-tex.el (texinfo-tex-start-shell): Runs "/bin/sh" so
`explicit-shell-file-name' is not set globally.
* emacs/texnfo-upd.el: Rewrite messages.
(texinfo-find-higher-level-node): Stop search at limit.
(texinfo-copy-menu-title): Rewrite to handle outer include files.
(texinfo-multi-file-update): Update all nodes properly;
rewrite doc string and interactive.
Sat Aug 3 10:46:13 1991 Robert J. Chassell (bob at grackle)
* emacs/texnfo-upd.el (texinfo-all-menus-update): Fixed typo that
caused the function to create a master menu when it shouldn't.
* emacs/texinfo.el (texinfo-mode): Make `indent-tabs-mode' a local
variable and set to nil to prevent TABs troubles with TeX.
Wed Jul 31 11:07:08 1991 Robert J. Chassell (bob at grackle)
* emacs/texnfo-tex.el (texinfo-quit-tex-job): New function: quit
currently running TeX job, by sending an `x' to it.
(texinfo-tex-shell-sentinel): New function to
restart texinfo-tex-shell after it is killed.
(texinfo-kill-tex-job): Rewrite to use kill-process rather than
quit-process; uses `texinfo-tex-shell-sentinel' to restart
texinfo-tex-shell after it is killed.
(texinfo-tex-region, texinfo-tex-buffer): Replace
texinfo-kill-tex-job with quit-process.
* emacs/texinfo.el (texinfo-define-common-keys): Add keybinding for
texinfo-quit-tex-job
Wed Jul 10 15:15:03 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el: New commands @set, @clear, @ifset...@end
ifset, and @ifclear...@end ifclear.
Definition functions rewritten to make them easier to
maintain.
Wed Jul 3 19:37:04 1991 Robert J. Chassell (bob at kropotki)
* emacs/texinfmt.el (texinfo-format-deftypefn-index): Remove reference
to data-type to make consistent with texinfo.tex and makeinfo.
texinfo.el: Fix page-delimiter and texinfo-chapter-level-regexp
variables.
Thu Jun 27 18:35:36 1991 Robert J. Chassell (bob at nutrimat)
* emacs/texinfmt.el: Add @dmn as `texinfo-format-noop'.
texinfo2.texi: Document @dmn.
texinfmt.el (texinfo{,-end}-{eleterate,ecapitate} renamed
{alphaenumerate, capsenumerate}.
Fri Jun 14 12:46:32 1991 Robert J. Chassell (bob at churchy.gnu.ai.mit.edu)
* emacs/texinfmt.el (texinfo-format-defun-1): @defivar prints name
correctly.
Thu Jun 6 21:38:33 1991 Robert J. Chassell (bob at churchy.gnu.ai.mit.edu)
* emacs/texinfo.el (texinfo-mode): Set page delimiter to
'texinfo-chapter-level-regexp' so that page commands work by
chapter or equivalent.
* emacs/texinfmt.el (texinfo-format-defun-1): @defop prints name
correctly.
(batch-texinfo-format): replace unsupported
'buffer-disable-undo' with 'buffer-flush-undo'
Fri Apr 5 15:17:17 1991 Robert J. Chassell (bob at wookumz.gnu.ai.mit.edu)
* emacs/makeinfo.el (makeinfo-compilation-sentinel): Check for
existance of makeinfo-temp-file to avoid harmless error message.
texinfo2.texi: Minor typos fixed.
Thu Mar 28 19:13:24 1991 Robert J. Chassell (bob at pogo.gnu.ai.mit.edu)
* util/texi2dvi: Revised.
Mon Mar 11 12:35:51 1991 Robert J. Chassell (bob at grackle)
* emacs/texinfmt.el: (@footnotestyle): New command to set
footnotestyle.
(@paragraphindent): New command to set indentation.
(texinfo-format-refill): Add indentation feature so as to
indent paragraph or leave indentation asis before refilling
according to value set by @paragraphindent command.
(texinfo-format-region): Insert header, if any, into Info buffer.
(texinfo-format-separate-node, texinfo-format-end-node): Run
texinfo-format-scan on footnote text only once.
(texinfo-format-scan): Shorten `---' to `--'.
* emacs/texinfo.el: Define key for `texinfo-master-menu'; define
start and end of header expressions.
* emacs/texnfo-upd.el (texinfo-all-menus-update): Update
pre-existing master menu, if there is one.
Fri May 11 14:36:07 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
* util/texindex.c: Rename `lines' to `nlines'.
(bzero): Pass arg to lib$movc5 through non-register var.
(perror_with_file, pfatal_with_file): Move extern decls and includes
to top of file.
[VMS]: If not using VMS C, define away `noshare' keyword.
Include perror.h.
Mon Jul 11 18:02:29 1988 Chris Hanson (cph at kleph)
* util/texindex.c (indexify): when comparing to initial strings to
decide whether to change the header, must use `strncmp' to avoid
comparing entire strings of which initials are a substring.
Sun Jun 26 18:46:16 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
* util/texindex.c (sort_in_core, sort_offline, parsefile):
Give up on input file if any line doesn't start with backslash.
texinfo-3.7/INSTALL 100666 11732 13 17051 6053165061 12311 0 ustar bfox user Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made.
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.
texinfo-3.7/INTRODUCTION 100666 21641 13 10717 5505636066 13766 0 ustar friedman user Getting Started with Texinfo
============================
25 March 1993
Most of the installation instructions are described in the file `INSTALL'.
One additional note to make is that if your info files are in a nonstandard
place (i.e. not in the `info' directory immediately under $prefix) you may
wish to change the default info path as specified via DEFAULT_INFOPATH in
info/Makefile.in.
"Texinfo" is a documentation system that uses a single source file to
produce both on-line information and printed output. Using Texinfo,
you can create a printed document with the normal features of a book,
including chapters, sections, cross references, and indices. From the
same Texinfo source file, you can create a menu-driven, on-line Info
file with nodes, menus, cross references, and indices.
The name of the Texinfo source documentation file is `texinfo.texi'.
You can produce both on-line information and printed output from this
source file. The documentation describes Texinfo in detail, including
how to write Texinfo files, how to format them for both hard copy and
Info, and how to install Info files.
To get started, you need to create either a printed manual or an
on-line Info file from the `texinfo.texi' file. You do not need to
create both, although you will probably want both eventually.
To learn how to use Info, read the info documentation. You can do this in
one of two ways: using the standalone `info' program, or using Info mode in
GNU Emacs.
* If you want to use the `info' program, type
$ info -f info-stnd
* If you want to use Emacs, start up emacs and type `C-h i' [M-x info].
Follow the instructions to learn how to use Info.
After learning how to use Info, you can read the Texinfo documentation.
Using the standalone `info', type the following at the shell prompt:
$ info -f texinfo
To use read this manual in Emacs, you first need to edit the Info-directory
menu (the file `dir' in the system info directory) to contain the
appropriate node. To learn how to do this, see node: Add in the Info
documentation.
The Texinfo documentation describes Texinfo in detail; among other things,
it tells how to install Info files in the usual manner. (See node: Install
an Info File.)
The `info-stnd.info' file describes the standalone Info reader in detail. To
read this file, type
$ info -f info-stnd
If you are using GNU Emacs, you may want to install the Emacs Lisp files
permanently. Move them them to a directory in the load-path for Emacs;
otherwise Emacs will not be able to load the autoloaded support files, such
as `texinfmt.el'.
The `texinfo.el' file contains the autoload commands; it is the only
file that needs to be loaded initially. If your Emacs does not
automatically load `texinfo.el', you can tell it to do so by placing
the following in `default.el' or in your `.emacs' file:
(load "texinfo")
To create a printed manual
==========================
You need:
* The `tex' program, which typesets the manual using TeX.
* The `texinfo.tex' definition file that tells TeX how to typeset
a Texinfo file.
* The `texindex' program, which sorts the unsorted index files
created by TeX.
* A printing program such as `lp' or `lpr',
* A printer.
This Texinfo distribution package contains `texinfo.tex', the C source
for `texindex', and the handy shell script `texi2dvi'. The `tex'
program is not part of this distribution, but is available separately.
(See `How to Obtain TeX' in the Texinfo documentation.)
* Install `tex'. (`texindex' is installed automagically by
`make install' in this distribution.)
* Move the `texinfo.tex' file to an appropriate directory; the current
directory will do. (`/usr/local/lib/tex/inputs' might be a good place.
See ``Preparing to Use TeX'' in the Texinfo manual, for more
information.)
After following those instructions, type the following to make the .dvi
files:
$ make texinfo.dvi
$ (cd info; make info.dvi info-stnd.dvi)
$ (cd makeinfo; make makeinfo.dvi)
You can then print the resulting .dvi files with the `lpr' command (on BSD
systems. On SysV systems the command is `lp'. Consult your man pages for
more information).
For example, the command to print the texinfo.dvi file might be:
$ lpr -d texinfo.dvi
The name of the printing command depends on the system; `lpr -d' is
common, and is illustrated here. You may use a different name for the
printing command.
Please report bugs to bug-texinfo@prep.ai.mit.edu.
Happy formatting.
texinfo-3.7/Makefile.in 100666 11732 13 12526 6067064344 13336 0 ustar bfox user # Makefile for Texinfo distribution. -*- Indented-Text -*-
# Copyright (C) 1993 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.
#### Start of system configuration section. ####
srcdir = @srcdir@
VPATH = $(srcdir):$(common)
common = $(srcdir)/libtxi
CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
LN = ln
RM = rm -f
TAR = tar
MKDIR = mkdir
DEFS = @DEFS@
LIBS = @LIBS@
LOADLIBES = $(LIBS)
ALLOCA = @ALLOCA@
SHELL = /bin/sh
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = $(exec_prefix)/bin
# Prefix for each installed program, normally empty or `g'.
binprefix =
libdir = $(prefix)/lib
# Prefix for each installed man page, normally empty or `g'.
manprefix =
mandir = $(prefix)/man/man1
manext = 1
infodir = $(prefix)/info
# For info program.
DEFAULT_INFOPATH = $(infodir):.
#### End of system configuration section. ####
VERSION = 3.7
DISTNAME = texinfo-$(VERSION)
# Subdirectories that have makefiles
SUBDIRS = libtxi makeinfo info util emacs
# All subdirectories that go into a distribution
ALL_SUBDIRS = $(SUBDIRS) makeinfo/macros
MDEFINES = bindir='$(bindir)' mandir='$(mandir)' manext='$(manext)' \
prefix='$(prefix)' binprefix='$(binprefix)' \
manprefix='$(manprefix)' infodir='$(infodir)' CFLAGS='$(CFLAGS)' \
CC='$(CC)' ALLOCA='$(ALLOCA)' LDFLAGS='$(LDFLAGS)' \
DEFAULT_INFOPATH='$(DEFAULT_INFOPATH)'
all: sub-all texinfo
install: all installdirs
for dir in $(SUBDIRS); do \
echo making $@ in $$dir; \
(cd $$dir && $(MAKE) $(MDEFINES) $@ || exit 1); \
done
d=$(srcdir); test -f ./texinfo && d=.; \
(cd $$d; \
for f in texinfo texinfo-* ; do \
$(INSTALL_DATA) $$f $(infodir)/$$f; \
done)
installdirs:
-sh $(srcdir)/util/mkinstalldirs $(bindir) $(datadir) $(libdir) $(infodir) $(mandir)
uninstall:
for dir in $(SUBDIRS); do \
echo making $@ in $$dir; \
(cd $$dir && $(MAKE) $(MDEFINES) $@ || exit 1); \
done
$(RM) $(infodir)/texinfo $(infodir)/texinfo-*
Makefile: Makefile.in config.status
sh ./config.status
config.status: configure
sh ./config.status --recheck
configure: configure.in
cd $(srcdir); autoconf
sub-all TAGS:
for dir in $(SUBDIRS); do \
echo making $@ in $$dir; \
(cd $$dir && $(MAKE) $(MDEFINES) $@ || exit 1); \
done
clean mostlyclean:
for dir in $(SUBDIRS); do \
echo making $@ in $$dir; \
(cd $$dir && $(MAKE) $(MDEFINES) $@ || exit 1); \
done
distclean: clean texclean
for dir in $(SUBDIRS); do \
echo making $@ in $$dir; \
(cd $$dir && $(MAKE) $(MDEFINES) $@ || exit 1); \
done
$(RM) Makefile *.status *.cache *.log texinfo texinfo-? texinfo-??
texclean:
$(RM) *.aux *.cp *.cps *.dvi *.fn *.fns *.ky *.kys *.pg *.pgs
$(RM) *.toc *.tp *.tps *.vr *.vrs
realclean: distclean
texinfo: sub-all
./makeinfo/makeinfo -I$(srcdir) texinfo.texi
texinfo.dvi:
PATH="$(srcdir)/util:$${PATH}" TEXINPUTS="$(srcdir):$(common):$${TEXINPUTS}" texi2dvi $(srcdir)/texinfo.texi
dist: DISTFILES
$(RM) -rf $(DISTNAME)
$(MKDIR) $(DISTNAME)
for d in `find . -type d ! -name RCS -print`; do \
d=`echo $$d | grep -v '='`; \
if [ "$$d" != "" ]; then \
if [ "$$d" != "." -a "$$d" != "./$(DISTNAME)" ]; then \
mkdir $(DISTNAME)/$$d; \
fi; \
fi; \
done
for f in `cat DISTFILES`; do \
$(LN) $(srcdir)/$$f $(DISTNAME)/$$f || \
{ echo copying $$f; cp -p $(srcdir)/$$f $(DISTNAME)/$$f ; } \
done
(cd $(DISTNAME); $(MAKE) $(MFLAGS) distclean)
$(TAR) chvf - $(DISTNAME) | gzip >$(DISTNAME).tar.gz
$(RM) -rf $(DISTNAME)
# Gets rid of most of the unwanted files. Verify manually (if necessary)
# that this produces a list of all the files desired in the distribution.
DISTFILES: force
(cd $(srcdir); find . ! -type d -print) \
| sed '/\/RCS\//d; \
/\/EMACS-BACKUPS\//d; \
/\.tar.*/d; \
/~$$/d; /\.o$$/d; \
/\.orig$$/d; \
/\#$$/d; \
/\/info\/info$$/d; \
/\.info$$/d; \
/\.elc/d; \
/\/makeinfo\/makeinfo$$/d; \
/\/$(DISTNAME)\/.*$$/d; \
/\/util\/texindex$$/d; \
/texinfo$$/d; \
/texinfo-[0-9]+$$/d; \
/\/.*\.BAK$$/d; \
/\/.*\.a$$/d; \
/\/core$$/d; \
/\/*\.core$$/d; \
/\/core\..*$$/d; \
/\/a.out$$/d; \
/\/=/d; \
/\/conftest\.c$$/d; \
/\/DISTFILES$$/d; \
/\/foo$$/d; \
/\/bar$$/d; \
/\.toc$$/d; \
/\.aux$$/d; /\.log$$/d; \
/\.cps$$/d; /\.cp$$/d; \
/\.fns$$/d; /\.fn$$/d; \
/\.tps$$/d; /\.tp$$/d; \
/\.vrs$$/d; /\.vr$$/d; \
/\.pgs$$/d; /\.pg$$/d; \
/\.kys$$/d; /\.ky$$/d; \
s/^.\///; /^\.$$/d;' \
| sort | uniq > DISTFILES
force:
# Prevent GNU make v3 from overflowing arg limit on SysV.
.NOEXPORT:
texinfo-3.7/NEWS 100666 11732 13 23150 5764642706 11772 0 ustar bfox user Please report bugs you find to bug-texinfo@prep.ai.mit.edu
Changes between Texinfo 3.0 and 3.2:
Many bug fixes, and a few functional additions. Note that standalone
Info can now read Un*x man pages.
Changes between Texinfo 3.0 and 3.1:
Just bug fixes, see ChangeLog for full details.
Texinfo 2
*********
The second edition of the Texinfo manual is now released in a package
with the second version of the various Texinfo support files,
including `texinfo.el', `texnfo-upd.el', and `makeinfo.c'. The new
manual is considerably larger than the previous one.
Here is a brief description of the new Texinfo mode commands
and the newly described @-commands:
New Texinfo Mode Commands
=========================
Texinfo mode provides commands and features especially designed for
working with Texinfo files. More than 20 new commands have been
added, including commands for automatically creating and updating both
nodes and menus. This is a tedious task when done by hand.
The keybindings are intended to be somewhat mnemonic.
Update everything
-----------------
The `texinfo-master-menu' command is the primary command:
C-c C-u m Create or update a master menu.
With an argument, first create or
update all nodes and regular menus.
Update Pointers
---------------
Create or update `Next', `Previous', and `Up' node pointers.
C-c C-u C-n Update a node.
C-c C-u C-e Update every node in the buffer.
Update Menus
------------
Create or update menus.
C-c C-u C-m Make or update a menu.
C-c C-u C-a Make or update all the menus
in a buffer; with an argument,
first update all the nodes.
Insert Title as Description
---------------------------
Insert a node's chapter or section title in the space for the
description in a menu entry line; position point so you can edit the
insert. (This command works somewhat differently than the other
insertion commands, which insert only a predefined string.)
C-c C-c C-d Insert title.
Format for Info
---------------
Provide keybindings both for the Info formatting commands that are
written in Emacs Lisp and for `makeinfo' which is written in C.
Use the Emacs lisp `texinfo-format...' commands:
C-c C-e C-r Format the region.
C-c C-e C-b Format the buffer.
Use `makeinfo':
C-c C-m C-r Format the region.
C-c C-m C-b Format the buffer.
C-c C-m C-l Recenter the `makeinfo' output buffer.
C-c C-m C-k Kill the `makeinfo' formatting job.
Typeset and Print
-----------------
Typeset and print Texinfo documents from within Emacs.
C-c C-t C-r Run TeX on the region.
C-c C-t C-b Run TeX on the buffer.
C-c C-t C-i Run `texindex'.
C-c C-t C-p Print the DVI file.
C-c C-t C-q Show the print queue.
C-c C-t C-d Delete a job from the print queue.
C-c C-t C-k Kill the current TeX formatting job.
C-c C-t C-x Quit a currently stopped TeX formatting job.
C-c C-t C-l Recenter the output buffer.
Other Updating Commands
-----------------------
The `other updating commands' do not have standard keybindings because
they are less frequently used.
M-x texinfo-insert-node-lines
Insert missing node lines using
section titles as node names.
M-x texinfo-multiple-files-update
Update a multi-file document.
M-x texinfo-indent-menu-description
Indent descriptions in menus.
M-x texinfo-sequential-update-node
Insert node pointers in strict sequence.
Newly Described Texinfo @-Commands
==================================
The second edition of the Texinfo manual describes more than 50
commands that were not described in the first edition. A third or so
of these commands existed in Texinfo but were not documented in the
manual; the others are new. Here is a listing, with brief
descriptions of them:
Commands for creating your own index and for merging two indices:
`@defindex INDEX-NAME'
Define a new index and its indexing command. Print entries in a
roman font. Also, the `@defcodeindex' command, which prints
entries in an `@code' font.
`@synindex FROM-INDEX INTO-INDEX'
Merge the index named in the first argument into the index named
in the second argument. Sets FROM-INDEX in the same (roman) font
as INTO-INDEX. Also, the `@syncodeindex' command, which prints
the entries from the first index in `@code' font.
Many commands to help you describe functions, variables, macros,
commands, user options, special forms and other such artifacts in a
uniform format.
`@deffn CATEGORY NAME ARGUMENTS...'
Format a description for functions, interactive commands, and
similar entities that may take arguments. Takes as arguments the
category of entity being described, the name of this particular
entity, and its arguments, if any.
`@defvr, @defop, ...'
15 other related commands.
Special symbols to indicate the results of evaluation or an expansion,
printed output, an error message, equivalence of expressions, and the
location of point.
`@equiv{}'
Indicate the exact equivalence of two forms; special glyph: `=='.
`@error{}'
Indicate that the following text is an error message: `error-->'.
`@expansion{}'
Indicate the result of a macro expansion; special glyph: `==>'.
`@point{}'
Indicate the position of point; special glyph: `-!-'.
`@print{}'
Indicate printed output; special glyph: `-|'.
`@result{}'
Indicate the result of an expression; special glyph: `=>'.
Commands to customize headings:
`@headings ON-OFF-SINGLE-DOUBLE'
Turn headings on or off, or specify single-sided or double-sided
headings for printing.
`@evenfooting [LEFT] @| [CENTER] @| [RIGHT]'
Specify footings for even-numbered (left-hand) pages. Not
relevant to Info.
`@evenheading, @everyheading, @oddheading, ...'
Five other related commands.
`@thischapter'
In a heading or footing, stands for the number and name of the
current chapter, in the format `Chapter 1: First Chapter'.
`@thischaptername, @thisfile, @thistitle, @thispage'
Related commands.
Commands for formatting text:
`@cartouche'
Draw rounded box surrounding text (not in Info).
`@enumerate OPTIONAL-ARG'
Enumerate a list with letters or numbers.
`@exdent LINE-OF-TEXT'
Remove any indentation a line might have.
`@flushleft'
Left justify every line but leave the right end ragged. Leave
font as is.
`@flushright'
Right justify every line but leave the left end ragged. Leave
font as is.
`@format'
Like `@example' or `@display', but do not narrow the margins or
select the fixed-width font.
`@ftable FORMATTING-COMMAND'
`@vtable FORMATTING-COMMAND'
Begin a two-column table, using `@item' for each entry.
`@ftable' automatically enters each of the items in the
first column into the index of functions and `@vtable'
enters them into the index of variables. The commands
are the same as `@table', except for indexing.
`@lisp'
Indent text, do not fill, select fixed-width font.
`@smallexample'
Indent text, do not fill, select fixed-width font. In
`@smallbook' format, print text in a smaller font than with the
`@example' environment. Also, the `@smalllisp' command.
Commands for formatting if a flag is set or cleared:
`@set FLAG [STRING]'
Set FLAG, causing the Texinfo formatting commands to format text
between subsequent pairs of `@ifset FLAG' and `@end ifset'
commands. Optionally, set value of FLAG to STRING.
`@value{FLAG}'
Replace with value to which FLAG is set.
`@ifset FLAG ... @end ifset'
If FLAG is set, the Texinfo formatting commands format text
between `@ifset FLAG' and the following `@end ifset' command.
`@clear FLAG'
Unset FLAG, preventing the Texinfo formatting commands from
formatting text between subsequent pairs of `@ifset FLAG' and
`@end ifset' commands.
`@ifclear FLAG ... @end ifclear'
If FLAG is unset, the Texinfo formatting commands format text
between `@ifclear FLAG' and the following `@end ifclear' command.
Produce unnumbered headings that do not appear in a table of contents:
`@heading TITLE'
Print an unnumbered section-like heading in the text, but not in
the table of contents of a printed manual.
`@chapheading, @majorheading'
`@subheading, @subsubheading'
Related commands.
Font commands:
`@r{TEXT}'
Print TEXT in roman font. No effect in Info.
`@sc{TEXT}'
Set TEXT in the printed output in THE SMALL CAPS FONT and set
text in the Info file in uppercase letters.
Miscellaneous:
`@author AUTHOR'
Typeset author's name flushleft and underline it.
`@finalout'
Prevent TeX from printing large black warning rectangles beside
over-wide lines.
`@footnotestyle STYLE'
Specify footnote style, end or separate.
`@dmn{DIMENSION}'
Format a dimension.
`@minus{}'
Generate a minus sign.
`@paragraphindent INDENT'
Specify paragraph indentation, asis or a number.
`@ref{NODE-NAME, [ENTRY], [TOPIC], [INFO-FILE], [MANUAL]}'
Make a reference. In the printed manual, the reference does not
start with a `See'.
`@title TITLE'
Alternative format for a title page. In the printed manual, set
a title flush to the left-hand side of the page in a larger than
normal font and underline it with a black rule. Also,
`@subtitle' command.
`@subtitle SUBTITLE'
Subtitle in the alternative title page format.
`@today{}'
Insert the current date.
texinfo-3.7/README 100666 21641 13 15535 5767654023 13010 0 ustar friedman user Texinfo, Version 3
==================
This is the README file for version 3 of the Texinfo distribution.
Files within this distribution have their own version and edition
numbers. When you refer to a file, please mention its own number.
PLEASE REPORT BUGS TO: bug-texinfo@prep.ai.mit.edu
23 March 1993
Texinfo is a documentation system that uses a single source file to
produce both on-line information and printed output. This means that
instead of writing two different documents, one for the on-line help
or other on-line information and the other for a typeset manual or
other printed work, you need write only one document. When the work
is revised, you need revise only one document. You can read the
on-line information, known as an "Info file", with an Info
documentation-reading program. By convention, Texinfo source file
names end with a `.texi' or `.texinfo' extension. Texinfo is
described in the Texinfo Manual.
You can write and format Texinfo files into Info files within GNU
Emacs, and read them using the Emacs Info reader. If you do not have
Emacs, you can format Texinfo files into Info files using `makeinfo'
and read them using `info'. Use TeX, which is not included in this
package, to typeset Texinfo files for printing.
For instructions on installing info, makeinfo, texi2dvi, and texindex,
please read the file `INSTALL'. The Emacs Lisp files are not
installed by default; to install them, use `make install' in the
`emacs' subdirectory.
This distribution includes (but is not limited to) the following files:
README This file.
INTRODUCTION This file tells you how to create
readable files from the Texinfo source
files in this distribution.
Texinfo source files:
texinfo.texi This manual describes Texinfo. It
tells how to use Texinfo to write
documentation, how to use Texinfo mode
in GNU Emacs, how to use TeX,
makeinfo, and the Emacs Lisp Texinfo
formatting commands.
info.texi This manual tells you how to use
Info. This document comes as part of
GNU Emacs. If you do not have Emacs,
you can format this Texinfo source
file with makeinfo or TeX and then
read the resulting Info file with the
standalone Info reader that is part of
this distribution.
info-stnd.texi This manual tells you how to use
the standalone GNU Info reader that is
included in this distribution as a C
source file, `info.c'.
makeinfo.texi This manual tells you how to use
makeinfo. The same information is
contained in a chapter of the Texinfo
manual; it has been extracted here for
your convenience.
Printing related files:
texinfo.tex This TeX definitions file tells
the TeX program how to typeset a
Texinfo file into a DVI file ready for
printing.
texindex.c This file contains the source for
the `texindex' program that generates
sorted indices used by TeX when
typesetting a file for printing.
texi2dvi This is a shell script for
producing an indexed DVI file using
TeX and texindex.
GNU Emacs related files:
texinfmt.el This Emacs Lisp file provides the
functions that GNU Emacs uses to
format a Texinfo file into an Info
file.
texinfo.el This file provides Texinfo mode
for GNU Emacs.
texnfo-upd.el These files provides commands to
texnfo-tex.el help you write Texinfo files
makeinfo.el using GNU Emacs Texinfo mode.
detexinfo.el This extra utility file contains functions
to remove Texinfo commands from a
Texinfo source file.
info.el These are the standard GNU Emacs
informat.el Info reading and support files,
included here for your convenience.
Source files for standalone C programs:
makeinfo.c This file contains the source for
the `makeinfo' program that you can
use to create an Info file from a
Texinfo file.
info.c This file contains the source for
the `info' program that you can use to
view Info files on an ASCII terminal.
getopt.c Various support files
getopt1.c
getopt.h
C Installation files:
configure This file creates creates a Makefile
which in turn creates an `info' or
`makeinfo' executable, or a C sources
distribution.
configure.in This is a template for creating
`configure' using m4 macros.
Makefile.in This is a template for `configure'
to use to make a Makefile.
Other files:
NEWS This contains a summary of new
features since the first edition
of Texinfo.
info.1 This is a `man' page that briefly
describes the standalone `info'
program.
fixfonts This is a shell script to install the
`lcircle10' TeX fonts as an alias for
the `circle10' fonts. In some older
TeX distributions the names are
different.
tex3patch This handles a bug for version
3.0 of TeX that does not occur in
more recent versions.
texinfo-3.7/TODO 100666 21641 13 403 5442736573 12545 0 ustar friedman user * Implement a detexinfo program, like detex or delatex. This command would
strip all the texinfo commands out, and would be used as a filter on the
way to a speller.
An option would be to NOT strip comments out.
makeinfo --noheaders come close.
texinfo-3.7/configure 100777 11732 13 141261 6067100120 13176 0 ustar bfox user #! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated automatically using autoconf version 2.7
# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
# Defaults:
ac_help=
ac_default_prefix=/usr/local
# Any additions from configure.in:
# Initialize some variables set by options.
# The variables have the same names as the options, with
# dashes changed to underlines.
build=NONE
cache_file=./config.cache
exec_prefix=NONE
host=NONE
no_create=
nonopt=NONE
no_recursion=
prefix=NONE
program_prefix=NONE
program_suffix=NONE
program_transform_name=s,x,x,
silent=
site=
srcdir=
target=NONE
verbose=
x_includes=NONE
x_libraries=NONE
bindir='${exec_prefix}/bin'
sbindir='${exec_prefix}/sbin'
libexecdir='${exec_prefix}/libexec'
datadir='${prefix}/share'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
libdir='${exec_prefix}/lib'
includedir='${prefix}/include'
oldincludedir='/usr/include'
infodir='${prefix}/info'
mandir='${prefix}/man'
# Initialize some other variables.
subdirs=
MFLAGS= MAKEFLAGS=
ac_prev=
for ac_option
do
# If the previous option needs an argument, assign it.
if test -n "$ac_prev"; then
eval "$ac_prev=\$ac_option"
ac_prev=
continue
fi
case "$ac_option" in
-*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) ac_optarg= ;;
esac
# Accept the important Cygnus configure options, so we can diagnose typos.
case "$ac_option" in
-bindir | --bindir | --bindi | --bind | --bin | --bi)
ac_prev=bindir ;;
-bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
bindir="$ac_optarg" ;;
-build | --build | --buil | --bui | --bu)
ac_prev=build ;;
-build=* | --build=* | --buil=* | --bui=* | --bu=*)
build="$ac_optarg" ;;
-cache-file | --cache-file | --cache-fil | --cache-fi \
| --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
ac_prev=cache_file ;;
-cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
| --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
cache_file="$ac_optarg" ;;
-datadir | --datadir | --datadi | --datad | --data | --dat | --da)
ac_prev=datadir ;;
-datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
| --da=*)
datadir="$ac_optarg" ;;
-disable-* | --disable-*)
ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
# Reject names that are not valid shell variable names.
if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
{ echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
fi
ac_feature=`echo $ac_feature| sed 's/-/_/g'`
eval "enable_${ac_feature}=no" ;;
-enable-* | --enable-*)
ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
# Reject names that are not valid shell variable names.
if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
{ echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
fi
ac_feature=`echo $ac_feature| sed 's/-/_/g'`
case "$ac_option" in
*=*) ;;
*) ac_optarg=yes ;;
esac
eval "enable_${ac_feature}='$ac_optarg'" ;;
-exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
| --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
| --exec | --exe | --ex)
ac_prev=exec_prefix ;;
-exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
| --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
| --exec=* | --exe=* | --ex=*)
exec_prefix="$ac_optarg" ;;
-gas | --gas | --ga | --g)
# Obsolete; use --with-gas.
with_gas=yes ;;
-help | --help | --hel | --he)
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat << EOF
Usage: configure [options] [host]
Options: [defaults in brackets after descriptions]
Configuration:
--cache-file=FILE cache test results in FILE
--help print this message
--no-create do not create output files
--quiet, --silent do not print \`checking...' messages
--version print the version of autoconf that created configure
Directory and file names:
--prefix=PREFIX install architecture-independent files in PREFIX
[$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
[same as prefix]
--bindir=DIR user executables in DIR [EPREFIX/bin]
--sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
--libexecdir=DIR program executables in DIR [EPREFIX/libexec]
--datadir=DIR read-only architecture-independent data in DIR
[PREFIX/share]
--sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data in DIR
[PREFIX/com]
--localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
--libdir=DIR object code libraries in DIR [EPREFIX/lib]
--includedir=DIR C header files in DIR [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
--infodir=DIR info documentation in DIR [PREFIX/info]
--mandir=DIR man documentation in DIR [PREFIX/man]
--srcdir=DIR find the sources in DIR [configure dir or ..]
--program-prefix=PREFIX prepend PREFIX to installed program names
--program-suffix=SUFFIX append SUFFIX to installed program names
--program-transform-name=PROGRAM
run sed PROGRAM on installed program names
EOF
cat << EOF
Host type:
--build=BUILD configure for building on BUILD [BUILD=HOST]
--host=HOST configure for HOST [guessed]
--target=TARGET configure for TARGET [TARGET=HOST]
Features and packages:
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--x-includes=DIR X include files are in DIR
--x-libraries=DIR X library files are in DIR
EOF
if test -n "$ac_help"; then
echo "--enable and --with options recognized:$ac_help"
fi
exit 0 ;;
-host | --host | --hos | --ho)
ac_prev=host ;;
-host=* | --host=* | --hos=* | --ho=*)
host="$ac_optarg" ;;
-includedir | --includedir | --includedi | --included | --include \
| --includ | --inclu | --incl | --inc)
ac_prev=includedir ;;
-includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
| --includ=* | --inclu=* | --incl=* | --inc=*)
includedir="$ac_optarg" ;;
-infodir | --infodir | --infodi | --infod | --info | --inf)
ac_prev=infodir ;;
-infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
infodir="$ac_optarg" ;;
-libdir | --libdir | --libdi | --libd)
ac_prev=libdir ;;
-libdir=* | --libdir=* | --libdi=* | --libd=*)
libdir="$ac_optarg" ;;
-libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
| --libexe | --libex | --libe)
ac_prev=libexecdir ;;
-libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
| --libexe=* | --libex=* | --libe=*)
libexecdir="$ac_optarg" ;;
-localstatedir | --localstatedir | --localstatedi | --localstated \
| --localstate | --localstat | --localsta | --localst \
| --locals | --local | --loca | --loc | --lo)
ac_prev=localstatedir ;;
-localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
| --localstate=* | --localstat=* | --localsta=* | --localst=* \
| --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
localstatedir="$ac_optarg" ;;
-mandir | --mandir | --mandi | --mand | --man | --ma | --m)
ac_prev=mandir ;;
-mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
mandir="$ac_optarg" ;;
-nfp | --nfp | --nf)
# Obsolete; use --without-fp.
with_fp=no ;;
-no-create | --no-create | --no-creat | --no-crea | --no-cre \
| --no-cr | --no-c)
no_create=yes ;;
-no-recursion | --no-recursion | --no-recursio | --no-recursi \
| --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
no_recursion=yes ;;
-oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
| --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
| --oldin | --oldi | --old | --ol | --o)
ac_prev=oldincludedir ;;
-oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
| --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
| --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
oldincludedir="$ac_optarg" ;;
-prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
ac_prev=prefix ;;
-prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
prefix="$ac_optarg" ;;
-program-prefix | --program-prefix | --program-prefi | --program-pref \
| --program-pre | --program-pr | --program-p)
ac_prev=program_prefix ;;
-program-prefix=* | --program-prefix=* | --program-prefi=* \
| --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
program_prefix="$ac_optarg" ;;
-program-suffix | --program-suffix | --program-suffi | --program-suff \
| --program-suf | --program-su | --program-s)
ac_prev=program_suffix ;;
-program-suffix=* | --program-suffix=* | --program-suffi=* \
| --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
program_suffix="$ac_optarg" ;;
-program-transform-name | --program-transform-name \
| --program-transform-nam | --program-transform-na \
| --program-transform-n | --program-transform- \
| --program-transform | --program-transfor \
| --program-transfo | --program-transf \
| --program-trans | --program-tran \
| --progr-tra | --program-tr | --program-t)
ac_prev=program_transform_name ;;
-program-transform-name=* | --program-transform-name=* \
| --program-transform-nam=* | --program-transform-na=* \
| --program-transform-n=* | --program-transform-=* \
| --program-transform=* | --program-transfor=* \
| --program-transfo=* | --program-transf=* \
| --program-trans=* | --program-tran=* \
| --progr-tra=* | --program-tr=* | --program-t=*)
program_transform_name="$ac_optarg" ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
| --sbi=* | --sb=*)
sbindir="$ac_optarg" ;;
-sharedstatedir | --sharedstatedir | --sharedstatedi \
| --sharedstated | --sharedstate | --sharedstat | --sharedsta \
| --sharedst | --shareds | --shared | --share | --shar \
| --sha | --sh)
ac_prev=sharedstatedir ;;
-sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
| --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
| --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
| --sha=* | --sh=*)
sharedstatedir="$ac_optarg" ;;
-site | --site | --sit)
ac_prev=site ;;
-site=* | --site=* | --sit=*)
site="$ac_optarg" ;;
-srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
ac_prev=srcdir ;;
-srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
srcdir="$ac_optarg" ;;
-sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
| --syscon | --sysco | --sysc | --sys | --sy)
ac_prev=sysconfdir ;;
-sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
| --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
sysconfdir="$ac_optarg" ;;
-target | --target | --targe | --targ | --tar | --ta | --t)
ac_prev=target ;;
-target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
target="$ac_optarg" ;;
-v | -verbose | --verbose | --verbos | --verbo | --verb)
verbose=yes ;;
-version | --version | --versio | --versi | --vers)
echo "configure generated by autoconf version 2.7"
exit 0 ;;
-with-* | --with-*)
ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
# Reject names that are not valid shell variable names.
if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
{ echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
fi
ac_package=`echo $ac_package| sed 's/-/_/g'`
case "$ac_option" in
*=*) ;;
*) ac_optarg=yes ;;
esac
eval "with_${ac_package}='$ac_optarg'" ;;
-without-* | --without-*)
ac_package=`echo $ac_option|sed -e 's/-*without-//'`
# Reject names that are not valid shell variable names.
if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
{ echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
fi
ac_package=`echo $ac_package| sed 's/-/_/g'`
eval "with_${ac_package}=no" ;;
--x)
# Obsolete; use --with-x.
with_x=yes ;;
-x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
| --x-incl | --x-inc | --x-in | --x-i)
ac_prev=x_includes ;;
-x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
| --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
x_includes="$ac_optarg" ;;
-x-libraries | --x-libraries | --x-librarie | --x-librari \
| --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
ac_prev=x_libraries ;;
-x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
| --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
x_libraries="$ac_optarg" ;;
-*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
;;
*)
if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
echo "configure: warning: $ac_option: invalid host type" 1>&2
fi
if test "x$nonopt" != xNONE; then
{ echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
fi
nonopt="$ac_option"
;;
esac
done
if test -n "$ac_prev"; then
{ echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
fi
trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
# File descriptor usage:
# 0 standard input
# 1 file creation
# 2 errors and warnings
# 3 some systems may open it to /dev/tty
# 4 used on the Kubota Titan
# 6 checking for... messages and results
# 5 compiler messages saved in config.log
if test "$silent" = yes; then
exec 6>/dev/null
else
exec 6>&1
fi
exec 5>./config.log
echo "\
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
" 1>&5
# Strip out --no-create and --no-recursion so they do not pile up.
# Also quote any args containing shell metacharacters.
ac_configure_args=
for ac_arg
do
case "$ac_arg" in
-no-create | --no-create | --no-creat | --no-crea | --no-cre \
| --no-cr | --no-c) ;;
-no-recursion | --no-recursion | --no-recursio | --no-recursi \
| --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
*" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
ac_configure_args="$ac_configure_args '$ac_arg'" ;;
*) ac_configure_args="$ac_configure_args $ac_arg" ;;
esac
done
# NLS nuisances.
# Only set LANG and LC_ALL to C if already set.
# These must not be set unconditionally because not all systems understand
# e.g. LANG=C (notably SCO).
if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
if test "${LANG+set}" = set; then LANG=C; export LANG; fi
# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -rf conftest* confdefs.h
# AIX cpp loses on an empty file, so make sure it contains at least a newline.
echo > confdefs.h
# A filename unique to this package, relative to the directory that
# configure is in, which we can look for to find out if srcdir is correct.
ac_unique_file=texinfo.texi
# Find the source files, if location was not specified.
if test -z "$srcdir"; then
ac_srcdir_defaulted=yes
# Try the directory containing this script, then its parent.
ac_prog=$0
ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
srcdir=$ac_confdir
if test ! -r $srcdir/$ac_unique_file; then
srcdir=..
fi
else
ac_srcdir_defaulted=no
fi
if test ! -r $srcdir/$ac_unique_file; then
if test "$ac_srcdir_defaulted" = yes; then
{ echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
else
{ echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
fi
fi
srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
# Prefer explicitly selected file to automatically selected ones.
if test -z "$CONFIG_SITE"; then
if test "x$prefix" != xNONE; then
CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
else
CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
fi
fi
for ac_site_file in $CONFIG_SITE; do
if test -r "$ac_site_file"; then
echo "loading site script $ac_site_file"
. "$ac_site_file"
fi
done
if test -r "$cache_file"; then
echo "loading cache $cache_file"
. $cache_file
else
echo "creating cache $cache_file"
> $cache_file
fi
ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
ac_cpp='echo $CPP $CPPFLAGS 1>&5;
$CPP $CPPFLAGS'
ac_compile='echo ${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5;
${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5'
ac_link='echo ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5;
${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5'
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
# Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
ac_n= ac_c='
' ac_t=' '
else
ac_n=-n ac_c= ac_t=
fi
else
ac_n= ac_c='\c' ac_t=
fi
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
for ac_dir in $PATH; do
test -z "$ac_dir" && ac_dir=.
if test -f $ac_dir/$ac_word; then
ac_cv_prog_CC="gcc"
break
fi
done
IFS="$ac_save_ifs"
test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc"
fi
fi
CC="$ac_cv_prog_CC"
if test -n "$CC"; then
echo "$ac_t""$CC" 1>&6
else
echo "$ac_t""no" 1>&6
fi
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.c <&5 | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gcc=yes
else
ac_cv_prog_gcc=no
fi
fi
echo "$ac_t""$ac_cv_prog_gcc" 1>&6
if test $ac_cv_prog_gcc = yes; then
GCC=yes
if test "${CFLAGS+set}" != set; then
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
echo 'void f(){}' > conftest.c
if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
ac_cv_prog_gcc_g=yes
else
ac_cv_prog_gcc_g=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6
if test $ac_cv_prog_gcc_g = yes; then
CFLAGS="-g -O"
else
CFLAGS="-O"
fi
fi
else
GCC=
test "${CFLAGS+set}" = set || CFLAGS="-g"
fi
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# This must be in double quotes, not single quotes, because CPP may get
# substituted into the Makefile and "${CC-cc}" will confuse make.
CPP="${CC-cc} -E"
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp.
cat > conftest.$ac_ext <
Syntax Error
EOF
eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
:
else
echo "$ac_err" >&5
rm -rf conftest*
CPP="${CC-cc} -E -traditional-cpp"
cat > conftest.$ac_ext <
Syntax Error
EOF
eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
:
else
echo "$ac_err" >&5
rm -rf conftest*
CPP=/lib/cpp
fi
rm -f conftest*
fi
rm -f conftest*
ac_cv_prog_CPP="$CPP"
fi
CPP="$ac_cv_prog_CPP"
else
ac_cv_prog_CPP="$CPP"
fi
echo "$ac_t""$CPP" 1>&6
if test $ac_cv_prog_gcc = yes; then
echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_pattern="Autoconf.*'x'"
cat > conftest.$ac_ext <
Autoconf TIOCGETP
EOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "$ac_pattern" >/dev/null 2>&1; then
rm -rf conftest*
ac_cv_prog_gcc_traditional=yes
else
rm -rf conftest*
ac_cv_prog_gcc_traditional=no
fi
rm -f conftest*
if test $ac_cv_prog_gcc_traditional = no; then
cat > conftest.$ac_ext <
Autoconf TCGETA
EOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "$ac_pattern" >/dev/null 2>&1; then
rm -rf conftest*
ac_cv_prog_gcc_traditional=yes
fi
rm -f conftest*
fi
fi
echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
if test $ac_cv_prog_gcc_traditional = yes; then
CC="$CC -traditional"
fi
fi
ac_aux_dir=
for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
if test -f $ac_dir/install-sh; then
ac_aux_dir=$ac_dir
ac_install_sh="$ac_aux_dir/install-sh -c"
break
elif test -f $ac_dir/install.sh; then
ac_aux_dir=$ac_dir
ac_install_sh="$ac_aux_dir/install.sh -c"
break
fi
done
if test -z "$ac_aux_dir"; then
{ echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
fi
ac_config_guess=$ac_aux_dir/config.guess
ac_config_sub=$ac_aux_dir/config.sub
ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
# incompatible versions:
# SysV /etc/install, /usr/sbin/install
# SunOS /usr/etc/install
# IRIX /sbin/install
# AIX /bin/install
# AFS /usr/afsws/bin/install, which mishandles nonexistent args
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
for ac_dir in $PATH; do
# Account for people who put trailing slashes in PATH elements.
case "$ac_dir/" in
/|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
*)
# OSF1 and SCO ODT 3.0 have their own names for install.
for ac_prog in ginstall installbsd scoinst install; do
if test -f $ac_dir/$ac_prog; then
if test $ac_prog = install &&
grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
# AIX install. It has an incompatible calling convention.
# OSF/1 installbsd also uses dspmsg, but is usable.
:
else
ac_cv_path_install="$ac_dir/$ac_prog -c"
break 2
fi
fi
done
;;
esac
done
IFS="$ac_save_ifs"
fi
if test "${ac_cv_path_install+set}" = set; then
INSTALL="$ac_cv_path_install"
else
# As a last resort, use the slow shell script. We don't cache a
# path for INSTALL within a source directory, because that will
# break other packages using the cache if that directory is
# removed, or if the path is relative.
INSTALL="$ac_install_sh"
fi
fi
echo "$ac_t""$INSTALL" 1>&6
# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
# It thinks the first close brace ends the variable substitution.
test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test -n "$RANLIB"; then
ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
else
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
for ac_dir in $PATH; do
test -z "$ac_dir" && ac_dir=.
if test -f $ac_dir/$ac_word; then
ac_cv_prog_RANLIB="ranlib"
break
fi
done
IFS="$ac_save_ifs"
test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
fi
fi
RANLIB="$ac_cv_prog_RANLIB"
if test -n "$RANLIB"; then
echo "$ac_t""$RANLIB" 1>&6
else
echo "$ac_t""no" 1>&6
fi
echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
if test -d /etc/conf/kconfig.d &&
grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
then
echo "$ac_t""yes" 1>&6
ISC=yes # If later tests want to check for ISC.
cat >> confdefs.h <<\EOF
#define _POSIX_SOURCE 1
EOF
if test "$GCC" = yes; then
CC="$CC -posix"
else
CC="$CC -Xp"
fi
else
echo "$ac_t""no" 1>&6
ISC=
fi
ac_safe=`echo "minix/config.h" | tr './\055' '___'`
echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
EOF
eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
eval "ac_cv_header_$ac_safe=yes"
else
echo "$ac_err" >&5
rm -rf conftest*
eval "ac_cv_header_$ac_safe=no"
fi
rm -f conftest*
fi
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
echo "$ac_t""yes" 1>&6
MINIX=yes
else
echo "$ac_t""no" 1>&6
MINIX=
fi
if test "$MINIX" = yes; then
cat >> confdefs.h <<\EOF
#define _POSIX_SOURCE 1
EOF
cat >> confdefs.h <<\EOF
#define _POSIX_1_SOURCE 2
EOF
cat >> confdefs.h <<\EOF
#define _MINIX 1
EOF
fi
# Needed on sysV68 for sigblock, sigsetmask.
echo $ac_n "checking for -lbsd""... $ac_c" 1>&6
ac_lib_var=`echo bsd | tr '.-/+' '___p'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_save_LIBS="$LIBS"
LIBS="-lbsd $LIBS"
cat > conftest.$ac_ext <&6
ac_tr_lib=HAVE_LIB`echo bsd | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
cat >> confdefs.h <&6
fi
TERMLIBS=
for termlib in curses termcap terminfo termlib ; do
echo $ac_n "checking for -l${termlib}""... $ac_c" 1>&6
ac_lib_var=`echo ${termlib} | tr '.-/+' '___p'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_save_LIBS="$LIBS"
LIBS="-l${termlib} $LIBS"
cat > conftest.$ac_ext <&6
TERMLIBS="${TERMLIBS} -l${termlib}"; break
else
echo "$ac_t""no" 1>&6
fi
done
# If we cannot run a trivial program, we must be cross compiling.
echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test "$cross_compiling" = yes; then
ac_cv_c_cross=yes
else
cat > conftest.$ac_ext </dev/null; then
ac_cv_c_cross=no
else
ac_cv_c_cross=yes
fi
fi
rm -fr conftest*
fi
echo "$ac_t""$ac_cv_c_cross" 1>&6
cross_compiling=$ac_cv_c_cross
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#include
#include
#include
EOF
eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
ac_cv_header_stdc=yes
else
echo "$ac_err" >&5
rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat > conftest.$ac_ext <
EOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "memchr" >/dev/null 2>&1; then
:
else
rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat > conftest.$ac_ext <
EOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "free" >/dev/null 2>&1; then
:
else
rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
fi
if test $ac_cv_header_stdc = yes; then
# /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
if test "$cross_compiling" = yes; then
:
else
cat > conftest.$ac_ext <
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
int main () { int i; for (i = 0; i < 256; i++)
if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
exit (0); }
EOF
eval $ac_link
if test -s conftest && (./conftest; exit) 2>/dev/null; then
:
else
ac_cv_header_stdc=no
fi
fi
rm -fr conftest*
fi
fi
echo "$ac_t""$ac_cv_header_stdc" 1>&6
if test $ac_cv_header_stdc = yes; then
cat >> confdefs.h <<\EOF
#define STDC_HEADERS 1
EOF
fi
for ac_hdr in unistd.h termio.h string.h varargs.h \
sys/time.h sys/fcntl.h sys/ttold.h sys/ptem.h sys/file.h
do
ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
EOF
eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
eval "ac_cv_header_$ac_safe=yes"
else
echo "$ac_err" >&5
rm -rf conftest*
eval "ac_cv_header_$ac_safe=no"
fi
rm -f conftest*
fi
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
echo "$ac_t""yes" 1>&6
ac_tr_hdr=HAVE_`echo $ac_hdr | tr 'abcdefghijklmnopqrstuvwxyz./\055' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ___'`
cat >> confdefs.h <&6
fi
done
echo $ac_n "checking for off_t""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#if STDC_HEADERS
#include
#endif
EOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "off_t" >/dev/null 2>&1; then
rm -rf conftest*
ac_cv_type_off_t=yes
else
rm -rf conftest*
ac_cv_type_off_t=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_type_off_t" 1>&6
if test $ac_cv_type_off_t = no; then
cat >> confdefs.h <<\EOF
#define off_t long
EOF
fi
echo $ac_n "checking for working const""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <j = 5;
}
{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
const int foo = 10;
}
; return 0; }
EOF
if eval $ac_compile; then
rm -rf conftest*
ac_cv_c_const=yes
else
rm -rf conftest*
ac_cv_c_const=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_c_const" 1>&6
if test $ac_cv_c_const = no; then
cat >> confdefs.h <<\EOF
#define const
EOF
fi
echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#include
int main() { return 0; }
int t() {
struct tm *tp; tp->tm_sec;
; return 0; }
EOF
if eval $ac_compile; then
rm -rf conftest*
ac_cv_struct_tm=time.h
else
rm -rf conftest*
ac_cv_struct_tm=sys/time.h
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_struct_tm" 1>&6
if test $ac_cv_struct_tm = sys/time.h; then
cat >> confdefs.h <<\EOF
#define TM_IN_SYS_TIME 1
EOF
fi
# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
# for constant arguments. Useless!
echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
int main() { return 0; }
int t() {
char *p = alloca(2 * sizeof(int));
; return 0; }
EOF
if eval $ac_link; then
rm -rf conftest*
ac_cv_header_alloca_h=yes
else
rm -rf conftest*
ac_cv_header_alloca_h=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
if test $ac_cv_header_alloca_h = yes; then
cat >> confdefs.h <<\EOF
#define HAVE_ALLOCA_H 1
EOF
fi
echo $ac_n "checking for alloca""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_func_alloca'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
char *alloca ();
# endif
# endif
# endif
#endif
int main() { return 0; }
int t() {
char *p = (char *) alloca(1);
; return 0; }
EOF
if eval $ac_link; then
rm -rf conftest*
ac_cv_func_alloca=yes
else
rm -rf conftest*
ac_cv_func_alloca=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_func_alloca" 1>&6
if test $ac_cv_func_alloca = yes; then
cat >> confdefs.h <<\EOF
#define HAVE_ALLOCA 1
EOF
fi
if test $ac_cv_func_alloca = no; then
# The SVR3 libPW and SVR4 libucb both contain incompatible functions
# that cause trouble. Some versions do not even contain alloca or
# contain a buggy version. If you still want to use their alloca,
# use ar to extract alloca.o from them instead of compiling alloca.c.
ALLOCA=alloca.o
cat >> confdefs.h <<\EOF
#define C_ALLOCA 1
EOF
echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&5 |
egrep "webecray" >/dev/null 2>&1; then
rm -rf conftest*
ac_cv_os_cray=yes
else
rm -rf conftest*
ac_cv_os_cray=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_os_cray" 1>&6
if test $ac_cv_os_cray = yes; then
for ac_func in _getb67 GETB67 getb67; do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
/* Override any gcc2 internal prototype to avoid an error. */
char $ac_func();
int main() { return 0; }
int t() {
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
choke me
#else
$ac_func();
#endif
; return 0; }
EOF
if eval $ac_link; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
rm -rf conftest*
eval "ac_cv_func_$ac_func=no"
fi
rm -f conftest*
fi
if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
echo "$ac_t""yes" 1>&6
cat >> confdefs.h <&6
fi
done
fi
echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test "$cross_compiling" = yes; then
ac_cv_c_stack_direction=0
else
cat > conftest.$ac_ext < addr) ? 1 : -1;
}
main ()
{
exit (find_stack_direction() < 0);
}
EOF
eval $ac_link
if test -s conftest && (./conftest; exit) 2>/dev/null; then
ac_cv_c_stack_direction=1
else
ac_cv_c_stack_direction=-1
fi
fi
rm -fr conftest*
fi
echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
cat >> confdefs.h <&6
if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test "$cross_compiling" = yes; then
{ echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
else
cat > conftest.$ac_ext <
/* If setvbuf has the reversed format, exit 0. */
main () {
/* This call has the arguments reversed.
A reversed system may check and see that the address of main
is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */
if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0)
exit(1);
putc('\r', stdout);
exit(0); /* Non-reversed systems segv here. */
}
EOF
eval $ac_link
if test -s conftest && (./conftest; exit) 2>/dev/null; then
ac_cv_func_setvbuf_reversed=yes
else
ac_cv_func_setvbuf_reversed=no
fi
fi
rm -fr conftest*
rm -f core core.* *.core
fi
echo "$ac_t""$ac_cv_func_setvbuf_reversed" 1>&6
if test $ac_cv_func_setvbuf_reversed = yes; then
cat >> confdefs.h <<\EOF
#define SETVBUF_REVERSED 1
EOF
fi
for ac_func in setvbuf getcwd bzero bcopy memset memcpy memmove strchr \
strcasecmp strdup vfprintf vsprintf strerror sigprocmask \
sigsetmask
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
/* Override any gcc2 internal prototype to avoid an error. */
char $ac_func();
int main() { return 0; }
int t() {
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
choke me
#else
$ac_func();
#endif
; return 0; }
EOF
if eval $ac_link; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
rm -rf conftest*
eval "ac_cv_func_$ac_func=no"
fi
rm -f conftest*
fi
if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
echo "$ac_t""yes" 1>&6
ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
cat >> confdefs.h <&6
fi
done
trap '' 1 2 15
cat > confcache <<\EOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
# scripts and configure runs. It is not useful on other systems.
# If it contains results you don't want to keep, you may remove or edit it.
#
# By default, configure uses ./config.cache as the cache file,
# creating it if it does not exist already. You can give configure
# the --cache-file=FILE option to use a different cache file; that is
# what configure does when it calls configure scripts in
# subdirectories, so they share the cache.
# Giving --cache-file=/dev/null disables caching, for debugging configure.
# config.status only pays attention to the cache file if you give it the
# --recheck option to rerun configure.
#
EOF
# Ultrix sh set writes to stderr and can't be redirected directly,
# and sets the high bit in the cache file unless we assign to the vars.
(set) 2>&1 |
sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \
>> confcache
if cmp -s $cache_file confcache; then
:
else
if test -w $cache_file; then
echo "updating cache $cache_file"
cat confcache > $cache_file
else
echo "not updating unwritable cache $cache_file"
fi
fi
rm -f confcache
trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
# Any assignment to VPATH causes Sun make to only execute
# the first set of double-colon rules, so remove it if not needed.
# If there is a colon in the path, we need to keep it.
if test "x$srcdir" = x.; then
ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
fi
trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
# Transform confdefs.h into DEFS.
# Protect against shell expansion while executing Makefile rules.
# Protect against Makefile macro expansion.
cat > conftest.defs <<\EOF
s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%-D\1=\2%g
s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
s%\[%\\&%g
s%\]%\\&%g
s%\$%$$%g
EOF
DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
rm -f conftest.defs
# Without the "./", some shells look in PATH for config.status.
: ${CONFIG_STATUS=./config.status}
echo creating $CONFIG_STATUS
rm -f $CONFIG_STATUS
cat > $CONFIG_STATUS </dev/null | sed 1q`:
#
# $0 $ac_configure_args
#
# Compiler output produced by configure, useful for debugging
# configure, is in ./config.log if it exists.
ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
for ac_option
do
case "\$ac_option" in
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
-version | --version | --versio | --versi | --vers | --ver | --ve | --v)
echo "$CONFIG_STATUS generated by autoconf version 2.7"
exit 0 ;;
-help | --help | --hel | --he | --h)
echo "\$ac_cs_usage"; exit 0 ;;
*) echo "\$ac_cs_usage"; exit 1 ;;
esac
done
ac_given_srcdir=$srcdir
ac_given_INSTALL="$INSTALL"
trap 'rm -fr `echo "Makefile libtxi/Makefile makeinfo/Makefile info/Makefile util/Makefile emacs/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
EOF
cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF
$ac_vpsub
$extrasub
s%@CFLAGS@%$CFLAGS%g
s%@CPPFLAGS@%$CPPFLAGS%g
s%@CXXFLAGS@%$CXXFLAGS%g
s%@DEFS@%$DEFS%g
s%@LDFLAGS@%$LDFLAGS%g
s%@LIBS@%$LIBS%g
s%@exec_prefix@%$exec_prefix%g
s%@prefix@%$prefix%g
s%@program_transform_name@%$program_transform_name%g
s%@bindir@%$bindir%g
s%@sbindir@%$sbindir%g
s%@libexecdir@%$libexecdir%g
s%@datadir@%$datadir%g
s%@sysconfdir@%$sysconfdir%g
s%@sharedstatedir@%$sharedstatedir%g
s%@localstatedir@%$localstatedir%g
s%@libdir@%$libdir%g
s%@includedir@%$includedir%g
s%@oldincludedir@%$oldincludedir%g
s%@infodir@%$infodir%g
s%@mandir@%$mandir%g
s%@CC@%$CC%g
s%@CPP@%$CPP%g
s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
s%@INSTALL_DATA@%$INSTALL_DATA%g
s%@RANLIB@%$RANLIB%g
s%@TERMLIBS@%$TERMLIBS%g
s%@ALLOCA@%$ALLOCA%g
CEOF
EOF
cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF
for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
# Support "outfile[:infile]", defaulting infile="outfile.in".
case "$ac_file" in
*:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
*) ac_file_in="${ac_file}.in" ;;
esac
# Adjust relative srcdir, etc. for subdirectories.
# Remove last slash and all that follows it. Not all systems have dirname.
ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
# The file is in a subdirectory.
test ! -d "$ac_dir" && mkdir "$ac_dir"
ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
# A "../" for each directory in $ac_dir_suffix.
ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
else
ac_dir_suffix= ac_dots=
fi
case "$ac_given_srcdir" in
.) srcdir=.
if test -z "$ac_dots"; then top_srcdir=.
else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
/*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
*) # Relative path.
srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
top_srcdir="$ac_dots$ac_given_srcdir" ;;
esac
case "$ac_given_INSTALL" in
[/$]*) INSTALL="$ac_given_INSTALL" ;;
*) INSTALL="$ac_dots$ac_given_INSTALL" ;;
esac
echo creating "$ac_file"
rm -f "$ac_file"
configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
case "$ac_file" in
*Makefile*) ac_comsub="1i\\
# $configure_input" ;;
*) ac_comsub= ;;
esac
sed -e "$ac_comsub
s%@configure_input@%$configure_input%g
s%@srcdir@%$srcdir%g
s%@top_srcdir@%$top_srcdir%g
s%@INSTALL@%$INSTALL%g
" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file
fi; done
rm -f conftest.subs
exit 0
EOF
chmod +x $CONFIG_STATUS
rm -fr confdefs* $ac_clean_files
test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
texinfo-3.7/configure.in 100444 11732 13 2053 6067100011 13524 0 ustar bfox user dnl Process this file with autoconf to produce a configure script.
AC_INIT(texinfo.texi)
dnl Checks for programs.
AC_PROG_GCC_TRADITIONAL
AC_PROG_INSTALL
AC_PROG_RANLIB
AC_ISC_POSIX
AC_MINIX
dnl Checks for libraries.
# Needed on sysV68 for sigblock, sigsetmask.
AC_CHECK_LIB(bsd, sigblock)
TERMLIBS=
for termlib in curses termcap terminfo termlib ; do
AC_CHECK_LIB(${termlib}, tputs,
[TERMLIBS="${TERMLIBS} -l${termlib}"; break])
done
AC_SUBST(TERMLIBS)
dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(unistd.h termio.h string.h varargs.h \
sys/time.h sys/fcntl.h sys/ttold.h sys/ptem.h sys/file.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_OFF_T
AC_C_CONST
AC_STRUCT_TM
dnl Checks for library functions.
AC_FUNC_ALLOCA
AC_FUNC_SETVBUF_REVERSED
AC_CHECK_FUNCS(setvbuf getcwd bzero bcopy memset memcpy memmove strchr \
strcasecmp strdup vfprintf vsprintf strerror sigprocmask \
sigsetmask)
AC_OUTPUT(Makefile libtxi/Makefile makeinfo/Makefile info/Makefile util/Makefile emacs/Makefile)
texinfo-3.7/install.sh 100555 11732 13 11245 6061263025 13254 0 ustar bfox user #! /bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0
texinfo-3.7/texinfo.tex 100444 11732 13 435512 6067014545 13503 0 ustar bfox user %% TeX macros to handle texinfo files
% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 1994 Free Software Foundation, Inc.
%This texinfo.tex 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 texinfo.tex 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 texinfo.tex file; see the file COPYING. If not, write
%to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
%USA.
%In other words, you are welcome to use, share and improve this program.
%You are forbidden to forbid anyone else to use, share and improve
%what you give them. Help stamp out software-hoarding!
% Send bug reports to bug-texinfo@prep.ai.mit.edu.
% Please include a *precise* test case in each bug report.
% Make it possible to create a .fmt file just by loading this file:
% if the underlying format is not loaded, start by loading it now.
% Added by gildea November 1993.
\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
% This automatically updates the version number based on RCS.
\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}}
\deftexinfoversion$Revision: 2.151 $
\message{Loading texinfo package [Version \texinfoversion]:}
% If in a .fmt file, print the version number
% and turn on active characters that we couldn't do earlier because
% they might have appeared in the input file name.
\everyjob{\message{[Texinfo version \texinfoversion]}\message{}
\catcode`+=\active \catcode`\_=\active}
% Save some parts of plain tex whose names we will redefine.
\let\ptextilde=\~
\let\ptexlbrace=\{
\let\ptexrbrace=\}
\let\ptexdots=\dots
\let\ptexdot=\.
\let\ptexstar=\*
\let\ptexend=\end
\let\ptexbullet=\bullet
\let\ptexb=\b
\let\ptexc=\c
\let\ptexi=\i
\let\ptext=\t
\let\ptexl=\l
\let\ptexL=\L
% Be sure we're in horizontal mode when doing a tie, since we make space
% equivalent to this in @example-like environments. Otherwise, a space
% at the beginning of a line will start with \penalty -- and
% since \penalty is valid in vertical mode, we'd end up putting the
% penalty on the vertical list instead of in the new paragraph.
{\catcode`@ = 11
% Avoid using \@M directly, because that causes trouble
% if the definition is written into an index file.
\global\let\tiepenalty = \@M
\gdef\tie{\leavevmode\penalty\tiepenalty\ }
}
\let\~ = \tie % And make it available as @~.
\message{Basics,}
\chardef\other=12
% If this character appears in an error message or help string, it
% starts a new line in the output.
\newlinechar = `^^J
% Set up fixed words for English.
\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi%
\def\putwordInfo{Info}%
\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi%
\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi%
\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi%
\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi%
\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi%
\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi%
\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi%
\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi%
\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi%
% Ignore a token.
%
\def\gobble#1{}
\hyphenation{ap-pen-dix}
\hyphenation{mini-buf-fer mini-buf-fers}
\hyphenation{eshell}
% Margin to add to right of even pages, to left of odd pages.
\newdimen \bindingoffset \bindingoffset=0pt
\newdimen \normaloffset \normaloffset=\hoffset
\newdimen\pagewidth \newdimen\pageheight
\pagewidth=\hsize \pageheight=\vsize
% Sometimes it is convenient to have everything in the transcript file
% and nothing on the terminal. We don't just call \tracingall here,
% since that produces some useless output on the terminal.
%
\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
\def\loggingall{\tracingcommands2 \tracingstats2
\tracingpages1 \tracingoutput1 \tracinglostchars1
\tracingmacros2 \tracingparagraphs1 \tracingrestores1
\showboxbreadth\maxdimen\showboxdepth\maxdimen
}%
%---------------------Begin change-----------------------
%
%%%% For @cropmarks command.
% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986
%
\newdimen\cornerlong \newdimen\cornerthick
\newdimen \topandbottommargin
\newdimen \outerhsize \newdimen \outervsize
\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks
\outerhsize=7in
%\outervsize=9.5in
% Alternative @smallbook page size is 9.25in
\outervsize=9.25in
\topandbottommargin=.75in
%
%---------------------End change-----------------------
% \onepageout takes a vbox as an argument. Note that \pagecontents
% does insertions itself, but you have to call it yourself.
\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}}
\def\onepageout#1{\hoffset=\normaloffset
\ifodd\pageno \advance\hoffset by \bindingoffset
\else \advance\hoffset by -\bindingoffset\fi
{\escapechar=`\\\relax % makes sure backslash is used in output files.
\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}%
{\let\hsize=\pagewidth \makefootline}}}%
\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
%%%% For @cropmarks command %%%%
% Here is a modification of the main output routine for Near East Publications
% This provides right-angle cropmarks at all four corners.
% The contents of the page are centerlined into the cropmarks,
% and any desired binding offset is added as an \hskip on either
% site of the centerlined box. (P. A. MacKay, 12 November, 1986)
%
\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up
{\escapechar=`\\\relax % makes sure backslash is used in output files.
\shipout
\vbox to \outervsize{\hsize=\outerhsize
\vbox{\line{\ewtop\hfill\ewtop}}
\nointerlineskip
\line{\vbox{\moveleft\cornerthick\nstop}
\hfill
\vbox{\moveright\cornerthick\nstop}}
\vskip \topandbottommargin
\centerline{\ifodd\pageno\hskip\bindingoffset\fi
\vbox{
{\let\hsize=\pagewidth \makeheadline}
\pagebody{#1}
{\let\hsize=\pagewidth \makefootline}}
\ifodd\pageno\else\hskip\bindingoffset\fi}
\vskip \topandbottommargin plus1fill minus1fill
\boxmaxdepth\cornerthick
\line{\vbox{\moveleft\cornerthick\nsbot}
\hfill
\vbox{\moveright\cornerthick\nsbot}}
\nointerlineskip
\vbox{\line{\ewbot\hfill\ewbot}}
}}
\advancepageno
\ifnum\outputpenalty>-20000 \else\dosupereject\fi}
%
% Do @cropmarks to get crop marks
\def\cropmarks{\let\onepageout=\croppageout }
\newinsert\margin \dimen\margin=\maxdimen
\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
{\catcode`\@ =11
\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
% marginal hacks, juha@viisa.uucp (Juha Takala)
\ifvoid\margin\else % marginal info is present
\rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
\dimen@=\dp#1 \unvbox#1
\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
}
%
% Here are the rules for the cropmarks. Note that they are
% offset so that the space between them is truly \outerhsize or \outervsize
% (P. A. MacKay, 12 November, 1986)
%
\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
\def\nstop{\vbox
{\hrule height\cornerthick depth\cornerlong width\cornerthick}}
\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
\def\nsbot{\vbox
{\hrule height\cornerlong depth\cornerthick width\cornerthick}}
% Parse an argument, then pass it to #1. The argument is the rest of
% the input line (except we remove a trailing comment). #1 should be a
% macro which expects an ordinary undelimited TeX argument.
%
\def\parsearg#1{%
\let\next = #1%
\begingroup
\obeylines
\futurelet\temp\parseargx
}
% If the next token is an obeyed space (from an @example environment or
% the like), remove it and recurse. Otherwise, we're done.
\def\parseargx{%
% \obeyedspace is defined far below, after the definition of \sepspaces.
\ifx\obeyedspace\temp
\expandafter\parseargdiscardspace
\else
\expandafter\parseargline
\fi
}
% Remove a single space (as the delimiter token to the macro call).
{\obeyspaces %
\gdef\parseargdiscardspace {\futurelet\temp\parseargx}}
{\obeylines %
\gdef\parseargline#1^^M{%
\endgroup % End of the group started in \parsearg.
%
% First remove any @c comment, then any @comment.
% Result of each macro is put in \toks0.
\argremovec #1\c\relax %
\expandafter\argremovecomment \the\toks0 \comment\relax %
%
% Call the caller's macro, saved as \next in \parsearg.
\expandafter\next\expandafter{\the\toks0}%
}%
}
% Since all \c{,omment} does is throw away the argument, we can let TeX
% do that for us. The \relax here is matched by the \relax in the call
% in \parseargline; it could be more or less anything, its purpose is
% just to delimit the argument to the \c.
\def\argremovec#1\c#2\relax{\toks0 = {#1}}
\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}}
% \argremovec{,omment} might leave us with trailing spaces, though; e.g.,
% @end itemize @c foo
% will have two active spaces as part of the argument with the
% `itemize'. Here we remove all active spaces from #1, and assign the
% result to \toks0.
%
% This loses if there are any *other* active characters besides spaces
% in the argument -- _ ^ +, for example -- since they get expanded.
% Fortunately, Texinfo does not define any such commands. (If it ever
% does, the catcode of the characters in questionwill have to be changed
% here.) But this means we cannot call \removeactivespaces as part of
% \argremovec{,omment}, since @c uses \parsearg, and thus the argument
% that \parsearg gets might well have any character at all in it.
%
\def\removeactivespaces#1{%
\begingroup
\ignoreactivespaces
\edef\temp{#1}%
\global\toks0 = \expandafter{\temp}%
\endgroup
}
% Change the active space to expand to nothing.
%
\begingroup
\obeyspaces
\gdef\ignoreactivespaces{\obeyspaces\let =\empty}
\endgroup
\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
%% These are used to keep @begin/@end levels from running away
%% Call \inENV within environments (after a \begingroup)
\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
\def\ENVcheck{%
\ifENV\errmessage{Still within an environment. Type Return to continue.}
\endgroup\fi} % This is not perfect, but it should reduce lossage
% @begin foo is the same as @foo, for now.
\newhelp\EMsimple{Type to continue.}
\outer\def\begin{\parsearg\beginxxx}
\def\beginxxx #1{%
\expandafter\ifx\csname #1\endcsname\relax
{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
\csname #1\endcsname\fi}
% @end foo executes the definition of \Efoo.
%
\def\end{\parsearg\endxxx}
\def\endxxx #1{%
\removeactivespaces{#1}%
\edef\endthing{\the\toks0}%
%
\expandafter\ifx\csname E\endthing\endcsname\relax
\expandafter\ifx\csname \endthing\endcsname\relax
% There's no \foo, i.e., no ``environment'' foo.
\errhelp = \EMsimple
\errmessage{Undefined command `@end \endthing'}%
\else
\unmatchedenderror\endthing
\fi
\else
% Everything's ok; the right environment has been started.
\csname E\endthing\endcsname
\fi
}
% There is an environment #1, but it hasn't been started. Give an error.
%
\def\unmatchedenderror#1{%
\errhelp = \EMsimple
\errmessage{This `@end #1' doesn't have a matching `@#1'}%
}
% Define the control sequence \E#1 to give an unmatched @end error.
%
\def\defineunmatchedend#1{%
\expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}%
}
% Single-spacing is done by various environments (specifically, in
% \nonfillstart and \quotations).
\newskip\singlespaceskip \singlespaceskip = 12.5pt
\def\singlespace{%
% Why was this kern here? It messes up equalizing space above and below
% environments. --karl, 6may93
%{\advance \baselineskip by -\singlespaceskip
%\kern \baselineskip}%
\setleading \singlespaceskip
}
%% Simple single-character @ commands
% @@ prints an @
% Kludge this until the fonts are right (grr).
\def\@{{\tt \char '100}}
% This is turned off because it was never documented
% and you can use @w{...} around a quote to suppress ligatures.
%% Define @` and @' to be the same as ` and '
%% but suppressing ligatures.
%\def\`{{`}}
%\def\'{{'}}
% Used to generate quoted braces.
\def\mylbrace {{\tt \char '173}}
\def\myrbrace {{\tt \char '175}}
\let\{=\mylbrace
\let\}=\myrbrace
% @: forces normal size whitespace following.
\def\:{\spacefactor=1000 }
% @* forces a line break.
\def\*{\hfil\break\hbox{}\ignorespaces}
% @. is an end-of-sentence period.
\def\.{.\spacefactor=3000 }
% @enddots{} is an end-of-sentence ellipsis.
\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000}
% @! is an end-of-sentence bang.
\gdef\!{!\spacefactor=3000 }
% @? is an end-of-sentence query.
\gdef\?{?\spacefactor=3000 }
% @w prevents a word break. Without the \leavevmode, @w at the
% beginning of a paragraph, when TeX is still in vertical mode, would
% produce a whole line of output instead of starting the paragraph.
\def\w#1{\leavevmode\hbox{#1}}
% @group ... @end group forces ... to be all on one page, by enclosing
% it in a TeX vbox. We use \vtop instead of \vbox to construct the box
% to keep its height that of a normal line. According to the rules for
% \topskip (p.114 of the TeXbook), the glue inserted is
% max (\topskip - \ht (first item), 0). If that height is large,
% therefore, no glue is inserted, and the space between the headline and
% the text is small, which looks bad.
%
\def\group{\begingroup
\ifnum\catcode13=\active \else
\errhelp = \groupinvalidhelp
\errmessage{@group invalid in context where filling is enabled}%
\fi
%
% The \vtop we start below produces a box with normal height and large
% depth; thus, TeX puts \baselineskip glue before it, and (when the
% next line of text is done) \lineskip glue after it. (See p.82 of
% the TeXbook.) Thus, space below is not quite equal to space
% above. But it's pretty close.
\def\Egroup{%
\egroup % End the \vtop.
\endgroup % End the \group.
}%
%
\vtop\bgroup
% We have to put a strut on the last line in case the @group is in
% the midst of an example, rather than completely enclosing it.
% Otherwise, the interline space between the last line of the group
% and the first line afterwards is too small. But we can't put the
% strut in \Egroup, since there it would be on a line by itself.
% Hence this just inserts a strut at the beginning of each line.
\everypar = {\strut}%
%
% Since we have a strut on every line, we don't need any of TeX's
% normal interline spacing.
\offinterlineskip
%
% OK, but now we have to do something about blank
% lines in the input in @example-like environments, which normally
% just turn into \lisppar, which will insert no space now that we've
% turned off the interline space. Simplest is to make them be an
% empty paragraph.
\ifx\par\lisppar
\edef\par{\leavevmode \par}%
%
% Reset ^^M's definition to new definition of \par.
\obeylines
\fi
%
% Do @comment since we are called inside an environment such as
% @example, where each end-of-line in the input causes an
% end-of-line in the output. We don't want the end-of-line after
% the `@group' to put extra space in the output. Since @group
% should appear on a line by itself (according to the Texinfo
% manual), we don't worry about eating any user text.
\comment
}
%
% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
% message, so this ends up printing `@group can only ...'.
%
\newhelp\groupinvalidhelp{%
group can only be used in environments such as @example,^^J%
where each line of input produces a line of output.}
% @need space-in-mils
% forces a page break if there is not space-in-mils remaining.
\newdimen\mil \mil=0.001in
\def\need{\parsearg\needx}
% Old definition--didn't work.
%\def\needx #1{\par %
%% This method tries to make TeX break the page naturally
%% if the depth of the box does not fit.
%{\baselineskip=0pt%
%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000
%\prevdepth=-1000pt
%}}
\def\needx#1{%
% Go into vertical mode, so we don't make a big box in the middle of a
% paragraph.
\par
%
% Don't add any leading before our big empty box, but allow a page
% break, since the best break might be right here.
\allowbreak
\nointerlineskip
\vtop to #1\mil{\vfil}%
%
% TeX does not even consider page breaks if a penalty added to the
% main vertical list is 10000 or more. But in order to see if the
% empty box we just added fits on the page, we must make it consider
% page breaks. On the other hand, we don't want to actually break the
% page after the empty box. So we use a penalty of 9999.
%
% There is an extremely small chance that TeX will actually break the
% page at this \penalty, if there are no other feasible breakpoints in
% sight. (If the user is using lots of big @group commands, which
% almost-but-not-quite fill up a page, TeX will have a hard time doing
% good page breaking, for example.) However, I could not construct an
% example where a page broke at this \penalty; if it happens in a real
% document, then we can reconsider our strategy.
\penalty9999
%
% Back up by the size of the box, whether we did a page break or not.
\kern -#1\mil
%
% Do not allow a page break right after this kern.
\nobreak
}
% @br forces paragraph break
\let\br = \par
% @dots{} output some dots
\def\dots{$\ldots$}
% @page forces the start of a new page
\def\page{\par\vfill\supereject}
% @exdent text....
% outputs text on separate line in roman font, starting at standard page margin
% This records the amount of indent in the innermost environment.
% That's how much \exdent should take out.
\newskip\exdentamount
% This defn is used inside fill environments such as @defun.
\def\exdent{\parsearg\exdentyyy}
\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}}
% This defn is used inside nofill environments such as @example.
\def\nofillexdent{\parsearg\nofillexdentyyy}
\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount
\leftline{\hskip\leftskip{\rm#1}}}}
%\hbox{{\rm#1}}\hfil\break}}
% @include file insert text of that file as input.
\def\include{\parsearg\includezzz}
%Use \input\thisfile to avoid blank after \input, which may be an active
%char (in which case the blank would become the \input argument).
%The grouping keeps the value of \thisfile correct even when @include
%is nested.
\def\includezzz #1{\begingroup
\def\thisfile{#1}\input\thisfile
\endgroup}
\def\thisfile{}
% @center line outputs that line, centered
\def\center{\parsearg\centerzzz}
\def\centerzzz #1{{\advance\hsize by -\leftskip
\advance\hsize by -\rightskip
\centerline{#1}}}
% @sp n outputs n lines of vertical space
\def\sp{\parsearg\spxxx}
\def\spxxx #1{\par \vskip #1\baselineskip}
% @comment ...line which is ignored...
% @c is the same as @comment
% @ignore ... @end ignore is another way to write a comment
\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other%
\parsearg \commentxxx}
\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 }
\let\c=\comment
% Prevent errors for section commands.
% Used in @ignore and in failing conditionals.
\def\ignoresections{%
\let\chapter=\relax
\let\unnumbered=\relax
\let\top=\relax
\let\unnumberedsec=\relax
\let\unnumberedsection=\relax
\let\unnumberedsubsec=\relax
\let\unnumberedsubsection=\relax
\let\unnumberedsubsubsec=\relax
\let\unnumberedsubsubsection=\relax
\let\section=\relax
\let\subsec=\relax
\let\subsubsec=\relax
\let\subsection=\relax
\let\subsubsection=\relax
\let\appendix=\relax
\let\appendixsec=\relax
\let\appendixsection=\relax
\let\appendixsubsec=\relax
\let\appendixsubsection=\relax
\let\appendixsubsubsec=\relax
\let\appendixsubsubsection=\relax
\let\contents=\relax
\let\smallbook=\relax
\let\titlepage=\relax
}
% Used in nested conditionals, where we have to parse the Texinfo source
% and so want to turn off most commands, in case they are used
% incorrectly.
%
\def\ignoremorecommands{%
\let\defcv = \relax
\let\deffn = \relax
\let\deffnx = \relax
\let\defindex = \relax
\let\defivar = \relax
\let\defmac = \relax
\let\defmethod = \relax
\let\defop = \relax
\let\defopt = \relax
\let\defspec = \relax
\let\deftp = \relax
\let\deftypefn = \relax
\let\deftypefun = \relax
\let\deftypevar = \relax
\let\deftypevr = \relax
\let\defun = \relax
\let\defvar = \relax
\let\defvr = \relax
\let\ref = \relax
\let\xref = \relax
\let\printindex = \relax
\let\pxref = \relax
\let\settitle = \relax
\let\include = \relax
\let\lowersections = \relax
\let\down = \relax
\let\raisesections = \relax
\let\up = \relax
\let\set = \relax
\let\clear = \relax
\let\item = \relax
\let\message = \relax
}
% Ignore @ignore ... @end ignore.
%
\def\ignore{\doignore{ignore}}
% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text.
%
\def\ifinfo{\doignore{ifinfo}}
\def\ifhtml{\doignore{ifhtml}}
\def\html{\doignore{html}}
\def\menu{\doignore{menu}}
\def\direntry{\doignore{direntry}}
% Ignore text until a line `@end #1'.
%
\def\doignore#1{\begingroup
% Don't complain about control sequences we have declared \outer.
\ignoresections
%
% Define a command to swallow text until we reach `@end #1'.
\long\def\doignoretext##1\end #1{\enddoignore}%
%
% Make sure that spaces turn into tokens that match what \doignoretext wants.
\catcode32 = 10
%
% And now expand that command.
\doignoretext
}
% What we do to finish off ignored text.
%
\def\enddoignore{\endgroup\ignorespaces}%
\newif\ifwarnedobs\warnedobsfalse
\def\obstexwarn{%
\ifwarnedobs\relax\else
% We need to warn folks that they may have trouble with TeX 3.0.
% This uses \immediate\write16 rather than \message to get newlines.
\immediate\write16{}
\immediate\write16{***WARNING*** for users of Unix TeX 3.0!}
\immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).}
\immediate\write16{If you are running another version of TeX, relax.}
\immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.}
\immediate\write16{ Then upgrade your TeX installation if you can.}
\immediate\write16{If you are stuck with version 3.0, run the}
\immediate\write16{ script ``tex3patch'' from the Texinfo distribution}
\immediate\write16{ to use a workaround.}
\immediate\write16{}
\warnedobstrue
\fi
}
% **In TeX 3.0, setting text in \nullfont hangs tex. For a
% workaround (which requires the file ``dummy.tfm'' to be installed),
% uncomment the following line:
%%%%%\font\nullfont=dummy\let\obstexwarn=\relax
% Ignore text, except that we keep track of conditional commands for
% purposes of nesting, up to an `@end #1' command.
%
\def\nestedignore#1{%
\obstexwarn
% We must actually expand the ignored text to look for the @end
% command, so that nested ignore constructs work. Thus, we put the
% text into a \vbox and then do nothing with the result. To minimize
% the change of memory overflow, we follow the approach outlined on
% page 401 of the TeXbook: make the current font be a dummy font.
%
\setbox0 = \vbox\bgroup
% Don't complain about control sequences we have declared \outer.
\ignoresections
%
% Define `@end #1' to end the box, which will in turn undefine the
% @end command again.
\expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}%
%
% We are going to be parsing Texinfo commands. Most cause no
% trouble when they are used incorrectly, but some commands do
% complicated argument parsing or otherwise get confused, so we
% undefine them.
%
% We can't do anything about stray @-signs, unfortunately;
% they'll produce `undefined control sequence' errors.
\ignoremorecommands
%
% Set the current font to be \nullfont, a TeX primitive, and define
% all the font commands to also use \nullfont. We don't use
% dummy.tfm, as suggested in the TeXbook, because not all sites
% might have that installed. Therefore, math mode will still
% produce output, but that should be an extremely small amount of
% stuff compared to the main input.
%
\nullfont
\let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont
\let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont
\let\tensf = \nullfont
% Similarly for index fonts (mostly for their use in
% smallexample)
\let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont
\let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont
\let\indsf = \nullfont
%
% Don't complain when characters are missing from the fonts.
\tracinglostchars = 0
%
% Don't bother to do space factor calculations.
\frenchspacing
%
% Don't report underfull hboxes.
\hbadness = 10000
%
% Do minimal line-breaking.
\pretolerance = 10000
%
% Do not execute instructions in @tex
\def\tex{\doignore{tex}}
}
% @set VAR sets the variable VAR to an empty value.
% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
%
% Since we want to separate VAR from REST-OF-LINE (which might be
% empty), we can't just use \parsearg; we have to insert a space of our
% own to delimit the rest of the line, and then take it out again if we
% didn't need it.
%
\def\set{\parsearg\setxxx}
\def\setxxx#1{\setyyy#1 \endsetyyy}
\def\setyyy#1 #2\endsetyyy{%
\def\temp{#2}%
\ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty
\else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted.
\fi
}
% Can't use \xdef to pre-expand #2 and save some time, since \temp or
% \next or other control sequences that we've defined might get us into
% an infinite loop. Consider `@set foo @cite{bar}'.
\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}}
% @clear VAR clears (i.e., unsets) the variable VAR.
%
\def\clear{\parsearg\clearxxx}
\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax}
% @value{foo} gets the text saved in variable foo.
%
\def\value#1{\expandafter
\ifx\csname SET#1\endcsname\relax
{\{No value for ``#1''\}}
\else \csname SET#1\endcsname \fi}
% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
% with @set.
%
\def\ifset{\parsearg\ifsetxxx}
\def\ifsetxxx #1{%
\expandafter\ifx\csname SET#1\endcsname\relax
\expandafter\ifsetfail
\else
\expandafter\ifsetsucceed
\fi
}
\def\ifsetsucceed{\conditionalsucceed{ifset}}
\def\ifsetfail{\nestedignore{ifset}}
\defineunmatchedend{ifset}
% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
% defined with @set, or has been undefined with @clear.
%
\def\ifclear{\parsearg\ifclearxxx}
\def\ifclearxxx #1{%
\expandafter\ifx\csname SET#1\endcsname\relax
\expandafter\ifclearsucceed
\else
\expandafter\ifclearfail
\fi
}
\def\ifclearsucceed{\conditionalsucceed{ifclear}}
\def\ifclearfail{\nestedignore{ifclear}}
\defineunmatchedend{ifclear}
% @iftex always succeeds; we read the text following, through @end
% iftex). But `@end iftex' should be valid only after an @iftex.
%
\def\iftex{\conditionalsucceed{iftex}}
\defineunmatchedend{iftex}
% We can't just want to start a group at @iftex (for example) and end it
% at @end iftex, since then @set commands inside the conditional have no
% effect (they'd get reverted at the end of the group). So we must
% define \Eiftex to redefine itself to be its previous value. (We can't
% just define it to fail again with an ``unmatched end'' error, since
% the @ifset might be nested.)
%
\def\conditionalsucceed#1{%
\edef\temp{%
% Remember the current value of \E#1.
\let\nece{prevE#1} = \nece{E#1}%
%
% At the `@end #1', redefine \E#1 to be its previous value.
\def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}%
}%
\temp
}
% We need to expand lots of \csname's, but we don't want to expand the
% control sequences after we've constructed them.
%
\def\nece#1{\expandafter\noexpand\csname#1\endcsname}
% @asis just yields its argument. Used with @table, for example.
%
\def\asis#1{#1}
% @math means output in math mode.
% We don't use $'s directly in the definition of \math because control
% sequences like \math are expanded when the toc file is written. Then,
% we read the toc file back, the $'s will be normal characters (as they
% should be, according to the definition of Texinfo). So we must use a
% control sequence to switch into and out of math mode.
%
% This isn't quite enough for @math to work properly in indices, but it
% seems unlikely it will ever be needed there.
%
\let\implicitmath = $
\def\math#1{\implicitmath #1\implicitmath}
% @bullet and @minus need the same treatment as @math, just above.
\def\bullet{\implicitmath\ptexbullet\implicitmath}
\def\minus{\implicitmath-\implicitmath}
\def\node{\ENVcheck\parsearg\nodezzz}
\def\nodezzz#1{\nodexxx [#1,]}
\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
\let\nwnode=\node
\let\lastnode=\relax
\def\donoderef{\ifx\lastnode\relax\else
\expandafter\expandafter\expandafter\setref{\lastnode}\fi
\global\let\lastnode=\relax}
\def\unnumbnoderef{\ifx\lastnode\relax\else
\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi
\global\let\lastnode=\relax}
\def\appendixnoderef{\ifx\lastnode\relax\else
\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi
\global\let\lastnode=\relax}
\let\refill=\relax
% @setfilename is done at the beginning of every texinfo file.
% So open here the files we need to have open while reading the input.
% This makes it possible to make a .fmt file for texinfo.
\def\setfilename{%
\readauxfile
\opencontents
\openindices
\fixbackslash % Turn off hack to swallow `\input texinfo'.
\global\let\setfilename=\comment % Ignore extra @setfilename cmds.
\comment % Ignore the actual filename.
}
\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
\def\inforef #1{\inforefzzz #1,,,,**}
\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
node \samp{\ignorespaces#1{}}}
\message{fonts,}
% Font-change commands.
% Texinfo supports the sans serif font style, which plain TeX does not.
% So we set up a \sf analogous to plain's \rm, etc.
\newfam\sffam
\def\sf{\fam=\sffam \tensf}
\let\li = \sf % Sometimes we call it \li, not \sf.
%% Try out Computer Modern fonts at \magstephalf
\let\mainmagstep=\magstephalf
% Set the font macro #1 to the font named #2, adding on the
% specified font prefix (normally `cm').
\def\setfont#1#2{\font#1=\fontprefix#2}
% Use cm as the default font prefix.
% To specify the font prefix, you must define \fontprefix
% before you read in texinfo.tex.
\ifx\fontprefix\undefined
\def\fontprefix{cm}
\fi
\ifx\bigger\relax
\let\mainmagstep=\magstep1
\setfont\textrm{r12}
\setfont\texttt{tt12}
\else
\setfont\textrm{r10 scaled \mainmagstep}
\setfont\texttt{tt10 scaled \mainmagstep}
\fi
% Instead of cmb10, you many want to use cmbx10.
% cmbx10 is a prettier font on its own, but cmb10
% looks better when embedded in a line with cmr10.
\setfont\textbf{b10 scaled \mainmagstep}
\setfont\textit{ti10 scaled \mainmagstep}
\setfont\textsl{sl10 scaled \mainmagstep}
\setfont\textsf{ss10 scaled \mainmagstep}
\setfont\textsc{csc10 scaled \mainmagstep}
\font\texti=cmmi10 scaled \mainmagstep
\font\textsy=cmsy10 scaled \mainmagstep
% A few fonts for @defun, etc.
\setfont\defbf{bx10 scaled \magstep1} %was 1314
\setfont\deftt{tt10 scaled \magstep1}
\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf}
% Fonts for indices and small examples.
% We actually use the slanted font rather than the italic,
% because texinfo normally uses the slanted fonts for that.
% Do not make many font distinctions in general in the index, since they
% aren't very useful.
\setfont\ninett{tt9}
\setfont\indrm{r9}
\setfont\indit{sl9}
\let\indsl=\indit
\let\indtt=\ninett
\let\indsf=\indrm
\let\indbf=\indrm
\setfont\indsc{csc10 at 9pt}
\font\indi=cmmi9
\font\indsy=cmsy9
% Fonts for headings
\setfont\chaprm{bx12 scaled \magstep2}
\setfont\chapit{ti12 scaled \magstep2}
\setfont\chapsl{sl12 scaled \magstep2}
\setfont\chaptt{tt12 scaled \magstep2}
\setfont\chapsf{ss12 scaled \magstep2}
\let\chapbf=\chaprm
\setfont\chapsc{csc10 scaled\magstep3}
\font\chapi=cmmi12 scaled \magstep2
\font\chapsy=cmsy10 scaled \magstep3
\setfont\secrm{bx12 scaled \magstep1}
\setfont\secit{ti12 scaled \magstep1}
\setfont\secsl{sl12 scaled \magstep1}
\setfont\sectt{tt12 scaled \magstep1}
\setfont\secsf{ss12 scaled \magstep1}
\setfont\secbf{bx12 scaled \magstep1}
\setfont\secsc{csc10 scaled\magstep2}
\font\seci=cmmi12 scaled \magstep1
\font\secsy=cmsy10 scaled \magstep2
% \setfont\ssecrm{bx10 scaled \magstep1} % This size an font looked bad.
% \setfont\ssecit{cmti10 scaled \magstep1} % The letters were too crowded.
% \setfont\ssecsl{sl10 scaled \magstep1}
% \setfont\ssectt{tt10 scaled \magstep1}
% \setfont\ssecsf{ss10 scaled \magstep1}
%\setfont\ssecrm{b10 scaled 1315} % Note the use of cmb rather than cmbx.
%\setfont\ssecit{ti10 scaled 1315} % Also, the size is a little larger than
%\setfont\ssecsl{sl10 scaled 1315} % being scaled magstep1.
%\setfont\ssectt{tt10 scaled 1315}
%\setfont\ssecsf{ss10 scaled 1315}
%\let\ssecbf=\ssecrm
\setfont\ssecrm{bx12 scaled \magstephalf}
\setfont\ssecit{ti12 scaled \magstephalf}
\setfont\ssecsl{sl12 scaled \magstephalf}
\setfont\ssectt{tt12 scaled \magstephalf}
\setfont\ssecsf{ss12 scaled \magstephalf}
\setfont\ssecbf{bx12 scaled \magstephalf}
\setfont\ssecsc{csc10 scaled \magstep1}
\font\sseci=cmmi12 scaled \magstephalf
\font\ssecsy=cmsy10 scaled \magstep1
% The smallcaps and symbol fonts should actually be scaled \magstep1.5,
% but that is not a standard magnification.
% Fonts for title page:
\setfont\titlerm{bx12 scaled \magstep3}
\let\authorrm = \secrm
% In order for the font changes to affect most math symbols and letters,
% we have to define the \textfont of the standard families. Since
% texinfo doesn't allow for producing subscripts and superscripts, we
% don't bother to reset \scriptfont and \scriptscriptfont (which would
% also require loading a lot more fonts).
%
\def\resetmathfonts{%
\textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy
\textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf
\textfont\ttfam = \tentt \textfont\sffam = \tensf
}
% The font-changing commands redefine the meanings of \tenSTYLE, instead
% of just \STYLE. We do this so that font changes will continue to work
% in math mode, where it is the current \fam that is relevant in most
% cases, not the current. Plain TeX does, for example,
% \def\bf{\fam=\bffam \tenbf} By redefining \tenbf, we obviate the need
% to redefine \bf itself.
\def\textfonts{%
\let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
\let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
\let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
\resetmathfonts}
\def\chapfonts{%
\let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
\let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
\let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
\resetmathfonts}
\def\secfonts{%
\let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
\let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
\let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
\resetmathfonts}
\def\subsecfonts{%
\let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
\let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
\let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
\resetmathfonts}
\def\indexfonts{%
\let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl
\let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc
\let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy
\resetmathfonts}
% Set up the default fonts, so we can use them for creating boxes.
%
\textfonts
% Count depth in font-changes, for error checks
\newcount\fontdepth \fontdepth=0
% Fonts for short table of contents.
\setfont\shortcontrm{r12}
\setfont\shortcontbf{bx12}
\setfont\shortcontsl{sl12}
%% Add scribe-like font environments, plus @l for inline lisp (usually sans
%% serif) and @ii for TeX italic
% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
% unless the following character is such as not to need one.
\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi}
\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx}
\let\i=\smartitalic
\let\var=\smartitalic
\let\dfn=\smartitalic
\let\emph=\smartitalic
\let\cite=\smartitalic
\def\b#1{{\bf #1}}
\let\strong=\b
% We can't just use \exhyphenpenalty, because that only has effect at
% the end of a paragraph. Restore normal hyphenation at the end of the
% group within which \nohyphenation is presumably called.
%
\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation}
\def\restorehyphenation{\hyphenchar\font = `- }
\def\t#1{%
{\tt \rawbackslash \frenchspacing #1}%
\null
}
\let\ttfont=\t
\def\samp #1{`\tclose{#1}'\null}
\def\key #1{{\tt \nohyphenation \uppercase{#1}}\null}
\def\ctrl #1{{\tt \rawbackslash \hat}#1}
\let\file=\samp
% @code is a modification of @t,
% which makes spaces the same size as normal in the surrounding text.
\def\tclose#1{%
{%
% Change normal interword space to be same as for the current font.
\spaceskip = \fontdimen2\font
%
% Switch to typewriter.
\tt
%
% But `\ ' produces the large typewriter interword space.
\def\ {{\spaceskip = 0pt{} }}%
%
% Turn off hyphenation.
\nohyphenation
%
\rawbackslash
\frenchspacing
#1%
}%
\null
}
% We *must* turn on hyphenation at `-' and `_' in \code.
% Otherwise, it is too hard to avoid overful hboxes
% in the Emacs manual, the Library manual, etc.
% Unfortunately, TeX uses one parameter (\hyphenchar) to control
% both hyphenation at - and hyphenation within words.
% We must therefore turn them both off (\tclose does that)
% and arrange explicitly to hyphenate an a dash.
% -- rms.
{
\catcode`\-=\active
\catcode`\_=\active
\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex}
% The following is used by \doprintindex to insure that long function names
% wrap around. It is necessary for - and _ to be active before the index is
% read from the file, as \entry parses the arguments long before \code is
% ever called. -- mycroft
\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder}
}
\def\realdash{-}
\def\realunder{_}
\def\codedash{-\discretionary{}{}{}}
\def\codeunder{\normalunderscore\discretionary{}{}{}}
\def\codex #1{\tclose{#1}\endgroup}
%\let\exp=\tclose %Was temporary
% @kbd is like @code, except that if the argument is just one @key command,
% then @kbd has no effect.
\def\xkey{\key}
\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
\ifx\one\xkey\ifx\threex\three \key{#2}%
\else\tclose{\look}\fi
\else\tclose{\look}\fi}
% Typeset a dimension, e.g., `in' or `pt'. The only reason for the
% argument is to make the input look right: @dmn{pt} instead of
% @dmn{}pt.
%
\def\dmn#1{\thinspace #1}
\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par}
\def\l#1{{\li #1}\null} %
\def\r#1{{\rm #1}} % roman font
% Use of \lowercase was suggested.
\def\sc#1{{\smallcaps#1}} % smallcaps font
\def\ii#1{{\it #1}} % italic font
\message{page headings,}
\newskip\titlepagetopglue \titlepagetopglue = 1.5in
\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
% First the title page. Must do @settitle before @titlepage.
\def\titlefont#1{{\titlerm #1}}
\newif\ifseenauthor
\newif\iffinishedtitlepage
\def\shorttitlepage{\parsearg\shorttitlepagezzz}
\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}%
\endgroup\page\hbox{}\page}
\def\titlepage{\begingroup \parindent=0pt \textfonts
\let\subtitlerm=\tenrm
% I deinstalled the following change because \cmr12 is undefined.
% This change was not in the ChangeLog anyway. --rms.
% \let\subtitlerm=\cmr12
\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}%
%
\def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
%
% Leave some space at the very top of the page.
\vglue\titlepagetopglue
%
% Now you can print the title using @title.
\def\title{\parsearg\titlezzz}%
\def\titlezzz##1{\leftline{\titlefont{##1}}
% print a rule at the page bottom also.
\finishedtitlepagefalse
\vskip4pt \hrule height 4pt width \hsize \vskip4pt}%
% No rule at page bottom unless we print one at the top with @title.
\finishedtitlepagetrue
%
% Now you can put text using @subtitle.
\def\subtitle{\parsearg\subtitlezzz}%
\def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
%
% @author should come last, but may come many times.
\def\author{\parsearg\authorzzz}%
\def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
{\authorfont \leftline{##1}}}%
%
% Most title ``pages'' are actually two pages long, with space
% at the top of the second. We don't want the ragged left on the second.
\let\oldpage = \page
\def\page{%
\iffinishedtitlepage\else
\finishtitlepage
\fi
\oldpage
\let\page = \oldpage
\hbox{}}%
% \def\page{\oldpage \hbox{}}
}
\def\Etitlepage{%
\iffinishedtitlepage\else
\finishtitlepage
\fi
% It is important to do the page break before ending the group,
% because the headline and footline are only empty inside the group.
% If we use the new definition of \page, we always get a blank page
% after the title page, which we certainly don't want.
\oldpage
\endgroup
\HEADINGSon
}
\def\finishtitlepage{%
\vskip4pt \hrule height 2pt width \hsize
\vskip\titlepagebottomglue
\finishedtitlepagetrue
}
%%% Set up page headings and footings.
\let\thispage=\folio
\newtoks \evenheadline % Token sequence for heading line of even pages
\newtoks \oddheadline % Token sequence for heading line of odd pages
\newtoks \evenfootline % Token sequence for footing line of even pages
\newtoks \oddfootline % Token sequence for footing line of odd pages
% Now make Tex use those variables
\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
\else \the\evenheadline \fi}}
\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
\else \the\evenfootline \fi}\HEADINGShook}
\let\HEADINGShook=\relax
% Commands to set those variables.
% For example, this is what @headings on does
% @evenheading @thistitle|@thispage|@thischapter
% @oddheading @thischapter|@thispage|@thistitle
% @evenfooting @thisfile||
% @oddfooting ||@thisfile
\def\evenheading{\parsearg\evenheadingxxx}
\def\oddheading{\parsearg\oddheadingxxx}
\def\everyheading{\parsearg\everyheadingxxx}
\def\evenfooting{\parsearg\evenfootingxxx}
\def\oddfooting{\parsearg\oddfootingxxx}
\def\everyfooting{\parsearg\everyfootingxxx}
{\catcode`\@=0 %
\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish}
\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{%
\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish}
\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{%
\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
%
}% unbind the catcode of @.
% @headings double turns headings on for double-sided printing.
% @headings single turns headings on for single-sided printing.
% @headings off turns them off.
% @headings on same as @headings double, retained for compatibility.
% @headings after turns on double-sided headings after this page.
% @headings doubleafter turns on double-sided headings after this page.
% @headings singleafter turns on single-sided headings after this page.
% By default, they are off.
\def\headings #1 {\csname HEADINGS#1\endcsname}
\def\HEADINGSoff{
\global\evenheadline={\hfil} \global\evenfootline={\hfil}
\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
\HEADINGSoff
% When we turn headings on, set the page number to 1.
% For double-sided printing, put current file name in lower left corner,
% chapter name on inside top of right hand pages, document
% title on inside top of left hand pages, and page numbers on outside top
% edge of all pages.
\def\HEADINGSdouble{
%\pagealignmacro
\global\pageno=1
\global\evenfootline={\hfil}
\global\oddfootline={\hfil}
\global\evenheadline={\line{\folio\hfil\thistitle}}
\global\oddheadline={\line{\thischapter\hfil\folio}}
}
% For single-sided printing, chapter title goes across top left of page,
% page number on top right.
\def\HEADINGSsingle{
%\pagealignmacro
\global\pageno=1
\global\evenfootline={\hfil}
\global\oddfootline={\hfil}
\global\evenheadline={\line{\thischapter\hfil\folio}}
\global\oddheadline={\line{\thischapter\hfil\folio}}
}
\def\HEADINGSon{\HEADINGSdouble}
\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
\let\HEADINGSdoubleafter=\HEADINGSafter
\def\HEADINGSdoublex{%
\global\evenfootline={\hfil}
\global\oddfootline={\hfil}
\global\evenheadline={\line{\folio\hfil\thistitle}}
\global\oddheadline={\line{\thischapter\hfil\folio}}
}
\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
\def\HEADINGSsinglex{%
\global\evenfootline={\hfil}
\global\oddfootline={\hfil}
\global\evenheadline={\line{\thischapter\hfil\folio}}
\global\oddheadline={\line{\thischapter\hfil\folio}}
}
% Subroutines used in generating headings
% Produces Day Month Year style of output.
\def\today{\number\day\space
\ifcase\month\or
January\or February\or March\or April\or May\or June\or
July\or August\or September\or October\or November\or December\fi
\space\number\year}
% Use this if you want the Month Day, Year style of output.
%\def\today{\ifcase\month\or
%January\or February\or March\or April\or May\or June\or
%July\or August\or September\or October\or November\or December\fi
%\space\number\day, \number\year}
% @settitle line... specifies the title of the document, for headings
% It generates no output of its own
\def\thistitle{No Title}
\def\settitle{\parsearg\settitlezzz}
\def\settitlezzz #1{\gdef\thistitle{#1}}
\message{tables,}
% @tabs -- simple alignment
% These don't work. For one thing, \+ is defined as outer.
% So these macros cannot even be defined.
%\def\tabs{\parsearg\tabszzz}
%\def\tabszzz #1{\settabs\+#1\cr}
%\def\tabline{\parsearg\tablinezzz}
%\def\tablinezzz #1{\+#1\cr}
%\def\&{&}
% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x).
% default indentation of table text
\newdimen\tableindent \tableindent=.8in
% default indentation of @itemize and @enumerate text
\newdimen\itemindent \itemindent=.3in
% margin between end of table item and start of table text.
\newdimen\itemmargin \itemmargin=.1in
% used internally for \itemindent minus \itemmargin
\newdimen\itemmax
% Note @table, @vtable, and @vtable define @item, @itemx, etc., with
% these defs.
% They also define \itemindex
% to index the item name in whatever manner is desired (perhaps none).
\newif\ifitemxneedsnegativevskip
\def\itemxpar{\par\ifitemxneedsnegativevskip\vskip-\parskip\nobreak\fi}
\def\internalBitem{\smallbreak \parsearg\itemzzz}
\def\internalBitemx{\itemxpar \parsearg\itemzzz}
\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz}
\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
\def\internalBkitemx{\itemxpar \parsearg\kitemzzz}
\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}%
\itemzzz {#1}}
\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}%
\itemzzz {#1}}
\def\itemzzz #1{\begingroup %
\advance\hsize by -\rightskip
\advance\hsize by -\tableindent
\setbox0=\hbox{\itemfont{#1}}%
\itemindex{#1}%
\nobreak % This prevents a break before @itemx.
%
% Be sure we are not still in the middle of a paragraph.
%{\parskip = 0in
%\par
%}%
%
% If the item text does not fit in the space we have, put it on a line
% by itself, and do not allow a page break either before or after that
% line. We do not start a paragraph here because then if the next
% command is, e.g., @kindex, the whatsit would get put into the
% horizontal list on a line by itself, resulting in extra blank space.
\ifdim \wd0>\itemmax
%
% Make this a paragraph so we get the \parskip glue and wrapping,
% but leave it ragged-right.
\begingroup
\advance\leftskip by-\tableindent
\advance\hsize by\tableindent
\advance\rightskip by0pt plus1fil
\leavevmode\unhbox0\par
\endgroup
%
% We're going to be starting a paragraph, but we don't want the
% \parskip glue -- logically it's part of the @item we just started.
\nobreak \vskip-\parskip
%
% Stop a page break at the \parskip glue coming up. Unfortunately
% we can't prevent a possible page break at the following
% \baselineskip glue.
\nobreak
\endgroup
\itemxneedsnegativevskipfalse
\else
% The item text fits into the space. Start a paragraph, so that the
% following text (if any) will end up on the same line. Since that
% text will be indented by \tableindent, we make the item text be in
% a zero-width box.
\noindent
\rlap{\hskip -\tableindent\box0}\ignorespaces%
\endgroup%
\itemxneedsnegativevskiptrue%
\fi
}
\def\item{\errmessage{@item while not in a table}}
\def\itemx{\errmessage{@itemx while not in a table}}
\def\kitem{\errmessage{@kitem while not in a table}}
\def\kitemx{\errmessage{@kitemx while not in a table}}
\def\xitem{\errmessage{@xitem while not in a table}}
\def\xitemx{\errmessage{@xitemx while not in a table}}
%% Contains a kludge to get @end[description] to work
\def\description{\tablez{\dontindex}{1}{}{}{}{}}
\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
{\obeylines\obeyspaces%
\gdef\tablex #1^^M{%
\tabley\dontindex#1 \endtabley}}
\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
{\obeylines\obeyspaces%
\gdef\ftablex #1^^M{%
\tabley\fnitemindex#1 \endtabley
\def\Eftable{\endgraf\afterenvbreak\endgroup}%
\let\Etable=\relax}}
\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex}
{\obeylines\obeyspaces%
\gdef\vtablex #1^^M{%
\tabley\vritemindex#1 \endtabley
\def\Evtable{\endgraf\afterenvbreak\endgroup}%
\let\Etable=\relax}}
\def\dontindex #1{}
\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
\def\vritemindex #1{\doind {vr}{\code{#1}}}%
{\obeyspaces %
\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
\def\tablez #1#2#3#4#5#6{%
\aboveenvbreak %
\begingroup %
\def\Edescription{\Etable}% Necessary kludge.
\let\itemindex=#1%
\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
\ifnum 0#4>0 \tableindent=#4\mil \fi %
\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
\def\itemfont{#2}%
\itemmax=\tableindent %
\advance \itemmax by -\itemmargin %
\advance \leftskip by \tableindent %
\exdentamount=\tableindent
\parindent = 0pt
\parskip = \smallskipamount
\ifdim \parskip=0pt \parskip=2pt \fi%
\def\Etable{\endgraf\afterenvbreak\endgroup}%
\let\item = \internalBitem %
\let\itemx = \internalBitemx %
\let\kitem = \internalBkitem %
\let\kitemx = \internalBkitemx %
\let\xitem = \internalBxitem %
\let\xitemx = \internalBxitemx %
}
% This is the counter used by @enumerate, which is really @itemize
\newcount \itemno
\def\itemize{\parsearg\itemizezzz}
\def\itemizezzz #1{%
\begingroup % ended by the @end itemsize
\itemizey {#1}{\Eitemize}
}
\def\itemizey #1#2{%
\aboveenvbreak %
\itemmax=\itemindent %
\advance \itemmax by -\itemmargin %
\advance \leftskip by \itemindent %
\exdentamount=\itemindent
\parindent = 0pt %
\parskip = \smallskipamount %
\ifdim \parskip=0pt \parskip=2pt \fi%
\def#2{\endgraf\afterenvbreak\endgroup}%
\def\itemcontents{#1}%
\let\item=\itemizeitem}
% Set sfcode to normal for the chars that usually have another value.
% These are `.?!:;,'
\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000
\sfcode58=1000 \sfcode59=1000 \sfcode44=1000 }
% \splitoff TOKENS\endmark defines \first to be the first token in
% TOKENS, and \rest to be the remainder.
%
\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
% Allow an optional argument of an uppercase letter, lowercase letter,
% or number, to specify the first label in the enumerated list. No
% argument is the same as `1'.
%
\def\enumerate{\parsearg\enumeratezzz}
\def\enumeratezzz #1{\enumeratey #1 \endenumeratey}
\def\enumeratey #1 #2\endenumeratey{%
\begingroup % ended by the @end enumerate
%
% If we were given no argument, pretend we were given `1'.
\def\thearg{#1}%
\ifx\thearg\empty \def\thearg{1}\fi
%
% Detect if the argument is a single token. If so, it might be a
% letter. Otherwise, the only valid thing it can be is a number.
% (We will always have one token, because of the test we just made.
% This is a good thing, since \splitoff doesn't work given nothing at
% all -- the first parameter is undelimited.)
\expandafter\splitoff\thearg\endmark
\ifx\rest\empty
% Only one token in the argument. It could still be anything.
% A ``lowercase letter'' is one whose \lccode is nonzero.
% An ``uppercase letter'' is one whose \lccode is both nonzero, and
% not equal to itself.
% Otherwise, we assume it's a number.
%
% We need the \relax at the end of the \ifnum lines to stop TeX from
% continuing to look for a .
%
\ifnum\lccode\expandafter`\thearg=0\relax
\numericenumerate % a number (we hope)
\else
% It's a letter.
\ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
\lowercaseenumerate % lowercase letter
\else
\uppercaseenumerate % uppercase letter
\fi
\fi
\else
% Multiple tokens in the argument. We hope it's a number.
\numericenumerate
\fi
}
% An @enumerate whose labels are integers. The starting integer is
% given in \thearg.
%
\def\numericenumerate{%
\itemno = \thearg
\startenumeration{\the\itemno}%
}
% The starting (lowercase) letter is in \thearg.
\def\lowercaseenumerate{%
\itemno = \expandafter`\thearg
\startenumeration{%
% Be sure we're not beyond the end of the alphabet.
\ifnum\itemno=0
\errmessage{No more lowercase letters in @enumerate; get a bigger
alphabet}%
\fi
\char\lccode\itemno
}%
}
% The starting (uppercase) letter is in \thearg.
\def\uppercaseenumerate{%
\itemno = \expandafter`\thearg
\startenumeration{%
% Be sure we're not beyond the end of the alphabet.
\ifnum\itemno=0
\errmessage{No more uppercase letters in @enumerate; get a bigger
alphabet}
\fi
\char\uccode\itemno
}%
}
% Call itemizey, adding a period to the first argument and supplying the
% common last two arguments. Also subtract one from the initial value in
% \itemno, since @item increments \itemno.
%
\def\startenumeration#1{%
\advance\itemno by -1
\itemizey{#1.}\Eenumerate\flushcr
}
% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
% to @enumerate.
%
\def\alphaenumerate{\enumerate{a}}
\def\capsenumerate{\enumerate{A}}
\def\Ealphaenumerate{\Eenumerate}
\def\Ecapsenumerate{\Eenumerate}
% Definition of @item while inside @itemize.
\def\itemizeitem{%
\advance\itemno by 1
{\let\par=\endgraf \smallbreak}%
\ifhmode \errmessage{\in hmode at itemizeitem}\fi
{\parskip=0in \hskip 0pt
\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
\vadjust{\penalty 1200}}%
\flushcr}
% @multitable macros
% Amy Hendrickson, 8/18/94
%
% @multitable ... @endmultitable will make as many columns as desired.
% Contents of each column will wrap at width given in preamble. Width
% can be specified either with sample text given in a template line,
% or in percent of \hsize, the current width of text on page.
% Table can continue over pages but will only break between lines.
% To make preamble:
%
% Either define widths of columns in terms of percent of \hsize:
% @multitable @percentofhsize .2 .3 .5
% @item ...
%
% Numbers following @percentofhsize are the percent of the total
% current hsize to be used for each column. You may use as many
% columns as desired.
% Or use a template:
% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
% @item ...
% using the widest term desired in each column.
% Each new table line starts with @item, each subsequent new column
% starts with @tab. Empty columns may be produced by supplying @tab's
% with nothing between them for as many times as empty columns are needed,
% ie, @tab@tab@tab will produce two empty columns.
% @item, @tab, @multicolumn or @endmulticolumn do not need to be on their
% own lines, but it will not hurt if they are.
% Sample multitable:
% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
% @item first col stuff @tab second col stuff @tab third col
% @item
% first col stuff
% @tab
% second col stuff
% @tab
% third col
% @item first col stuff @tab second col stuff
% @tab Many paragraphs of text may be used in any column.
%
% They will wrap at the width determined by the template.
% @item@tab@tab This will be in third column.
% @endmultitable
% Default dimensions may be reset by user.
% @intableparskip will set vertical space between paragraphs in table.
% @intableparindent will set paragraph indent in table.
% @spacebetweencols will set horizontal space to be left between columns.
% @spacebetweenlines will set vertical space to be left between lines.
%%%%
% Dimensions
\newdimen\intableparskip
\newdimen\intableparindent
\newdimen\spacebetweencols
\newdimen\spacebetweenlines
\intableparskip=0pt
\intableparindent=6pt
\spacebetweencols=12pt
\spacebetweenlines=12pt
%%%%
% Macros used to set up halign preamble:
\let\endsetuptable\relax
\def\xendsetuptable{\endsetuptable}
\let\percentofhsize\relax
\def\xpercentofhsize{\percentofhsize}
\newif\ifsetpercent
\newcount\colcount
\def\setuptable#1{\def\firstarg{#1}%
\ifx\firstarg\xendsetuptable\let\go\relax%
\else
\ifx\firstarg\xpercentofhsize\global\setpercenttrue%
\else
\ifsetpercent
\if#1.\else%
\global\advance\colcount by1 %
\expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}%
\fi
\else
\global\advance\colcount by1
\setbox0=\hbox{#1}%
\expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
\fi%
\fi%
\let\go\setuptable%
\fi\go}
%%%%
% multitable syntax
\def\tab{&}
%%%%
% @multitable ... @endmultitable definitions:
\def\multitable#1\item{\bgroup
\let\item\cr
\tolerance=9500
\hbadness=9500
\parskip=\intableparskip
\parindent=\intableparindent
\overfullrule=0pt
\global\colcount=0\relax%
\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}%
% To parse everything between @multitable and @item :
\def\one{#1}\expandafter\setuptable\one\endsetuptable
% Need to reset this to 0 after \setuptable.
\global\colcount=0\relax%
%
% This preamble sets up a generic column definition, which will
% be used as many times as user calls for columns.
% \vtop will set a single line and will also let text wrap and
% continue for many paragraphs if desired.
\halign\bgroup&\global\advance\colcount by 1\relax%
\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname
% In order to keep entries from bumping into each other
% we will add a \leftskip of \spacebetweencols to all columns after
% the first one.
% If a template has been used, we will add \spacebetweencols
% to the width of each template entry.
% If user has set preamble in terms of percent of \hsize
% we will use that dimension as the width of the column, and
% the \leftskip will keep entries from bumping into each other.
% Table will start at left margin and final column will justify at
% right margin.
\ifnum\colcount=1
\else
\ifsetpercent
\else
% If user has set preamble in terms of percent of \hsize
% we will advance \hsize by \spacebetweencols
\advance\hsize by \spacebetweencols
\fi
% In either case we will make \leftskip=\spacebetweencols:
\leftskip=\spacebetweencols
\fi
\noindent##}\cr%
% \everycr will reset column counter, \colcount, at the end of
% each line. Every column entry will cause \colcount to advance by one.
% The table preamble
% looks at the current \colcount to find the correct column width.
\global\everycr{\noalign{\nointerlineskip\vskip\spacebetweenlines
\filbreak%% keeps underfull box messages off when table breaks over pages.
\global\colcount=0\relax}}}
\message{indexing,}
% Index generation facilities
% Define \newwrite to be identical to plain tex's \newwrite
% except not \outer, so it can be used within \newindex.
{\catcode`\@=11
\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
% \newindex {foo} defines an index named foo.
% It automatically defines \fooindex such that
% \fooindex ...rest of line... puts an entry in the index foo.
% It also defines \fooindfile to be the number of the output channel for
% the file that accumulates this index. The file's extension is foo.
% The name of an index should be no more than 2 characters long
% for the sake of vms.
\def\newindex #1{
\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
\noexpand\doindex {#1}}
}
% @defindex foo == \newindex{foo}
\def\defindex{\parsearg\newindex}
% Define @defcodeindex, like @defindex except put all entries in @code.
\def\newcodeindex #1{
\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
\openout \csname#1indfile\endcsname \jobname.#1 % Open the file
\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
\noexpand\docodeindex {#1}}
}
\def\defcodeindex{\parsearg\newcodeindex}
% @synindex foo bar makes index foo feed into index bar.
% Do this instead of @defindex foo if you don't want it as a separate index.
\def\synindex #1 #2 {%
\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
\expandafter\let\csname#1indfile\endcsname=\synindexfoo
\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
\noexpand\doindex {#2}}%
}
% @syncodeindex foo bar similar, but put all entries made for index foo
% inside @code.
\def\syncodeindex #1 #2 {%
\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
\expandafter\let\csname#1indfile\endcsname=\synindexfoo
\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex
\noexpand\docodeindex {#2}}%
}
% Define \doindex, the driver for all \fooindex macros.
% Argument #1 is generated by the calling \fooindex macro,
% and it is "foo", the name of the index.
% \doindex just uses \parsearg; it calls \doind for the actual work.
% This is because \doind is more useful to call from other macros.
% There is also \dosubind {index}{topic}{subtopic}
% which makes an entry in a two-level index such as the operation index.
\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
\def\singleindexer #1{\doind{\indexname}{#1}}
% like the previous two, but they put @code around the argument.
\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
\def\indexdummies{%
% Take care of the plain tex accent commands.
\def\"{\realbackslash "}%
\def\`{\realbackslash `}%
\def\'{\realbackslash '}%
\def\^{\realbackslash ^}%
\def\~{\realbackslash ~}%
\def\={\realbackslash =}%
\def\b{\realbackslash b}%
\def\c{\realbackslash c}%
\def\d{\realbackslash d}%
\def\u{\realbackslash u}%
\def\v{\realbackslash v}%
\def\H{\realbackslash H}%
% Take care of the plain tex special European modified letters.
\def\oe{\realbackslash oe}%
\def\ae{\realbackslash ae}%
\def\aa{\realbackslash aa}%
\def\OE{\realbackslash OE}%
\def\AE{\realbackslash AE}%
\def\AA{\realbackslash AA}%
\def\o{\realbackslash o}%
\def\O{\realbackslash O}%
\def\l{\realbackslash l}%
\def\L{\realbackslash L}%
\def\ss{\realbackslash ss}%
% Take care of texinfo commands likely to appear in an index entry.
\def\_{{\realbackslash _}}%
\def\w{\realbackslash w }%
\def\bf{\realbackslash bf }%
\def\rm{\realbackslash rm }%
\def\sl{\realbackslash sl }%
\def\sf{\realbackslash sf}%
\def\tt{\realbackslash tt}%
\def\gtr{\realbackslash gtr}%
\def\less{\realbackslash less}%
\def\hat{\realbackslash hat}%
\def\char{\realbackslash char}%
\def\TeX{\realbackslash TeX}%
\def\dots{\realbackslash dots }%
\def\copyright{\realbackslash copyright }%
\def\tclose##1{\realbackslash tclose {##1}}%
\def\code##1{\realbackslash code {##1}}%
\def\samp##1{\realbackslash samp {##1}}%
\def\t##1{\realbackslash r {##1}}%
\def\r##1{\realbackslash r {##1}}%
\def\i##1{\realbackslash i {##1}}%
\def\b##1{\realbackslash b {##1}}%
\def\cite##1{\realbackslash cite {##1}}%
\def\key##1{\realbackslash key {##1}}%
\def\file##1{\realbackslash file {##1}}%
\def\var##1{\realbackslash var {##1}}%
\def\kbd##1{\realbackslash kbd {##1}}%
\def\dfn##1{\realbackslash dfn {##1}}%
\def\emph##1{\realbackslash emph {##1}}%
\unsepspaces
}
% If an index command is used in an @example environment, any spaces
% therein should become regular spaces in the raw index file, not the
% expansion of \tie (\\leavevmode \penalty \@M \ ).
{\obeyspaces
\gdef\unsepspaces{\obeyspaces\let =\space}}
% \indexnofonts no-ops all font-change commands.
% This is used when outputting the strings to sort the index by.
\def\indexdummyfont#1{#1}
\def\indexdummytex{TeX}
\def\indexdummydots{...}
\def\indexnofonts{%
% Just ignore accents.
\let\"=\indexdummyfont
\let\`=\indexdummyfont
\let\'=\indexdummyfont
\let\^=\indexdummyfont
\let\~=\indexdummyfont
\let\==\indexdummyfont
\let\b=\indexdummyfont
\let\c=\indexdummyfont
\let\d=\indexdummyfont
\let\u=\indexdummyfont
\let\v=\indexdummyfont
\let\H=\indexdummyfont
% Take care of the plain tex special European modified letters.
\def\oe{oe}%
\def\ae{ae}%
\def\aa{aa}%
\def\OE{OE}%
\def\AE{AE}%
\def\AA{AA}%
\def\o{o}%
\def\O{O}%
\def\l{l}%
\def\L{L}%
\def\ss{ss}%
\let\w=\indexdummyfont
\let\t=\indexdummyfont
\let\r=\indexdummyfont
\let\i=\indexdummyfont
\let\b=\indexdummyfont
\let\emph=\indexdummyfont
\let\strong=\indexdummyfont
\let\cite=\indexdummyfont
\let\sc=\indexdummyfont
%Don't no-op \tt, since it isn't a user-level command
% and is used in the definitions of the active chars like <, >, |...
%\let\tt=\indexdummyfont
\let\tclose=\indexdummyfont
\let\code=\indexdummyfont
\let\file=\indexdummyfont
\let\samp=\indexdummyfont
\let\kbd=\indexdummyfont
\let\key=\indexdummyfont
\let\var=\indexdummyfont
\let\TeX=\indexdummytex
\let\dots=\indexdummydots
}
% To define \realbackslash, we must make \ not be an escape.
% We must first make another character (@) an escape
% so we do not become unable to do a definition.
{\catcode`\@=0 \catcode`\\=\other
@gdef@realbackslash{\}}
\let\indexbackslash=0 %overridden during \printindex.
\let\SETmarginindex=\relax %initialize!
% workhorse for all \fooindexes
% #1 is name of index, #2 is stuff to put there
\def\doind #1#2{%
% Put the index entry in the margin if desired.
\ifx\SETmarginindex\relax\else%
\insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}%
\fi%
{\count10=\lastpenalty %
{\indexdummies % Must do this here, since \bf, etc expand at this stage
\escapechar=`\\%
{\let\folio=0% Expand all macros now EXCEPT \folio
\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
% so it will be output as is; and it will print as backslash in the indx.
%
% Now process the index-string once, with all font commands turned off,
% to get the string to sort the index by.
{\indexnofonts
\xdef\temp1{#2}%
}%
% Now produce the complete index entry. We process the index-string again,
% this time with font commands expanded, to get what to print in the index.
\edef\temp{%
\write \csname#1indfile\endcsname{%
\realbackslash entry {\temp1}{\folio}{#2}}}%
\temp }%
}\penalty\count10}}
\def\dosubind #1#2#3{%
{\count10=\lastpenalty %
{\indexdummies % Must do this here, since \bf, etc expand at this stage
\escapechar=`\\%
{\let\folio=0%
\def\rawbackslashxx{\indexbackslash}%
%
% Now process the index-string once, with all font commands turned off,
% to get the string to sort the index by.
{\indexnofonts
\xdef\temp1{#2 #3}%
}%
% Now produce the complete index entry. We process the index-string again,
% this time with font commands expanded, to get what to print in the index.
\edef\temp{%
\write \csname#1indfile\endcsname{%
\realbackslash entry {\temp1}{\folio}{#2}{#3}}}%
\temp }%
}\penalty\count10}}
% The index entry written in the file actually looks like
% \entry {sortstring}{page}{topic}
% or
% \entry {sortstring}{page}{topic}{subtopic}
% The texindex program reads in these files and writes files
% containing these kinds of lines:
% \initial {c}
% before the first topic whose initial is c
% \entry {topic}{pagelist}
% for a topic that is used without subtopics
% \primary {topic}
% for the beginning of a topic that is used with subtopics
% \secondary {subtopic}{pagelist}
% for each subtopic.
% Define the user-accessible indexing commands
% @findex, @vindex, @kindex, @cindex.
\def\findex {\fnindex}
\def\kindex {\kyindex}
\def\cindex {\cpindex}
\def\vindex {\vrindex}
\def\tindex {\tpindex}
\def\pindex {\pgindex}
\def\cindexsub {\begingroup\obeylines\cindexsub}
{\obeylines %
\gdef\cindexsub "#1" #2^^M{\endgroup %
\dosubind{cp}{#2}{#1}}}
% Define the macros used in formatting output of the sorted index material.
% This is what you call to cause a particular index to get printed.
% Write
% @unnumbered Function Index
% @printindex fn
\def\printindex{\parsearg\doprintindex}
\def\doprintindex#1{%
\tex
\dobreak \chapheadingskip {10000}
\catcode`\%=\other\catcode`\&=\other\catcode`\#=\other
\catcode`\$=\other
\catcode`\~=\other
\indexbreaks
%
% The following don't help, since the chars were translated
% when the raw index was written, and their fonts were discarded
% due to \indexnofonts.
%\catcode`\"=\active
%\catcode`\^=\active
%\catcode`\_=\active
%\catcode`\|=\active
%\catcode`\<=\active
%\catcode`\>=\active
% %
\def\indexbackslash{\rawbackslashxx}
\indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt
\begindoublecolumns
%
% See if the index file exists and is nonempty.
\openin 1 \jobname.#1s
\ifeof 1
% \enddoublecolumns gets confused if there is no text in the index,
% and it loses the chapter title and the aux file entries for the
% index. The easiest way to prevent this problem is to make sure
% there is some text.
(Index is nonexistent)
\else
%
% If the index file exists but is empty, then \openin leaves \ifeof
% false. We have to make TeX try to read something from the file, so
% it can discover if there is anything in it.
\read 1 to \temp
\ifeof 1
(Index is empty)
\else
\input \jobname.#1s
\fi
\fi
\closein 1
\enddoublecolumns
\Etex
}
% These macros are used by the sorted index file itself.
% Change them to control the appearance of the index.
% Same as \bigskipamount except no shrink.
% \balancecolumns gets confused if there is any shrink.
\newskip\initialskipamount \initialskipamount 12pt plus4pt
\def\initial #1{%
{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
\ifdim\lastskip<\initialskipamount
\removelastskip \penalty-200 \vskip \initialskipamount\fi
\line{\secbf#1\hfill}\kern 2pt\penalty10000}}
% This typesets a paragraph consisting of #1, dot leaders, and then #2
% flush to the right margin. It is used for index and table of contents
% entries. The paragraph is indented by \leftskip.
%
\def\entry #1#2{\begingroup
%
% Start a new paragraph if necessary, so our assignments below can't
% affect previous text.
\par
%
% Do not fill out the last line with white space.
\parfillskip = 0in
%
% No extra space above this paragraph.
\parskip = 0in
%
% Do not prefer a separate line ending with a hyphen to fewer lines.
\finalhyphendemerits = 0
%
% \hangindent is only relevant when the entry text and page number
% don't both fit on one line. In that case, bob suggests starting the
% dots pretty far over on the line. Unfortunately, a large
% indentation looks wrong when the entry text itself is broken across
% lines. So we use a small indentation and put up with long leaders.
%
% \hangafter is reset to 1 (which is the value we want) at the start
% of each paragraph, so we need not do anything with that.
\hangindent=2em
%
% When the entry text needs to be broken, just fill out the first line
% with blank space.
\rightskip = 0pt plus1fil
%
% Start a ``paragraph'' for the index entry so the line breaking
% parameters we've set above will have an effect.
\noindent
%
% Insert the text of the index entry. TeX will do line-breaking on it.
#1%
% The following is kludged to not output a line of dots in the index if
% there are no page numbers. The next person who breaks this will be
% cursed by a Unix daemon.
\def\tempa{{\rm }}%
\def\tempb{#2}%
\edef\tempc{\tempa}%
\edef\tempd{\tempb}%
\ifx\tempc\tempd\ \else%
%
% If we must, put the page number on a line of its own, and fill out
% this line with blank space. (The \hfil is overwhelmed with the
% fill leaders glue in \indexdotfill if the page number does fit.)
\hfil\penalty50
\null\nobreak\indexdotfill % Have leaders before the page number.
%
% The `\ ' here is removed by the implicit \unskip that TeX does as
% part of (the primitive) \par. Without it, a spurious underfull
% \hbox ensues.
\ #2% The page number ends the paragraph.
\fi%
\par
\endgroup}
% Like \dotfill except takes at least 1 em.
\def\indexdotfill{\cleaders
\hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill}
\def\primary #1{\line{#1\hfil}}
\newskip\secondaryindent \secondaryindent=0.5cm
\def\secondary #1#2{
{\parfillskip=0in \parskip=0in
\hangindent =1in \hangafter=1
\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par
}}
%% Define two-column mode, which is used in indexes.
%% Adapted from the TeXbook, page 416.
\catcode `\@=11
\newbox\partialpage
\newdimen\doublecolumnhsize
\def\begindoublecolumns{\begingroup
% Grab any single-column material above us.
\output = {\global\setbox\partialpage
=\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}%
\eject
%
% Now switch to the double-column output routine.
\output={\doublecolumnout}%
%
% Change the page size parameters. We could do this once outside this
% routine, in each of @smallbook, @afourpaper, and the default 8.5x11
% format, but then we repeat the same computation. Repeating a couple
% of assignments once per index is clearly meaningless for the
% execution time, so we may as well do it once.
%
% First we halve the line length, less a little for the gutter between
% the columns. We compute the gutter based on the line length, so it
% changes automatically with the paper format. The magic constant
% below is chosen so that the gutter has the same value (well, +- <
% 1pt) as it did when we hard-coded it.
%
% We put the result in a separate register, \doublecolumhsize, so we
% can restore it in \pagesofar, after \hsize itself has (potentially)
% been clobbered.
%
\doublecolumnhsize = \hsize
\advance\doublecolumnhsize by -.04154\hsize
\divide\doublecolumnhsize by 2
\hsize = \doublecolumnhsize
%
% Double the \vsize as well. (We don't need a separate register here,
% since nobody clobbers \vsize.)
\vsize = 2\vsize
\doublecolumnpagegoal
}
\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage}
\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth
\global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage
\global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1}
\global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3}
\ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi
\ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi
}
\def\doublecolumnpagegoal{%
\dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@
}
\def\pagesofar{\unvbox\partialpage %
\hsize=\doublecolumnhsize % have to restore this since output routine
\wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
\def\doublecolumnout{%
\setbox5=\copy255
{\vbadness=10000 \doublecolumnsplit}
\ifvbox255
\setbox0=\vtop to\dimen@{\unvbox0}
\setbox2=\vtop to\dimen@{\unvbox2}
\onepageout\pagesofar \unvbox255 \penalty\outputpenalty
\else
\setbox0=\vbox{\unvbox5}
\ifvbox0
\dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
\divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth
{\vbadness=10000
\loop \global\setbox5=\copy0
\setbox1=\vsplit5 to\dimen@
\setbox3=\vsplit5 to\dimen@
\ifvbox5 \global\advance\dimen@ by1pt \repeat
\setbox0=\vbox to\dimen@{\unvbox1}
\setbox2=\vbox to\dimen@{\unvbox3}
\global\setbox\partialpage=\vbox{\pagesofar}
\doublecolumnpagegoal
}
\fi
\fi
}
\catcode `\@=\other
\message{sectioning,}
% Define chapters, sections, etc.
\newcount \chapno
\newcount \secno \secno=0
\newcount \subsecno \subsecno=0
\newcount \subsubsecno \subsubsecno=0
% This counter is funny since it counts through charcodes of letters A, B, ...
\newcount \appendixno \appendixno = `\@
\def\appendixletter{\char\the\appendixno}
\newwrite \contentsfile
% This is called from \setfilename.
\def\opencontents{\openout \contentsfile = \jobname.toc}
% Each @chapter defines this as the name of the chapter.
% page headings and footings can use it. @section does likewise
\def\thischapter{} \def\thissection{}
\def\seccheck#1{\if \pageno<0 %
\errmessage{@#1 not allowed after generating table of contents}\fi
%
}
\def\chapternofonts{%
\let\rawbackslash=\relax%
\let\frenchspacing=\relax%
\def\result{\realbackslash result}
\def\equiv{\realbackslash equiv}
\def\expansion{\realbackslash expansion}
\def\print{\realbackslash print}
\def\TeX{\realbackslash TeX}
\def\dots{\realbackslash dots}
\def\copyright{\realbackslash copyright}
\def\tt{\realbackslash tt}
\def\bf{\realbackslash bf }
\def\w{\realbackslash w}
\def\less{\realbackslash less}
\def\gtr{\realbackslash gtr}
\def\hat{\realbackslash hat}
\def\char{\realbackslash char}
\def\tclose##1{\realbackslash tclose {##1}}
\def\code##1{\realbackslash code {##1}}
\def\samp##1{\realbackslash samp {##1}}
\def\r##1{\realbackslash r {##1}}
\def\b##1{\realbackslash b {##1}}
\def\key##1{\realbackslash key {##1}}
\def\file##1{\realbackslash file {##1}}
\def\kbd##1{\realbackslash kbd {##1}}
% These are redefined because @smartitalic wouldn't work inside xdef.
\def\i##1{\realbackslash i {##1}}
\def\cite##1{\realbackslash cite {##1}}
\def\var##1{\realbackslash var {##1}}
\def\emph##1{\realbackslash emph {##1}}
\def\dfn##1{\realbackslash dfn {##1}}
}
\newcount\absseclevel % used to calculate proper heading level
\newcount\secbase\secbase=0 % @raise/lowersections modify this count
% @raisesections: treat @section as chapter, @subsection as section, etc.
\def\raisesections{\global\advance\secbase by -1}
\let\up=\raisesections % original BFox name
% @lowersections: treat @chapter as section, @section as subsection, etc.
\def\lowersections{\global\advance\secbase by 1}
\let\down=\lowersections % original BFox name
% Choose a numbered-heading macro
% #1 is heading level if unmodified by @raisesections or @lowersections
% #2 is text for heading
\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
\ifcase\absseclevel
\chapterzzz{#2}
\or
\seczzz{#2}
\or
\numberedsubseczzz{#2}
\or
\numberedsubsubseczzz{#2}
\else
\ifnum \absseclevel<0
\chapterzzz{#2}
\else
\numberedsubsubseczzz{#2}
\fi
\fi
}
% like \numhead, but chooses appendix heading levels
\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
\ifcase\absseclevel
\appendixzzz{#2}
\or
\appendixsectionzzz{#2}
\or
\appendixsubseczzz{#2}
\or
\appendixsubsubseczzz{#2}
\else
\ifnum \absseclevel<0
\appendixzzz{#2}
\else
\appendixsubsubseczzz{#2}
\fi
\fi
}
% like \numhead, but chooses numberless heading levels
\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
\ifcase\absseclevel
\unnumberedzzz{#2}
\or
\unnumberedseczzz{#2}
\or
\unnumberedsubseczzz{#2}
\or
\unnumberedsubsubseczzz{#2}
\else
\ifnum \absseclevel<0
\unnumberedzzz{#2}
\else
\unnumberedsubsubseczzz{#2}
\fi
\fi
}
\def\thischaptername{No Chapter Title}
\outer\def\chapter{\parsearg\chapteryyy}
\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz
\def\chapterzzz #1{\seccheck{chapter}%
\secno=0 \subsecno=0 \subsubsecno=0
\global\advance \chapno by 1 \message{\putwordChapter \the\chapno}%
\chapmacro {#1}{\the\chapno}%
\gdef\thissection{#1}%
\gdef\thischaptername{#1}%
% We don't substitute the actual chapter name into \thischapter
% because we don't want its macros evaluated now.
\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}%
{\chapternofonts%
\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\donoderef %
\global\let\section = \numberedsec
\global\let\subsection = \numberedsubsec
\global\let\subsubsection = \numberedsubsubsec
}}
\outer\def\appendix{\parsearg\appendixyyy}
\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz
\def\appendixzzz #1{\seccheck{appendix}%
\secno=0 \subsecno=0 \subsubsecno=0
\global\advance \appendixno by 1 \message{Appendix \appendixletter}%
\chapmacro {#1}{\putwordAppendix{} \appendixletter}%
\gdef\thissection{#1}%
\gdef\thischaptername{#1}%
\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}%
{\chapternofonts%
\edef\temp{{\realbackslash chapentry
{#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\appendixnoderef %
\global\let\section = \appendixsec
\global\let\subsection = \appendixsubsec
\global\let\subsubsection = \appendixsubsubsec
}}
\outer\def\top{\parsearg\unnumberedyyy}
\outer\def\unnumbered{\parsearg\unnumberedyyy}
\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
\def\unnumberedzzz #1{\seccheck{unnumbered}%
\secno=0 \subsecno=0 \subsubsecno=0
%
% This used to be simply \message{#1}, but TeX fully expands the
% argument to \message. Therefore, if #1 contained @-commands, TeX
% expanded them. For example, in `@unnumbered The @cite{Book}', TeX
% expanded @cite (which turns out to cause errors because \cite is meant
% to be executed, not expanded).
%
% Anyway, we don't want the fully-expanded definition of @cite to appear
% as a result of the \message, we just want `@cite' itself. We use
% \the to achieve this: TeX expands \the only once,
% simply yielding the contents of the .
\toks0 = {#1}\message{(\the\toks0)}%
%
\unnumbchapmacro {#1}%
\gdef\thischapter{#1}\gdef\thissection{#1}%
{\chapternofonts%
\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\unnumbnoderef %
\global\let\section = \unnumberedsec
\global\let\subsection = \unnumberedsubsec
\global\let\subsubsection = \unnumberedsubsubsec
}}
\outer\def\numberedsec{\parsearg\secyyy}
\def\secyyy #1{\numhead1{#1}} % normally calls seczzz
\def\seczzz #1{\seccheck{section}%
\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
{\chapternofonts%
\edef\temp{{\realbackslash secentry %
{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\donoderef %
\penalty 10000 %
}}
\outer\def\appendixsection{\parsearg\appendixsecyyy}
\outer\def\appendixsec{\parsearg\appendixsecyyy}
\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz
\def\appendixsectionzzz #1{\seccheck{appendixsection}%
\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
{\chapternofonts%
\edef\temp{{\realbackslash secentry %
{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\appendixnoderef %
\penalty 10000 %
}}
\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy}
\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz
\def\unnumberedseczzz #1{\seccheck{unnumberedsec}%
\plainsecheading {#1}\gdef\thissection{#1}%
{\chapternofonts%
\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\unnumbnoderef %
\penalty 10000 %
}}
\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy}
\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz
\def\numberedsubseczzz #1{\seccheck{subsection}%
\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
{\chapternofonts%
\edef\temp{{\realbackslash subsecentry %
{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\donoderef %
\penalty 10000 %
}}
\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy}
\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz
\def\appendixsubseczzz #1{\seccheck{appendixsubsec}%
\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
{\chapternofonts%
\edef\temp{{\realbackslash subsecentry %
{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\appendixnoderef %
\penalty 10000 %
}}
\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy}
\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}%
\plainsecheading {#1}\gdef\thissection{#1}%
{\chapternofonts%
\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\unnumbnoderef %
\penalty 10000 %
}}
\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy}
\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz
\def\numberedsubsubseczzz #1{\seccheck{subsubsection}%
\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
\subsubsecheading {#1}
{\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
{\chapternofonts%
\edef\temp{{\realbackslash subsubsecentry %
{#1}
{\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}
{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\donoderef %
\penalty 10000 %
}}
\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy}
\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz
\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}%
\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
\subsubsecheading {#1}
{\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
{\chapternofonts%
\edef\temp{{\realbackslash subsubsecentry{#1}%
{\appendixletter}
{\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\appendixnoderef %
\penalty 10000 %
}}
\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy}
\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}%
\plainsecheading {#1}\gdef\thissection{#1}%
{\chapternofonts%
\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}%
\escapechar=`\\%
\write \contentsfile \temp %
\unnumbnoderef %
\penalty 10000 %
}}
% These are variants which are not "outer", so they can appear in @ifinfo.
% Actually, they should now be obsolete; ordinary section commands should work.
\def\infotop{\parsearg\unnumberedzzz}
\def\infounnumbered{\parsearg\unnumberedzzz}
\def\infounnumberedsec{\parsearg\unnumberedseczzz}
\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
\def\infoappendix{\parsearg\appendixzzz}
\def\infoappendixsec{\parsearg\appendixseczzz}
\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
\def\infochapter{\parsearg\chapterzzz}
\def\infosection{\parsearg\sectionzzz}
\def\infosubsection{\parsearg\subsectionzzz}
\def\infosubsubsection{\parsearg\subsubsectionzzz}
% These macros control what the section commands do, according
% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
% Define them by default for a numbered chapter.
\global\let\section = \numberedsec
\global\let\subsection = \numberedsubsec
\global\let\subsubsection = \numberedsubsubsec
% Define @majorheading, @heading and @subheading
% NOTE on use of \vbox for chapter headings, section headings, and
% such:
% 1) We use \vbox rather than the earlier \line to permit
% overlong headings to fold.
% 2) \hyphenpenalty is set to 10000 because hyphenation in a
% heading is obnoxious; this forbids it.
% 3) Likewise, headings look best if no \parindent is used, and
% if justification is not attempted. Hence \raggedright.
\def\majorheading{\parsearg\majorheadingzzz}
\def\majorheadingzzz #1{%
{\advance\chapheadingskip by 10pt \chapbreak }%
{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
\parindent=0pt\raggedright
\rm #1\hfill}}\bigskip \par\penalty 200}
\def\chapheading{\parsearg\chapheadingzzz}
\def\chapheadingzzz #1{\chapbreak %
{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
\parindent=0pt\raggedright
\rm #1\hfill}}\bigskip \par\penalty 200}
\def\heading{\parsearg\secheadingi}
\def\subheading{\parsearg\subsecheadingi}
\def\subsubheading{\parsearg\subsubsecheadingi}
% These macros generate a chapter, section, etc. heading only
% (including whitespace, linebreaking, etc. around it),
% given all the information in convenient, parsed form.
%%% Args are the skip and penalty (usually negative)
\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
%%% Define plain chapter starts, and page on/off switching for it
% Parameter controlling skip before chapter headings (if needed)
\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt
\def\chapbreak{\dobreak \chapheadingskip {-4000}}
\def\chappager{\par\vfill\supereject}
\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
\def\CHAPPAGoff{
\global\let\pchapsepmacro=\chapbreak
\global\let\pagealignmacro=\chappager}
\def\CHAPPAGon{
\global\let\pchapsepmacro=\chappager
\global\let\pagealignmacro=\chappager
\global\def\HEADINGSon{\HEADINGSsingle}}
\def\CHAPPAGodd{
\global\let\pchapsepmacro=\chapoddpage
\global\let\pagealignmacro=\chapoddpage
\global\def\HEADINGSon{\HEADINGSdouble}}
\CHAPPAGon
\def\CHAPFplain{
\global\let\chapmacro=\chfplain
\global\let\unnumbchapmacro=\unnchfplain}
\def\chfplain #1#2{%
\pchapsepmacro
{%
\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
\parindent=0pt\raggedright
\rm #2\enspace #1}%
}%
\bigskip
\penalty5000
}
\def\unnchfplain #1{%
\pchapsepmacro %
{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
\parindent=0pt\raggedright
\rm #1\hfill}}\bigskip \par\penalty 10000 %
}
\CHAPFplain % The default
\def\unnchfopen #1{%
\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
\parindent=0pt\raggedright
\rm #1\hfill}}\bigskip \par\penalty 10000 %
}
\def\chfopen #1#2{\chapoddpage {\chapfonts
\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
\par\penalty 5000 %
}
\def\CHAPFopen{
\global\let\chapmacro=\chfopen
\global\let\unnumbchapmacro=\unnchfopen}
% Parameter controlling skip before section headings.
\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt
\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt
\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
% @paragraphindent is defined for the Info formatting commands only.
\let\paragraphindent=\comment
% Section fonts are the base font at magstep2, which produces
% a size a bit more than 14 points in the default situation.
\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}}
\def\plainsecheading #1{\secheadingi {#1}}
\def\secheadingi #1{{\advance \secheadingskip by \parskip %
\secheadingbreak}%
{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000
\parindent=0pt\raggedright
\rm #1\hfill}}%
\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
% Subsection fonts are the base font at magstep1,
% which produces a size of 12 points.
\def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}}
\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip %
\subsecheadingbreak}%
{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
\parindent=0pt\raggedright
\rm #1\hfill}}%
\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
\def\subsubsecfonts{\subsecfonts} % Maybe this should change:
% Perhaps make sssec fonts scaled
% magstep half
\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}}
\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip %
\subsecheadingbreak}%
{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
\parindent=0pt\raggedright
\rm #1\hfill}}%
\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000}
\message{toc printing,}
% Finish up the main text and prepare to read what we've written
% to \contentsfile.
\newskip\contentsrightmargin \contentsrightmargin=1in
\def\startcontents#1{%
\pagealignmacro
\immediate\closeout \contentsfile
\ifnum \pageno>0
\pageno = -1 % Request roman numbered pages.
\fi
% Don't need to put `Contents' or `Short Contents' in the headline.
% It is abundantly clear what they are.
\unnumbchapmacro{#1}\def\thischapter{}%
\begingroup % Set up to handle contents files properly.
\catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11
\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi
\raggedbottom % Worry more about breakpoints than the bottom.
\advance\hsize by -\contentsrightmargin % Don't use the full line length.
}
% Normal (long) toc.
\outer\def\contents{%
\startcontents{\putwordTableofContents}%
\input \jobname.toc
\endgroup
\vfill \eject
}
% And just the chapters.
\outer\def\summarycontents{%
\startcontents{\putwordShortContents}%
%
\let\chapentry = \shortchapentry
\let\unnumbchapentry = \shortunnumberedentry
% We want a true roman here for the page numbers.
\secfonts
\let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
\rm
\advance\baselineskip by 1pt % Open it up a little.
\def\secentry ##1##2##3##4{}
\def\unnumbsecentry ##1##2{}
\def\subsecentry ##1##2##3##4##5{}
\def\unnumbsubsecentry ##1##2{}
\def\subsubsecentry ##1##2##3##4##5##6{}
\def\unnumbsubsubsecentry ##1##2{}
\input \jobname.toc
\endgroup
\vfill \eject
}
\let\shortcontents = \summarycontents
% These macros generate individual entries in the table of contents.
% The first argument is the chapter or section name.
% The last argument is the page number.
% The arguments in between are the chapter number, section number, ...
% Chapter-level things, for both the long and short contents.
\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
% See comments in \dochapentry re vbox and related settings
\def\shortchapentry#1#2#3{%
\tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}%
}
% Typeset the label for a chapter or appendix for the short contents.
% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter.
% We could simplify the code here by writing out an \appendixentry
% command in the toc file for appendices, instead of using \chapentry
% for both, but it doesn't seem worth it.
\setbox0 = \hbox{\shortcontrm \putwordAppendix }
\newdimen\shortappendixwidth \shortappendixwidth = \wd0
\def\shortchaplabel#1{%
% We typeset #1 in a box of constant width, regardless of the text of
% #1, so the chapter titles will come out aligned.
\setbox0 = \hbox{#1}%
\dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi
%
% This space should be plenty, since a single number is .5em, and the
% widest letter (M) is 1em, at least in the Computer Modern fonts.
% (This space doesn't include the extra space that gets added after
% the label; that gets put in in \shortchapentry above.)
\advance\dimen0 by 1.1em
\hbox to \dimen0{#1\hfil}%
}
\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}}
% Sections.
\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
% Subsections.
\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
% And subsubsections.
\def\subsubsecentry#1#2#3#4#5#6{%
\dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
% This parameter controls the indentation of the various levels.
\newdimen\tocindent \tocindent = 3pc
% Now for the actual typesetting. In all these, #1 is the text and #2 is the
% page number.
%
% If the toc has to be broken over pages, we would want to be at chapters
% if at all possible; hence the \penalty.
\def\dochapentry#1#2{%
\penalty-300 \vskip\baselineskip
\begingroup
\chapentryfonts
\tocentry{#1}{\dopageno{#2}}%
\endgroup
\nobreak\vskip .25\baselineskip
}
\def\dosecentry#1#2{\begingroup
\secentryfonts \leftskip=\tocindent
\tocentry{#1}{\dopageno{#2}}%
\endgroup}
\def\dosubsecentry#1#2{\begingroup
\subsecentryfonts \leftskip=2\tocindent
\tocentry{#1}{\dopageno{#2}}%
\endgroup}
\def\dosubsubsecentry#1#2{\begingroup
\subsubsecentryfonts \leftskip=3\tocindent
\tocentry{#1}{\dopageno{#2}}%
\endgroup}
% Final typesetting of a toc entry; we use the same \entry macro as for
% the index entries, but we want to suppress hyphenation here. (We
% can't do that in the \entry macro, since index entries might consist
% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.)
%
% \turnoffactive is for the sake of @" used for umlauts.
\def\tocentry#1#2{\begingroup
\hyphenpenalty = 10000
\entry{\turnoffactive #1}{\turnoffactive #2}%
\endgroup}
% Space between chapter (or whatever) number and the title.
\def\labelspace{\hskip1em \relax}
\def\dopageno#1{{\rm #1}}
\def\doshortpageno#1{{\rm #1}}
\def\chapentryfonts{\secfonts \rm}
\def\secentryfonts{\textfonts}
\let\subsecentryfonts = \textfonts
\let\subsubsecentryfonts = \textfonts
\message{environments,}
% Since these characters are used in examples, it should be an even number of
% \tt widths. Each \tt character is 1en, so two makes it 1em.
% Furthermore, these definitions must come after we define our fonts.
\newbox\dblarrowbox \newbox\longdblarrowbox
\newbox\pushcharbox \newbox\bullbox
\newbox\equivbox \newbox\errorbox
\let\ptexequiv = \equiv
%{\tentt
%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
% Adapted from the manmac format (p.420 of TeXbook)
%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
% depth .1ex\hfil}
%}
\def\point{$\star$}
\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}}
\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}}
% Adapted from the TeXbook's \boxit.
{\tentt \global\dimen0 = 3em}% Width of the box.
\dimen2 = .55pt % Thickness of rules
% The text. (`r' is open on the right, `e' somewhat less so on the left.)
\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
\global\setbox\errorbox=\hbox to \dimen0{\hfil
\hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
\advance\hsize by -2\dimen2 % Rules.
\vbox{
\hrule height\dimen2
\hbox{\vrule width\dimen2 \kern3pt % Space to left of text.
\vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
\kern3pt\vrule width\dimen2}% Space to right.
\hrule height\dimen2}
\hfil}
% The @error{} command.
\def\error{\leavevmode\lower.7ex\copy\errorbox}
% @tex ... @end tex escapes into raw Tex temporarily.
% One exception: @ is still an escape character, so that @end tex works.
% But \@ or @@ will get a plain tex @ character.
\def\tex{\begingroup
\catcode `\\=0 \catcode `\{=1 \catcode `\}=2
\catcode `\$=3 \catcode `\&=4 \catcode `\#=6
\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
\catcode `\%=14
\catcode 43=12
\catcode`\"=12
\catcode`\==12
\catcode`\|=12
\catcode`\<=12
\catcode`\>=12
\escapechar=`\\
%
\let\~=\ptextilde
\let\{=\ptexlbrace
\let\}=\ptexrbrace
\let\.=\ptexdot
\let\*=\ptexstar
\let\dots=\ptexdots
\def\@{@}%
\let\bullet=\ptexbullet
\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl
\let\L=\ptexL
%
\let\Etex=\endgroup}
% Define @lisp ... @endlisp.
% @lisp does a \begingroup so it can rebind things,
% including the definition of @endlisp (which normally is erroneous).
% Amount to narrow the margins by for @lisp.
\newskip\lispnarrowing \lispnarrowing=0.4in
% This is the definition that ^^M gets inside @lisp, @example, and other
% such environments. \null is better than a space, since it doesn't
% have any width.
\def\lisppar{\null\endgraf}
% Make each space character in the input produce a normal interword
% space in the output. Don't allow a line break at this space, as this
% is used only in environments like @example, where each line of input
% should produce a line of output anyway.
%
{\obeyspaces %
\gdef\sepspaces{\obeyspaces\let =\tie}}
% Define \obeyedspace to be our active space, whatever it is. This is
% for use in \parsearg.
{\sepspaces%
\global\let\obeyedspace= }
% This space is always present above and below environments.
\newskip\envskipamount \envskipamount = 0pt
% Make spacing and below environment symmetrical. We use \parskip here
% to help in doing that, since in @example-like environments \parskip
% is reset to zero; thus the \afterenvbreak inserts no space -- but the
% start of the next paragraph will insert \parskip
%
\def\aboveenvbreak{{\advance\envskipamount by \parskip
\endgraf \ifdim\lastskip<\envskipamount
\removelastskip \penalty-50 \vskip\envskipamount \fi}}
\let\afterenvbreak = \aboveenvbreak
% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins.
\let\nonarrowing=\relax
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \cartouche: draw rectangle w/rounded corners around argument
\font\circle=lcircle10
\newdimen\circthick
\newdimen\cartouter\newdimen\cartinner
\newskip\normbskip\newskip\normpskip\newskip\normlskip
\circthick=\fontdimen8\circle
%
\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
\def\ctr{{\hskip 6pt\circle\char'010}}
\def\cbl{{\circle\char'012\hskip -6pt}}
\def\cbr{{\hskip 6pt\circle\char'011}}
\def\carttop{\hbox to \cartouter{\hskip\lskip
\ctl\leaders\hrule height\circthick\hfil\ctr
\hskip\rskip}}
\def\cartbot{\hbox to \cartouter{\hskip\lskip
\cbl\leaders\hrule height\circthick\hfil\cbr
\hskip\rskip}}
%
\newskip\lskip\newskip\rskip
\long\def\cartouche{%
\begingroup
\lskip=\leftskip \rskip=\rightskip
\leftskip=0pt\rightskip=0pt %we want these *outside*.
\cartinner=\hsize \advance\cartinner by-\lskip
\advance\cartinner by-\rskip
\cartouter=\hsize
\advance\cartouter by 18pt % allow for 3pt kerns on either
% side, and for 6pt waste from
% each corner char
\normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
% Flag to tell @lisp, etc., not to narrow margin.
\let\nonarrowing=\comment
\vbox\bgroup
\baselineskip=0pt\parskip=0pt\lineskip=0pt
\carttop
\hbox\bgroup
\hskip\lskip
\vrule\kern3pt
\vbox\bgroup
\hsize=\cartinner
\kern3pt
\begingroup
\baselineskip=\normbskip
\lineskip=\normlskip
\parskip=\normpskip
\vskip -\parskip
\def\Ecartouche{%
\endgroup
\kern3pt
\egroup
\kern3pt\vrule
\hskip\rskip
\egroup
\cartbot
\egroup
\endgroup
}}
% This macro is called at the beginning of all the @example variants,
% inside a group.
\def\nonfillstart{%
\aboveenvbreak
\inENV % This group ends at the end of the body
\hfuzz = 12pt % Don't be fussy
\sepspaces % Make spaces be word-separators rather than space tokens.
\singlespace
\let\par = \lisppar % don't ignore blank lines
\obeylines % each line of input is a line of output
\parskip = 0pt
\parindent = 0pt
\emergencystretch = 0pt % don't try to avoid overfull boxes
% @cartouche defines \nonarrowing to inhibit narrowing
% at next level down.
\ifx\nonarrowing\relax
\advance \leftskip by \lispnarrowing
\exdentamount=\lispnarrowing
\let\exdent=\nofillexdent
\let\nonarrowing=\relax
\fi
}
% To ending an @example-like environment, we first end the paragraph
% (via \afterenvbreak's vertical glue), and then the group. That way we
% keep the zero \parskip that the environments set -- \parskip glue
% will be inserted at the beginning of the next paragraph in the
% document, after the environment.
%
\def\nonfillfinish{\afterenvbreak\endgroup}%
% This macro is
\def\lisp{\begingroup
\nonfillstart
\let\Elisp = \nonfillfinish
\tt
\rawbackslash % have \ input char produce \ char from current font
\gobble
}
% Define the \E... control sequence only if we are inside the
% environment, so the error checking in \end will work.
%
% We must call \lisp last in the definition, since it reads the
% return following the @example (or whatever) command.
%
\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp}
\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp}
\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp}
% @smallexample and @smalllisp. This is not used unless the @smallbook
% command is given. Originally contributed by Pavel@xerox.
%
\def\smalllispx{\begingroup
\nonfillstart
\let\Esmalllisp = \nonfillfinish
\let\Esmallexample = \nonfillfinish
%
% Smaller interline space and fonts for small examples.
\setleading{10pt}%
\indexfonts \tt
\rawbackslash % make \ output the \ character from the current font (tt)
\gobble
}
% This is @display; same as @lisp except use roman font.
%
\def\display{\begingroup
\nonfillstart
\let\Edisplay = \nonfillfinish
\gobble
}
% This is @format; same as @display except don't narrow margins.
%
\def\format{\begingroup
\let\nonarrowing = t
\nonfillstart
\let\Eformat = \nonfillfinish
\gobble
}
% @flushleft (same as @format) and @flushright.
%
\def\flushleft{\begingroup
\let\nonarrowing = t
\nonfillstart
\let\Eflushleft = \nonfillfinish
\gobble
}
\def\flushright{\begingroup
\let\nonarrowing = t
\nonfillstart
\let\Eflushright = \nonfillfinish
\advance\leftskip by 0pt plus 1fill
\gobble}
% @quotation does normal linebreaking (hence we can't use \nonfillstart)
% and narrows the margins.
%
\def\quotation{%
\begingroup\inENV %This group ends at the end of the @quotation body
{\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
\singlespace
\parindent=0pt
% We have retained a nonzero parskip for the environment, since we're
% doing normal filling. So to avoid extra space below the environment...
\def\Equotation{\parskip = 0pt \nonfillfinish}%
%
% @cartouche defines \nonarrowing to inhibit narrowing at next level down.
\ifx\nonarrowing\relax
\advance\leftskip by \lispnarrowing
\advance\rightskip by \lispnarrowing
\exdentamount = \lispnarrowing
\let\nonarrowing = \relax
\fi
}
\message{defuns,}
% Define formatter for defuns
% First, allow user to change definition object font (\df) internally
\def\setdeffont #1 {\csname DEF#1\endcsname}
\newskip\defbodyindent \defbodyindent=.4in
\newskip\defargsindent \defargsindent=50pt
\newskip\deftypemargin \deftypemargin=12pt
\newskip\deflastargmargin \deflastargmargin=18pt
\newcount\parencount
% define \functionparens, which makes ( and ) and & do special things.
% \functionparens affects the group it is contained in.
\def\activeparens{%
\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
\catcode`\[=\active \catcode`\]=\active}
% Make control sequences which act like normal parenthesis chars.
\let\lparen = ( \let\rparen = )
{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
% Be sure that we always have a definition for `(', etc. For example,
% if the fn name has parens in it, \boldbrax will not be in effect yet,
% so TeX would otherwise complain about undefined control sequence.
\global\let(=\lparen \global\let)=\rparen
\global\let[=\lbrack \global\let]=\rbrack
\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
% This is used to turn on special parens
% but make & act ordinary (given that it's active).
\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr}
% Definitions of (, ) and & used in args for functions.
% This is the definition of ( outside of all parentheses.
\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested %
\global\advance\parencount by 1 }
%
% This is the definition of ( when already inside a level of parens.
\gdef\opnested{\char`\(\global\advance\parencount by 1 }
%
\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
% also in that case restore the outer-level definition of (.
\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
\global\advance \parencount by -1 }
% If we encounter &foo, then turn on ()-hacking afterwards
\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ }
%
\gdef\normalparens{\boldbrax\let&=\ampnr}
} % End of definition inside \activeparens
%% These parens (in \boldbrax) actually are a little bolder than the
%% contained text. This is especially needed for [ and ]
\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&}
\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}}
% First, defname, which formats the header line itself.
% #1 should be the function name.
% #2 should be the type of definition, such as "Function".
\def\defname #1#2{%
% Get the values of \leftskip and \rightskip as they were
% outside the @def...
\dimen2=\leftskip
\advance\dimen2 by -\defbodyindent
\dimen3=\rightskip
\advance\dimen3 by -\defbodyindent
\noindent %
\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
\parshape 2 0in \dimen0 \defargsindent \dimen1 %
% Now output arg 2 ("Function" or some such)
% ending at \deftypemargin from the right margin,
% but stuck inside a box of width 0 so it does not interfere with linebreaking
{% Adjust \hsize to exclude the ambient margins,
% so that \rightline will obey them.
\advance \hsize by -\dimen2 \advance \hsize by -\dimen3
\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}%
% Make all lines underfull and no complaints:
\tolerance=10000 \hbadness=10000
\advance\leftskip by -\defbodyindent
\exdentamount=\defbodyindent
{\df #1}\enskip % Generate function name
}
% Actually process the body of a definition
% #1 should be the terminating control sequence, such as \Edefun.
% #2 should be the "another name" control sequence, such as \defunx.
% #3 should be the control sequence that actually processes the header,
% such as \defunheader.
\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
\medbreak %
% Define the end token that this defining construct specifies
% so that it will exit this group.
\def#1{\endgraf\endgroup\medbreak}%
\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
\parindent=0in
\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
\exdentamount=\defbodyindent
\begingroup %
\catcode 61=\active % 61 is `='
\obeylines\activeparens\spacesplit#3}
\def\defmethparsebody #1#2#3#4 {\begingroup\inENV %
\medbreak %
% Define the end token that this defining construct specifies
% so that it will exit this group.
\def#1{\endgraf\endgroup\medbreak}%
\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
\parindent=0in
\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
\exdentamount=\defbodyindent
\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
\medbreak %
% Define the end token that this defining construct specifies
% so that it will exit this group.
\def#1{\endgraf\endgroup\medbreak}%
\def#2##1 ##2 {\def#4{##1}%
\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
\parindent=0in
\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
\exdentamount=\defbodyindent
\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
% These parsing functions are similar to the preceding ones
% except that they do not make parens into active characters.
% These are used for "variables" since they have no arguments.
\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
\medbreak %
% Define the end token that this defining construct specifies
% so that it will exit this group.
\def#1{\endgraf\endgroup\medbreak}%
\def#2{\begingroup\obeylines\spacesplit#3}%
\parindent=0in
\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
\exdentamount=\defbodyindent
\begingroup %
\catcode 61=\active %
\obeylines\spacesplit#3}
% This is used for \def{tp,vr}parsebody. It could probably be used for
% some of the others, too, with some judicious conditionals.
%
\def\parsebodycommon#1#2#3{%
\begingroup\inENV %
\medbreak %
% Define the end token that this defining construct specifies
% so that it will exit this group.
\def#1{\endgraf\endgroup\medbreak}%
\def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}%
\parindent=0in
\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
\exdentamount=\defbodyindent
\begingroup\obeylines
}
\def\defvrparsebody#1#2#3#4 {%
\parsebodycommon{#1}{#2}{#3}%
\spacesplit{#3{#4}}%
}
% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the
% type is just `struct', because we lose the braces in `{struct
% termios}' when \spacesplit reads its undelimited argument. Sigh.
% \let\deftpparsebody=\defvrparsebody
%
% So, to get around this, we put \empty in with the type name. That
% way, TeX won't find exactly `{...}' as an undelimited argument, and
% won't strip off the braces.
%
\def\deftpparsebody #1#2#3#4 {%
\parsebodycommon{#1}{#2}{#3}%
\spacesplit{\parsetpheaderline{#3{#4}}}\empty
}
% Fine, but then we have to eventually remove the \empty *and* the
% braces (if any). That's what this does, putting the result in \tptemp.
%
\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}%
% After \spacesplit has done its work, this is called -- #1 is the final
% thing to call, #2 the type name (which starts with \empty), and #3
% (which might be empty) the arguments.
%
\def\parsetpheaderline#1#2#3{%
\removeemptybraces#2\relax
#1{\tptemp}{#3}%
}%
\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV %
\medbreak %
% Define the end token that this defining construct specifies
% so that it will exit this group.
\def#1{\endgraf\endgroup\medbreak}%
\def#2##1 ##2 {\def#4{##1}%
\begingroup\obeylines\spacesplit{#3{##2}}}%
\parindent=0in
\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
\exdentamount=\defbodyindent
\begingroup\obeylines\spacesplit{#3{#5}}}
% Split up #2 at the first space token.
% call #1 with two arguments:
% the first is all of #2 before the space token,
% the second is all of #2 after that space token.
% If #2 contains no space token, all of it is passed as the first arg
% and the second is passed as empty.
{\obeylines
\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
\ifx\relax #3%
#1{#2}{}\else #1{#2}{#3#4}\fi}}
% So much for the things common to all kinds of definitions.
% Define @defun.
% First, define the processing that is wanted for arguments of \defun
% Use this to expand the args and terminate the paragraph they make up
\def\defunargs #1{\functionparens \sl
% Expand, preventing hyphenation at `-' chars.
% Note that groups don't affect changes in \hyphenchar.
\hyphenchar\tensl=0
#1%
\hyphenchar\tensl=45
\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi%
\interlinepenalty=10000
\advance\rightskip by 0pt plus 1fil
\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
}
\def\deftypefunargs #1{%
% Expand, preventing hyphenation at `-' chars.
% Note that groups don't affect changes in \hyphenchar.
% Use \boldbraxnoamp, not \functionparens, so that & is not special.
\boldbraxnoamp
\tclose{#1}% avoid \code because of side effects on active chars
\interlinepenalty=10000
\advance\rightskip by 0pt plus 1fil
\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
}
% Do complete processing of one @defun or @defunx line already parsed.
% @deffn Command forward-char nchars
\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
\catcode 61=\other % Turn off change made in \defparsebody
}
% @defun == @deffn Function
\def\defun{\defparsebody\Edefun\defunx\defunheader}
\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
\begingroup\defname {#1}{Function}%
\defunargs {#2}\endgroup %
\catcode 61=\other % Turn off change made in \defparsebody
}
% @deftypefun int foobar (int @var{foo}, float @var{bar})
\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
% #1 is the data type. #2 is the name and args.
\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
% #1 is the data type, #2 the name, #3 the args.
\def\deftypefunheaderx #1#2 #3\relax{%
\doind {fn}{\code{#2}}% Make entry in function index
\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}%
\deftypefunargs {#3}\endgroup %
\catcode 61=\other % Turn off change made in \defparsebody
}
% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
% \defheaderxcond#1\relax$$$
% puts #1 in @code, followed by a space, but does nothing if #1 is null.
\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi}
% #1 is the classification. #2 is the data type. #3 is the name and args.
\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
% #1 is the classification, #2 the data type, #3 the name, #4 the args.
\def\deftypefnheaderx #1#2#3 #4\relax{%
\doind {fn}{\code{#3}}% Make entry in function index
\begingroup
\normalparens % notably, turn off `&' magic, which prevents
% at least some C++ text from working
\defname {\defheaderxcond#2\relax$$$#3}{#1}%
\deftypefunargs {#4}\endgroup %
\catcode 61=\other % Turn off change made in \defparsebody
}
% @defmac == @deffn Macro
\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
\begingroup\defname {#1}{Macro}%
\defunargs {#2}\endgroup %
\catcode 61=\other % Turn off change made in \defparsebody
}
% @defspec == @deffn Special Form
\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
\begingroup\defname {#1}{Special Form}%
\defunargs {#2}\endgroup %
\catcode 61=\other % Turn off change made in \defparsebody
}
% This definition is run if you use @defunx
% anywhere other than immediately after a @defun or @defunx.
\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
\def\defunx #1 {\errmessage{@defunx in invalid context}}
\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}}
\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}}
% @defmethod, and so on
% @defop {Funny Method} foo-class frobnicate argument
\def\defop #1 {\def\defoptype{#1}%
\defopparsebody\Edefop\defopx\defopheader\defoptype}
\def\defopheader #1#2#3{%
\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index
\begingroup\defname {#2}{\defoptype{} on #1}%
\defunargs {#3}\endgroup %
}
% @defmethod == @defop Method
\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
\def\defmethodheader #1#2#3{%
\dosubind {fn}{\code{#2}}{on #1}% entry in function index
\begingroup\defname {#2}{Method on #1}%
\defunargs {#3}\endgroup %
}
% @defcv {Class Option} foo-class foo-flag
\def\defcv #1 {\def\defcvtype{#1}%
\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
\def\defcvarheader #1#2#3{%
\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
\begingroup\defname {#2}{\defcvtype{} of #1}%
\defvarargs {#3}\endgroup %
}
% @defivar == @defcv {Instance Variable}
\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader}
\def\defivarheader #1#2#3{%
\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
\begingroup\defname {#2}{Instance Variable of #1}%
\defvarargs {#3}\endgroup %
}
% These definitions are run if you use @defmethodx, etc.,
% anywhere other than immediately after a @defmethod, etc.
\def\defopx #1 {\errmessage{@defopx in invalid context}}
\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
% Now @defvar
% First, define the processing that is wanted for arguments of @defvar.
% This is actually simple: just print them in roman.
% This must expand the args and terminate the paragraph they make up
\def\defvarargs #1{\normalparens #1%
\interlinepenalty=10000
\endgraf\penalty 10000\vskip -\parskip\penalty 10000}
% @defvr Counter foo-count
\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader}
\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
% @defvar == @defvr Variable
\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader}
\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
\begingroup\defname {#1}{Variable}%
\defvarargs {#2}\endgroup %
}
% @defopt == @defvr {User Option}
\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader}
\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
\begingroup\defname {#1}{User Option}%
\defvarargs {#2}\endgroup %
}
% @deftypevar int foobar
\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader}
% #1 is the data type. #2 is the name.
\def\deftypevarheader #1#2{%
\doind {vr}{\code{#2}}% Make entry in variables index
\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}%
\interlinepenalty=10000
\endgraf\penalty 10000\vskip -\parskip\penalty 10000
\endgroup}
% @deftypevr {Global Flag} int enable
\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader}
\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}%
\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1}
\interlinepenalty=10000
\endgraf\penalty 10000\vskip -\parskip\penalty 10000
\endgroup}
% This definition is run if you use @defvarx
% anywhere other than immediately after a @defvar or @defvarx.
\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}}
\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}}
% Now define @deftp
% Args are printed in bold, a slight difference from @defvar.
\def\deftpargs #1{\bf \defvarargs{#1}}
% @deftp Class window height width ...
\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader}
\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
% This definition is run if you use @deftpx, etc
% anywhere other than immediately after a @deftp, etc.
\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
\message{cross reference,}
% Define cross-reference macros
\newwrite \auxfile
\newif\ifhavexrefs % True if xref values are known.
\newif\ifwarnedxrefs % True if we warned once that they aren't known.
% \setref{foo} defines a cross-reference point named foo.
\def\setref#1{%
\dosetq{#1-title}{Ytitle}%
\dosetq{#1-pg}{Ypagenumber}%
\dosetq{#1-snt}{Ysectionnumberandtype}}
\def\unnumbsetref#1{%
\dosetq{#1-title}{Ytitle}%
\dosetq{#1-pg}{Ypagenumber}%
\dosetq{#1-snt}{Ynothing}}
\def\appendixsetref#1{%
\dosetq{#1-title}{Ytitle}%
\dosetq{#1-pg}{Ypagenumber}%
\dosetq{#1-snt}{Yappendixletterandtype}}
% \xref, \pxref, and \ref generate cross-references to specified points.
% For \xrefX, #1 is the node name, #2 the name of the Info
% cross-reference, #3 the printed node name, #4 the name of the Info
% file, #5 the name of the printed manual. All but the node name can be
% omitted.
%
\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
\def\ref#1{\xrefX[#1,,,,,,,]}
\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
\def\printedmanual{\ignorespaces #5}%
\def\printednodename{\ignorespaces #3}%
\setbox1=\hbox{\printedmanual}%
\setbox0=\hbox{\printednodename}%
\ifdim \wd0 = 0pt
% No printed node name was explicitly given.
\ifx\SETxref-automatic-section-title\thisisundefined
% Use the node name inside the square brackets.
\def\printednodename{\ignorespaces #1}%
\else
% Use the actual chapter/section title appear inside
% the square brackets. Use the real section title if we have it.
\ifdim \wd1>0pt%
% It is in another manual, so we don't have it.
\def\printednodename{\ignorespaces #1}%
\else
\ifhavexrefs
% We know the real title if we have the xref values.
\def\printednodename{\refx{#1-title}{}}%
\else
% Otherwise just copy the Info node name.
\def\printednodename{\ignorespaces #1}%
\fi%
\fi
\fi
\fi
%
% If we use \unhbox0 and \unhbox1 to print the node names, TeX does not
% insert empty discretionaries after hyphens, which means that it will
% not find a line break at a hyphen in a node names. Since some manuals
% are best written with fairly long node names, containing hyphens, this
% is a loss. Therefore, we give the text of the node name again, so it
% is as if TeX is seeing it for the first time.
\ifdim \wd1 > 0pt
\putwordsection{} ``\printednodename'' in \cite{\printedmanual}%
\else
% _ (for example) has to be the character _ for the purposes of the
% control sequence corresponding to the node, but it has to expand
% into the usual \leavevmode...\vrule stuff for purposes of
% printing. So we \turnoffactive for the \refx-snt, back on for the
% printing, back off for the \refx-pg.
{\turnoffactive \refx{#1-snt}{}}%
\space [\printednodename],\space
\turnoffactive \putwordpage\tie\refx{#1-pg}{}%
\fi
\endgroup}
% \dosetq is the interface for calls from other macros
% Use \turnoffactive so that punctuation chars such as underscore
% work in node names.
\def\dosetq #1#2{{\let\folio=0 \turnoffactive \auxhat%
\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}%
\next}}
% \internalsetq {foo}{page} expands into
% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
% When the aux file is read, ' is the escape character
\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
% Things to be expanded by \internalsetq
\def\Ypagenumber{\folio}
\def\Ytitle{\thissection}
\def\Ynothing{}
\def\Ysectionnumberandtype{%
\ifnum\secno=0 \putwordChapter\xreftie\the\chapno %
\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno %
\else \ifnum \subsubsecno=0 %
\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno %
\else %
\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
\fi \fi \fi }
\def\Yappendixletterandtype{%
\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}%
\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno %
\else \ifnum \subsubsecno=0 %
\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
\else %
\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
\fi \fi \fi }
\gdef\xreftie{'tie}
% Use TeX 3.0's \inputlineno to get the line number, for better error
% messages, but if we're using an old version of TeX, don't do anything.
%
\ifx\inputlineno\thisisundefined
\let\linenumber = \empty % Non-3.0.
\else
\def\linenumber{\the\inputlineno:\space}
\fi
% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
% If its value is nonempty, SUFFIX is output afterward.
\def\refx#1#2{%
\expandafter\ifx\csname X#1\endcsname\relax
% If not defined, say something at least.
$\langle$un\-de\-fined$\rangle$%
\ifhavexrefs
\message{\linenumber Undefined cross reference `#1'.}%
\else
\ifwarnedxrefs\else
\global\warnedxrefstrue
\message{Cross reference values unknown; you must run TeX again.}%
\fi
\fi
\else
% It's defined, so just use it.
\csname X#1\endcsname
\fi
#2% Output the suffix in any case.
}
% Read the last existing aux file, if any. No error if none exists.
% This is the macro invoked by entries in the aux file.
\def\xrdef #1#2{
{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}}
\def\readauxfile{%
\begingroup
\catcode `\^^@=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\^^C=\other
\catcode `\^^D=\other
\catcode `\^^E=\other
\catcode `\^^F=\other
\catcode `\^^G=\other
\catcode `\^^H=\other
\catcode `\=\other
\catcode `\^^L=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode `\=\other
\catcode 26=\other
\catcode `\^^[=\other
\catcode `\^^\=\other
\catcode `\^^]=\other
\catcode `\^^^=\other
\catcode `\^^_=\other
\catcode `\@=\other
\catcode `\^=\other
\catcode `\~=\other
\catcode `\[=\other
\catcode `\]=\other
\catcode`\"=\other
\catcode`\_=\other
\catcode`\|=\other
\catcode`\<=\other
\catcode`\>=\other
\catcode `\$=\other
\catcode `\#=\other
\catcode `\&=\other
% `\+ does not work, so use 43.
\catcode 43=\other
% Make the characters 128-255 be printing characters
{%
\count 1=128
\def\loop{%
\catcode\count 1=\other
\advance\count 1 by 1
\ifnum \count 1<256 \loop \fi
}%
}%
% the aux file uses ' as the escape.
% Turn off \ as an escape so we do not lose on
% entries which were dumped with control sequences in their names.
% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
% Reference to such entries still does not work the way one would wish,
% but at least they do not bomb out when the aux file is read in.
\catcode `\{=1 \catcode `\}=2
\catcode `\%=\other
\catcode `\'=0
\catcode`\^=7 % to make ^^e4 etc usable in xref tags
\catcode `\\=\other
\openin 1 \jobname.aux
\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue
\global\warnedobstrue
\fi
% Open the new aux file. Tex will close it automatically at exit.
\openout \auxfile=\jobname.aux
\endgroup}
% Footnotes.
\newcount \footnoteno
% The trailing space in the following definition for supereject is
% vital for proper filling; pages come out unaligned when you do a
% pagealignmacro call if that space before the closing brace is
% removed.
\def\supereject{\par\penalty -20000\footnoteno =0 }
% @footnotestyle is meaningful for info output only..
\let\footnotestyle=\comment
\let\ptexfootnote=\footnote
{\catcode `\@=11
%
% Auto-number footnotes. Otherwise like plain.
\gdef\footnote{%
\global\advance\footnoteno by \@ne
\edef\thisfootno{$^{\the\footnoteno}$}%
%
% In case the footnote comes at the end of a sentence, preserve the
% extra spacing after we do the footnote number.
\let\@sf\empty
\ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
%
% Remove inadvertent blank space before typesetting the footnote number.
\unskip
\thisfootno\@sf
\footnotezzz
}%
% Don't bother with the trickery in plain.tex to not require the
% footnote text as a parameter. Our footnotes don't need to be so general.
%
\long\gdef\footnotezzz#1{\insert\footins{%
% We want to typeset this text as a normal paragraph, even if the
% footnote reference occurs in (for example) a display environment.
% So reset some parameters.
\interlinepenalty\interfootnotelinepenalty
\splittopskip\ht\strutbox % top baseline for broken footnotes
\splitmaxdepth\dp\strutbox
\floatingpenalty\@MM
\leftskip\z@skip
\rightskip\z@skip
\spaceskip\z@skip
\xspaceskip\z@skip
\parindent\defaultparindent
%
% Hang the footnote text off the number.
\hang
\textindent{\thisfootno}%
%
% Don't crash into the line above the footnote text. Since this
% expands into a box, it must come within the paragraph, lest it
% provide a place where TeX can split the footnote.
\footstrut
#1\strut}%
}
}%end \catcode `\@=11
% Set the baselineskip to #1, and the lineskip and strut size
% correspondingly. There is no deep meaning behind these magic numbers
% used as factors; they just match (closely enough) what Knuth defined.
%
\def\lineskipfactor{.08333}
\def\strutheightpercent{.70833}
\def\strutdepthpercent {.29167}
%
\def\setleading#1{%
\normalbaselineskip = #1\relax
\normallineskip = \lineskipfactor\normalbaselineskip
\normalbaselines
\setbox\strutbox =\hbox{%
\vrule width0pt height\strutheightpercent\baselineskip
depth \strutdepthpercent \baselineskip
}%
}
% @| inserts a changebar to the left of the current line. It should
% surround any changed text. This approach does *not* work if the
% change spans more than two lines of output. To handle that, we would
% have adopt a much more difficult approach (putting marks into the main
% vertical list for the beginning and end of each change).
%
\def\|{%
% \vadjust can only be used in horizontal mode.
\leavevmode
%
% Append this vertical mode material after the current line in the output.
\vadjust{%
% We want to insert a rule with the height and depth of the current
% leading; that is exactly what \strutbox is supposed to record.
\vskip-\baselineskip
%
% \vadjust-items are inserted at the left edge of the type. So
% the \llap here moves out into the left-hand margin.
\llap{%
%
% For a thicker or thinner bar, change the `1pt'.
\vrule height\baselineskip width1pt
%
% This is the space between the bar and the text.
\hskip 12pt
}%
}%
}
% For a final copy, take out the rectangles
% that mark overfull boxes (in case you have decided
% that the text looks ok even though it passes the margin).
%
\def\finalout{\overfullrule=0pt}
% End of control word definitions.
\message{and turning on texinfo input format.}
\def\openindices{%
\newindex{cp}%
\newcodeindex{fn}%
\newcodeindex{vr}%
\newcodeindex{tp}%
\newcodeindex{ky}%
\newcodeindex{pg}%
}
% Set some numeric style parameters, for 8.5 x 11 format.
%\hsize = 6.5in
\newdimen\defaultparindent \defaultparindent = 15pt
\parindent = \defaultparindent
\parskip 18pt plus 1pt
\setleading{15pt}
\advance\topskip by 1.2cm
% Prevent underfull vbox error messages.
\vbadness=10000
% Following George Bush, just get rid of widows and orphans.
\widowpenalty=10000
\clubpenalty=10000
% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
% using an old version of TeX, don't do anything. We want the amount of
% stretch added to depend on the line length, hence the dependence on
% \hsize. This makes it come to about 9pt for the 8.5x11 format.
%
\ifx\emergencystretch\thisisundefined
% Allow us to assign to \emergencystretch anyway.
\def\emergencystretch{\dimen0}%
\else
\emergencystretch = \hsize
\divide\emergencystretch by 45
\fi
% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25)
\def\smallbook{
% These values for secheadingskip and subsecheadingskip are
% experiments. RJC 7 Aug 1992
\global\secheadingskip = 17pt plus 6pt minus 3pt
\global\subsecheadingskip = 14pt plus 6pt minus 3pt
\global\lispnarrowing = 0.3in
\setleading{12pt}
\advance\topskip by -1cm
\global\parskip 3pt plus 1pt
\global\hsize = 5in
\global\vsize=7.5in
\global\tolerance=700
\global\hfuzz=1pt
\global\contentsrightmargin=0pt
\global\deftypemargin=0pt
\global\defbodyindent=.5cm
\global\pagewidth=\hsize
\global\pageheight=\vsize
\global\let\smalllisp=\smalllispx
\global\let\smallexample=\smalllispx
\global\def\Esmallexample{\Esmalllisp}
}
% Use @afourpaper to print on European A4 paper.
\def\afourpaper{
\global\tolerance=700
\global\hfuzz=1pt
\setleading{12pt}
\global\parskip 15pt plus 1pt
\global\vsize= 53\baselineskip
\advance\vsize by \topskip
%\global\hsize= 5.85in % A4 wide 10pt
\global\hsize= 6.5in
\global\outerhsize=\hsize
\global\advance\outerhsize by 0.5in
\global\outervsize=\vsize
\global\advance\outervsize by 0.6in
\global\pagewidth=\hsize
\global\pageheight=\vsize
}
% Allow control of the text dimensions. Parameters in order: textheight;
% textwidth; \voffset; \hoffset (!); binding offset. All require a dimension;
% header is additional; added length extends the bottom of the page.
\def\changepagesizes#1#2#3#4#5{
\global\vsize= #1
\advance\vsize by \topskip
\global\voffset= #3
\global\hsize= #2
\global\outerhsize=\hsize
\global\advance\outerhsize by 0.5in
\global\outervsize=\vsize
\global\advance\outervsize by 0.6in
\global\pagewidth=\hsize
\global\pageheight=\vsize
\global\normaloffset= #4
\global\bindingoffset= #5}
% This layout is compatible with Latex on A4 paper.
\def\afourlatex{\changepagesizes{22cm}{15cm}{7mm}{4.6mm}{5mm}}
% Use @afourwide to print on European A4 paper in wide format.
\def\afourwide{\afourpaper
\changepagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}}
% Define macros to output various characters with catcode for normal text.
\catcode`\"=\other
\catcode`\~=\other
\catcode`\^=\other
\catcode`\_=\other
\catcode`\|=\other
\catcode`\<=\other
\catcode`\>=\other
\catcode`\+=\other
\def\normaldoublequote{"}
\def\normaltilde{~}
\def\normalcaret{^}
\def\normalunderscore{_}
\def\normalverticalbar{|}
\def\normalless{<}
\def\normalgreater{>}
\def\normalplus{+}
% This macro is used to make a character print one way in ttfont
% where it can probably just be output, and another way in other fonts,
% where something hairier probably needs to be done.
%
% #1 is what to print if we are indeed using \tt; #2 is what to print
% otherwise. Since all the Computer Modern typewriter fonts have zero
% interword stretch (and shrink), and it is reasonable to expect all
% typewriter fonts to have this, we can check that font parameter.
%
\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi}
% Turn off all special characters except @
% (and those which the user can use as if they were ordinary).
% Most of these we simply print from the \tt font, but for some, we can
% use math or other variants that look better in normal text.
\catcode`\"=\active
\def\activedoublequote{{\tt \char '042}}
\let"=\activedoublequote
\catcode`\~=\active
\def~{{\tt \char '176}}
\chardef\hat=`\^
\catcode`\^=\active
\def\auxhat{\def^{'hat}}
\def^{{\tt \hat}}
\catcode`\_=\active
\def_{\ifusingtt\normalunderscore\_}
% Subroutine for the previous macro.
\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}}
\catcode`\|=\active
\def|{{\tt \char '174}}
\chardef \less=`\<
\catcode`\<=\active
\def<{{\tt \less}}
\chardef \gtr=`\>
\catcode`\>=\active
\def>{{\tt \gtr}}
\catcode`\+=\active
\def+{{\tt \char 43}}
%\catcode 27=\active
%\def^^[{$\diamondsuit$}
% Set up an active definition for =, but don't enable it most of the time.
{\catcode`\==\active
\global\def={{\tt \char 61}}}
\catcode`+=\active
\catcode`\_=\active
% If a .fmt file is being used, characters that might appear in a file
% name cannot be active until we have parsed the command line.
% So turn them off again, and have \everyjob (or @setfilename) turn them on.
% \otherifyactive is called near the end of this file.
\def\otherifyactive{\catcode`+=\other \catcode`\_=\other}
\catcode`\@=0
% \rawbackslashxx output one backslash character in current font
\global\chardef\rawbackslashxx=`\\
%{\catcode`\\=\other
%@gdef@rawbackslashxx{\}}
% \rawbackslash redefines \ as input to do \rawbackslashxx.
{\catcode`\\=\active
@gdef@rawbackslash{@let\=@rawbackslashxx }}
% \normalbackslash outputs one backslash in fixed width font.
\def\normalbackslash{{\tt\rawbackslashxx}}
% Say @foo, not \foo, in error messages.
\escapechar=`\@
% \catcode 17=0 % Define control-q
\catcode`\\=\active
% Used sometimes to turn off (effectively) the active characters
% even after parsing them.
@def@turnoffactive{@let"=@normaldoublequote
@let\=@realbackslash
@let~=@normaltilde
@let^=@normalcaret
@let_=@normalunderscore
@let|=@normalverticalbar
@let<=@normalless
@let>=@normalgreater
@let+=@normalplus}
@def@normalturnoffactive{@let"=@normaldoublequote
@let\=@normalbackslash
@let~=@normaltilde
@let^=@normalcaret
@let_=@normalunderscore
@let|=@normalverticalbar
@let<=@normalless
@let>=@normalgreater
@let+=@normalplus}
% Make _ and + \other characters, temporarily.
% This is canceled by @fixbackslash.
@otherifyactive
% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
% That is what \eatinput is for; after that, the `\' should revert to printing
% a backslash.
%
@gdef@eatinput input texinfo{@fixbackslash}
@global@let\ = @eatinput
% On the other hand, perhaps the file did not have a `\input texinfo'. Then
% the first `\{ in the file would cause an error. This macro tries to fix
% that, assuming it is called before the first `\' could plausibly occur.
% Also back turn on active characters that might appear in the input
% file name, in case not using a pre-dumped format.
%
@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi
@catcode`+=@active @catcode`@_=@active}
%% These look ok in all fonts, so just make them not special. The @rm below
%% makes sure that the current font starts out as the newly loaded cmr10
@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
@textfonts
@rm
@c Local variables:
@c page-delimiter: "^\\\\message"
@c End:
texinfo-3.7/texinfo.texi 100444 12120 13 2102172 6040541520 13507 0 ustar rms user \input texinfo.tex @c -*-texinfo-*-
@comment %**start of header
@setfilename texinfo
@settitle Texinfo @value{edition}
@syncodeindex vr fn
@footnotestyle separate
@paragraphindent 2
@smallbook
@comment %**end of header
@c Set smallbook if printing in smallbook format so the example of the
@c smallbook font is actually written using smallbook; in bigbook, a kludge
@c is used for TeX output.
@set smallbook
@c @@clear smallbook
@ignore
@ifinfo
@format
START-INFO-DIR-ENTRY
* Texinfo: (texinfo). The documentation format for the GNU Project.
END-INFO-DIR-ENTRY
@end format
@end ifinfo
@end ignore
@set edition 2.21
@set update-date 7 June 1995
@set update-month June 1995
@c Experiment with smaller amounts of whitespace between chapters
@c and sections.
@tex
\global\chapheadingskip = 15pt plus 4pt minus 2pt
\global\secheadingskip = 12pt plus 3pt minus 2pt
\global\subsecheadingskip = 9pt plus 2pt minus 2pt
@end tex
@c Experiment with smaller amounts of whitespace between paragraphs in
@c the 8.5 by 11 inch format.
@ifclear smallbook
@tex
\global\parskip 6pt plus 1pt
@end tex
@end ifclear
@finalout
@c Currently undocumented command, 5 December 1993:
@c
@c nwnode (Same as node, but no warnings; for `makeinfo'.)
@ifinfo
This file documents Texinfo, a documentation system that uses a single
source file to produce both on-line information and a printed manual.
Copyright (C) 1988, 1990, 1991, 1992, 1993, 1995 Free Software Foundation, Inc.
This is the second edition of the Texinfo documentation,@*
and is consistent with version 2 of @file{texinfo.tex}.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@ignore
Permission is granted to process this file through TeX and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the Free Software Foundation.
@end ifinfo
@setchapternewpage odd
@shorttitlepage Texinfo
@titlepage
@c use the new format for titles
@title Texinfo
@subtitle The GNU Documentation Format
@subtitle Edition @value{edition}, for Texinfo Version Three
@subtitle @value{update-month}
@author by Robert J. Chassell and Richard M. Stallman
@comment Include the Distribution inside the titlepage so
@c that headings are turned off.
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1988, 1990, 1991, 1992, 1993, 1995 Free Software Foundation, Inc.
@sp 2
This is the second edition of the Texinfo documentation,@*
and is consistent with version 2 of @file{texinfo.tex}.
@sp 2
Published by the Free Software Foundation @*
59 Temple Place Suite 330, @*
Boston, MA 02111-1307 USA @*
Printed copies are available for $15 each.@*
ISBN 1-882114-63-9
@c ISBN number 1-882114-63-9 is for edition 2.20 of 28 February 1995
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the Free Software Foundation.
@sp 2
Cover art by Etienne Suvasa.
@end titlepage
@ifinfo
@node Top, Copying, (dir), (dir)
@top Texinfo
Texinfo is a documentation system that uses a single source file to
produce both on-line information and printed output.@refill
The first part of this master menu lists the major nodes in this Info
document, including the @@-command and concept indices. The rest of
the menu lists all the lower level nodes in the document.@refill
This is Edition @value{edition} of the Texinfo documentation,
@w{@value{update-date},} for Texinfo Version Three.
@end ifinfo
@c Here is a spare copy of the chapter menu entry descriptions,
@c in case they are accidently deleted
@ignore
Your rights.
Texinfo in brief.
How to use Texinfo mode.
What is at the beginning of a Texinfo file?
What is at the end of a Texinfo file?
How to create chapters, sections, subsections,
appendices, and other parts.
How to provide structure for a document.
How to write nodes.
How to write menus.
How to write cross references.
How to mark words and phrases as code,
keyboard input, meta-syntactic
variables, and the like.
How to write quotations, examples, etc.
How to write lists and tables.
How to create indices.
How to insert @@-signs, braces, etc.
How to indicate results of evaluation,
expansion of macros, errors, etc.
How to force and prevent line and page breaks.
How to describe functions and the like in a uniform manner.
How to write footnotes.
How to specify text for either @TeX{} or Info.
How to print hardcopy.
How to create an Info file.
How to install an Info file
A list of all the Texinfo @@-commands.
Hints on how to write a Texinfo document.
A sample Texinfo file to look at.
Tell readers they have the right to copy
and distribute.
How to incorporate other Texinfo files.
How to write page headings and footings.
How to find formatting mistakes.
All about paragraph refilling.
A description of @@-Command syntax.
Texinfo second edition features.
A menu containing commands and variables.
A menu covering many topics.
@end ignore
@menu
* Copying:: Your rights.
* Overview:: Texinfo in brief.
* Texinfo Mode:: How to use Texinfo mode.
* Beginning a File:: What is at the beginning of a Texinfo file?
* Ending a File:: What is at the end of a Texinfo file?
* Structuring:: How to create chapters, sections, subsections,
appendices, and other parts.
* Nodes:: How to write nodes.
* Menus:: How to write menus.
* Cross References:: How to write cross references.
* Marking Text:: How to mark words and phrases as code,
keyboard input, meta-syntactic
variables, and the like.
* Quotations and Examples:: How to write quotations, examples, etc.
* Lists and Tables:: How to write lists and tables.
* Indices:: How to create indices.
* Insertions:: How to insert @@-signs, braces, etc.
* Glyphs:: How to indicate results of evaluation,
expansion of macros, errors, etc.
* Breaks:: How to force and prevent line and page breaks.
* Definition Commands:: How to describe functions and the like
in a uniform manner.
* Footnotes:: How to write footnotes.
* Conditionals:: How to specify text for either @TeX{} or Info.
* Format/Print Hardcopy:: How to convert a Texinfo file to a file
for printing and how to print that file.
* Create an Info File:: Convert a Texinfo file into an Info file.
* Install an Info File:: Make an Info file accessible to users.
* Command List:: All the Texinfo @@-commands.
* Tips:: Hints on how to write a Texinfo document.
* Sample Texinfo File:: A sample Texinfo file to look at.
* Sample Permissions:: Tell readers they have the right to copy
and distribute.
* Include Files:: How to incorporate other Texinfo files.
* Headings:: How to write page headings and footings.
* Catching Mistakes:: How to find formatting mistakes.
* Refilling Paragraphs:: All about paragraph refilling.
* Command Syntax:: A description of @@-Command syntax.
* Obtaining TeX:: How to Obtain @TeX{}.
* New Features:: Texinfo second edition features.
* Command and Variable Index:: A menu containing commands and variables.
* Concept Index:: A menu covering many topics.
--- The Detailed Node Listing ---
Overview of Texinfo
* Using Texinfo:: Create a conventional printed book
or an Info file.
* Info Files:: What is an Info file?
* Printed Books:: Characteristics of a printed book or manual.
* Formatting Commands:: @@-commands are used for formatting.
* Conventions:: General rules for writing a Texinfo file.
* Comments:: How to write comments and mark regions that
the formatting commands will ignore.
* Minimum:: What a Texinfo file must have.
* Six Parts:: Usually, a Texinfo file has six parts.
* Short Sample:: A short sample Texinfo file.
* Acknowledgements::
Using Texinfo Mode
* Texinfo Mode Overview:: How Texinfo mode can help you.
* Emacs Editing:: Texinfo mode adds to GNU Emacs' general
purpose editing features.
* Inserting:: How to insert frequently used @@-commands.
* Showing the Structure:: How to show the structure of a file.
* Updating Nodes and Menus:: How to update or create new nodes and menus.
* Info Formatting:: How to format for Info.
* Printing:: How to format and print part or all of a file.
* Texinfo Mode Summary:: Summary of all the Texinfo mode commands.
Updating Nodes and Menus
* Updating Commands:: Five major updating commands.
* Updating Requirements:: How to structure a Texinfo file for
using the updating command.
* Other Updating Commands:: How to indent descriptions, insert
missing nodes lines, and update
nodes in sequence.
Beginning a Texinfo File
* Four Parts:: Four parts begin a Texinfo file.
* Sample Beginning:: Here is a sample beginning for a Texinfo file.
* Header:: The very beginning of a Texinfo file.
* Info Summary and Permissions:: Summary and copying permissions for Info.
* Titlepage & Copyright Page:: Creating the title and copyright pages.
* The Top Node:: Creating the `Top' node and master menu.
* Software Copying Permissions:: Ensure that you and others continue to
have the right to use and share software.
The Texinfo File Header
* First Line:: The first line of a Texinfo file.
* Start of Header:: Formatting a region requires this.
* setfilename:: Tell Info the name of the Info file.
* settitle:: Create a title for the printed work.
* setchapternewpage:: Start chapters on right-hand pages.
* paragraphindent:: An option to specify paragraph indentation.
* End of Header:: Formatting a region requires this.
The Title and Copyright Pages
* titlepage:: Create a title for the printed document.
* titlefont center sp:: The @code{@@titlefont}, @code{@@center},
and @code{@@sp} commands.
* title subtitle author:: The @code{@@title}, @code{@@subtitle},
and @code{@@author} commands.
* Copyright & Permissions:: How to write the copyright notice and
include copying permissions.
* end titlepage:: Turn on page headings after the title and
copyright pages.
* headings on off:: An option for turning headings on and off
and double or single sided printing.
The `Top' Node and Master Menu
* Title of Top Node:: Sketch what the file is about.
* Master Menu Parts:: A master menu has three or more parts.
Ending a Texinfo File
* Printing Indices & Menus:: How to print an index in hardcopy and
generate index menus in Info.
* Contents:: How to create a table of contents.
* File End:: How to mark the end of a file.
Chapter Structuring
* Tree Structuring:: A manual is like an upside down tree @dots{}
* Structuring Command Types:: How to divide a manual into parts.
* makeinfo top:: The @code{@@top} command, part of the `Top' node.
* chapter::
* unnumbered & appendix::
* majorheading & chapheading::
* section::
* unnumberedsec appendixsec heading::
* subsection::
* unnumberedsubsec appendixsubsec subheading::
* subsubsection:: Commands for the lowest level sections.
* Raise/lower sections:: How to change commands' hierarchical level.
Nodes
* Two Paths:: Different commands to structure
Info output and printed output.
* Node Menu Illustration:: A diagram, and sample nodes and menus.
* node:: How to write a node, in detail.
* makeinfo Pointer Creation:: How to create node pointers with @code{makeinfo}.
The @code{@@node} Command
* Node Names:: How to choose node and pointer names.
* Writing a Node:: How to write an @code{@@node} line.
* Node Line Tips:: Keep names short.
* Node Line Requirements:: Keep names unique, without @@-commands.
* First Node:: How to write a `Top' node.
* makeinfo top command:: How to use the @code{@@top} command.
* Top Node Summary:: Write a brief description for readers.
Menus
* Menu Location:: Put a menu in a short node.
* Writing a Menu:: What is a menu?
* Menu Parts:: A menu entry has three parts.
* Less Cluttered Menu Entry:: Two part menu entry.
* Menu Example:: Two and three part menu entries.
* Other Info Files:: How to refer to a different Info file.
Cross References
* References:: What cross references are for.
* Cross Reference Commands:: A summary of the different commands.
* Cross Reference Parts:: A cross reference has several parts.
* xref:: Begin a reference with `See' @dots{}
* Top Node Naming:: How to refer to the beginning of another file.
* ref:: A reference for the last part of a sentence.
* pxref:: How to write a parenthetical cross reference.
* inforef:: How to refer to an Info-only file.
@code{@@xref}
* Reference Syntax:: What a reference looks like and requires.
* One Argument:: @code{@@xref} with one argument.
* Two Arguments:: @code{@@xref} with two arguments.
* Three Arguments:: @code{@@xref} with three arguments.
* Four and Five Arguments:: @code{@@xref} with four and five arguments.
Marking Words and Phrases
* Indicating:: How to indicate definitions, files, etc.
* Emphasis:: How to emphasize text.
Indicating Definitions, Commands, etc.
* Useful Highlighting:: Highlighting provides useful information.
* code:: How to indicate code.
* kbd:: How to show keyboard input.
* key:: How to specify keys.
* samp:: How to show a literal sequence of characters.
* var:: How to indicate a metasyntactic variable.
* file:: How to indicate the name of a file.
* dfn:: How to specify a definition.
* cite:: How to refer to a book that is not in Info.
Emphasizing Text
* emph & strong:: How to emphasize text in Texinfo.
* Smallcaps:: How to use the small caps font.
* Fonts:: Various font commands for printed output.
* Customized Highlighting:: How to define highlighting commands.
Quotations and Examples
* Block Enclosing Commands:: Use different constructs for
different purposes.
* quotation:: How to write a quotation.
* example:: How to write an example in a fixed-width font.
* noindent:: How to prevent paragraph indentation.
* Lisp Example:: How to illustrate Lisp code.
* smallexample & smalllisp:: Forms for the @code{@@smallbook} option.
* display:: How to write an example in the current font.
* format:: How to write an example that does not narrow
the margins.
* exdent:: How to undo the indentation of a line.
* flushleft & flushright:: How to push text flushleft or flushright.
* cartouche:: How to draw cartouches around examples.
Making Lists and Tables
* Introducing Lists:: Texinfo formats lists for you.
* itemize:: How to construct a simple list.
* enumerate:: How to construct a numbered list.
* Two-column Tables:: How to construct a two-column table.
Making a Two-column Table
* table:: How to construct a two-column table.
* ftable vtable:: How to construct a two-column table
with automatic indexing.
* itemx:: How to put more entries in the first column.
Creating Indices
* Index Entries:: Choose different words for index entries.
* Predefined Indices:: Use different indices for different kinds
of entry.
* Indexing Commands:: How to make an index entry.
* Combining Indices:: How to combine indices.
* New Indices:: How to define your own indices.
Combining Indices
* syncodeindex:: How to merge two indices, using @code{@@code}
font for the merged-from index.
* synindex:: How to merge two indices, using the
default font of the merged-to index.
Special Insertions
* Braces Atsigns Periods:: How to insert braces, @samp{@@} and periods.
* dmn:: How to format a dimension.
* Dots Bullets:: How to insert dots and bullets.
* TeX and copyright:: How to insert the @TeX{} logo
and the copyright symbol.
* minus:: How to insert a minus sign.
* math:: How to format a mathematical expression.
Inserting @samp{@@}, Braces, and Periods
* Inserting An Atsign::
* Inserting Braces:: How to insert @samp{@{} and @samp{@}}
* Controlling Spacing:: How to insert the right amount of space
after punctuation within a sentence.
Inserting Ellipsis, Dots, and Bullets
* dots:: How to insert dots @dots{}
* bullet:: How to insert a bullet.
Inserting @TeX{} and the Copyright Symbol
* tex:: How to insert the @TeX{} logo.
* copyright symbol:: How to use @code{@@copyright}@{@}.
Glyphs for Examples
* Glyphs Summary::
* result:: How to show the result of expression.
* expansion:: How to indicate an expansion.
* Print Glyph:: How to indicate printed output.
* Error Glyph:: How to indicate an error message.
* Equivalence:: How to indicate equivalence.
* Point Glyph:: How to indicate the location of point.
Making and Preventing Breaks
* Break Commands:: Cause and prevent splits.
* Line Breaks:: How to force a single line to use two lines.
* w:: How to prevent unwanted line breaks.
* sp:: How to insert blank lines.
* page:: How to force the start of a new page.
* group:: How to prevent unwanted page breaks.
* need:: Another way to prevent unwanted page breaks.
Definition Commands
* Def Cmd Template:: How to structure a description using a
definition command.
* Optional Arguments:: How to handle optional and repeated arguments.
* deffnx:: How to group two or more `first' lines.
* Def Cmds in Detail:: All the definition commands.
* Def Cmd Conventions:: Conventions for writing definitions.
* Sample Function Definition::
The Definition Commands
* Functions Commands:: Commands for functions and similar entities.
* Variables Commands:: Commands for variables and similar entities.
* Typed Functions:: Commands for functions in typed languages.
* Typed Variables:: Commands for variables in typed languages.
* Abstract Objects:: Commands for object-oriented programming.
* Data Types:: The definition command for data types.
Footnotes
* Footnote Commands:: How to write a footnote in Texinfo.
* Footnote Styles:: Controlling how footnotes appear in Info.
Conditionally Visible Text
* Conditional Commands:: How to specify text for Info or @TeX{}.
* Using Ordinary TeX Commands:: You can use any and all @TeX{} commands.
* set clear value:: How to designate which text to format (for
both Info and @TeX{}); and how to set a
flag to a string that you can insert.
@code{@@set}, @code{@@clear}, and @code{@@value}
* ifset ifclear:: Format a region if a flag is set.
* value:: Replace a flag with a string.
* value Example:: An easy way to update edition information.
Format and Print Hardcopy
* Use TeX:: Use @TeX{} to format for hardcopy.
* Format with tex/texindex:: How to format in a shell.
* Format with texi2dvi:: A simpler way to use the shell.
* Print with lpr:: How to print.
* Within Emacs:: How to format and print from an Emacs shell.
* Texinfo Mode Printing:: How to format and print in Texinfo mode.
* Compile-Command:: How to print using Emacs's compile command.
* Requirements Summary:: @TeX{} formatting requirements summary.
* Preparing for TeX:: What you need to do to use @TeX{}.
* Overfull hboxes:: What are and what to do with overfull hboxes.
* smallbook:: How to print small format books and manuals.
* A4 Paper:: How to print on European A4 paper.
* Cropmarks and Magnification:: How to print marks to indicate the size
of pages and how to print scaled up output.
Creating an Info File
* makeinfo advantages:: @code{makeinfo} provides better error checking.
* Invoking makeinfo:: How to run @code{makeinfo} from a shell.
* makeinfo options:: Specify fill-column and other options.
* Pointer Validation:: How to check that pointers point somewhere.
* makeinfo in Emacs:: How to run @code{makeinfo} from Emacs.
* texinfo-format commands:: Two Info formatting commands written
in Emacs Lisp are an alternative
to @code{makeinfo}.
* Batch Formatting:: How to format for Info in Emacs Batch mode.
* Tag and Split Files:: How tagged and split files help Info
to run better.
Installing an Info File
* Directory file:: The top level menu for all Info files.
* New Info File:: Listing a new info file.
* Other Info Directories:: How to specify Info files that are
located in other directories.
Sample Permissions
* Inserting Permissions:: How to put permissions in your document.
* ifinfo Permissions:: Sample @samp{ifinfo} copying permissions.
* Titlepage Permissions:: Sample Titlepage copying permissions.
Include Files
* Using Include Files:: How to use the @code{@@include} command.
* texinfo-multiple-files-update:: How to create and update nodes and
menus when using included files.
* Include File Requirements:: What @code{texinfo-multiple-files-update} expects.
* Sample Include File:: A sample outer file with included files
within it; and a sample included file.
* Include Files Evolution:: How use of the @code{@@include} command
has changed over time.
Page Headings
* Headings Introduced:: Conventions for using page headings.
* Heading Format:: Standard page heading formats.
* Heading Choice:: How to specify the type of page heading.
* Custom Headings:: How to create your own headings and footings.
Formatting Mistakes
* makeinfo preferred:: @code{makeinfo} finds errors.
* Debugging with Info:: How to catch errors with Info formatting.
* Debugging with TeX:: How to catch errors with @TeX{} formatting.
* Using texinfo-show-structure:: How to use @code{texinfo-show-structure}.
* Using occur:: How to list all lines containing a pattern.
* Running Info-Validate:: How to find badly referenced nodes.
Finding Badly Referenced Nodes
* Using Info-validate:: How to run @code{Info-validate}.
* Unsplit:: How to create an unsplit file.
* Tagifying:: How to tagify a file.
* Splitting:: How to split a file manually.
Second Edition Features
* New Texinfo Mode Commands:: The updating commands are especially useful.
* New Commands:: Many newly described @@-commands.
@end menu
@node Copying, Overview, Top, Top
@comment node-name, next, previous, up
@unnumbered Texinfo Copying Conditions
@cindex Copying conditions
@cindex Conditions for copying Texinfo
The programs currently being distributed that relate to Texinfo include
portions of GNU Emacs, plus other separate programs (including
@code{makeinfo}, @code{info}, @code{texindex}, and @file{texinfo.tex}).
These programs are @dfn{free}; this means that everyone is free to use
them and free to redistribute them on a free basis. The Texinfo-related
programs are not in the public domain; they are copyrighted and there
are restrictions on their distribution, but these restrictions are
designed to permit everything that a good cooperating citizen would want
to do. What is not allowed is to try to prevent others from further
sharing any version of these programs that they might get from
you.@refill
Specifically, we want to make sure that you have the right to give
away copies of the programs that relate to Texinfo, that you receive
source code or else can get it if you want it, that you can change these
programs or use pieces of them in new free programs, and that you know
you can do these things.@refill
To make sure that everyone has such rights, we have to forbid you to
deprive anyone else of these rights. For example, if you distribute
copies of the Texinfo related programs, you must give the recipients all
the rights that you have. You must make sure that they, too, receive or
can get the source code. And you must tell them their rights.@refill
Also, for our own protection, we must make certain that everyone finds
out that there is no warranty for the programs that relate to Texinfo.
If these programs are modified by someone else and passed on, we want
their recipients to know that what they have is not what we distributed,
so that any problems introduced by others will not reflect on our
reputation.@refill
The precise conditions of the licenses for the programs currently
being distributed that relate to Texinfo are found in the General Public
Licenses that accompany them.@refill
@node Overview, Texinfo Mode, Copying, Top
@comment node-name, next, previous, up
@chapter Overview of Texinfo
@cindex Overview of Texinfo
@cindex Texinfo overview
@dfn{Texinfo}@footnote{Note that the first syllable of ``Texinfo'' is
pronounced like ``speck'', not ``hex''. This odd pronunciation is
derived from, but is not the same as, the pronunciation of @TeX{}. In
the word @TeX{}, the @samp{X} is actually the Greek letter ``chi''
rather than the English letter ``ex''. Pronounce @TeX{} as if the
@samp{X} were the last sound in the name `Bach'; but pronounce Texinfo
as if the @samp{x} were a `k'. Spell ``Texinfo'' with a capital ``T''
and write the other letters in lower case.}
is a documentation system that uses a single source file to produce both
on-line information and printed output. This means that instead of
writing two different documents, one for the on-line help or other on-line
information and the other for a typeset manual or other printed work, you
need write only one document. When the work is revised, you need revise
only one document. (You can read the on-line information, known as an
@dfn{Info file}, with an Info documentation-reading program.)@refill
@menu
* Using Texinfo:: Create a conventional printed book
or an Info file.
* Info Files:: What is an Info file?
* Printed Books:: Characteristics of a printed book or manual.
* Formatting Commands:: @@-commands are used for formatting.
* Conventions:: General rules for writing a Texinfo file.
* Comments:: How to write comments and mark regions that
the formatting commands will ignore.
* Minimum:: What a Texinfo file must have.
* Six Parts:: Usually, a Texinfo file has six parts.
* Short Sample:: A short sample Texinfo file.
* Acknowledgements::
@end menu
@node Using Texinfo, Info Files, Overview, Overview
@ifinfo
@heading Using Texinfo
@end ifinfo
Using Texinfo, you can create a printed document with the normal
features of a book, including chapters, sections, cross references,
and indices. From the same Texinfo source file, you can create a
menu-driven, on-line Info file with nodes, menus, cross references,
and indices. You can, if you wish, make the chapters and sections of
the printed document correspond to the nodes of the on-line
information; and you use the same cross references and indices for
both the Info file and the printed work. @cite{The GNU
Emacs Manual} is a good example of a Texinfo file, as is this manual.@refill
To make a printed document, you process a Texinfo source file with the
@TeX{} typesetting program. This creates a @sc{dvi} file that you can
typeset and print as a book or report. (Note that the Texinfo language is
completely different from @TeX{}'s usual language, Plain@TeX{}, which
Texinfo replaces.) If you do not have @TeX{}, but do have
@code{troff} or @code{nroff}, you can use the @code{texi2roff} program
instead.@refill
To make an Info file, you process a Texinfo source file with the
@code{makeinfo} utility or Emacs's @code{texinfo-format-buffer} command;
this creates an Info file that you can install on-line.@refill
@TeX{} and @code{texi2roff} work with many types of printer; similarly,
Info works with almost every type of computer terminal. This power
makes Texinfo a general purpose system, but brings with it a constraint,
which is that a Texinfo file may contain only the customary
``typewriter'' characters (letters, numbers, spaces, and punctuation
marks) but no special graphics.@refill
A Texinfo file is a plain @sc{ascii} file containing text and
@dfn{@@-commands} (words preceded by an @samp{@@}) that tell the
typesetting and formatting programs what to do. You may edit a
Texinfo file with any text editor; but it is especially convenient to
use GNU Emacs since that editor has a special mode, called Texinfo
mode, that provides various Texinfo-related features. (@xref{Texinfo
Mode}.)@refill
Before writing a Texinfo source file, you should become familiar with
the Info documentation reading program and learn about nodes,
menus, cross references, and the rest. (@inforef{Top, info, info},
for more information.)@refill
You can use Texinfo to create both on-line help and printed manuals;
moreover, Texinfo is freely redistributable. For these reasons, Texinfo
is the format in which documentation for GNU utilities and libraries is
written.@refill
@node Info Files, Printed Books, Using Texinfo, Overview
@comment node-name, next, previous, up
@section Info files
@cindex Info files
An Info file is a Texinfo file formatted so that the Info documentation
reading program can operate on it. (@code{makeinfo}
and @code{texinfo-format-buffer} are two commands that convert a Texinfo file
into an Info file.)@refill
Info files are divided into pieces called @dfn{nodes}, each of which
contains the discussion of one topic. Each node has a name, and
contains both text for the user to read and pointers to other nodes,
which are identified by their names. The Info program displays one node
at a time, and provides commands with which the user can move to other
related nodes.@refill
@ifinfo
@inforef{Top, info, info}, for more information about using Info.@refill
@end ifinfo
Each node of an Info file may have any number of child nodes that
describe subtopics of the node's topic. The names of child
nodes are listed in a @dfn{menu} within the parent node; this
allows you to use certain Info commands to move to one of the child
nodes. Generally, an Info file is organized like a book. If a node
is at the logical level of a chapter, its child nodes are at the level
of sections; likewise, the child nodes of sections are at the level
of subsections.@refill
All the children of any one parent are linked together in a
bidirectional chain of `Next' and `Previous' pointers. The `Next'
pointer provides a link to the next section, and the `Previous' pointer
provides a link to the previous section. This means that all the nodes
that are at the level of sections within a chapter are linked together.
Normally the order in this chain is the same as the order of the
children in the parent's menu. Each child node records the parent node
name as its `Up' pointer. The last child has no `Next' pointer, and the
first child has the parent both as its `Previous' and as its `Up'
pointer.@footnote{In some documents, the first child has no `Previous'
pointer. Occasionally, the last child has the node name of the next
following higher level node as its `Next' pointer.}@refill
The book-like structuring of an Info file into nodes that correspond
to chapters, sections, and the like is a matter of convention, not a
requirement. The `Up', `Previous', and `Next' pointers of a node can
point to any other nodes, and a menu can contain any other nodes.
Thus, the node structure can be any directed graph. But it is usually
more comprehensible to follow a structure that corresponds to the
structure of chapters and sections in a printed book or report.@refill
In addition to menus and to `Next', `Previous', and `Up' pointers, Info
provides pointers of another kind, called references, that can be
sprinkled throughout the text. This is usually the best way to
represent links that do not fit a hierarchical structure.@refill
Usually, you will design a document so that its nodes match the
structure of chapters and sections in the printed output. But there
are times when this is not right for the material being discussed.
Therefore, Texinfo uses separate commands to specify the node
structure for the Info file and the section structure for the printed
output.@refill
Generally, you enter an Info file through a node that by convention is
called @samp{Top}. This node normally contains just a brief summary
of the file's purpose, and a large menu through which the rest of the
file is reached. From this node, you can either traverse the file
systematically by going from node to node, or you can go to a specific
node listed in the main menu, or you can search the index menus and
then go directly to the node that has the information you want.@refill
@c !!! With the standalone Info system you may go to specific nodes
@c directly..
If you want to read through an Info file in sequence, as if it were a
printed manual, you can get the whole file with the advanced Info
command @kbd{g* @key{RET}}. (@inforef{Expert, Advanced Info commands,
info}.)@refill
@c !!! dir file may be located in one of many places:
@c /usr/local/emacs/info mentioned in info.c DEFAULT_INFOPATH
@c /usr/local/lib/emacs/info mentioned in info.c DEFAULT_INFOPATH
@c /usr/gnu/info mentioned in info.c DEFAULT_INFOPATH
@c /usr/local/info
@c /usr/local/lib/info
The @file{dir} file in the @file{info} directory serves as the
departure point for the whole Info system. From it, you can reach the
`Top' nodes of each of the documents in a complete Info system.@refill
@node Printed Books, Formatting Commands, Info Files, Overview
@comment node-name, next, previous, up
@section Printed Books
@cindex Printed book and manual characteristics
@cindex Manual characteristics, printed
@cindex Book characteristics, printed
@cindex Texinfo printed book characteristics
@cindex Characteristics, printed books or manuals
A Texinfo file can be formatted and typeset as a printed book or manual.
To do this, you need @TeX{}, a powerful, sophisticated typesetting
program written by Donald Knuth.@footnote{You can also use the
@code{texi2roff} program if you do not have @TeX{}; since Texinfo is
designed for use with @TeX{}, @code{texi2roff} is not described here.
@code{texi2roff} is part of the standard GNU distribution.}@refill
A Texinfo-based book is similar to any other typeset, printed work: it
can have a title page, copyright page, table of contents, and preface,
as well as chapters, numbered or unnumbered sections and subsections,
page headers, cross references, footnotes, and indices.@refill
You can use Texinfo to write a book without ever having the intention
of converting it into on-line information. You can use Texinfo for
writing a printed novel, and even to write a printed memo, although
this latter application is not recommended since electronic mail is so
much easier.@refill
@TeX{} is a general purpose typesetting program. Texinfo provides a
file called @file{texinfo.tex} that contains information (definitions or
@dfn{macros}) that @TeX{} uses when it typesets a Texinfo file.
(@file{texinfo.tex} tells @TeX{} how to convert the Texinfo @@-commands
to @TeX{} commands, which @TeX{} can then process to create the typeset
document.) @file{texinfo.tex} contains the specifications for printing
a document.@refill
Most often, documents are printed on 8.5 inch by 11 inch
pages (216@dmn{mm} by 280@dmn{mm}; this is the default size), but you
can also print for 7 inch by 9.25 inch pages (178@dmn{mm} by
235@dmn{mm}; the @code{@@smallbook} size) or on European A4 size paper
(@code{@@afourpaper}). (@xref{smallbook, , Printing ``Small'' Books}.
Also, see @ref{A4 Paper, ,Printing on A4 Paper}.)@refill
By changing the parameters in @file{texinfo.tex}, you can change the
size of the printed document. In addition, you can change the style in
which the printed document is formatted; for example, you can change the
sizes and fonts used, the amount of indentation for each paragraph, the
degree to which words are hyphenated, and the like. By changing the
specifications, you can make a book look dignified, old and serious, or
light-hearted, young and cheery.@refill
@TeX{} is freely distributable. It is written in a dialect of Pascal
called WEB and can be compiled either in Pascal or (by using a
conversion program that comes with the @TeX{} distribution) in C.
(@xref{TeX Mode, ,@TeX{} Mode, emacs, The GNU Emacs Manual}, for information
about @TeX{}.)@refill
@TeX{} is very powerful and has a great many features. Because a
Texinfo file must be able to present information both on a
character-only terminal in Info form and in a typeset book, the
formatting commands that Texinfo supports are necessarily
limited.@refill
@xref{Obtaining TeX, , How to Obtain @TeX{}}.
@node Formatting Commands, Conventions, Printed Books, Overview
@comment node-name, next, previous, up
@section @@-commands
@cindex @@-commands
@cindex Formatting commands
In a Texinfo file, the commands that tell @TeX{} how to typeset the
printed manual and tell @code{makeinfo} and
@code{texinfo-format-buffer} how to create an Info file are preceded
by @samp{@@}; they are called @dfn{@@-commands}. For example,
@code{@@node} is the command to indicate a node and @code{@@chapter}
is the command to indicate the start of a chapter.@refill
@quotation
@strong{Please note:} All the @@-commands, with the exception of the
@code{@@TeX@{@}} command, must be written entirely in lower
case.@refill
@end quotation
The Texinfo @@-commands are a strictly limited set of constructs. The
strict limits make it possible for Texinfo files to be understood both
by @TeX{} and by the code that converts them into Info files. You can
display Info files on any terminal that displays alphabetic and
numeric characters. Similarly, you can print the output generated by
@TeX{} on a wide variety of printers.@refill
Depending on what they do or what arguments@footnote{The word
@dfn{argument} comes from the way it is used in mathematics and does
not refer to a disputation between two people; it refers to the
information presented to the command. According to the @cite{Oxford
English Dictionary}, the word derives from the Latin for @dfn{to make
clear, prove}; thus it came to mean `the evidence offered as proof',
which is to say, `the information offered', which led to its
mathematical meaning. In its other thread of derivation, the word
came to mean `to assert in a manner against which others may make
counter assertions', which led to the meaning of `argument' as a
disputation.} they take, you need to write @@-commands on lines of
their own or as part of sentences:@refill
@itemize @bullet
@item
Write a command such as @code{@@noindent} at the beginning of a line as
the only text on the line. (@code{@@noindent} prevents the beginning of
the next line from being indented as the beginning of a
paragraph.)@refill
@item
Write a command such as @code{@@chapter} at the beginning of a line
followed by the command's arguments, in this case the chapter title, on
the rest of the line. (@code{@@chapter} creates chapter titles.)@refill
@item
Write a command such as @code{@@dots@{@}} wherever you wish but usually
within a sentence. (@code{@@dots@{@}} creates dots @dots{})@refill
@item
Write a command such as @code{@@code@{@var{sample-code}@}} wherever you
wish (but usually within a sentence) with its argument,
@var{sample-code} in this example, between the braces. (@code{@@code}
marks text as being code.)@refill
@item
Write a command such as @code{@@example} at the beginning of a line of
its own; write the body-text on following lines; and write the matching
@code{@@end} command, @code{@@end example} in this case, at the
beginning of a line of its own after the body-text. (@code{@@example}
@dots{} @code{@@end example} indents and typesets body-text as an
example.)@refill
@end itemize
@noindent
@cindex Braces, when to use
As a general rule, a command requires braces if it mingles among other
text; but it does not need braces if it starts a line of its own. The
non-alphabetic commands, such as @code{@@:}, are exceptions to the rule;
they do not need braces.@refill
As you gain experience with Texinfo, you will rapidly learn how to
write the different commands: the different ways to write commands
make it easier to write and read Texinfo files than if all commands
followed exactly the same syntax. (For details about @@-command
syntax, see @ref{Command Syntax, , @@-Command Syntax}.)@refill
@node Conventions, Comments, Formatting Commands, Overview
@comment node-name, next, previous, up
@section General Syntactic Conventions
@cindex General syntactic conventions
@cindex Syntactic conventions
@cindex Conventions, syntactic
All @sc{ascii} printing characters except @samp{@@}, @samp{@{} and
@samp{@}} can appear in a Texinfo file and stand for themselves.
@samp{@@} is the escape character which introduces commands.
@samp{@{} and @samp{@}} should be used only to surround arguments to
certain commands. To put one of these special characters into the
document, put an @samp{@@} character in front of it, like this:
@samp{@@@@}, @samp{@@@{}, and @samp{@@@}}.@refill
@ifinfo
It is customary in @TeX{} to use doubled single-quote characters to
begin and end quotations: ` ` and ' ' (but without a space between the
two single-quote characters). This convention should be followed in
Texinfo files. @TeX{} converts doubled single-quote characters to
left- and right-hand doubled quotation marks and Info converts doubled
single-quote characters to @sc{ascii} double-quotes: ` ` and ' ' to " .@refill
@end ifinfo
@iftex
It is customary in @TeX{} to use doubled single-quote characters to
begin and end quotations: @w{@tt{ `` }} and @w{@tt{ '' }}. This
convention should be followed in Texinfo files. @TeX{} converts
doubled single-quote characters to left- and right-hand doubled
quotation marks, ``like this'', and Info converts doubled single-quote
characters to @sc{ascii} double-quotes: @w{@tt{ `` }} and
@w{@tt{ '' }} to @w{@tt{ " }}.@refill
@end iftex
Use three hyphens in a row, @samp{---}, for a dash---like this. In
@TeX{}, a single or even a double hyphen produces a printed dash that
is shorter than the usual typeset dash. Info reduces three hyphens to two for
display on the screen.@refill
To prevent a paragraph from being indented in the printed manual, put
the command @code{@@noindent} on a line by itself before the
paragraph.@refill
If you mark off a region of the Texinfo file with the @code{@@iftex}
and @w{@code{@@end iftex}} commands, that region will appear only in
the printed copy; in that region, you can use certain commands
borrowed from Plain@TeX{} that you cannot use in Info. Likewise, if
you mark off a region with the @code{@@ifinfo} and @code{@@end ifinfo}
commands, that region will appear only in the Info file; in that
region, you can use Info commands that you cannot use in @TeX{}.
(@xref{Conditionals}.)
@cindex Tabs; don't use!
@quotation
@strong{Caution:} Do not use tabs in a Texinfo file! @TeX{} uses
variable-width fonts, which means that it cannot predefine a tab to work
in all circumstances. Consequently, @TeX{} treats tabs like single
spaces, and that is not what they look like.@refill
@noindent
To avoid this problem, Texinfo mode causes GNU Emacs to insert multiple
spaces when you press the @key{TAB} key.@refill
@noindent
Also, you can run @code{untabify} in Emacs to convert tabs in a region
to multiple spaces.@refill
@end quotation
@node Comments, Minimum, Conventions, Overview
@comment node-name, next, previous, up
@section Comments
You can write comments in a Texinfo file that will not appear in
either the Info file or the printed manual by using the
@code{@@comment} command (which may be abbreviated to @code{@@c}).
Such comments are for the person who reads the Texinfo file. All the
text on a line that follows either @code{@@comment} or @code{@@c} is a
comment; the rest of the line does not appear in either the Info file
or the printed manual. (Often, you can write the @code{@@comment} or
@code{@@c} in the middle of a line, and only the text that follows after
the @code{@@comment} or @code{@@c} command does not appear; but some
commands, such as @code{@@settitle} and @code{@@setfilename}, work on a
whole line. You cannot use @code{@@comment} or @code{@@c} in a line
beginning with such a command.)@refill
@cindex Comments
@findex comment
@findex c @r{(comment)}
You can write long stretches of text that will not appear in either
the Info file or the printed manual by using the @code{@@ignore} and
@code{@@end ignore} commands. Write each of these commands on a line
of its own, starting each command at the beginning of the line. Text
between these two commands does not appear in the processed output.
You can use @code{@@ignore} and @code{@@end ignore} for writing
comments. Often, @code{@@ignore} and @code{@@end ignore} is used
to enclose a part of the copying permissions that applies to the
Texinfo source file of a document, but not to the Info or printed
version of the document.@refill
@cindex Ignored text
@cindex Unprocessed text
@findex ignore
@c !!! Perhaps include this comment about ignore and ifset:
@ignore
Text enclosed by @code{@@ignore} or by failing @code{@@ifset} or
@code{@@ifclear} conditions is ignored in the sense that it will not
contribute to the formatted output. However, TeX and makeinfo must
still parse the ignored text, in order to understand when to
@emph{stop} ignoring text from the source file; that means that you
will still get error messages if you have invalid Texinfo markup
within ignored text.
@end ignore
@node Minimum, Six Parts, Comments, Overview
@comment node-name, next, previous, up
@section What a Texinfo File Must Have
@cindex Minimal Texinfo file (requirements)
@cindex Must have in Texinfo file
@cindex Required in Texinfo file
@cindex Texinfo file minimum
By convention, the names of Texinfo files end with one of the
extensions @file{.texinfo}, @file{.texi}, or @file{.tex}. The longer
extension is preferred since it describes more clearly to a human
reader the nature of the file. The shorter extensions are for
operating systems that cannot handle long file names.@refill
In order to be made into a printed manual and an Info file, a
Texinfo file @strong{must} begin with lines like this:@refill
@example
@group
\input texinfo
@@setfilename @var{info-file-name}
@@settitle @var{name-of-manual}
@end group
@end example
@noindent
The contents of the file follow this beginning, and then you @strong{must} end
a Texinfo file with a line like this:@refill
@example
@@bye
@end example
@findex input @r{(@TeX{} command)}
@noindent
The @samp{\input texinfo} line tells @TeX{} to use the
@file{texinfo.tex} file, which tells @TeX{} how to translate the Texinfo
@@-commands into @TeX{} typesetting commands. (Note the use of the
backslash, @samp{\}; this is correct for @TeX{}.) The
@samp{@@setfilename} line provides a name for the Info file and the
@samp{@@settitle} line specifies a title for the page headers (or
footers) of the printed manual.@refill
The @code{@@bye} line at the end of the file on a line of its own tells
the formatters that the file is ended and to stop formatting.@refill
Usually, you will not use quite such a spare format, but will include
mode setting and start-of-header and end-of-header lines at the
beginning of a Texinfo file, like this:@refill
@example
@group
\input texinfo @@c -*-texinfo-*-
@@c %**start of header
@@setfilename @var{info-file-name}
@@settitle @var{name-of-manual}
@@c %**end of header
@end group
@end example
@noindent
In the first line, @samp{-*-texinfo-*-} causes Emacs to switch into
Texinfo mode when you edit the file.
The @code{@@c} lines which surround the @samp{@@setfilename} and
@samp{@@settitle} lines are optional, but you need them in order to
run @TeX{} or Info on just part of the file. (@xref{Start of Header},
for more information.)@refill
Furthermore, you will usually provide a Texinfo file with a title
page, indices, and the like. But the minimum, which can be useful
for short documents, is just the three lines at the beginning and the
one line at the end.@refill
@node Six Parts, Short Sample, Minimum, Overview
@comment node-name, next, previous, up
@section Six Parts of a Texinfo File
Generally, a Texinfo file contains more than the minimal
beginning and end---it usually contains six parts:@refill
@table @r
@item 1. Header
The @dfn{Header} names the file, tells @TeX{} which definitions' file to
use, and performs other ``housekeeping'' tasks.@refill
@item 2. Summary Description and Copyright
The @dfn{Summary Description and Copyright} segment describes the document
and contains the copyright notice and copying permissions for the Info
file. The segment must be enclosed between @code{@@ifinfo} and
@code{@@end ifinfo} commands so that the formatters place it only in the Info
file.@refill
@item 3. Title and Copyright
The @dfn{Title and Copyright} segment contains the title and copyright pages
and copying permissions for the printed manual. The segment must be
enclosed between @code{@@titlepage} and @code{@@end titlepage} commands.
The title and copyright page appear only in the printed @w{manual}.@refill
@item 4. `Top' Node and Master Menu
The @dfn{Master Menu} contains a complete menu of all the nodes in the whole
Info file. It appears only in the Info file, in the `Top' node.@refill
@item 5. Body
The @dfn{Body} of the document may be structured like a traditional book or
encyclopedia or it may be free form.@refill
@item 6. End
The @dfn{End} contains commands for printing indices and generating
the table of contents, and the @code{@@bye} command on a line of its
own.@refill
@end table
@node Short Sample, Acknowledgements, Six Parts, Overview
@comment node-name, next, previous, up
@section A Short Sample Texinfo File
@cindex Sample Texinfo file
Here is a complete but very short Texinfo file, in 6 parts. The first
three parts of the file, from @samp{\input texinfo} through to
@samp{@@end titlepage}, look more intimidating than they are. Most of
the material is standard boilerplate; when you write a manual, simply
insert the names for your own manual in this segment. (@xref{Beginning a
File}.)@refill
@noindent
In the following, the sample text is @emph{indented}; comments on it are
not. The complete file, without any comments, is shown in
@ref{Sample Texinfo File}.
@subheading Part 1: Header
@noindent
The header does not appear in either the Info file or the@*
printed output. It sets various parameters, including the@*
name of the Info file and the title used in the header.
@example
@group
\input texinfo @@c -*-texinfo-*-
@@c %**start of header
@@setfilename sample.info
@@settitle Sample Document
@@c %**end of header
@@setchapternewpage odd
@end group
@end example
@subheading Part 2: Summary Description and Copyright
@noindent
The summary description and copyright segment does not@*
appear in the printed document.
@example
@group
@@ifinfo
This is a short example of a complete Texinfo file.
Copyright @@copyright@{@} 1990 Free Software Foundation, Inc.
@@end ifinfo
@end group
@end example
@subheading Part 3: Titlepage and Copyright
@noindent
The titlepage segment does not appear in the Info file.
@example
@group
@@titlepage
@@sp 10
@@comment The title is printed in a large font.
@@center @@titlefont@{Sample Title@}
@end group
@group
@@c The following two commands start the copyright page.
@@page
@@vskip 0pt plus 1filll
Copyright @@copyright@{@} 1990 Free Software Foundation, Inc.
@@end titlepage
@end group
@end example
@subheading Part 4: `Top' Node and Master Menu
@noindent
The `Top' node contains the master menu for the Info file.@*
Since a printed manual uses a table of contents rather than@*
a menu, the master menu appears only in the Info file.
@example
@group
@@node Top, First Chapter, (dir), (dir)
@@comment node-name, next, previous, up
@end group
@end example
@example
@group
@@menu
* First Chapter:: The first chapter is the
only chapter in this sample.
* Concept Index:: This index has two entries.
@@end menu
@end group
@end example
@subheading Part 5: The Body of the Document
@noindent
The body segment contains all the text of the document, but not the
indices or table of contents. This example illustrates a node and a
chapter containing an enumerated list.@refill
@example
@group
@@node First Chapter, Concept Index, Top, Top
@@comment node-name, next, previous, up
@@chapter First Chapter
@@cindex Sample index entry
@end group
@group
This is the contents of the first chapter.
@@cindex Another sample index entry
@end group
@group
Here is a numbered list.
@@enumerate
@@item
This is the first item.
@@item
This is the second item.
@@end enumerate
@end group
@group
The @@code@{makeinfo@} and @@code@{texinfo-format-buffer@}
commands transform a Texinfo file such as this into
an Info file; and @@TeX@{@} typesets it for a printed
manual.
@end group
@end example
@subheading Part 6: The End of the Document
@noindent
The end segment contains commands both for generating an index in a node
and unnumbered chapter of its own and for generating the table of
contents; and it contains the @code{@@bye} command that marks the end of
the document.@refill
@example
@group
@@node Concept Index, , First Chapter, Top
@@comment node-name, next, previous, up
@@unnumbered Concept Index
@end group
@group
@@printindex cp
@@contents
@@bye
@end group
@end example
@subheading The Results
Here is what the contents of the first chapter of the sample look like:
@sp 1
@need 700
@quotation
This is the contents of the first chapter.
Here is a numbered list.
@enumerate
@item
This is the first item.
@item
This is the second item.
@end enumerate
The @code{makeinfo} and @code{texinfo-format-buffer}
commands transform a Texinfo file such as this into
an Info file; and @TeX{} typesets it for a printed
manual.
@end quotation
@node Acknowledgements, , Short Sample, Overview
@comment node-name, next, previous, up
@section Acknowledgements
Richard M.@: Stallman wrote Edition 1.0 of this manual.
@w{Robert J.@: Chassell} revised and extended it,
starting with Edition 1.1.
Our thanks go out to all who helped improve this work, particularly to
@w{Francois Pinard} and @w{David D.@: Zuhn}, who tirelessly recorded
and reported mistakes and obscurities; our special thanks go to
@w{Melissa Weisshaus} for her frequent and often tedious reviews of
nearly similar editions. Our mistakes are our own.
Please send suggestions and corrections to:
@example
@group
@r{Internet address:}
bug-texinfo@@prep.ai.mit.edu
@end group
@end example
@noindent
Please include the manual's edition number in your messages.
@node Texinfo Mode, Beginning a File, Overview, Top
@comment node-name, next, previous, up
@chapter Using Texinfo Mode
@cindex Texinfo mode
@cindex Mode, using Texinfo
@cindex GNU Emacs
@cindex Emacs
You may edit a Texinfo file with any text editor you choose. A Texinfo
file is no different from any other @sc{ascii} file. However, GNU Emacs
comes with a special mode, called Texinfo
mode, that provides Emacs commands and tools to help ease your work.@refill
This chapter describes features of GNU Emacs' Texinfo mode but not any
features of the Texinfo formatting language. If you are reading this
manual straight through from the beginning, you may want to skim through
this chapter briefly and come back to it after reading succeeding
chapters which describe the Texinfo formatting language in
detail.@refill
@menu
* Texinfo Mode Overview:: How Texinfo mode can help you.
* Emacs Editing:: Texinfo mode adds to GNU Emacs' general
purpose editing features.
* Inserting:: How to insert frequently used @@-commands.
* Showing the Structure:: How to show the structure of a file.
* Updating Nodes and Menus:: How to update or create new nodes and menus.
* Info Formatting:: How to format for Info.
* Printing:: How to format and print part or all of a file.
* Texinfo Mode Summary:: Summary of all the Texinfo mode commands.
@end menu
@node Texinfo Mode Overview, Emacs Editing, Texinfo Mode, Texinfo Mode
@ifinfo
@heading Texinfo Mode Overview
@end ifinfo
Texinfo mode provides special features for working with Texinfo
files:@refill
@itemize @bullet
@item
Insert frequently used @@-commands. @refill
@item
Automatically create @code{@@node} lines.
@item
Show the structure of a Texinfo source file.@refill
@item
Automatically create or update the `Next',@*
`Previous', and `Up' pointers of a node.
@item
Automatically create or update menus.@refill
@item
Automatically create a master menu.@refill
@item
Format a part or all of a file for Info.@refill
@item
Typeset and print part or all of a file.@refill
@end itemize
Perhaps the two most helpful features are those for inserting frequently
used @@-commands and for creating node pointers and menus.@refill
@node Emacs Editing, Inserting, Texinfo Mode Overview, Texinfo Mode
@section The Usual GNU Emacs Editing Commands
In most cases, the usual Text mode commands work the same in Texinfo
mode as they do in Text mode. Texinfo mode adds new editing commands
and tools to GNU Emacs' general purpose editing features. The major
difference concerns filling. In Texinfo mode, the paragraph
separation variable and syntax table are redefined so that Texinfo
commands that should be on lines of their own are not inadvertently
included in paragraphs. Thus, the @kbd{M-q} (@code{fill-paragraph})
command will refill a paragraph but not mix an indexing command on a
line adjacent to it into the paragraph.@refill
In addition, Texinfo mode sets the @code{page-delimiter} variable to
the value of @code{texinfo-chapter-level-regexp}; by default, this is
a regular expression matching the commands for chapters and their
equivalents, such as appendices. With this value for the page
delimiter, you can jump from chapter title to chapter title with the
@kbd{C-x ]} (@code{forward-page}) and @kbd{C-x [}
(@code{backward-page}) commands and narrow to a chapter with the
@kbd{C-x p} (@code{narrow-to-page}) command. (@xref{Pages, , ,emacs,
The GNU Emacs Manual}, for details about the page commands.)@refill
You may name a Texinfo file however you wish, but the convention is to
end a Texinfo file name with one of the three extensions
@file{.texinfo}, @file{.texi}, or @file{.tex}. A longer extension is
preferred, since it is explicit, but a shorter extension may be
necessary for operating systems that limit the length of file names.
GNU Emacs automatically enters Texinfo mode when you visit a file with
a @file{.texinfo} or @file{.texi}
extension. Also, Emacs switches to Texinfo mode
when you visit a
file that has @samp{-*-texinfo-*-} in its first line. If ever you are
in another mode and wish to switch to Texinfo mode, type @code{M-x
texinfo-mode}.@refill
Like all other Emacs features, you can customize or enhance Texinfo
mode as you wish. In particular, the keybindings are very easy to
change. The keybindings described here are the default or standard
ones.@refill
@node Inserting, Showing the Structure, Emacs Editing, Texinfo Mode
@comment node-name, next, previous, up
@section Inserting Frequently Used Commands
@cindex Inserting frequently used commands
@cindex Frequently used commands, inserting
@cindex Commands, inserting them
Texinfo mode provides commands to insert various frequently used
@@-commands into the buffer. You can use these commands to save
keystrokes.@refill
The insert commands are invoked by typing @kbd{C-c} twice and then the
first letter of the @@-command:@refill
@table @kbd
@item C-c C-c c
@itemx M-x texinfo-insert-@@code
@findex texinfo-insert-@@code
Insert @code{@@code@{@}} and put the
cursor between the braces.@refill
@item C-c C-c d
@itemx M-x texinfo-insert-@@dfn
@findex texinfo-insert-@@dfn
Insert @code{@@dfn@{@}} and put the
cursor between the braces.@refill
@item C-c C-c e
@itemx M-x texinfo-insert-@@end
@findex texinfo-insert-@@end
Insert @code{@@end} and attempt to insert the correct following word,
such as @samp{example} or @samp{table}. (This command does not handle
nested lists correctly, but inserts the word appropriate to the
immediately preceding list.)@refill
@item C-c C-c i
@itemx M-x texinfo-insert-@@item
@findex texinfo-insert-@@item
Insert @code{@@item} and put the
cursor at the beginning of the next line.@refill
@item C-c C-c k
@itemx M-x texinfo-insert-@@kbd
@findex texinfo-insert-@@kbd
Insert @code{@@kbd@{@}} and put the
cursor between the braces.@refill
@item C-c C-c n
@itemx M-x texinfo-insert-@@node
@findex texinfo-insert-@@node
Insert @code{@@node} and a comment line
listing the sequence for the `Next',
`Previous', and `Up' nodes.
Leave point after the @code{@@node}.@refill
@item C-c C-c o
@itemx M-x texinfo-insert-@@noindent
@findex texinfo-insert-@@noindent
Insert @code{@@noindent} and put the
cursor at the beginning of the next line.@refill
@item C-c C-c s
@itemx M-x texinfo-insert-@@samp
@findex texinfo-insert-@@samp
Insert @code{@@samp@{@}} and put the
cursor between the braces.@refill
@item C-c C-c t
@itemx M-x texinfo-insert-@@table
@findex texinfo-insert-@@table
Insert @code{@@table} followed by a @key{SPC}
and leave the cursor after the @key{SPC}.@refill
@item C-c C-c v
@itemx M-x texinfo-insert-@@var
@findex texinfo-insert-@@var
Insert @code{@@var@{@}} and put the
cursor between the braces.@refill
@item C-c C-c x
@itemx M-x texinfo-insert-@@example
@findex texinfo-insert-@@example
Insert @code{@@example} and put the
cursor at the beginning of the next line.@refill
@c M-@{ was the binding for texinfo-insert-braces;
@c in Emacs 19, backward-paragraph will take this binding.
@item C-c C-c @{
@itemx M-x texinfo-insert-braces
@findex texinfo-insert-braces
Insert @code{@{@}} and put the cursor between the braces.@refill
@item C-c C-c @}
@itemx C-c C-c ]
@itemx M-x up-list
@findex up-list
Move from between a pair of braces forward past the closing brace.
Typing @kbd{C-c C-c ]} is easier than typing @kbd{C-c C-c @}}, which
is, however, more mnemonic; hence the two keybindings. (Also, you can
move out from between braces by typing @kbd{C-f}.)@refill
@end table
To put a command such as @w{@code{@@code@{@dots{}@}}} around an
@emph{existing} word, position the cursor in front of the word and type
@kbd{C-u 1 C-c C-c c}. This makes it easy to edit existing plain text.
The value of the prefix argument tells Emacs how many words following
point to include between braces---1 for one word, 2 for two words, and
so on. Use a negative argument to enclose the previous word or words.
If you do not specify a prefix argument, Emacs inserts the @@-command
string and positions the cursor between the braces. This feature works
only for those @@-commands that operate on a word or words within one
line, such as @code{@@kbd} and @code{@@var}.@refill
This set of insert commands was created after analyzing the frequency
with which different @@-commands are used in the @cite{GNU Emacs
Manual} and the @cite{GDB Manual}. If you wish to add your own insert
commands, you can bind a keyboard macro to a key, use abbreviations,
or extend the code in @file{texinfo.el}.@refill
@findex texinfo-start-menu-description
@cindex Menu description, start
@cindex Description for menu, start
@kbd{C-c C-c C-d} (@code{texinfo-start-menu-description}) is an insert
command that works differently from the other insert commands. It
inserts a node's section or chapter title in the space for the
description in a menu entry line. (A menu entry has three parts, the
entry name, the node name, and the description. Only the node name is
required, but a description helps explain what the node is about.
@xref{Menu Parts, , The Parts of a Menu}.)@refill
To use @code{texinfo-start-menu-description}, position point in a menu
entry line and type @kbd{C-c C-c C-d}. The command looks for and copies
the title that goes with the node name, and inserts the title as a
description; it positions point at beginning of the inserted text so you
can edit it. The function does not insert the title if the menu entry
line already contains a description.@refill
This command is only an aid to writing descriptions; it does not do the
whole job. You must edit the inserted text since a title tends to use
the same words as a node name but a useful description uses different
words.@refill
@node Showing the Structure, Updating Nodes and Menus, Inserting, Texinfo Mode
@comment node-name, next, previous, up
@section Showing the Section Structure of a File
@cindex Showing the section structure of a file
@cindex Section structure of a file, showing it
@cindex Structure of a file, showing it
@cindex Outline of file structure, showing it
@cindex Contents-like outline of file structure
@cindex File section structure, showing it
@cindex Texinfo file section structure, showing it
You can show the section structure of a Texinfo file by using the
@kbd{C-c C-s} command (@code{texinfo-show-structure}). This command
shows the section structure of a Texinfo file by listing the lines
that begin with the @@-commands for @code{@@chapter},
@code{@@section}, and the like. It constructs what amounts
to a table of contents. These lines are displayed in another buffer
called the @samp{*Occur*} buffer. In that buffer, you can position
the cursor over one of the lines and use the @kbd{C-c C-c} command
(@code{occur-mode-goto-occurrence}), to jump to the corresponding spot
in the Texinfo file.@refill
@table @kbd
@item C-c C-s
@itemx M-x texinfo-show-structure
@findex texinfo-show-structure
Show the @code{@@chapter}, @code{@@section}, and such lines of a
Texinfo file.@refill
@item C-c C-c
@itemx M-x occur-mode-goto-occurrence
@findex occur-mode-goto-occurrence
Go to the line in the Texinfo file corresponding to the line under the
cursor in the @file{*Occur*} buffer.@refill
@end table
If you call @code{texinfo-show-structure} with a prefix argument by
typing @w{@kbd{C-u C-c C-s}}, it will list not only those lines with the
@@-commands for @code{@@chapter}, @code{@@section}, and the like,
but also the @code{@@node} lines. (This is how the
@code{texinfo-show-structure} command worked without an argument in
the first version of Texinfo. It was changed because @code{@@node}
lines clutter up the @samp{*Occur*} buffer and are usually not
needed.) You can use @code{texinfo-show-structure} with a prefix
argument to check whether the `Next', `Previous', and `Up' pointers of
an @code{@@node} line are correct.@refill
Often, when you are working on a manual, you will be interested only
in the structure of the current chapter. In this case, you can mark
off the region of the buffer that you are interested in by using the
@kbd{C-x n n} (@code{narrow-to-region}) command and
@code{texinfo-show-structure} will work on only that region. To see
the whole buffer again, use @w{@kbd{C-x n w}} (@code{widen}).
(@xref{Narrowing, , , emacs, The GNU Emacs Manual}, for more
information about the narrowing commands.)@refill
@vindex page-delimiter
@cindex Page delimiter in Texinfo mode
In addition to providing the @code{texinfo-show-structure} command,
Texinfo mode sets the value of the page delimiter variable to match
the chapter-level @@-commands. This enables you to use the @kbd{C-x
]} (@code{forward-page}) and @kbd{C-x [} (@code{backward-page})
commands to move forward and backward by chapter, and to use the
@kbd{C-x p} (@code{narrow-to-page}) command to narrow to a chapter.
@xref{Pages, , , emacs, The GNU Emacs Manual}, for more information
about the page commands.@refill
@node Updating Nodes and Menus, Info Formatting, Showing the Structure, Texinfo Mode
@comment node-name, next, previous, up
@section Updating Nodes and Menus
@cindex Updating nodes and menus
@cindex Create nodes, menus automatically
@cindex Insert nodes, menus automatically
@cindex Automatically insert nodes, menus
Texinfo mode provides commands for automatically creating or updating
menus and node pointers. The commands are called ``update'' commands
because their most frequent use is for updating a Texinfo file after
you have worked on it; but you can use them to insert the `Next',
`Previous', and `Up' pointers into an @code{@@node} line that has none and to
create menus in a file that has none.@refill
If you do not use the updating commands, you need to write menus and
node pointers by hand, which is a tedious task.@refill
@menu
* Updating Commands:: Five major updating commands.
* Updating Requirements:: How to structure a Texinfo file for
using the updating command.
* Other Updating Commands:: How to indent descriptions, insert
missing nodes lines, and update
nodes in sequence.
@end menu
@node Updating Commands, Updating Requirements, Updating Nodes and Menus, Updating Nodes and Menus
@ifinfo
@subheading The Updating Commands
@end ifinfo
You can use the updating commands@refill
@itemize @bullet
@item
to insert or update the `Next', `Previous', and `Up' pointers of a
node,@refill
@item
to insert or update the menu for a section, and@refill
@item
to create a master menu for a Texinfo source file.@refill
@end itemize
You can also use the commands to update all the nodes and menus in a
region or in a whole Texinfo file.@refill
The updating commands work only with conventional Texinfo files, which
are structured hierarchically like books. In such files, a structuring
command line must follow closely after each @code{@@node} line, except
for the `Top' @code{@@node} line. (A @dfn{structuring command line} is
a line beginning with @code{@@chapter}, @code{@@section}, or other
similar command.)
You can write the structuring command line on the line that follows
immediately after an @code{@@node} line or else on the line that
follows after a single @code{@@comment} line or a single
@code{@@ifinfo} line. You cannot interpose more than one line between
the @code{@@node} line and the structuring command line; and you may
interpose only an @code{@@comment} line or an @code{@@ifinfo} line.
Commands which work on a whole buffer require that the `Top' node be
followed by a node with an @code{@@chapter} or equivalent-level command.
Note that the menu updating commands will not create a main or master
menu for a Texinfo file that has only @code{@@chapter}-level nodes! The
menu updating commands only create menus @emph{within} nodes for lower level
nodes. To create a menu of chapters, you must provide a `Top'
node.@refill
The menu updating commands remove menu entries that refer to other Info
files since they do not refer to nodes within the current buffer. This
is a deficiency. Rather than use menu entries, you can use cross
references to refer to other Info files. None of the updating commands
affect cross references.@refill
Texinfo mode has five updating commands that are used most often: two
are for updating the node pointers or menu of a single node (or a
region); two are for updating every node pointer and menu in a file;
and one, the @code{texinfo-master-menu} command, is for creating a
master menu for a complete file, and optionally, for updating every
node and menu in the whole Texinfo file.@refill
The @code{texinfo-master-menu} command is the primary command:@refill
@table @kbd
@item C-c C-u m
@itemx M-x texinfo-master-menu
@findex texinfo-master-menu
Create or update a master menu that includes all the other menus
(incorporating the descriptions from pre-existing menus, if
any).@refill
With an argument (prefix argument, @kbd{C-u,} if interactive), first create or
update all the nodes and all the regular menus in the buffer before
constructing the master menu. (@xref{The Top Node, , The Top Node and
Master Menu}, for more about a master menu.)@refill
For @code{texinfo-master-menu} to work, the Texinfo file must have a
`Top' node and at least one subsequent node.@refill
After extensively editing a Texinfo file, you can type the following:
@example
C-u M-x texinfo-master-menu
@exdent or
C-u C-c C-u m
@end example
@noindent
This updates all the nodes and menus completely and all at once.@refill
@end table
The other major updating commands do smaller jobs and are designed for
the person who updates nodes and menus as he or she writes a Texinfo
file.@refill
@need 1000
The commands are:@refill
@table @kbd
@item C-c C-u C-n
@itemx M-x texinfo-update-node
@findex texinfo-update-node
Insert the `Next', `Previous', and `Up' pointers for the node that point is
within (i.e., for the @code{@@node} line preceding point). If the
@code{@@node} line has pre-existing `Next', `Previous', or `Up'
pointers in it, the old pointers are removed and new ones inserted.
With an argument (prefix argument, @kbd{C-u}, if interactive), this command
updates all @code{@@node} lines in the region (which is the text
between point and mark).@refill
@item C-c C-u C-m
@itemx M-x texinfo-make-menu
@findex texinfo-make-menu
Create or update the menu in the node that point is within.
With an argument (@kbd{C-u} as prefix argument, if
interactive), the command makes or updates menus for the
nodes which are either within or a part of the
region.@refill
Whenever @code{texinfo-make-menu} updates an existing menu, the
descriptions from that menu are incorporated into the new menu. This
is done by copying descriptions from the existing menu to the entries
in the new menu that have the same node names. If the node names are
different, the descriptions are not copied to the new menu.@refill
@item C-c C-u C-e
@itemx M-x texinfo-every-node-update
@findex texinfo-every-node-update
Insert or update the `Next', `Previous', and `Up' pointers for every
node in the buffer.@refill
@item C-c C-u C-a
@itemx M-x texinfo-all-menus-update
@findex texinfo-all-menus-update
Create or update all the menus in the buffer. With an argument
(@kbd{C-u} as prefix argument, if interactive), first insert
or update all the node
pointers before working on the menus.@refill
If a master menu exists, the @code{texinfo-all-menus-update} command
updates it; but the command does not create a new master menu if none
already exists. (Use the @code{texinfo-master-menu} command for
that.)@refill
When working on a document that does not merit a master menu, you can
type the following:
@example
C-u C-c C-u C-a
@exdent or
C-u M-x texinfo-all-menus-update
@end example
@noindent
This updates all the nodes and menus.@refill
@end table
The @code{texinfo-column-for-description} variable specifies the
column to which menu descriptions are indented. By default, the value
is 32 although it is often useful to reduce it to as low as 24. You
can set the variable with the @kbd{M-x edit-options} command
(@pxref{Edit Options, , Editing Variable Values, emacs, The GNU Emacs
Manual}) or with the @kbd{M-x set-variable} command (@pxref{Examining,
, Examining and Setting Variables, emacs, The GNU Emacs
Manual}).@refill
Also, the @code{texinfo-indent-menu-description} command may be used to
indent existing menu descriptions to a specified column. Finally, if
you wish, you can use the @code{texinfo-insert-node-lines} command to
insert missing @code{@@node} lines into a file. (@xref{Other Updating
Commands}, for more information.)@refill
@node Updating Requirements, Other Updating Commands, Updating Commands, Updating Nodes and Menus
@comment node-name, next, previous, up
@subsection Updating Requirements
@cindex Updating requirements
@cindex Requirements for updating commands
To use the updating commands, you must organize the Texinfo file
hierarchically with chapters, sections, subsections, and the like.
When you construct the hierarchy of the manual, do not `jump down'
more than one level at a time: you can follow the `Top' node with a
chapter, but not with a section; you can follow a chapter with a
section, but not with a subsection. However, you may `jump up' any
number of levels at one time---for example, from a subsection to a
chapter.@refill
Each @code{@@node} line, with the exception of the line for the `Top'
node, must be followed by a line with a structuring command such as
@code{@@chapter}, @code{@@section}, or
@code{@@unnumberedsubsec}.@refill
Each @code{@@node} line/structuring-command line combination
must look either like this:@refill
@example
@group
@@node Comments, Minimum, Conventions, Overview
@@comment node-name, next, previous, up
@@section Comments
@end group
@end example
or like this (without the @code{@@comment} line):
@example
@group
@@node Comments, Minimum, Conventions, Overview
@@section Comments
@end group
@end example
@noindent
In this example, `Comments' is the name of both the node and the
section. The next node is called `Minimum' and the previous node is
called `Conventions'. The `Comments' section is within the `Overview'
node, which is specified by the `Up' pointer. (Instead of an
@code{@@comment} line, you can write an @code{@@ifinfo} line.)@refill
If a file has a `Top' node, it must be called @samp{top} or @samp{Top}
and be the first node in the file.@refill
The menu updating commands create a menu of sections within a chapter,
a menu of subsections within a section, and so on. This means that
you must have a `Top' node if you want a menu of chapters.@refill
Incidentally, the @code{makeinfo} command will create an Info file for
a hierarchically organized Texinfo file that lacks `Next', `Previous'
and `Up' pointers. Thus, if you can be sure that your Texinfo file
will be formatted with @code{makeinfo}, you have no need for the
`update node' commands. (@xref{Create an Info File, , Creating an
Info File}, for more information about @code{makeinfo}.) However,
both @code{makeinfo} and the @code{texinfo-format-@dots{}} commands
require that you insert menus in the file.@refill
@node Other Updating Commands, , Updating Requirements, Updating Nodes and Menus
@comment node-name, next, previous, up
@subsection Other Updating Commands
In addition to the five major updating commands, Texinfo mode
possesses several less frequently used updating commands:@refill
@table @kbd
@item M-x texinfo-insert-node-lines
@findex texinfo-insert-node-lines
Insert @code{@@node} lines before the @code{@@chapter},
@code{@@section}, and other sectioning commands wherever they are
missing throughout a region in a Texinfo file.@refill
With an argument (@kbd{C-u} as prefix argument, if interactive), the
@code{texinfo-insert-node-lines} command not only inserts
@code{@@node} lines but also inserts the chapter or section titles as
the names of the corresponding nodes. In addition, it inserts the
titles as node names in pre-existing @code{@@node} lines that lack
names. Since node names should be more concise than section or
chapter titles, you must manually edit node names so inserted.@refill
For example, the following marks a whole buffer as a region and inserts
@code{@@node} lines and titles throughout:@refill
@example
C-x h C-u M-x texinfo-insert-node-lines
@end example
(Note that this command inserts titles as node names in @code{@@node}
lines; the @code{texinfo-start-menu-description} command
(@pxref{Inserting, Inserting Frequently Used Commands}) inserts titles
as descriptions in menu entries, a different action. However, in both
cases, you need to edit the inserted text.)@refill
@item M-x texinfo-multiple-files-update
@findex texinfo-multiple-files-update @r{(in brief)}
Update nodes and menus in a document built from several separate files.
With @kbd{C-u} as a prefix argument, create and insert a master menu in
the outer file. With a numeric prefix argument, such as @kbd{C-u 2}, first
update all the menus and all the `Next', `Previous', and `Up' pointers
of all the included files before creating and inserting a master menu in
the outer file. The @code{texinfo-multiple-files-update} command is
described in the appendix on @code{@@include} files.
@ifinfo
@xref{texinfo-multiple-files-update}.@refill
@end ifinfo
@iftex
@xref{texinfo-multiple-files-update, ,
@code{texinfo-multiple-files-update}}.@refill
@end iftex
@item M-x texinfo-indent-menu-description
@findex texinfo-indent-menu-description
Indent every description in the menu following point to the specified
column. You can use this command to give yourself more space for
descriptions. With an argument (@kbd{C-u} as prefix argument, if
interactive), the @code{texinfo-indent-menu-description} command indents
every description in every menu in the region. However, this command
does not indent the second and subsequent lines of a multi-line
description.@refill
@item M-x texinfo-sequential-node-update
@findex texinfo-sequential-node-update
Insert the names of the nodes immediately following and preceding the
current node as the `Next' or `Previous' pointers regardless of those
nodes' hierarchical level. This means that the `Next' node of a
subsection may well be the next chapter. Sequentially ordered nodes are
useful for novels and other documents that you read through
sequentially. (However, in Info, the @code{g* @key{RET}} command lets
you look through the file sequentially, so sequentially ordered nodes
are not strictly necessary.) With an argument (prefix argument, if
interactive), the @code{texinfo-sequential-node-update} command
sequentially updates all the nodes in the region.@refill
@end table
@node Info Formatting, Printing, Updating Nodes and Menus, Texinfo Mode
@comment node-name, next, previous, up
@section Formatting for Info
@cindex Formatting for Info
@cindex Running an Info formatter
@cindex Info formatting
Texinfo mode provides several commands for formatting part or all of a
Texinfo file for Info. Often, when you are writing a document, you
want to format only part of a file---that is, a region.@refill
You can use either the @code{texinfo-format-region} or the
@code{makeinfo-region} command to format a region:@refill
@table @kbd
@findex texinfo-format-region
@item C-c C-e C-r
@itemx M-x texinfo-format-region
@itemx C-c C-m C-r
@itemx M-x makeinfo-region
Format the current region for Info.@refill
@end table
You can use either the @code{texinfo-format-buffer} or the
@code{makeinfo-buffer} command to format a whole buffer:@refill
@table @kbd
@findex texinfo-format-buffer
@item C-c C-e C-b
@itemx M-x texinfo-format-buffer
@itemx C-c C-m C-b
@itemx M-x makeinfo-buffer
Format the current buffer for Info.@refill
@end table
@need 1000
For example, after writing a Texinfo file, you can type the following:
@example
C-u C-c C-u m
@exdent or
C-u M-x texinfo-master-menu
@end example
@noindent
This updates all the nodes and menus. Then type the following to create
an Info file:
@example
C-c C-m C-b
@exdent or
M-x makeinfo-buffer
@end example
For the Info formatting commands to work, the file @emph{must} include
a line that has @code{@@setfilename} in its header.@refill
Not all systems support the @code{makeinfo}-based formatting commands.@refill
@xref{Create an Info File}, for details about Info formatting.@refill
@node Printing, Texinfo Mode Summary, Info Formatting, Texinfo Mode
@comment node-name, next, previous, up
@section Formatting and Printing
@cindex Formatting for printing
@cindex Printing a region or buffer
@cindex Region formatting and printing
@cindex Buffer formatting and printing
@cindex Part of file formatting and printing
Typesetting and printing a Texinfo file is a multi-step process in which
you first create a file for printing (called a @sc{dvi} file), and then
print the file. Optionally, you may also create indices. To do this,
you must run the @code{texindex} command after first running the
@code{tex} typesetting command; and then you must run the @code{tex}
command again. Or else run the @code{texi2dvi} command which
automatically creates indices as needed.@refill
Often, when you are writing a document, you want to typeset and print
only part of a file to see what it will look like. You can use the
@code{texinfo-tex-region} and related commands for this purpose. Use
the @code{texinfo-tex-buffer} command to format all of a
buffer.@refill
@table @kbd
@item C-c C-t C-b
@itemx M-x texinfo-tex-buffer
@findex texinfo-tex-buffer
Run @code{texi2dvi} on the buffer. In addition to running @TeX{} on the
buffer, this command automatically creates or updates indices as
needed.@refill
@item C-c C-t C-r
@itemx M-x texinfo-tex-region
@findex texinfo-tex-region
Run @TeX{} on the region.@refill
@item C-c C-t C-i
@itemx M-x texinfo-texindex
Run @code{texindex} to sort the indices of a Texinfo file formatted with
@code{texinfo-tex-region}. The @code{texinfo-tex-region} command does
not run @code{texindex} automatically; it only runs the @code{tex}
typesetting command. You must run the @code{texinfo-tex-region} command
a second time after sorting the raw index files with the @code{texindex}
command. (Usually, you do not format an index when you format a region,
only when you format a buffer. Now that the @code{texi2dvi} command
exists, there is no little need for this command.)@refill
@item C-c C-t C-p
@itemx M-x texinfo-tex-print
@findex texinfo-tex-print
Print the file (or the part of the file) previously formatted with
@code{texinfo-tex-buffer} or @code{texinfo-tex-region}.@refill
@end table
For @code{texinfo-tex-region} or @code{texinfo-tex-buffer} to work, the
file @emph{must} start with a @samp{\input texinfo} line and must
include an @code{@@settitle} line. The file must end with @code{@@bye}
on a line by itself. (When you use @code{texinfo-tex-region}, you must
surround the @code{@@settitle} line with start-of-header and
end-of-header lines.)@refill
@xref{Format/Print Hardcopy}, for a description of the other @TeX{} related
commands, such as @code{tex-show-print-queue}.@refill
@node Texinfo Mode Summary, , Printing, Texinfo Mode
@comment node-name, next, previous, up
@section Texinfo Mode Summary
In Texinfo mode, each set of commands has default keybindings that
begin with the same keys. All the commands that are custom-created
for Texinfo mode begin with @kbd{C-c}. The keys are somewhat
mnemonic.@refill
@subheading Insert Commands
The insert commands are invoked by typing @kbd{C-c} twice and then the
first letter of the @@-command to be inserted. (It might make more
sense mnemonically to use @kbd{C-c C-i}, for `custom insert', but
@kbd{C-c C-c} is quick to type.)@refill
@example
C-c C-c c @r{Insert} @samp{@@code}.
C-c C-c d @r{Insert} @samp{@@dfn}.
C-c C-c e @r{Insert} @samp{@@end}.
C-c C-c i @r{Insert} @samp{@@item}.
C-c C-c n @r{Insert} @samp{@@node}.
C-c C-c s @r{Insert} @samp{@@samp}.
C-c C-c v @r{Insert} @samp{@@var}.
C-c C-c @{ @r{Insert braces.}
C-c C-c ]
C-c C-c @} @r{Move out of enclosing braces.}
@group
C-c C-c C-d @r{Insert a node's section title}
@r{in the space for the description}
@r{in a menu entry line.}
@end group
@end example
@subheading Show Structure
The @code{texinfo-show-structure} command is often used within a
narrowed region.@refill
@example
C-c C-s @r{List all the headings.}
@end example
@subheading The Master Update Command
The @code{texinfo-master-menu} command creates a master menu; and can
be used to update every node and menu in a file as well.@refill
@example
@group
C-c C-u m
M-x texinfo-master-menu
@r{Create or update a master menu.}
@end group
@group
C-u C-c C-u m @r{With @kbd{C-u} as a prefix argument, first}
@r{create or update all nodes and regular}
@r{menus, and then create a master menu.}
@end group
@end example
@subheading Update Pointers
The update pointer commands are invoked by typing @kbd{C-c C-u} and
then either @kbd{C-n} for @code{texinfo-update-node} or @kbd{C-e} for
@code{texinfo-every-node-update}.@refill
@example
C-c C-u C-n @r{Update a node.}
C-c C-u C-e @r{Update every node in the buffer.}
@end example
@subheading Update Menus
Invoke the update menu commands by typing @kbd{C-c C-u}
and then either @kbd{C-m} for @code{texinfo-make-menu} or
@kbd{C-a} for @code{texinfo-all-menus-update}. To update
both nodes and menus at the same time, precede @kbd{C-c C-u
C-a} with @kbd{C-u}.@refill
@example
C-c C-u C-m @r{Make or update a menu.}
@group
C-c C-u C-a @r{Make or update all}
@r{menus in a buffer.}
@end group
@group
C-u C-c C-u C-a @r{With @kbd{C-u} as a prefix argument,}
@r{first create or update all nodes and}
@r{then create or update all menus.}
@end group
@end example
@subheading Format for Info
The Info formatting commands that are written in Emacs Lisp are
invoked by typing @kbd{C-c C-e} and then either @kbd{C-r} for a region
or @kbd{C-b} for the whole buffer.@refill
The Info formatting commands that are written in C and based on the
@code{makeinfo} program are invoked by typing @kbd{C-c C-m} and then
either @kbd{C-r} for a region or @kbd{C-b} for the whole buffer.@refill
@need 800
@noindent
Use the @code{texinfo-format@dots{}} commands:
@example
@group
C-c C-e C-r @r{Format the region.}
C-c C-e C-b @r{Format the buffer.}
@end group
@end example
@need 750
@noindent
Use @code{makeinfo}:
@example
C-c C-m C-r @r{Format the region.}
C-c C-m C-b @r{Format the buffer.}
C-c C-m C-l @r{Recenter the @code{makeinfo} output buffer.}
C-c C-m C-k @r{Kill the @code{makeinfo} formatting job.}
@end example
@subheading Typeset and Print
The @TeX{} typesetting and printing commands are invoked by typing
@kbd{C-c C-t} and then another control command: @kbd{C-r} for
@code{texinfo-tex-region}, @kbd{C-b} for @code{texinfo-tex-buffer},
and so on.@refill
@example
C-c C-t C-r @r{Run @TeX{} on the region.}
C-c C-t C-b @r{Run} @code{texi2dvi} @r{on the buffer.}
C-c C-t C-i @r{Run} @code{texindex}.
C-c C-t C-p @r{Print the @sc{dvi} file.}
C-c C-t C-q @r{Show the print queue.}
C-c C-t C-d @r{Delete a job from the print queue.}
C-c C-t C-k @r{Kill the current @TeX{} formatting job.}
C-c C-t C-x @r{Quit a currently stopped @TeX{} formatting job.}
C-c C-t C-l @r{Recenter the output buffer.}
@end example
@subheading Other Updating Commands
The `other updating commands' do not have standard keybindings because
they are rarely used.
@example
@group
M-x texinfo-insert-node-lines
@r{Insert missing @code{@@node} lines in region.}
@r{With @kbd{C-u} as a prefix argument,}
@r{use section titles as node names.}
@end group
@group
M-x texinfo-multiple-files-update
@r{Update a multi-file document.}
@r{With @kbd{C-u 2} as a prefix argument,}
@r{create or update all nodes and menus}
@r{in all included files first.}
@end group
@group
M-x texinfo-indent-menu-description
@r{Indent descriptions.}
@end group
@group
M-x texinfo-sequential-node-update
@r{Insert node pointers in strict sequence.}
@end group
@end example
@node Beginning a File, Ending a File, Texinfo Mode, Top
@comment node-name, next, previous, up
@chapter Beginning a Texinfo File
@cindex Beginning a Texinfo file
@cindex Texinfo file beginning
@cindex File beginning
Certain pieces of information must be provided at the beginning of a
Texinfo file, such as the name of the file and the title of the
document.@refill
@menu
* Four Parts:: Four parts begin a Texinfo file.
* Sample Beginning:: Here is a sample beginning for a Texinfo file.
* Header:: The very beginning of a Texinfo file.
* Info Summary and Permissions:: Summary and copying permissions for Info.
* Titlepage & Copyright Page:: Creating the title and copyright pages.
* The Top Node:: Creating the `Top' node and master menu.
* Software Copying Permissions:: Ensure that you and others continue to
have the right to use and share software.
@end menu
@node Four Parts, Sample Beginning, Beginning a File, Beginning a File
@ifinfo
@heading Four Parts Begin a File
@end ifinfo
Generally, the beginning of a Texinfo file has four parts:@refill
@enumerate
@item
The header, delimited by special comment lines, that includes the
commands for naming the Texinfo file and telling @TeX{} what
definitions' file to use when processing the Texinfo file.@refill
@item
A short statement of what the file is about, with a copyright notice
and copying permissions. This is enclosed in @code{@@ifinfo} and
@code{@@end ifinfo} commands so that the formatters place it only
in the Info file.@refill
@item
A title page and copyright page, with a copyright notice and copying
permissions. This is enclosed between @code{@@titlepage} and
@code{@@end titlepage} commands. The title and copyright page appear
only in the printed @w{manual}.@refill
@item
The `Top' node that contains a menu for the whole Info file. The
contents of this node appear only in the Info file.@refill
@end enumerate
Also, optionally, you may include the copying conditions for a program
and a warranty disclaimer. The copying section will be followed by an
introduction or else by the first chapter of the manual.@refill
Since the copyright notice and copying permissions for the Texinfo
document (in contrast to the copying permissions for a program) are in
parts that appear only in the Info file or only in the printed manual,
this information must be given twice.@refill
@node Sample Beginning, Header, Four Parts, Beginning a File
@comment node-name, next, previous, up
@section Sample Texinfo File Beginning
The following sample shows what is needed.@refill
@example
\input texinfo @@c -*-texinfo-*-
@@c %**start of header
@@setfilename @var{name-of-info-file}
@@settitle @var{name-of-manual}
@@setchapternewpage odd
@@c %**end of header
@@ifinfo
This file documents @dots{}
Copyright @var{year} @var{copyright-owner}
@group
Permission is granted to @dots{}
@@end ifinfo
@end group
@group
@@c This title page illustrates only one of the
@@c two methods of forming a title page.
@end group
@group
@@titlepage
@@title @var{name-of-manual-when-printed}
@@subtitle @var{subtitle-if-any}
@@subtitle @var{second-subtitle}
@@author @var{author}
@end group
@group
@@c The following two commands
@@c start the copyright page.
@@page
@@vskip 0pt plus 1filll
Copyright @@copyright@{@} @var{year} @var{copyright-owner}
@end group
Published by @dots{}
Permission is granted to @dots{}
@@end titlepage
@@node Top, Overview, (dir), (dir)
@@ifinfo
This document describes @dots{}
This document applies to version @dots{}
of the program named @dots{}
@@end ifinfo
@group
@@menu
* Copying:: Your rights and freedoms.
* First Chapter:: Getting started @dots{}
* Second Chapter:: @dots{}
@dots{}
@dots{}
@@end menu
@end group
@group
@@node First Chapter, Second Chapter, top, top
@@comment node-name, next, previous, up
@@chapter First Chapter
@@cindex Index entry for First Chapter
@end group
@end example
@node Header, Info Summary and Permissions, Sample Beginning, Beginning a File
@comment node-name, next, previous, up
@section The Texinfo File Header
@cindex Header for Texinfo files
@cindex Texinfo file header
Texinfo files start with at least three lines that provide Info and
@TeX{} with necessary information. These are the @code{\input
texinfo} line, the @code{@@settitle} line, and the
@code{@@setfilename} line. If you want to run @TeX{} on just a part
of the Texinfo File, you must write the @code{@@settitle}
and @code{@@setfilename} lines between start-of-header and end-of-header
lines.@refill
Thus, the beginning of a Texinfo file looks like this:
@example
@group
\input texinfo @@c -*-texinfo-*-
@@setfilename sample.info
@@settitle Sample Document
@end group
@end example
@noindent
or else like this:
@example
@group
\input texinfo @@c -*-texinfo-*-
@@c %**start of header
@@setfilename sample.info
@@settitle Sample Document
@@c %**end of header
@end group
@end example
@menu
* First Line:: The first line of a Texinfo file.
* Start of Header:: Formatting a region requires this.
* setfilename:: Tell Info the name of the Info file.
* settitle:: Create a title for the printed work.
* setchapternewpage:: Start chapters on right-hand pages.
* paragraphindent:: An option to specify paragraph indentation.
* End of Header:: Formatting a region requires this.
@end menu
@node First Line, Start of Header, Header, Header
@comment node-name, next, previous, up
@subsection The First Line of a Texinfo File
@cindex First line of a Texinfo file
@cindex Beginning line of a Texinfo file
@cindex Header of a Texinfo file
Every Texinfo file that is to be the top-level input to @TeX{} must begin
with a line that looks like this:@refill
@example
\input texinfo @@c -*-texinfo-*-
@end example
@noindent
This line serves two functions:
@enumerate
@item
When the file is processed by @TeX{}, the @code{\input texinfo} command
tells @TeX{} to load the macros needed for processing a Texinfo file.
These are in a file called @file{texinfo.tex}, which is usually located
in the @file{/usr/lib/tex/macros} directory. @TeX{} uses the backslash,
@samp{\}, to mark the beginning of a command, just as Texinfo uses
@code{@@}. The @file{texinfo.tex} file causes the switch from @samp{\}
to @samp{@@}; before the switch occurs, @TeX{} requires @samp{\}, which
is why it appears at the beginning of the file.@refill
@item
When the file is edited in GNU Emacs, the @samp{-*-texinfo-*-} mode
specification tells Emacs to use Texinfo mode.@refill
@end enumerate
@node Start of Header, setfilename, First Line, Header
@comment node-name, next, previous, up
@subsection Start of Header
@cindex Start of header line
Write a start-of-header line on the second line of a Texinfo file.
Follow the start-of-header line with @code{@@setfilename} and
@code{@@settitle} lines and, optionally, with other command lines, such
as @code{@@smallbook} or @code{@@footnotestyle}; and then by an
end-of-header line (@pxref{End of Header}).@refill
With these lines, you can format part of a Texinfo file for Info or
typeset part for printing.@refill
A start-of-header line looks like this:@refill
@example
@@c %**start of header
@end example
The odd string of characters, @samp{%**}, is to ensure that no other
comment is accidentally taken for a start-of-header line.@refill
@node setfilename, settitle, Start of Header, Header
@comment node-name, next, previous, up
@subsection @code{@@setfilename}
@cindex Info file requires @code{@@setfilename}
@findex setfilename
In order to be made into an Info file, a Texinfo file must contain a line
that looks like this:@refill
@example
@@setfilename @var{info-file-name}
@end example
Write the @code{@@setfilename} command at the beginning of a line and
follow it on the same line by the Info file name. Do not write
anything else on the line; anything on the line after the command is
considered part of the file name, including a comment.@refill
The @code{@@setfilename} line specifies the name of the Info file to be
generated. This name should be different from the name of the Texinfo
file. The convention is to write a name with a @samp{.info} extension,
to produce an Info file name such as @file{texinfo.info}.@refill
Some operating systems cannot handle long file names. You can run into
a problem even when the file name you specify is itself short enough.
This occurs because the Info formatters split a long Info file into
short indirect subfiles, and name them by appending `-1', `-2', @dots{},
`-10', `-11', and so on, to the original file name. (@xref{Tag and
Split Files, , Tag Files and Split Files}.) The subfile name
@file{texinfo.info-10}, for example, is too long for some systems; so
the Info file name for this document is actually @file{texinfo} rather than
@file{texinfo.info}.@refill
The Info formatting commands ignore everything written before the
@code{@@setfilename} line, which is why the very first line of
the file (the @code{\input} line) does not need to be commented out.
The @code{@@setfilename} line is ignored when you typeset a printed
manual.@refill
@node settitle, setchapternewpage, setfilename, Header
@comment node-name, next, previous, up
@subsection @code{@@settitle}
@findex settitle
In order to be made into a printed manual, a Texinfo file must contain
a line that looks like this:@refill
@example
@@settitle @var{title}
@end example
Write the @code{@@settitle} command at the beginning of a line and
follow it on the same line by the title. This tells @TeX{} the title
to use in a header or footer. Do not write anything else on the line;
anything on the line after the command is considered part of the
title, including a comment.@refill
Conventionally, when @TeX{} formats a Texinfo file for double-sided
output, the title is printed in the left-hand (even-numbered) page
headings and the current chapter title is printed in the right-hand
(odd-numbered) page headings. (@TeX{} learns the title of each chapter
from each @code{@@chapter} command.) Page footers are not
printed.@refill
Even if you are printing in a single-sided style, @TeX{} looks for an
@code{@@settitle} command line, in case you include the manual title
in the heading. @refill
The @code{@@settitle} command should precede everything that generates
actual output in @TeX{}.@refill
Although the title in the @code{@@settitle} command is usually the
same as the title on the title page, it does not affect the title as
it appears on the title page. Thus, the two do not need not match
exactly; and the title in the @code{@@settitle} command can be a
shortened or expanded version of the title as it appears on the title
page. (@xref{titlepage, , @code{@@titlepage}}.)@refill
@TeX{} prints page headings only for that text that comes after the
@code{@@end titlepage} command in the Texinfo file, or that comes
after an @code{@@headings} command that turns on headings.
(@xref{headings on off, , The @code{@@headings} Command}, for more
information.)@refill
You may, if you wish, create your own, customized headings and
footings. @xref{Headings, , Page Headings}, for a detailed discussion
of this process.@refill
@node setchapternewpage, paragraphindent, settitle, Header
@comment node-name, next, previous, up
@subsection @code{@@setchapternewpage}
@cindex Starting chapters
@cindex Pages, starting odd
@findex setchapternewpage
In a book or a manual, text is usually printed on both sides of the
paper, chapters start on right-hand pages, and right-hand pages have
odd numbers. But in short reports, text often is printed only on one
side of the paper. Also in short reports, chapters sometimes do not
start on new pages, but are printed on the same page as the end of the
preceding chapter, after a small amount of vertical whitespace.@refill
You can use the @code{@@setchapternewpage} command with various
arguments to specify how @TeX{} should start chapters and whether it
should typeset pages for printing on one or both sides of the paper
(single-sided or double-sided printing).@refill
Write the @code{@@setchapternewpage} command at the beginning of a
line followed by its argument.@refill
For example, you would write the following to cause each chapter to
start on a fresh odd-numbered page:@refill
@example
@@setchapternewpage odd
@end example
You can specify one of three alternatives with the
@code{@@setchapternewpage} command:@refill
@table @asis
@ignore
@item No @code{@@setchapternewpage} command
If the Texinfo file does not contain an @code{@@setchapternewpage}
command before the @code{@@titlepage} command, @TeX{} automatically
begins chapters on new pages and prints headings in the standard
format for single-sided printing. This is the conventional format for
single-sided printing.@refill
The result is exactly the same as when you write
@code{@@setchapternewpage on}.@refill
@end ignore
@item @code{@@setchapternewpage off}
Cause @TeX{} to typeset a new chapter on the same page as the last
chapter, after skipping some vertical whitespace. Also, cause @TeX{} to
format page headers for single-sided printing. (You can override the
headers format with the @code{@@headings double} command; see
@ref{headings on off, , The @code{@@headings} Command}.)@refill
@item @code{@@setchapternewpage on}
Cause @TeX{} to start new chapters on new pages and to typeset page
headers for single-sided printing. This is the form most often
used for short reports.@refill
This alternative is the default.@refill
@item @code{@@setchapternewpage odd}
Cause @TeX{} to start new chapters on new, odd-numbered pages
(right-handed pages) and to typeset for double-sided printing. This is
the form most often used for books and manuals.@refill
@end table
@noindent
Texinfo does not have an @code{@@setchapternewpage even} command.@refill
@noindent
(You can countermand or modify an @code{@@setchapternewpage} command
with an @code{@@headings} command. @xref{headings on off, , The
@code{@@headings} Command}.)@refill
At the beginning of a manual or book, pages are not numbered---for
example, the title and copyright pages of a book are not numbered.
By convention, table of contents pages are numbered with roman
numerals and not in sequence with the rest of the document.@refill
Since an Info file does not have pages, the @code{@@setchapternewpage}
command has no effect on it.@refill
Usually, you do not write an @code{@@setchapternewpage} command for
single-sided printing, but accept the default which is to typeset for
single-sided printing and to start new chapters on new pages. Usually,
you write an @code{@@setchapternewpage odd} command for double-sided
printing.@refill
@node paragraphindent, End of Header, setchapternewpage, Header
@comment node-name, next, previous, up
@subsection Paragraph Indenting
@cindex Indenting paragraphs
@cindex Paragraph indentation
@findex paragraphindent
The Info formatting commands may insert spaces at the beginning of the
first line of each paragraph, thereby indenting that paragraph. You
can use the @code{@@paragraphindent} command to specify the
indentation. Write an @code{@@paragraphindent} command at the
beginning of a line followed by either @samp{asis} or a number. The
template is:@refill
@example
@@paragraphindent @var{indent}
@end example
The Info formatting commands indent according to the value of
@var{indent}:@refill
@itemize @bullet
@item
If the value of @var{indent} is @samp{asis}, the Info formatting
commands do not change the existing indentation.@refill
@item
If the value of @var{indent} is 0, the Info formatting commands delete
existing indentation.@refill
@item
If the value of @var{indent} is greater than 0, the Info formatting
commands indent the paragraph by that number of spaces.@refill
@end itemize
The default value of @var{indent} is @samp{asis}.@refill
Write the @code{@@paragraphindent} command before or shortly after the
end-of-header line at the beginning of a Texinfo file. (If you write
the command between the start-of-header and end-of-header lines, the
region formatting commands indent paragraphs as specified.)@refill
A peculiarity of the @code{texinfo-format-buffer} and
@code{texinfo-format-region} commands is that they do not indent (nor
fill) paragraphs that contain @code{@@w} or @code{@@*} commands.
@xref{Refilling Paragraphs}, for a detailed description of what goes
on.@refill
@node End of Header, , paragraphindent, Header
@comment node-name, next, previous, up
@subsection End of Header
@cindex End of header line
Follow the header lines with an @w{end-of-header} line.
An end-of-header line looks like this:@refill
@example
@@c %**end of header
@end example
If you include the @code{@@setchapternewpage} command between the
start-of-header and end-of-header lines, @TeX{} will typeset a region as
that command specifies. Similarly, if you include an @code{@@smallbook}
command between the start-of-header and end-of-header lines, @TeX{} will
typeset a region in the ``small'' book format.@refill
@ifinfo
The reason for the odd string of characters (@samp{%**}) is so that the
@code{texinfo-tex-region} command does not accidentally find
something that it should not when it is looking for the header.@refill
The start-of-header line and the end-of-header line are Texinfo mode
variables that you can change.@refill
@end ifinfo
@iftex
@xref{Start of Header}.
@end iftex
@node Info Summary and Permissions, Titlepage & Copyright Page, Header, Beginning a File
@comment node-name, next, previous, up
@section Summary and Copying Permissions for Info
The title page and the copyright page appear only in the printed copy of
the manual; therefore, the same information must be inserted in a
section that appears only in the Info file. This section usually
contains a brief description of the contents of the Info file, a
copyright notice, and copying permissions.@refill
The copyright notice should read:@refill
@example
Copyright @var{year} @var{copyright-owner}
@end example
@noindent
and be put on a line by itself.@refill
Standard text for the copyright permissions is contained in an appendix
to this manual; see @ref{ifinfo Permissions, , @samp{ifinfo} Copying
Permissions}, for the complete text.@refill
The permissions text appears in an Info file @emph{before} the first
node. This mean that a reader does @emph{not} see this text when
reading the file using Info, except when using the advanced Info command
@kbd{g *}.
@node Titlepage & Copyright Page, The Top Node, Info Summary and Permissions, Beginning a File
@comment node-name, next, previous, up
@section The Title and Copyright Pages
A manual's name and author are usually printed on a title page.
Sometimes copyright information is printed on the title page as well;
more often, copyright information is printed on the back of the title
page.
The title and copyright pages appear in the printed manual, but not in the
Info file. Because of this, it is possible to use several slightly
obscure @TeX{} typesetting commands that cannot be used in an Info file.
In addition, this part of the beginning of a Texinfo file contains the text
of the copying permissions that will appear in the printed manual.@refill
@xref{Titlepage Permissions, , Titlepage Copying Permissions}, for the
standard text for the copyright permissions.@refill
@menu
* titlepage:: Create a title for the printed document.
* titlefont center sp:: The @code{@@titlefont}, @code{@@center},
and @code{@@sp} commands.
* title subtitle author:: The @code{@@title}, @code{@@subtitle},
and @code{@@author} commands.
* Copyright & Permissions:: How to write the copyright notice and
include copying permissions.
* end titlepage:: Turn on page headings after the title and
copyright pages.
* headings on off:: An option for turning headings on and off
and double or single sided printing.
@end menu
@node titlepage, titlefont center sp, Titlepage & Copyright Page, Titlepage & Copyright Page
@comment node-name, next, previous, up
@subsection @code{@@titlepage}
@cindex Title page
@findex titlepage
Start the material for the title page and following copyright page
with @code{@@titlepage} on a line by itself and end it with
@code{@@end titlepage} on a line by itself.@refill
The @code{@@end titlepage} command starts a new page and turns on page
numbering. (@xref{Headings, , Page Headings}, for details about how to
generate of page headings.) All the material that you want to
appear on unnumbered pages should be put between the
@code{@@titlepage} and @code{@@end titlepage} commands. By using the
@code{@@page} command you can force a page break within the region
delineated by the @code{@@titlepage} and @code{@@end titlepage}
commands and thereby create more than one unnumbered page. This is
how the copyright page is produced. (The @code{@@titlepage} command
might perhaps have been better named the
@code{@@titleandadditionalpages} command, but that would have been
rather long!)@refill
@c !!! append refill to footnote when makeinfo can handle it.
When you write a manual about a computer program, you should write the
version of the program to which the manual applies on the title
page. If the manual changes more frequently than the program or is
independent of it, you should also include an edition
number@footnote{We have found that it is helpful to refer to versions
of manuals as `editions' and versions of programs as `versions';
otherwise, we find we are liable to confuse each other in conversation
by referring to both the documentation and the software with the same
words.} for the manual. This helps readers keep track of which manual
is for which version of the program. (The `Top' node
should also contain this information; see @ref{makeinfo top, ,
@code{@@top}}.)@refill
Texinfo provides two methods for creating a title page. One method
uses the @code{@@titlefont}, @code{@@sp}, and @code{@@center} commands
to generate a title page in which the words on the page are
centered.@refill
The second method uses the @code{@@title}, @code{@@subtitle}, and
@code{@@author} commands to create a title page with black rules under
the title and author lines and the subtitle text set flush to the
right hand side of the page. With this method, you do not specify any
of the actual formatting of the title page. You specify the text
you want, and Texinfo does the formatting. You may use either
method.@refill
@node titlefont center sp, title subtitle author, titlepage, Titlepage & Copyright Page
@comment node-name, next, previous, up
@subsection @code{@@titlefont}, @code{@@center}, and @code{@@sp}
@findex titlefont
@findex center
@findex sp @r{(titlepage line spacing)}
You can use the @code{@@titlefont}, @code{@@sp}, and @code{@@center}
commands to create a title page for a printed document. (This is the
first of the two methods for creating a title page in Texinfo.)@refill
Use the @code{@@titlefont} command to select a large font suitable for
the title itself.@refill
@need 700
For example:
@example
@@titlefont@{Texinfo@}
@end example
Use the @code{@@center} command at the beginning of a line to center
the remaining text on that line. Thus,@refill
@example
@@center @@titlefont@{Texinfo@}
@end example
@noindent
centers the title, which in this example is ``Texinfo'' printed
in the title font.@refill
Use the @code{@@sp} command to insert vertical space. For example:@refill
@example
@@sp 2
@end example
@noindent
This inserts two blank lines on the printed page. (@xref{sp, ,
@code{@@sp}}, for more information about the @code{@@sp}
command.)@refill
A template for this method looks like this:@refill
@example
@group
@@titlepage
@@sp 10
@@center @@titlefont@{@var{name-of-manual-when-printed}@}
@@sp 2
@@center @var{subtitle-if-any}
@@sp 2
@@center @var{author}
@dots{}
@@end titlepage
@end group
@end example
The spacing of the example fits an 8 1/2 by 11 inch manual.@refill
@node title subtitle author, Copyright & Permissions, titlefont center sp, Titlepage & Copyright Page
@comment node-name, next, previous, up
@subsection @code{@@title}, @code{@@subtitle}, and @code{@@author}
@findex title
@findex subtitle
@findex author
You can use the @code{@@title}, @code{@@subtitle}, and @code{@@author}
commands to create a title page in which the vertical and horizontal
spacing is done for you automatically. This contrasts with the method
described in
the previous section, in which the @code{@@sp} command is needed to
adjust vertical spacing.@refill
Write the @code{@@title}, @code{@@subtitle}, or @code{@@author}
commands at the beginning of a line followed by the title, subtitle,
or author.@refill
The @code{@@title} command produces a line in which the title is set
flush to the left-hand side of the page in a larger than normal font.
The title is underlined with a black rule.@refill
The @code{@@subtitle} command sets subtitles in a normal-sized font
flush to the right-hand side of the page.@refill
The @code{@@author} command sets the names of the author or authors in
a middle-sized font flush to the left-hand side of the page on a line
near the bottom of the title page. The names are underlined with a
black rule that is thinner than the rule that underlines the title.
(The black rule only occurs if the @code{@@author} command line is
followed by an @code{@@page} command line.)@refill
There are two ways to use the @code{@@author} command: you can write
the name or names on the remaining part of the line that starts with
an @code{@@author} command:@refill
@example
@@author by Jane Smith and John Doe
@end example
@noindent
or you can write the names one above each other by using two (or more)
@code{@@author} commands:@refill
@example
@group
@@author Jane Smith
@@author John Doe
@end group
@end example
@noindent
(Only the bottom name is underlined with a black rule.)@refill
@need 950
A template for this method looks like this:@refill
@example
@group
@@titlepage
@@title @var{name-of-manual-when-printed}
@@subtitle @var{subtitle-if-any}
@@subtitle @var{second-subtitle}
@@author @var{author}
@@page
@dots{}
@@end titlepage
@end group
@end example
@ifinfo
@noindent
Contrast this form with the form of a title page written using the
@code{@@sp}, @code{@@center}, and @code{@@titlefont} commands:@refill
@example
@@titlepage
@@sp 10
@@center @@titlefont@{Name of Manual When Printed@}
@@sp 2
@@center Subtitle, If Any
@@sp 1
@@center Second subtitle
@@sp 2
@@center Author
@@page
@dots{}
@@end titlepage
@end example
@end ifinfo
@node Copyright & Permissions, end titlepage, title subtitle author, Titlepage & Copyright Page
@comment node-name, next, previous, up
@subsection Copyright Page and Permissions
@cindex Copyright page
@cindex Printed permissions
@cindex Permissions, printed
By international treaty, the copyright notice for a book should be
either on the title page or on the back of the title page. The
copyright notice should include the year followed by the name of the
organization or person who owns the copyright.@refill
When the copyright notice is on the back of the title page, that page
is customarily not numbered. Therefore, in Texinfo, the information
on the copyright page should be within @code{@@titlepage} and
@code{@@end titlepage} commands.@refill
@findex vskip
@findex filll
@cindex Vertical whitespace (@samp{vskip})
Use the @code{@@page} command to cause a page break. To push the
copyright notice and the other text on the copyright page towards the
bottom of the page, you can write a somewhat mysterious line after the
@code{@@page} command that reads like this:@refill
@example
@@vskip 0pt plus 1filll
@end example
@noindent
This is a @TeX{} command that is not supported by the Info formatting
commands. The @code{@@vskip} command inserts whitespace. The
@samp{0pt plus 1filll} means to put in zero points of mandatory whitespace,
and as much optional whitespace as needed to push the
following text to the bottom of the page. Note the use of three
@samp{l}s in the word @samp{filll}; this is the correct usage in
@TeX{}.@refill
@findex copyright
In a printed manual, the @code{@@copyright@{@}} command generates a
@samp{c} inside a circle. (In Info, it generates @samp{(C)}.) The
copyright notice itself has the following legally defined sequence:@refill
@example
Copyright @copyright{} @var{year} @var{copyright-owner}
@end example
It is customary to put information on how to get a manual after the
copyright notice, followed by the copying permissions for the
manual.@refill
Note that permissions must be given here as well as in the summary
segment within @code{@@ifinfo} and @code{@@end ifinfo} that
immediately follows the header since this text appears only in the
printed manual and the @samp{ifinfo} text appears only in the Info
file.@refill
@xref{Sample Permissions}, for the standard text.@refill
@node end titlepage, headings on off, Copyright & Permissions, Titlepage & Copyright Page
@comment node-name, next, previous, up
@subsection Heading Generation
@findex end titlepage
@cindex Headings, page, begin to appear
@cindex Titlepage end starts headings
@cindex End titlepage starts headings
An @code{@@end titlepage} command on a line by itself not only marks
the end of the title and copyright pages, but also causes @TeX{} to start
generating page headings and page numbers.
To repeat what is said elsewhere, Texinfo has two standard page heading
formats, one for documents which are printed on one side of each sheet of paper
(single-sided printing), and the other for documents which are printed on both
sides of each sheet (double-sided printing).
(@xref{setchapternewpage, ,@code{@@setchapternewpage}}.)
You can specify these formats in different ways:@refill
@itemize @bullet
@item
The conventional way is to write an @code{@@setchapternewpage} command
before the title page commands, and then have the @code{@@end
titlepage} command start generating page headings in the manner desired.
(@xref{setchapternewpage, , @code{@@setchapternewpage}}.)@refill
@item
Alternatively, you can use the @code{@@headings} command to prevent page
headings from being generated or to start them for either single or
double-sided printing. (Write an @code{@@headings} command immediately
after the @code{@@end titlepage} command. @xref{headings on off, , The
@code{@@headings} Command}, for more information.)@refill
@item
Or, you may specify your own page heading and footing format.
@xref{Headings, , Page Headings}, for detailed
information about page headings and footings.@refill
@end itemize
Most documents are formatted with the standard single-sided or
double-sided format, using @code{@@setchapternewpage odd} for
double-sided printing and no @code{@@setchapternewpage} command for
single-sided printing.@refill
@node headings on off, , end titlepage, Titlepage & Copyright Page
@comment node-name, next, previous, up
@subsection The @code{@@headings} Command
@findex headings
The @code{@@headings} command is rarely used. It specifies what kind of
page headings and footings to print on each page. Usually, this is
controlled by the @code{@@setchapternewpage} command. You need the
@code{@@headings} command only if the @code{@@setchapternewpage} command
does not do what you want, or if you want to turn off pre-defined page
headings prior to defining your own. Write an @code{@@headings} command
immediately after the @code{@@end titlepage} command.@refill
There are four ways to use the @code{@@headings} command:@refill
@table @code
@item @@headings off
Turn off printing of page headings.@refill
@item @@headings single
Turn on page headings appropriate for single-sided printing.
@refill
@item @@headings double
@itemx @@headings on
Turn on page headings appropriate for double-sided printing. The two
commands, @code{@@headings on} and @code{@@headings double}, are
synonymous.@refill
@end table
For example, suppose you write @code{@@setchapternewpage off} before the
@code{@@titlepage} command to tell @TeX{} to start a new chapter on the
same page as the end of the last chapter. This command also causes
@TeX{} to typeset page headers for single-sided printing. To cause
@TeX{} to typeset for double sided printing, write @code{@@headings
double} after the @code{@@end titlepage} command.
You can stop @TeX{} from generating any page headings at all by
writing @code{@@headings off} on a line of its own immediately after the
line containing the @code{@@end titlepage} command, like this:@refill
@example
@@end titlepage
@@headings off
@end example
@noindent
The @code{@@headings off} command overrides the @code{@@end titlepage}
command, which would otherwise cause @TeX{} to print page
headings.@refill
You can also specify your own style of page heading and footing.
@xref{Headings, , Page Headings}, for more information.@refill
@node The Top Node, Software Copying Permissions, Titlepage & Copyright Page, Beginning a File
@comment node-name, next, previous, up
@section The `Top' Node and Master Menu
@cindex @samp{@r{Top}} node
@cindex Master menu
@cindex Node, `Top'
The `Top' node is the node from which you enter an Info file.@refill
A `Top' node should contain a brief description of the Info file and an
extensive, master menu for the whole Info file.
This helps the reader understand what the Info file is
about. Also, you should write the version number of the program to
which the Info file applies; or, at least, the edition number.@refill
The contents of the `Top' node should appear only in the Info file; none
of it should appear in printed output, so enclose it between
@code{@@ifinfo} and @code{@@end ifinfo} commands. (@TeX{} does not
print either an @code{@@node} line or a menu; they appear only in Info;
strictly speaking, you are not required to enclose these parts between
@code{@@ifinfo} and @code{@@end ifinfo}, but it is simplest to do so.
@xref{Conditionals, , Conditionally Visible Text}.)@refill
@menu
* Title of Top Node:: Sketch what the file is about.
* Master Menu Parts:: A master menu has three or more parts.
@end menu
@node Title of Top Node, Master Menu Parts, The Top Node, The Top Node
@ifinfo
@subheading `Top' Node Title
@end ifinfo
Sometimes, you will want to place an @code{@@top} sectioning command
line containing the title of the document immediately after the
@code{@@node Top} line (@pxref{makeinfo top command, , The @code{@@top}
Sectioning Command}, for more information).@refill
For example, the beginning of the Top node of this manual contains an
@code{@@top} sectioning command, a short description, and edition and
version information. It looks like this:@refill
@example
@group
@dots{}
@@end titlepage
@@ifinfo
@@node Top, Copying, (dir), (dir)
@@top Texinfo
Texinfo is a documentation system@dots{}
@end group
@group
This is edition@dots{}
@dots{}
@@end ifinfo
@end group
@group
@@menu
* Copying:: Texinfo is freely
redistributable.
* Overview:: What is Texinfo?
@dots{}
@end group
@@end menu
@end example
In a `Top' node, the `Previous', and `Up' nodes usually refer to the top
level directory of the whole Info system, which is called @samp{(dir)}.
The `Next' node refers to the first node that follows the main or master
menu, which is usually the copying permissions, introduction, or first
chapter.@refill
@node Master Menu Parts, , Title of Top Node, The Top Node
@subsection Parts of a Master Menu
@cindex Master menu parts
@cindex Parts of a master menu
A @dfn{master menu} is a detailed main menu listing all the nodes in a
file.
A master menu is enclosed in @code{@@menu} and @code{@@end menu}
commands and does not appear in the printed document.@refill
Generally, a master menu is divided into parts.@refill
@itemize @bullet
@item
The first part contains the major nodes in the Texinfo file: the nodes
for the chapters, chapter-like sections, and the appendices.@refill
@item
The second part contains nodes for the indices.@refill
@item
The third and subsequent parts contain a listing of the other, lower
level nodes, often ordered by chapter. This way, rather than go
through an intermediary menu, an inquirer can go directly to a
particular node when searching for specific information. These menu
items are not required; add them if you think they are a
convenience.@refill
@end itemize
Each section in the menu can be introduced by a descriptive line. So
long as the line does not begin with an asterisk, it will not be
treated as a menu entry. (@xref{Writing a Menu}, for more
information.)@refill
For example, the master menu for this manual looks like the following
(but has many more entries):@refill
@example
@group
@@menu
* Copying:: Texinfo is freely
redistributable.
* Overview:: What is Texinfo?
* Texinfo Mode:: Special features in GNU Emacs.
@dots{}
@dots{}
@end group
@group
* Command and Variable Index::
An entry for each @@-command.
* Concept Index:: An entry for each concept.
@end group
@group
--- The Detailed Node Listing ---
Overview of Texinfo
* Info Files:: What is an Info file?
* Printed Manuals:: Characteristics of
a printed manual.
@dots{}
@dots{}
@end group
@group
Using Texinfo Mode
* Info on a Region:: Formatting part of a file
for Info.
@dots{}
@dots{}
@@end menu
@end group
@end example
@node Software Copying Permissions, , The Top Node, Beginning a File
@comment node-name, next, previous, up
@section Software Copying Permissions
@cindex Software copying permissions
@cindex Copying software
@cindex Distribution
@cindex License agreement
If the Texinfo file has a section containing the ``General Public
License'' and the distribution information and a warranty disclaimer
for the software that is documented, this section usually follows the
`Top' node. The General Public License is very important to Project
GNU software. It ensures that you and others will continue to have a
right to use and share the software.@refill
The copying and distribution information and the disclaimer are
followed by an introduction or else by the first chapter of the
manual.@refill
@cindex Introduction, as part of file
Although an introduction is not a required part of a Texinfo file, it
is very helpful. Ideally, it should state clearly and concisely what
the file is about and who would be interested in reading it. In
general, an introduction would follow the licensing and distribution
information, although sometimes people put it earlier in the document.
Usually, an introduction is put in an @code{@@unnumbered} section.
(@xref{unnumbered & appendix, , The @code{@@unnumbered} and
@code{@@appendix} Commands}.)@refill
@node Ending a File, Structuring, Beginning a File, Top
@comment node-name, next, previous, up
@chapter Ending a Texinfo File
@cindex Ending a Texinfo file
@cindex Texinfo file ending
@cindex File ending
@findex bye
The end of a Texinfo file should include the commands that create
indices and generate detailed and summary tables of contents.
And it must include the @code{@@bye} command that marks the last line
processed by @TeX{}.@refill
@need 700
For example:
@example
@@node Concept Index, , Variables Index, Top
@@c node-name, next, previous, up
@@unnumbered Concept Index
@@printindex cp
@@contents
@@bye
@end example
@menu
* Printing Indices & Menus:: How to print an index in hardcopy and
generate index menus in Info.
* Contents:: How to create a table of contents.
* File End:: How to mark the end of a file.
@end menu
@node Printing Indices & Menus, Contents, Ending a File, Ending a File
@comment node-name, next, previous, up
@section Index Menus and Printing an Index
@findex printindex
@cindex Printing an index
@cindex Indices, printing and menus
@cindex Generating menus with indices
@cindex Menus generated with indices
To print an index means to include it as part of a manual or Info
file. This does not happen automatically just because you use
@code{@@cindex} or other index-entry generating commands in the
Texinfo file; those just cause the raw data for the index to be
accumulated. To generate an index, you must include the
@code{@@printindex} command at the place in the document where you
want the index to appear. Also, as part of the process of creating a
printed manual, you must run a program called @code{texindex}
(@pxref{Format/Print Hardcopy}) to sort the raw data to produce a sorted
index file. The sorted index file is what is actually used to
print the index.@refill
Texinfo offers six different types of predefined index: the concept
index, the function index, the variables index, the keystroke index, the
program index, and the data type index (@pxref{Predefined Indices}). Each
index type has a two-letter name: @samp{cp}, @samp{fn}, @samp{vr},
@samp{ky}, @samp{pg}, and @samp{tp}. You may merge indices, or put them
into separate sections (@pxref{Combining Indices}); or you may define
your own indices (@pxref{New Indices, , Defining New Indices}).@refill
The @code{@@printindex} command takes a two-letter index name, reads
the corresponding sorted index file and formats it appropriately into
an index.@refill
@ignore
The two-letter index names are:
@table @samp
@item cp
concept index
@item fn
function index
@item vr
variable index
@item ky
key index
@item pg
program index
@item tp
data type index
@end table
@end ignore
The @code{@@printindex} command does not generate a chapter heading
for the index. Consequently, you should precede the
@code{@@printindex} command with a suitable section or chapter command
(usually @code{@@unnumbered}) to supply the chapter heading and put
the index into the table of contents. Precede the @code{@@unnumbered}
command with an @code{@@node} line.@refill
@need 1200
For example:
@smallexample
@group
@@node Variable Index, Concept Index, Function Index, Top
@@comment node-name, next, previous, up
@@unnumbered Variable Index
@@printindex vr
@end group
@group
@@node Concept Index, , Variable Index, Top
@@comment node-name, next, previous, up
@@unnumbered Concept Index
@@printindex cp
@end group
@group
@@summarycontents
@@contents
@@bye
@end group
@end smallexample
@noindent
(Readers often prefer that the concept index come last in a book,
since that makes it easiest to find.)@refill
@ignore
In @TeX{}, the @code{@@printindex} command needs a sorted index file
to work from. @TeX{} does not know how to do sorting; this is a
deficiency. @TeX{} writes output files of raw index data; use the
@code{texindex} program to convert these files to sorted index files.
(@xref{Format/Print Hardcopy}, for more information.)@refill
@end ignore
@node Contents, File End, Printing Indices & Menus, Ending a File
@comment node-name, next, previous, up
@section Generating a Table of Contents
@cindex Table of contents
@cindex Contents, Table of
@findex contents
@findex summarycontents
@findex shortcontents
The @code{@@chapter}, @code{@@section}, and other structuring commands
supply the information to make up a table of contents, but they do not
cause an actual table to appear in the manual. To do this, you must
use the @code{@@contents} and @code{@@summarycontents}
commands:@refill
@table @code
@item @@contents
Generate a table of contents in a printed manual, including all
chapters, sections, subsections, etc., as well as appendices and
unnumbered chapters. (Headings generated by the @code{@@heading}
series of commands do not appear in the table of contents.) The
@code{@@contents} command should be written on a line by
itself.@refill
@item @@shortcontents
@itemx @@summarycontents
(@code{@@summarycontents} is a synonym for @code{@@shortcontents}; the
two commands are exactly the same.)@refill
Generate a short or summary table of contents that lists only the
chapters (and appendices and unnumbered chapters). Omit sections, subsections
and subsubsections. Only a long manual needs a short table
of contents in addition to the full table of contents.@refill
Write the @code{@@shortcontents} command on a line by itself right
@emph{before} the @code{@@contents} command.@refill
@end table
The table of contents commands automatically generate a chapter-like
heading at the top of the first table of contents page. Write the table
of contents commands at the very end of a Texinfo file, just before the
@code{@@bye} command, following any index sections---anything in the
Texinfo file after the table of contents commands will be omitted from
the table of contents.@refill
When you print a manual with a table of contents, the table of
contents are printed last and numbered with roman numerals. You need
to place those pages in their proper place, after the title page,
yourself. (This is the only collating you need to do for a printed
manual. The table of contents is printed last because it is generated
after the rest of the manual is typeset.)@refill
@need 700
Here is an example of where to write table of contents commands:@refill
@example
@group
@var{indices}@dots{}
@@shortcontents
@@contents
@@bye
@end group
@end example
Since an Info file uses menus instead of tables of contents, the Info
formatting commands ignore the @code{@@contents} and
@code{@@shortcontents} commands.@refill
@node File End, , Contents, Ending a File
@comment node-name, next, previous, up
@section @code{@@bye} File Ending
@findex bye
An @code{@@bye} command terminates @TeX{} or Info formatting. None of
the formatting commands see any of the file following @code{@@bye}.
The @code{@@bye} command should be on a line by itself.@refill
If you wish, you may follow the @code{@@bye} line with notes. These notes
will not be formatted and will not appear in either Info or a printed
manual; it is as if text after @code{@@bye} were within @code{@@ignore}
@dots{} @code{@@end ignore}. Also, you may follow the @code{@@bye} line
with a local variables list. @xref{Compile-Command, , Using Local
Variables and the Compile Command}, for more information.@refill
@node Structuring, Nodes, Ending a File, Top
@comment node-name, next, previous, up
@chapter Chapter Structuring
@cindex Chapter structuring
@cindex Structuring of chapters
The @dfn{chapter structuring} commands divide a document into a hierarchy of
chapters, sections, subsections, and subsubsections. These commands
generate large headings; they also provide information for the table
of contents of a printed manual (@pxref{Contents, , Generating a Table
of Contents}).@refill
The chapter structuring commands do not create an Info node structure,
so normally you should put an @code{@@node} command immediately before
each chapter structuring command (@pxref{Nodes}). The only time you
are likely to use the chapter structuring commands without using the
node structuring commands is if you are writing a document that
contains no cross references and will never be transformed into Info
format.@refill
It is unlikely that you will ever write a Texinfo file that is
intended only as an Info file and not as a printable document. If you
do, you might still use chapter structuring commands to create a
heading at the top of each node---but you don't need to.@refill
@menu
* Tree Structuring:: A manual is like an upside down tree @dots{}
* Structuring Command Types:: How to divide a manual into parts.
* makeinfo top:: The @code{@@top} command, part of the `Top' node.
* chapter::
* unnumbered & appendix::
* majorheading & chapheading::
* section::
* unnumberedsec appendixsec heading::
* subsection::
* unnumberedsubsec appendixsubsec subheading::
* subsubsection:: Commands for the lowest level sections.
* Raise/lower sections:: How to change commands' hierarchical level.
@end menu
@node Tree Structuring, Structuring Command Types, Structuring, Structuring
@comment node-name, next, previous, up
@section Tree Structure of Sections
@cindex Tree structuring
A Texinfo file is usually structured like a book with chapters,
sections, subsections, and the like. This structure can be visualized
as a tree (or rather as an upside-down tree) with the root at the top
and the levels corresponding to chapters, sections, subsection, and
subsubsections.@refill
Here is a diagram that shows a Texinfo file with three chapters,
each of which has two sections.@refill
@example
@group
Top
|
-------------------------------------
| | |
Chapter 1 Chapter 2 Chapter 3
| | |
-------- -------- --------
| | | | | |
Section Section Section Section Section Section
1.1 1.2 2.1 2.2 3.1 3.2
@end group
@end example
In a Texinfo file that has this structure, the beginning of Chapter 2
looks like this:@refill
@example
@group
@@node Chapter 2, Chapter 3, Chapter 1, top
@@chapter Chapter 2
@end group
@end example
The chapter structuring commands are described in the sections that
follow; the @code{@@node} and @code{@@menu} commands are described in
following chapters. (@xref{Nodes}, and see @ref{Menus}.)@refill
@node Structuring Command Types, makeinfo top, Tree Structuring, Structuring
@comment node-name, next, previous, up
@section Types of Structuring Command
The chapter structuring commands fall into four groups or series, each
of which contains structuring commands corresponding to the
hierarchical levels of chapters, sections, subsections, and
subsubsections.@refill
The four groups are the @code{@@chapter} series, the
@code{@@unnumbered} series, the @code{@@appendix} series, and the
@code{@@heading} series.@refill
Each command produces titles that have a different appearance on the
printed page or Info file; only some of the commands produce
titles that are listed in the table of contents of a printed book or
manual.@refill
@itemize @bullet
@item
The @code{@@chapter} and @code{@@appendix} series of commands produce
numbered or lettered entries both in the body of a printed work and in
its table of contents.@refill
@item
The @code{@@unnumbered} series of commands produce unnumbered entries
both in the body of a printed work and in its table of contents. The
@code{@@top} command, which has a special use, is a member of this
series (@pxref{makeinfo top, , @code{@@top}}).@refill
@item
The @code{@@heading} series of commands produce unnumbered headings
that do not appear in a table of contents. The heading commands never
start a new page.@refill
@item
The @code{@@majorheading} command produces results similar to using
the @code{@@chapheading} command but generates a larger vertical
whitespace before the heading.@refill
@item
When an @code{@@setchapternewpage} command says to do so, the
@code{@@chapter}, @code{@@unnumbered}, and @code{@@appendix} commands
start new pages in the printed manual; the @code{@@heading} commands
do not.@refill
@end itemize
@need 1000
Here are the four groups of chapter structuring commands:@refill
@c Slightly different formatting for regular sized books and smallbooks.
@ifset smallbook
@sp 1
@tex
{\let\rm=\indrm \let\tt=\indtt
\halign{\hskip\itemindent#\hfil& \hskip.5em#\hfil& \hskip.5em#\hfil&
\hskip.5em#\hfil\cr
& & & \rm No new pages\cr
\rm Numbered& \rm Unnumbered& \rm Lettered and numbered& \rm Unnumbered\cr
\rm In contents& \rm In contents& \rm In contents& \rm Not in contents\cr
& & & \cr
& \tt @@top& & \tt @@majorheading\cr
\tt @@chapter& \tt @@unnumbered& \tt @@appendix& \tt @@chapheading\cr
\tt @@section& \tt @@unnumberedsec& \tt @@appendixsec& \tt @@heading\cr
\tt @@subsection&\tt @@unnumberedsubsec&\tt @@appendixsubsec&
\tt @@subheading\cr
\tt @@subsubsection& \tt @@unnumberedsubsubsec& \tt @@appendixsubsubsec&
\tt @@subsubheading\cr}}
@end tex
@end ifset
@ifclear smallbook
@sp 1
@tex
\vbox{
\halign{\hskip\itemindent\hskip.5em#\hfil& \hskip.5em#\hfil&
\hskip.5em#\hfil& \hskip.5em #\hfil\cr
& & & \cr
& & & \rm No new pages\cr
\rm Numbered& \rm Unnumbered& \rm Lettered and numbered& \rm Unnumbered\cr
\rm In contents& \rm In contents& \rm In contents& \rm Not in contents\cr
& & & \cr
& \tt @@top& & \tt @@majorheading\cr
\tt @@chapter& \tt @@unnumbered& \tt @@appendix& \tt @@chapheading\cr
\tt @@section& \tt @@unnumberedsec& \tt @@appendixsec& \tt @@heading\cr
\tt @@subsection&\tt @@unnumberedsubsec&\tt @@appendixsubsec&
\tt @@subheading\cr
\tt @@subsubsection& \tt @@unnumberedsubsubsec& \tt @@appendixsubsubsec&
\tt @@subsubheading\cr}}
@end tex
@end ifclear
@ifinfo
@example
@group
@r{No new pages}
@r{Numbered} @r{Unnumbered} @r{Lettered and numbered} @r{Unnumbered}
@r{In contents} @r{In contents} @r{In contents} @r{Not in contents}
@@top @@majorheading
@@chapter @@unnumbered @@appendix @@chapheading
@@section @@unnumberedsec @@appendixsec @@heading
@@subsection @@unnumberedsubsec @@appendixsubsec @@subheading
@@subsubsection @@unnumberedsubsubsec @@appendixsubsubsec @@subsubheading
@end group
@end example
@end ifinfo
@c Cannot line up columns properly inside of an example because of roman
@c proportional fonts.
@ignore
@ifset smallbook
@iftex
@smallexample
@group
@r{No new pages}
@r{Numbered} @r{Unnumbered} @r{Lettered and numbered} @r{Unnumbered}
@r{In contents} @r{In contents} @r{In contents} @r{Not in contents}
@@top @@majorheading
@@chapter @@unnumbered @@appendix @@chapheading
@@section @@unnumberedsec @@appendixsec @@heading
@@subsection @@unnumberedsubsec @@appendixsubsec @@subheading
@@subsubsection @@unnumberedsubsubsec @@appendixsubsubsec @@subsubheading
@end group
@end smallexample
@end iftex
@end ifset
@ifclear smallbook
@iftex
@smallexample
@group
@r{No new pages}
@r{Numbered} @r{Unnumbered} @r{Lettered and numbered} @r{Unnumbered}
@r{In contents} @r{In contents} @r{In contents} @r{Not in contents}
@@top @@majorheading
@@chapter @@unnumbered @@appendix @@chapheading
@@section @@unnumberedsec @@appendixsec @@heading
@@subsection @@unnumberedsubsec @@appendixsubsec @@subheading
@@subsubsection @@unnumberedsubsubsec @@appendixsubsubsec @@subsubheading
@end group
@end smallexample
@end iftex
@end ignore
@node makeinfo top, chapter, Structuring Command Types, Structuring
@comment node-name, next, previous, up
@section @code{@@top}
The @code{@@top} command is a special sectioning command that you use
only after an @code{@@node Top} line at the beginning of a Texinfo file.
The @code{@@top} command tells the @code{makeinfo} formatter
which node is the `Top'
node. It has the same typesetting effect as @code{@@unnumbered}
(@pxref{unnumbered & appendix, , @code{@@unnumbered}, @code{@@appendix}}).
For detailed information, see
@ref{makeinfo top command, , The @code{@@top} Command}.@refill
@node chapter, unnumbered & appendix, makeinfo top, Structuring
@comment node-name, next, previous, up
@section @code{@@chapter}
@findex chapter
@code{@@chapter} identifies a chapter in the document. Write the
command at the beginning of a line and follow it on the same line by
the title of the chapter.@refill
For example, this chapter in this manual is entitled ``Chapter
Structuring''; the @code{@@chapter} line looks like this:@refill
@example
@@chapter Chapter Structuring
@end example
In @TeX{}, the @code{@@chapter} command creates a chapter in the
document, specifying the chapter title. The chapter is numbered
automatically.@refill
In Info, the @code{@@chapter} command causes the title to appear on a
line by itself, with a line of asterisks inserted underneath. Thus,
in Info, the above example produces the following output:@refill
@example
Chapter Structuring
*******************
@end example
@node unnumbered & appendix, majorheading & chapheading, chapter, Structuring
@comment node-name, next, previous, up
@section @code{@@unnumbered}, @code{@@appendix}
@findex unnumbered
@findex appendix
Use the @code{@@unnumbered} command to create a chapter that appears
in a printed manual without chapter numbers of any kind. Use the
@code{@@appendix} command to create an appendix in a printed manual
that is labelled by letter instead of by number.@refill
For Info file output, the @code{@@unnumbered} and @code{@@appendix}
commands are equivalent to @code{@@chapter}: the title is printed on a
line by itself with a line of asterisks underneath. (@xref{chapter, ,
@code{@@chapter}}.)@refill
To create an appendix or an unnumbered chapter, write an
@code{@@appendix} or @code{@@unnumbered} command at the beginning of a
line and follow it on the same line by the title, as you would if you
were creating a chapter.@refill
@node majorheading & chapheading, section, unnumbered & appendix, Structuring
@section @code{@@majorheading}, @code{@@chapheading}
@findex majorheading
@findex chapheading
The @code{@@majorheading} and @code{@@chapheading} commands put
chapter-like headings in the body of a document.@refill
However, neither command causes @TeX{} to produce a numbered heading
or an entry in the table of contents; and neither command causes
@TeX{} to start a new page in a printed manual.@refill
In @TeX{}, an @code{@@majorheading} command generates a larger vertical
whitespace before the heading than an @code{@@chapheading} command but
is otherwise the same.@refill
In Info,
the @code{@@majorheading} and
@code{@@chapheading} commands are equivalent to
@code{@@chapter}: the title is printed on a line by itself with a line
of asterisks underneath. (@xref{chapter, , @code{@@chapter}}.)@refill
@node section, unnumberedsec appendixsec heading, majorheading & chapheading, Structuring
@comment node-name, next, previous, up
@section @code{@@section}
@findex section
In a printed manual, an @code{@@section} command identifies a
numbered section within a chapter. The section title appears in the
table of contents. In Info, an @code{@@section} command provides a
title for a segment of text, underlined with @samp{=}.@refill
This section is headed with an @code{@@section} command and looks like
this in the Texinfo file:@refill
@example
@@section @@code@{@@@@section@}
@end example
To create a section, write the @code{@@section} command at the
beginning of a line and follow it on the same line by the section
title.@refill
Thus,
@example
@@section This is a section
@end example
@noindent
produces
@example
@group
This is a section
=================
@end group
@end example
@noindent
in Info.
@node unnumberedsec appendixsec heading, subsection, section, Structuring
@comment node-name, next, previous, up
@section @code{@@unnumberedsec}, @code{@@appendixsec}, @code{@@heading}
@findex unnumberedsec
@findex appendixsec
@findex heading
The @code{@@unnumberedsec}, @code{@@appendixsec}, and @code{@@heading}
commands are, respectively, the unnumbered, appendix-like, and
heading-like equivalents of the @code{@@section} command.
(@xref{section, , @code{@@section}}.)@refill
@table @code
@item @@unnumberedsec
The @code{@@unnumberedsec} command may be used within an
unnumbered chapter or within a regular chapter or appendix to
provide an unnumbered section.@refill
@item @@appendixsec
@itemx @@appendixsection
@code{@@appendixsection} is a longer spelling of the
@code{@@appendixsec} command; the two are synonymous.@refill
@findex appendixsection
Conventionally, the @code{@@appendixsec} or @code{@@appendixsection}
command is used only within appendices.@refill
@item @@heading
You may use the @code{@@heading} command anywhere you wish for a
section-style heading that will not appear in the table of contents.@refill
@end table
@node subsection, unnumberedsubsec appendixsubsec subheading, unnumberedsec appendixsec heading, Structuring
@comment node-name, next, previous, up
@section The @code{@@subsection} Command
@findex subsection
Subsections are to sections as sections are to chapters.
(@xref{section, , @code{@@section}}.) In Info, subsection titles are
underlined with @samp{-}. For example,@refill
@example
@@subsection This is a subsection
@end example
@noindent
produces
@example
@group
This is a subsection
--------------------
@end group
@end example
In a printed manual, subsections are listed in the table of contents
and are numbered three levels deep.@refill
@node unnumberedsubsec appendixsubsec subheading, subsubsection, subsection, Structuring
@comment node-name, next, previous, up
@section The @code{@@subsection}-like Commands
@cindex Subsection-like commands
@findex unnumberedsubsec
@findex appendixsubsec
@findex subheading
The @code{@@unnumberedsubsec}, @code{@@appendixsubsec}, and
@code{@@subheading} commands are, respectively, the unnumbered,
appendix-like, and heading-like equivalents of the @code{@@subsection}
command. (@xref{subsection, , @code{@@subsection}}.)@refill
In Info, the @code{@@subsection}-like commands generate a title
underlined with hyphens. In a printed manual, an @code{@@subheading}
command produces a heading like that of a subsection except that it is
not numbered and does not appear in the table of contents. Similarly,
an @code{@@unnumberedsubsec} command produces an unnumbered heading like
that of a subsection and an @code{@@appendixsubsec} command produces a
subsection-like heading labelled with a letter and numbers; both of
these commands produce headings that appear in the table of
contents.@refill
@node subsubsection, Raise/lower sections, unnumberedsubsec appendixsubsec subheading, Structuring
@comment node-name, next, previous, up
@section The `subsub' Commands
@cindex Subsub commands
@findex subsubsection
@findex unnumberedsubsubsec
@findex appendixsubsubsec
@findex subsubheading
The fourth and lowest level sectioning commands in Texinfo are the
`subsub' commands. They are:@refill
@table @code
@item @@subsubsection
Subsubsections are to subsections as subsections are to sections.
(@xref{subsection, , @code{@@subsection}}.) In a printed manual,
subsubsection titles appear in the table of contents and are numbered
four levels deep.@refill
@item @@unnumberedsubsubsec
Unnumbered subsubsection titles appear in the table of contents of a
printed manual, but lack numbers. Otherwise, unnumbered
subsubsections are the same as subsubsections. In Info, unnumbered
subsubsections look exactly like ordinary subsubsections.@refill
@item @@appendixsubsubsec
Conventionally, appendix commands are used only for appendices and are
lettered and numbered appropriately in a printed manual. They also
appear in the table of contents. In Info, appendix subsubsections look
exactly like ordinary subsubsections.@refill
@item @@subsubheading
The @code{@@subsubheading} command may be used anywhere that you need
a small heading that will not appear in the table of contents. In
Info, subsubheadings look exactly like ordinary subsubsection
headings.@refill
@end table
In Info, `subsub' titles are underlined with periods.
For example,@refill
@example
@@subsubsection This is a subsubsection
@end example
@noindent
produces
@example
@group
This is a subsubsection
.......................
@end group
@end example
@node Raise/lower sections, , subsubsection, Structuring
@comment node-name, next, previous, up
@section @code{@@raisesections} and @code{@@lowersections}
@findex @@raisesections
@findex @@lowersections
@cindex Raising and lowering sections
@cindex Sections, raising and lowering
The @code{@@raisesections} and @code{@@lowersections} commands raise and
lower the hierarchical level of chapters, sections, subsections and the
like. The @code{@@raisesections} command changes sections to chapters,
subsections to sections, and so on. The @code{@@lowersections} command
changes chapters to sections, sections to subsections, and so on.
An @code{@@lowersections} command is useful if you wish to include text
that is written as an outer or standalone Texinfo file in another
Texinfo file as an inner, included file. If you write the command at
the beginning of the file, all your @code{@@chapter} commands are
formatted as if they were @code{@@section} commands, all your
@code{@@section} command are formatted as if they were
@code{@@subsection} commands, and so on.
@need 1000
@code{@@raisesections} raises a command one level in the chapter
structuring hierarchy:@refill
@example
@group
@r{Change} @r{To}
@@subsection @@section,
@@section @@chapter,
@@heading @@chapheading,
@r{etc.}
@end group
@end example
@need 1000
@code{@@lowersections} lowers a command one level in the chapter
structuring hierarchy:@refill
@example
@group
@r{Change} @r{To}
@@chapter @@section,
@@subsection @@subsubsection,
@@heading @@subheading,
@r{etc.}
@end group
@end example
An @code{@@raisesections} or @code{@@lowersections} command changes only
those structuring commands that follow the command in the Texinfo file.
Write an @code{@@raisesections} or @code{@@lowersections} command on a
line of its own.
An @code{@@lowersections} command cancels an @code{@@raisesections}
command, and vice versa.
Repeated use of the commands continue to raise or lower the hierarchical
level a step at a time.
An attempt to raise above `chapters' reproduces chapter commands; an
attempt to lower below `subsubsections' reproduces subsubsection
commands.
@node Nodes, Menus, Structuring, Top
@comment node-name, next, previous, up
@chapter Nodes
@dfn{Nodes} are the primary segments of a Texinfo file. They do not
themselves impose a hierarchic or any other kind of structure on a file.
Nodes contain @dfn{node pointers} that name other nodes, and can contain
@dfn{menus} which are lists of nodes. In Info, the movement commands
can carry you to a pointed-to node or to a node listed in a menu. Node
pointers and menus provide structure for Info files just as chapters,
sections, subsections, and the like, provide structure for printed
books.@refill
@menu
* Two Paths:: Different commands to structure
Info output and printed output.
* Node Menu Illustration:: A diagram, and sample nodes and menus.
* node:: How to write a node, in detail.
* makeinfo Pointer Creation:: How to create node pointers with @code{makeinfo}.
@end menu
@node Two Paths, Node Menu Illustration, Nodes, Nodes
@ifinfo
@heading Two Paths
@end ifinfo
The node and menu commands and the chapter structuring commands are
independent of each other:
@itemize @bullet
@item
In Info, node and menu commands provide structure. The chapter
structuring commands generate headings with different kinds of
underlining---asterisks for chapters, hyphens for sections, and so on;
they do nothing else.@refill
@item
In @TeX{}, the chapter structuring commands generate chapter and section
numbers and tables of contents. The node and menu commands provide
information for cross references; they do nothing else.@refill
@end itemize
You can use node pointers and menus to structure an Info file any way
you want; and you can write a Texinfo file so that its Info output has a
different structure than its printed output. However, most Texinfo
files are written such that the structure for the Info output
corresponds to the structure for the printed output. It is not
convenient to do otherwise.@refill
Generally, printed output is structured in a tree-like hierarchy in
which the chapters are the major limbs from which the sections branch
out. Similarly, node pointers and menus are organized to create a
matching structure in the Info output.@refill
@node Node Menu Illustration, node, Two Paths, Nodes
@comment node-name, next, previous, up
@section Node and Menu Illustration
Here is a copy of the diagram shown earlier that illustrates a Texinfo
file with three chapters, each of which contains two sections.@refill
Note that the ``root'' is at the top of the diagram and the ``leaves''
are at the bottom. This is how such a diagram is drawn conventionally;
it illustrates an upside-down tree. For this reason, the root node is
called the `Top' node, and `Up' node pointers carry you closer to the
root.@refill
@example
@group
Top
|
-------------------------------------
| | |
Chapter 1 Chapter 2 Chapter 3
| | |
-------- -------- --------
| | | | | |
Section Section Section Section Section Section
1.1 1.2 2.1 2.2 3.1 3.2
@end group
@end example
Write the beginning of the node for Chapter 2 like this:@refill
@example
@group
@@node Chapter 2, Chapter 3, Chapter 1, top
@@comment node-name, next, previous, up
@end group
@end example
@noindent
This @code{@@node} line says that the name of this node is ``Chapter 2'', the
name of the `Next' node is ``Chapter 3'', the name of the `Previous'
node is ``Chapter 1'', and the name of the `Up' node is ``Top''.
@quotation
@strong{Please Note:} `Next' refers to the next node at the same
hierarchical level in the manual, not necessarily to the next node
within the Texinfo file. In the Texinfo file, the subsequent node may
be at a lower level---a section-level node may follow a chapter-level
node, and a subsection-level node may follow a section-level node.
`Next' and `Previous' refer to nodes at the @emph{same} hierarchical
level. (The `Top' node contains the exception to this rule. Since the
`Top' node is the only node at that level, `Next' refers to the first
following node, which is almost always a chapter or chapter-level
node.)@refill
@end quotation
To go to Sections 2.1 and 2.2 using Info, you need a menu inside Chapter
2. (@xref{Menus}.) You would write the menu just
before the beginning of Section 2.1, like this:@refill
@example
@group
@@menu
* Sect. 2.1:: Description of this section.
* Sect. 2.2::
@@end menu
@end group
@end example
Write the node for Sect. 2.1 like this:@refill
@example
@group
@@node Sect. 2.1, Sect. 2.2, Chapter 2, Chapter 2
@@comment node-name, next, previous, up
@end group
@end example
In Info format, the `Next' and `Previous' pointers of a node usually
lead to other nodes at the same level---from chapter to chapter or from
section to section (sometimes, as shown, the `Previous' pointer points
up); an `Up' pointer usually leads to a node at the level above (closer
to the `Top' node); and a `Menu' leads to nodes at a level below (closer
to `leaves'). (A cross reference can point to a node at any level;
see @ref{Cross References}.)@refill
Usually, an @code{@@node} command and a chapter structuring command are
used in sequence, along with indexing commands. (You may follow the
@code{@@node} line with a comment line that reminds you which pointer is
which.)@refill
Here is the beginning of the chapter in this manual called ``Ending a
Texinfo File''. This shows an @code{@@node} line followed by a comment
line, an @code{@@chapter} line, and then by indexing lines.@refill
@example
@group
@@node Ending a File, Structuring, Beginning a File, Top
@@comment node-name, next, previous, up
@@chapter Ending a Texinfo File
@@cindex Ending a Texinfo file
@@cindex Texinfo file ending
@@cindex File ending
@end group
@end example
@node node, makeinfo Pointer Creation, Node Menu Illustration, Nodes
@comment node-name, next, previous, up
@section The @code{@@node} Command
@cindex Node, defined
A @dfn{node} is a segment of text that begins at an @code{@@node}
command and continues until the next @code{@@node} command. The
definition of node is different from that for chapter or section. A
chapter may contain sections and a section may contain subsections;
but a node cannot contain subnodes; the text of a node continues only
until the next @code{@@node} command in the file. A node usually
contains only one chapter structuring command, the one that follows
the @code{@@node} line. On the other hand, in printed output nodes
are used only for cross references, so a chapter or section may
contain any number of nodes. Indeed, a chapter usually contains
several nodes, one for each section, subsection, and
subsubsection.@refill
To create a node, write an @code{@@node} command at the beginning of a
line, and follow it with four arguments, separated by commas, on the
rest of the same line. These arguments are the name of the node, and
the names of the `Next', `Previous', and `Up' pointers, in that order.
You may insert spaces before each pointer if you wish; the spaces are
ignored. You must write the name of the node, and the names of the
`Next', `Previous', and `Up' pointers, all on the same line. Otherwise,
the formatters fail. (@inforef{Top, info, info}, for more information
about nodes in Info.)@refill
Usually, you write one of the chapter-structuring command lines
immediately after an @code{@@node} line---for example, an
@code{@@section} or @code{@@subsection} line. (@xref{Structuring
Command Types, , Types of Structuring Command}.)@refill
@quotation
@strong{Please note:} The GNU Emacs Texinfo mode updating commands work
only with Texinfo files in which @code{@@node} lines are followed by chapter
structuring lines. @xref{Updating Requirements}.@refill
@end quotation
@TeX{} uses @code{@@node} lines to identify the names to use for cross
references. For this reason, you must write @code{@@node} lines in a
Texinfo file that you intend to format for printing, even if you do not
intend to format it for Info. (Cross references, such as the one at the
end of this sentence, are made with @code{@@xref} and its related
commands; see @ref{Cross References}.)@refill
@menu
* Node Names:: How to choose node and pointer names.
* Writing a Node:: How to write an @code{@@node} line.
* Node Line Tips:: Keep names short.
* Node Line Requirements:: Keep names unique, without @@-commands.
* First Node:: How to write a `Top' node.
* makeinfo top command:: How to use the @code{@@top} command.
* Top Node Summary:: Write a brief description for readers.
@end menu
@node Node Names, Writing a Node, node, node
@ifinfo
@subheading Choosing Node and Pointer Names
@end ifinfo
The name of a node identifies the node. The pointers enable
you to reach other nodes and consist of the names of those nodes.@refill
Normally, a node's `Up' pointer contains the name of the node whose menu
mentions that node. The node's `Next' pointer contains the name of the
node that follows that node in that menu and its `Previous' pointer
contains the name of the node that precedes it in that menu. When a
node's `Previous' node is the same as its `Up' node, both node pointers
name the same node.@refill
Usually, the first node of a Texinfo file is the `Top' node, and its
`Up' and `Previous' pointers point to the @file{dir} file, which
contains the main menu for all of Info.@refill
The `Top' node itself contains the main or master menu for the manual.
Also, it is helpful to include a brief description of the manual in the
`Top' node. @xref{First Node}, for information on how to write the
first node of a Texinfo file.@refill
@node Writing a Node, Node Line Tips, Node Names, node
@comment node-name, next, previous, up
@subsection How to Write an @code{@@node} Line
@cindex Writing an @code{@@node} line
@cindex @code{@@node} line writing
@cindex Node line writing
The easiest way to write an @code{@@node} line is to write @code{@@node}
at the beginning of a line and then the name of the node, like
this:@refill
@example
@@node @var{node-name}
@end example
If you are using GNU Emacs, you can use the update node commands
provided by Texinfo mode to insert the names of the pointers; or you
can leave the pointers out of the Texinfo file and let @code{makeinfo}
insert node pointers into the Info file it creates. (@xref{Texinfo
Mode}, and @ref{makeinfo Pointer Creation}.)@refill
Alternatively, you can insert the `Next', `Previous', and `Up'
pointers yourself. If you do this, you may find it helpful to use the
Texinfo mode keyboard command @kbd{C-c C-c n}. This command inserts
@samp{@@node} and a comment line listing the names of the pointers in
their proper order. The comment line helps you keep track of which
arguments are for which pointers. This comment line is especially useful
if you are not familiar with Texinfo.@refill
The template for a node line with `Next', `Previous', and `Up' pointers
looks like this:@refill
@example
@@node @var{node-name}, @var{next}, @var{previous}, @var{up}
@end example
If you wish, you can ignore @code{@@node} lines altogether in your first
draft and then use the @code{texinfo-insert-node-lines} command to
create @code{@@node} lines for you. However, we do not
recommend this practice. It is better to name the node itself
at the same time that you
write a segment so you can easily make cross references. A large number
of cross references are an especially important feature of a good Info
file.@refill
After you have inserted an @code{@@node} line, you should immediately
write an @@-command for the chapter or section and insert its name.
Next (and this is important!), put in several index entries. Usually,
you will find at least two and often as many as four or five ways of
referring to the node in the index. Use them all. This will make it
much easier for people to find the node.@refill
@node Node Line Tips, Node Line Requirements, Writing a Node, node
@comment node-name, next, previous, up
@subsection @code{@@node} Line Tips
Here are three suggestions:
@itemize @bullet
@item
Try to pick node names that are informative but short.@refill
In the Info file, the file name, node name, and pointer names are all
inserted on one line, which may run into the right edge of the window.
(This does not cause a problem with Info, but is ugly.)@refill
@item
Try to pick node names that differ from each other near the beginnings
of their names. This way, it is easy to use automatic name completion in
Info.@refill
@item
By convention, node names are capitalized just as they would be for
section or chapter titles---initial and significant words are
capitalized; others are not.@refill
@end itemize
@node Node Line Requirements, First Node, Node Line Tips, node
@comment node-name, next, previous, up
@subsection @code{@@node} Line Requirements
@cindex Node line requirements
Here are several requirements for @code{@@node} lines:
@itemize @bullet
@cindex Unique nodename requirement
@cindex Nodename must be unique
@item
All the node names for a single Info file must be unique.@refill
Duplicates confuse the Info movement commands. This means, for
example, that if you end every chapter with a summary, you must name
each summary node differently. You cannot just call each one
``Summary''. You may, however, duplicate the titles of chapters, sections,
and the like. Thus you can end each chapter in a book with a section
called ``Summary'', so long as the node names for those sections are all
different.@refill
@item
A pointer name must be the name of a node.@refill
The node to which a pointer points may come before or after the
node containing the pointer.@refill
@cindex @@-command in nodename
@cindex Nodename, cannot contain
@item
You cannot use any of the Texinfo @@-commands in a node name;
@w{@@-commands} confuse Info.@refill
@need 750
Thus, the beginning of the section called @code{@@chapter} looks like
this:@refill
@smallexample
@group
@@node chapter, unnumbered & appendix, makeinfo top, Structuring
@@comment node-name, next, previous, up
@@section @@code@{@@@@chapter@}
@@findex chapter
@end group
@end smallexample
@cindex Comma in nodename
@cindex Colon in nodename
@cindex Apostrophe in nodename
@item
You cannot use commas, colons, or apostrophes within a node name; these
confuse @TeX{} or the Info formatters.@refill
@need 700
For example, the following is a section title:
@smallexample
@@code@{@@@@unnumberedsec@}, @@code@{@@@@appendixsec@}, @@code@{@@@@heading@}
@end smallexample
@noindent
The corresponding node name is:
@smallexample
unnumberedsec appendixsec heading
@end smallexample
@cindex Case in nodename
@item
Case is significant.
@end itemize
@node First Node, makeinfo top command, Node Line Requirements, node
@comment node-name, next, previous, up
@subsection The First Node
@cindex @samp{@r{Top}} node is first
@cindex First node
The first node of a Texinfo file is the `Top' node, except in an
included file (@pxref{Include Files}).
The `Top' node (which must be named @samp{top} or @samp{Top}) should
have as its `Up' and `Previous' nodes the name of a node in another
file, where there is a menu that leads to this file. Specify the file
name in parentheses. If the file is to be installed directly in the
Info directory file, use @samp{(dir)} as the parent of the `Top' node;
this is short for @samp{(dir)top}, and specifies the `Top' node in the
@file{dir} file, which contains the main menu for Info. For example,
the @code{@@node Top} line of this manual looks like this:@refill
@example
@@node Top, Overview, (dir), (dir)
@end example
@noindent
(You may use the Texinfo updating commands or the @code{makeinfo}
utility to insert these `Next' and @samp{(dir)} pointers
automatically.)@refill
@xref{Install an Info File}, for more information about installing
an Info file in the @file{info} directory.@refill
The `Top' node contains the main or master menu for the document.
@node makeinfo top command, Top Node Summary, First Node, node
@comment node-name, next, previous, up
@subsection The @code{@@top} Sectioning Command
@findex top @r{(@@-command)}
A special sectioning command, @code{@@top}, has been created for use
with the @code{@@node Top} line. The @code{@@top} sectioning command tells
@code{makeinfo} that it marks the `Top' node in the file. It provides
the information that @code{makeinfo} needs to insert node
pointers automatically. Write the @code{@@top} command at the
beginning of the line immediately following the @code{@@node Top}
line. Write the title on the remaining part of the same line as the
@code{@@top} command.@refill
In Info, the @code{@@top} sectioning command causes the title to appear on a
line by itself, with a line of asterisks inserted underneath.@refill
In @TeX{} and @code{texinfo-format-buffer}, the @code{@@top}
sectioning command is merely a synonym for @code{@@unnumbered}.
Neither of these formatters require an @code{@@top} command, and do
nothing special with it. You can use @code{@@chapter} or
@code{@@unnumbered} after the @code{@@node Top} line when you use
these formatters. Also, you can use @code{@@chapter} or
@code{@@unnumbered} when you use the Texinfo updating commands to
create or update pointers and menus.@refill
@node Top Node Summary, , makeinfo top command, node
@subsection The `Top' Node Summary
@cindex @samp{@r{Top}} node summary
You can help readers by writing a summary in the `Top' node, after the
@code{@@top} line, before the main or master menu. The summary should
briefly describe the document. In Info, this summary will appear just
before the master menu. In a printed manual, this summary will appear
on a page of its own.@refill
If you do not want the summary to appear on a page of its own in a
printed manual, you can enclose the whole of the `Top' node, including
the @code{@@node Top} line and the @code{@@top} sectioning command line
or other sectioning command line between @code{@@ifinfo} and @code{@@end
ifinfo}. This prevents any of the text from appearing in the printed
output. (@pxref{Conditionals, , Conditionally Visible Text}). You can
repeat the brief description from the `Top' node within @code{@@iftex}
@dots{} @code{@@end iftex} at the beginning of the first chapter, for
those who read the printed manual. This saves paper and may look
neater.@refill
You should write the version number of the program to which the manual
applies in the summary. This helps the reader keep track of which
manual is for which version of the program. If the manual changes more
frequently than the program or is independent of it, you should also
include an edition number for the manual. (The title page should also
contain this information: see @ref{titlepage, ,
@code{@@titlepage}}.)@refill
@node makeinfo Pointer Creation, , node, Nodes
@section Creating Pointers with @code{makeinfo}
@cindex Creating pointers with @code{makeinfo}
@cindex Pointer creation with @code{makeinfo}
@cindex Automatic pointer creation with @code{makeinfo}
The @code{makeinfo} program has a feature for automatically creating
node pointers for a hierarchically organized file that lacks
them.@refill
When you take advantage of this feature, you do not need to write the
`Next', `Previous', and `Up' pointers after the name of a node.
However, you must write a sectioning command, such as @code{@@chapter}
or @code{@@section}, on the line immediately following each truncated
@code{@@node} line. You cannot write a comment line after a node
line; the section line must follow it immediately.@refill
In addition, you must follow the `Top' @code{@@node} line with a line beginning
with @code{@@top} to mark the `Top' node in the file. @xref{makeinfo
top, , @code{@@top}}.
Finally, you must write the name of each node (except for the `Top'
node) in a menu that is one or more hierarchical levels above the
node's hierarchical level.@refill
This node pointer insertion feature in @code{makeinfo} is an
alternative to the menu and pointer creation and update commands in
Texinfo mode. (@xref{Updating Nodes and Menus}.) It is especially
helpful to people who do not use GNU Emacs for writing Texinfo
documents.@refill
@node Menus, Cross References, Nodes, Top
@comment node-name, next, previous, up
@chapter Menus
@cindex Menus
@findex menu
@dfn{Menus} contain pointers to subordinate
nodes.@footnote{Menus can carry you to any node, regardless
of the hierarchical structure; even to nodes in a different
Info file. However, the GNU Emacs Texinfo mode updating
commands work only to create menus of subordinate nodes.
Conventionally, cross references are used to refer to other
nodes.} In Info, you use menus to go to such nodes. Menus
have no effect in printed manuals and do not appear in
them.@refill
By convention, a menu is put at the end of a node since a reader who
uses the menu may not see text that follows it.@refill
@ifinfo
A node that has a menu should @emph{not} contain much text. If you
have a lot of text and a menu, move most of the text into a new
subnode---all but a few lines.@refill
@end ifinfo
@iftex
@emph{A node that has a menu should not contain much text.} If you
have a lot of text and a menu, move most of the text into a new
subnode---all but a few lines. Otherwise, a reader with a terminal
that displays only a few lines may miss the menu and its associated
text. As a practical matter, you should locate a menu within 20 lines
of the beginning of the node.@refill
@end iftex
@menu
* Menu Location:: Put a menu in a short node.
* Writing a Menu:: What is a menu?
* Menu Parts:: A menu entry has three parts.
* Less Cluttered Menu Entry:: Two part menu entry.
* Menu Example:: Two and three part menu entries.
* Other Info Files:: How to refer to a different Info file.
@end menu
@node Menu Location, Writing a Menu, Menus, Menus
@ifinfo
@heading Menus Need Short Nodes
@end ifinfo
@cindex Menu location
@cindex Location of menus
@cindex Nodes for menus are short
@cindex Short nodes for menus
@ifinfo
A reader can easily see a menu that is close to the beginning of the
node. The node should be short. As a practical matter, you should
locate a menu within 20 lines of the beginning of the node.
Otherwise, a reader with a terminal that displays only a few lines may
miss the menu and its associated text.@refill
@end ifinfo
The short text before a menu may look awkward in a printed manual. To
avoid this, you can write a menu near the beginning of its node and
follow the menu by an @code{@@node} line, and then an @code{@@heading}
line located within @code{@@ifinfo} and @code{@@end ifinfo}. This way,
the menu, @code{@@node} line, and title appear only in the Info file,
not the printed document.@refill
For example, the preceding two paragraphs follow an Info-only menu,
@code{@@node} line, and heading, and look like this:@refill
@example
@group
@@menu
* Menu Location:: Put a menu in a short node.
* Writing a Menu:: What is a menu?
* Menu Parts:: A menu entry has three parts.
* Less Cluttered Menu Entry:: Two part menu entry.
* Menu Example:: Two and three part entries.
* Other Info Files:: How to refer to a different
Info file.
@@end menu
@@node Menu Location, Writing a Menu, , Menus
@@ifinfo
@@heading Menus Need Short Nodes
@@end ifinfo
@end group
@end example
The Texinfo file for this document contains more than a dozen
examples of this procedure. One is at the beginning of this chapter;
another is at the beginning of the ``Cross References'' chapter.@refill
@node Writing a Menu, Menu Parts, Menu Location, Menus
@section Writing a Menu
@cindex Writing a menu
@cindex Menu writing
A menu consists of an @code{@@menu} command on a line by
itself followed by menu entry lines or menu comment lines
and then by an @code{@@end menu} command on a line by
itself.@refill
A menu looks like this:@refill
@example
@group
@@menu
Larger Units of Text
* Files:: All about handling files.
* Multiples: Buffers. Multiple buffers; editing
several files at once.
@@end menu
@end group
@end example
In a menu, every line that begins with an @w{@samp{* }} is a
@dfn{menu entry}. (Note the space after the asterisk.) A
line that does not start with an @w{@samp{* }} may also
appear in a menu. Such a line is not a menu entry but is a
menu comment line that appears in the Info file. In
the example above, the line @samp{Larger Units of Text} is a
menu comment line; the two lines starting with @w{@samp{* }}
are menu entries.
@node Menu Parts, Less Cluttered Menu Entry, Writing a Menu, Menus
@section The Parts of a Menu
@cindex Parts of a menu
@cindex Menu parts
@cindex @code{@@menu} parts
A menu entry has three parts, only the second of which is
required:@refill
@enumerate
@item
The menu entry name.
@item
The name of the node (required).
@item
A description of the item.
@end enumerate
The template for a menu entry looks like this:@refill
@example
* @var{menu-entry-name}: @var{node-name}. @var{description}
@end example
Follow the menu entry name with a single colon and follow the node name
with tab, comma, period, or newline.@refill
In Info, a user selects a node with the @kbd{m} (@code{Info-menu})
command. The menu entry name is what the user types after the @kbd{m}
command.@refill
The third part of a menu entry is a descriptive phrase or
sentence. Menu entry names and node names are often short; the
description explains to the reader what the node is about. The
description, which is optional, can spread over two or more lines. A
useful description complements the node name rather than repeats
it.@refill
@node Less Cluttered Menu Entry, Menu Example, Menu Parts, Menus
@comment node-name, next, previous, up
@section Less Cluttered Menu Entry
@cindex Two part menu entry
@cindex Double-colon menu entries
@cindex Menu entries with two colons
@cindex Less cluttered menu entry
@cindex Uncluttered menu entry
When the menu entry name and node name are the same, you can write
the name immediately after the asterisk and space at the beginning of
the line and follow the name with two colons.@refill
@need 800
For example, write
@example
* Name:: @var{description}
@end example
@need 800
@noindent
instead of
@example
* Name: Name. @var{description}
@end example
You should use the node name for the menu entry name whenever possible,
since it reduces visual clutter in the menu.@refill
@node Menu Example, Other Info Files, Less Cluttered Menu Entry, Menus
@comment node-name, next, previous, up
@section A Menu Example
@cindex Menu example
@cindex Example menu
A menu looks like this in Texinfo:@refill
@example
@group
@@menu
* menu entry name: Node name. A short description.
* Node name:: This form is preferred.
@@end menu
@end group
@end example
@need 800
@noindent
This produces:
@example
@group
* menu:
* menu entry name: Node name. A short description.
* Node name:: This form is preferred.
@end group
@end example
@need 700
Here is an example as you might see it in a Texinfo file:@refill
@example
@group
@@menu
Larger Units of Text
* Files:: All about handling files.
* Multiples: Buffers. Multiple buffers; editing
several files at once.
@@end menu
@end group
@end example
@need 800
@noindent
This produces:
@example
@group
* menu:
Larger Units of Text
* Files:: All about handling files.
* Multiples: Buffers. Multiple buffers; editing
several files at once.
@end group
@end example
In this example, the menu has two entries. @samp{Files} is both a menu
entry name and the name of the node referred to by that name.
@samp{Multiples} is the menu entry name; it refers to the node named
@samp{Buffers}. The line @samp{Larger Units of Text} is a comment; it
appears in the menu, but is not an entry.@refill
Since no file name is specified with either @samp{Files} or
@samp{Buffers}, they must be the names of nodes in the same Info file
(@pxref{Other Info Files, , Referring to Other Info Files}).@refill
@node Other Info Files, , Menu Example, Menus
@comment node-name, next, previous, up
@section Referring to Other Info Files
@cindex Referring to other Info files
@cindex Nodes in other Info files
@cindex Other Info files' nodes
@cindex Going to other Info files' nodes
@cindex Info; other files' nodes
You can create a menu entry that enables a reader in Info to go to a
node in another Info file by writing the file name in parentheses just
before the node name. In this case, you should use the three-part menu
entry format, which saves the reader from having to type the file
name.@refill
@need 800
The format looks like this:@refill
@example
@group
@@menu
* @var{first-entry-name}:(@var{filename})@var{nodename}. @var{description}
* @var{second-entry-name}:(@var{filename})@var{second-node}. @var{description}
@@end menu
@end group
@end example
For example, to refer directly to the @samp{Outlining} and
@samp{Rebinding} nodes in the @cite{Emacs Manual}, you would write a
menu like this:@refill
@example
@group
@@menu
* Outlining: (emacs)Outline Mode. The major mode for
editing outlines.
* Rebinding: (emacs)Rebinding. How to redefine the
meaning of a key.
@@end menu
@end group
@end example
If you do not list the node name, but only name the file, then Info
presumes that you are referring to the `Top' node.@refill
The @file{dir} file that contains the main menu for Info has menu
entries that list only file names. These take you directly to the `Top'
nodes of each Info document. (@xref{Install an Info File}.)@refill
@need 700
For example:
@example
@group
* Info: (info). Documentation browsing system.
* Emacs: (emacs). The extensible, self-documenting
text editor.
@end group
@end example
@noindent
(The @file{dir} top level directory for the Info system is an Info file,
not a Texinfo file, but a menu entry looks the same in both types of
file.)@refill
Note that the GNU Emacs Texinfo mode menu updating commands only work
with nodes within the current buffer, so you cannot use them to create
menus that refer to other files. You must write such menus by hand.@refill
@node Cross References, Marking Text, Menus, Top
@comment node-name, next, previous, up
@chapter Cross References
@cindex Making cross references
@cindex Cross references
@cindex References
@dfn{Cross references} are used to refer the reader to other parts of the
same or different Texinfo files. In Texinfo, nodes are the
places to which cross references can refer.@refill
@menu
* References:: What cross references are for.
* Cross Reference Commands:: A summary of the different commands.
* Cross Reference Parts:: A cross reference has several parts.
* xref:: Begin a reference with `See' @dots{}
* Top Node Naming:: How to refer to the beginning of another file.
* ref:: A reference for the last part of a sentence.
* pxref:: How to write a parenthetical cross reference.
* inforef:: How to refer to an Info-only file.
@end menu
@node References, Cross Reference Commands, Cross References, Cross References
@ifinfo
@heading What References Are For
@end ifinfo
Often, but not always, a printed document should be designed so that
it can be read sequentially. People tire of flipping back and forth
to find information that should be presented to them as they need
it.@refill
However, in any document, some information will be too detailed for
the current context, or incidental to it; use cross references to
provide access to such information. Also, an on-line help system or a
reference manual is not like a novel; few read such documents in
sequence from beginning to end. Instead, people look up what they
need. For this reason, such creations should contain many cross
references to help readers find other information that they may not
have read.@refill
In a printed manual, a cross reference results in a page reference,
unless it is to another manual altogether, in which case the cross
reference names that manual.@refill
In Info, a cross reference results in an entry that you can follow using
the Info @samp{f} command. (@inforef{Help-Adv, Some advanced Info
commands, info}.)@refill
The various cross reference commands use nodes to define cross
reference locations. This is evident in Info, in which a cross
reference takes you to the specified node. @TeX{} also uses nodes to
define cross reference locations, but the action is less obvious. When
@TeX{} generates a @sc{dvi} file, it records nodes' page numbers and
uses the page numbers in making references. Thus, if you are writing
a manual that will only be printed, and will not be used on-line, you
must nonetheless write @code{@@node} lines to name the places to which
you make cross references.@refill
@need 800
@node Cross Reference Commands, Cross Reference Parts, References, Cross References
@comment node-name, next, previous, up
@section Different Cross Reference Commands
@cindex Different cross reference commands
There are four different cross reference commands:@refill
@table @code
@item @@xref
Used to start a sentence in the printed manual saying @w{`See @dots{}'}
or an Info cross-reference saying @samp{*Note @var{name}: @var{node}.}.
@item @@ref
Used within or, more often, at the end of a sentence; same as
@code{@@xref} for Info; produces just the reference in the printed
manual without a preceding `See'.@refill
@item @@pxref
Used within parentheses to make a reference that suits both an Info
file and a printed book. Starts with a lower case `see' within the
printed manual. (@samp{p} is for `parenthesis'.)@refill
@item @@inforef
Used to make a reference to an Info file for which there is no printed
manual.@refill
@end table
@noindent
(The @code{@@cite} command is used to make references to books and
manuals for which there is no corresponding Info file and, therefore,
no node to which to point. @xref{cite, , @code{@@cite}}.)@refill
@node Cross Reference Parts, xref, Cross Reference Commands, Cross References
@comment node-name, next, previous, up
@section Parts of a Cross Reference
@cindex Cross reference parts
@cindex Parts of a cross reference
A cross reference command requires only one argument, which is the
name of the node to which it refers. But a cross reference command
may contain up to four additional arguments. By using these
arguments, you can provide a cross reference name for Info, a topic
description or section title for the printed output, the name of a
different Info file, and the name of a different printed
manual.@refill
Here is a simple cross reference example:@refill
@example
@@xref@{Node name@}.
@end example
@noindent
which produces
@example
*Note Node name::.
@end example
@noindent
and
@quotation
See Section @var{nnn} [Node name], page @var{ppp}.
@end quotation
@need 700
Here is an example of a full five-part cross reference:@refill
@example
@group
@@xref@{Node name, Cross Reference Name, Particular Topic,
info-file-name, A Printed Manual@}, for details.
@end group
@end example
@noindent
which produces
@example
*Note Cross Reference Name: (info-file-name)Node name,
for details.
@end example
@noindent
in Info and
@quotation
See section ``Particular Topic'' in @i{A Printed Manual}, for details.
@end quotation
@noindent
in a printed book.
The five possible arguments for a cross reference are:@refill
@enumerate
@item
The node name (required). This is the node to which the
cross reference takes you. In a printed document, the location of the
node provides the page reference only for references within the same
document.@refill
@item
The cross reference name for the Info reference, if it is to be different
from the node name. If you include this argument, it argument becomes
the first part of the cross reference. It is usually omitted.@refill
@item
A topic description or section name. Often, this is the title of the
section. This is used as the name of the reference in the printed
manual. If omitted, the node name is used.@refill
@item
The name of the Info file in which the reference is located, if it is
different from the current file.@refill
@item
The name of a printed manual from a different Texinfo file.@refill
@end enumerate
The template for a full five argument cross reference looks like
this:@refill
@example
@group
@@xref@{@var{node-name}, @var{cross-reference-name}, @var{title-or-topic},
@var{info-file-name}, @var{printed-manual-title}@}.
@end group
@end example
Cross references with one, two, three, four, and five arguments are
described separately following the description of @code{@@xref}.@refill
Write a node name in a cross reference in exactly the same way as in
the @code{@@node} line, including the same capitalization; otherwise, the
formatters may not find the reference.@refill
You can write cross reference commands within a paragraph, but note
how Info and @TeX{} format the output of each of the various commands:
write @code{@@xref} at the beginning of a sentence; write
@code{@@pxref} only within parentheses, and so on.@refill
@node xref, Top Node Naming, Cross Reference Parts, Cross References
@comment node-name, next, previous, up
@section @code{@@xref}
@findex xref
@cindex Cross references using @code{@@xref}
@cindex References using @code{@@xref}
The @code{@@xref} command generates a cross reference for the
beginning of a sentence. The Info formatting commands convert it into
an Info cross reference, which the Info @samp{f} command can use to
bring you directly to another node. The @TeX{} typesetting commands
convert it into a page reference, or a reference to another book or
manual.@refill
@menu
* Reference Syntax:: What a reference looks like and requires.
* One Argument:: @code{@@xref} with one argument.
* Two Arguments:: @code{@@xref} with two arguments.
* Three Arguments:: @code{@@xref} with three arguments.
* Four and Five Arguments:: @code{@@xref} with four and five arguments.
@end menu
@node Reference Syntax, One Argument, xref, xref
@ifinfo
@subheading What a Reference Looks Like and Requires
@end ifinfo
Most often, an Info cross reference looks like this:@refill
@example
*Note @var{node-name}::.
@end example
@noindent
or like this
@example
*Note @var{cross-reference-name}: @var{node-name}.
@end example
@noindent
In @TeX{}, a cross reference looks like this:
@example
See Section @var{section-number} [@var{node-name}], page @var{page}.
@end example
@noindent
or like this
@example
See Section @var{section-number} [@var{title-or-topic}], page @var{page}.
@end example
The @code{@@xref} command does not generate a period or comma to end
the cross reference in either the Info file or the printed output.
You must write that period or comma yourself; otherwise, Info will not
recognize the end of the reference. (The @code{@@pxref} command works
differently. @xref{pxref, , @code{@@pxref}}.)@refill
@quotation
@strong{Please note:} A period or comma @strong{must} follow the closing
brace of an @code{@@xref}. It is required to terminate the cross
reference. This period or comma will appear in the output, both in
the Info file and in the printed manual.@refill
@end quotation
@code{@@xref} must refer to an Info node by name. Use @code{@@node}
to define the node (@pxref{Writing a Node}).@refill
@code{@@xref} is followed by several arguments inside braces, separated by
commas. Whitespace before and after these commas is ignored.@refill
A cross reference requires only the name of a node; but it may contain
up to four additional arguments. Each of these variations produces a
cross reference that looks somewhat different.@refill
@quotation
@strong{Please note:} Commas separate arguments in a cross reference;
avoid including them in the title or other part lest the formatters
mistake them for separators.@refill
@end quotation
@node One Argument, Two Arguments, Reference Syntax, xref
@subsection @code{@@xref} with One Argument
The simplest form of @code{@@xref} takes one argument, the name of
another node in the same Info file. The Info formatters produce
output that the Info readers can use to jump to the reference; @TeX{}
produces output that specifies the page and section number for you.@refill
@need 700
@noindent
For example,
@example
@@xref@{Tropical Storms@}.
@end example
@noindent
produces
@example
*Note Tropical Storms::.
@end example
@noindent
and
@quotation
See Section 3.1 [Tropical Storms], page 24.
@end quotation
@noindent
(Note that in the preceding example the closing brace is followed by a
period.)@refill
You can write a clause after the cross reference, like this:@refill
@example
@@xref@{Tropical Storms@}, for more info.
@end example
@noindent
which produces
@example
*Note Tropical Storms::, for more info.
@end example
@quotation
See Section 3.1 [Tropical Storms], page 24, for more info.
@end quotation
@noindent
(Note that in the preceding example the closing brace is followed by a
comma, and then by the clause, which is followed by a period.)@refill
@node Two Arguments, Three Arguments, One Argument, xref
@subsection @code{@@xref} with Two Arguments
With two arguments, the second is used as the name of the Info cross
reference, while the first is still the name of the node to which the
cross reference points.@refill
@need 750
@noindent
The template is like this:
@example
@@xref@{@var{node-name}, @var{cross-reference-name}@}.
@end example
@need 700
@noindent
For example,
@example
@@xref@{Electrical Effects, Lightning@}.
@end example
@noindent
produces:
@example
*Note Lightning: Electrical Effects.
@end example
@noindent
and
@quotation
See Section 5.2 [Electrical Effects], page 57.
@end quotation
@noindent
(Note that in the preceding example the closing brace is followed by a
period; and that the node name is printed, not the cross reference name.)@refill
You can write a clause after the cross reference, like this:@refill
@example
@@xref@{Electrical Effects, Lightning@}, for more info.
@end example
@noindent
which produces
@example
*Note Lightning: Electrical Effects, for more info.
@end example
@noindent
and
@quotation
See Section 5.2 [Electrical Effects], page 57, for more info.
@end quotation
@noindent
(Note that in the preceding example the closing brace is followed by a
comma, and then by the clause, which is followed by a period.)@refill
@node Three Arguments, Four and Five Arguments, Two Arguments, xref
@subsection @code{@@xref} with Three Arguments
A third argument replaces the node name in the @TeX{} output. The third
argument should be the name of the section in the printed output, or
else state the topic discussed by that section. Often, you will want to
use initial upper case letters so it will be easier to read when the
reference is printed. Use a third argument when the node name is
unsuitable because of syntax or meaning.@refill
Remember to avoid placing a comma within the title or topic section of
a cross reference, or within any other section. The formatters divide
cross references into arguments according to the commas; a comma
within a title or other section will divide it into two arguments. In
a reference, you need to write a title such as ``Clouds, Mist, and
Fog'' without the commas.@refill
Also, remember to write a comma or period after the closing brace of a
@code{@@xref} to terminate the cross reference. In the following
examples, a clause follows a terminating comma.@refill
@need 750
@noindent
The template is like this:
@example
@group
@@xref@{@var{node-name}, @var{cross-reference-name}, @var{title-or-topic}@}.
@end group
@end example
@need 700
@noindent
For example,
@example
@group
@@xref@{Electrical Effects, Lightning, Thunder and Lightning@},
for details.
@end group
@end example
@noindent
produces
@example
*Note Lightning: Electrical Effects, for details.
@end example
@noindent
and
@quotation
See Section 5.2 [Thunder and Lightning], page 57, for details.
@end quotation
If a third argument is given and the second one is empty, then the
third argument serves both. (Note how two commas, side by side, mark
the empty second argument.)@refill
@example
@group
@@xref@{Electrical Effects, , Thunder and Lightning@},
for details.
@end group
@end example
@noindent
produces
@example
*Note Thunder and Lightning: Electrical Effects, for details.
@end example
@noindent
and
@quotation
See Section 5.2 [Thunder and Lightning], page 57, for details.
@end quotation
As a practical matter, it is often best to write cross references with
just the first argument if the node name and the section title are the
same, and with the first and third arguments if the node name and title
are different.@refill
Here are several examples from @cite{The GAWK Manual}:@refill
@smallexample
@@xref@{Sample Program@}.
@@xref@{Glossary@}.
@@xref@{Case-sensitivity, ,Case-sensitivity in Matching@}.
@@xref@{Close Output, , Closing Output Files and Pipes@},
for more information.
@@xref@{Regexp, , Regular Expressions as Patterns@}.
@end smallexample
@node Four and Five Arguments, , Three Arguments, xref
@subsection @code{@@xref} with Four and Five Arguments
In a cross reference, a fourth argument specifies the name of another
Info file, different from the file in which the reference appears, and
a fifth argument specifies its title as a printed manual.@refill
Remember that a comma or period must follow the closing brace of an
@code{@@xref} command to terminate the cross reference. In the
following examples, a clause follows a terminating comma.@refill
@need 800
@noindent
The template is:
@example
@group
@@xref@{@var{node-name}, @var{cross-reference-name}, @var{title-or-topic},
@var{info-file-name}, @var{printed-manual-title}@}.
@end group
@end example
@need 700
@noindent
For example,
@example
@@xref@{Electrical Effects, Lightning, Thunder and Lightning,
weather, An Introduction to Meteorology@}, for details.
@end example
@noindent
produces
@example
*Note Lightning: (weather)Electrical Effects, for details.
@end example
@noindent
The name of the Info file is enclosed in parentheses and precedes
the name of the node.
@noindent
In a printed manual, the reference looks like this:@refill
@quotation
See section ``Thunder and Lightning'' in @i{An Introduction to
Meteorology}, for details.
@end quotation
@noindent
The title of the printed manual is typeset in italics; and the
reference lacks a page number since @TeX{} cannot know to which page a
reference refers when that reference is to another manual.@refill
Often, you will leave out the second argument when you use the long
version of @code{@@xref}. In this case, the third argument, the topic
description, will be used as the cross reference name in Info.@refill
@noindent
The template looks like this:
@example
@@xref@{@var{node-name}, , @var{title-or-topic}, @var{info-file-name},
@var{printed-manual-title}@}, for details.
@end example
@noindent
which produces
@example
*Note @var{title-or-topic}: (@var{info-file-name})@var{node-name}, for details.
@end example
@noindent
and
@quotation
See section @var{title-or-topic} in @var{printed-manual-title}, for details.
@end quotation
@need 700
@noindent
For example,
@example
@@xref@{Electrical Effects, , Thunder and Lightning,
weather, An Introduction to Meteorology@}, for details.
@end example
@noindent
produces
@example
@group
*Note Thunder and Lightning: (weather)Electrical Effects,
for details.
@end group
@end example
@noindent
and
@quotation
See section ``Thunder and Lightning'' in @i{An Introduction to
Meteorology}, for details.
@end quotation
On rare occasions, you may want to refer to another Info file that
is within a single printed manual---when multiple Texinfo files are
incorporated into the same @TeX{} run but make separate Info files.
In this case, you need to specify only the fourth argument, and not
the fifth.@refill
@node Top Node Naming, ref, xref, Cross References
@section Naming a `Top' Node
@cindex Naming a `Top' Node in references
@cindex @samp{@r{Top}} node naming for references
In a cross reference, you must always name a node. This means that in
order to refer to a whole manual, you must identify the `Top' node by
writing it as the first argument to the @code{@@xref} command. (This
is different from the way you write a menu entry; see @ref{Other Info
Files, , Referring to Other Info Files}.) At the same time, to
provide a meaningful section topic or title in the printed cross
reference (instead of the word `Top'), you must write an appropriate
entry for the third argument to the @code{@@xref} command.
@refill
@noindent
Thus, to make a cross reference to @cite{The GNU Make Manual},
write:@refill
@example
@@xref@{Top, , Overview, make, The GNU Make Manual@}.
@end example
@noindent
which produces
@example
*Note Overview: (make)Top.
@end example
@noindent
and
@quotation
See section ``Overview'' in @i{The GNU Make Manual}.
@end quotation
@noindent
In this example, @samp{Top} is the name of the first node, and
@samp{Overview} is the name of the first section of the manual.@refill
@node ref, pxref, Top Node Naming, Cross References
@comment node-name, next, previous, up
@section @code{@@ref}
@cindex Cross references using @code{@@ref}
@cindex References using @code{@@ref}
@findex ref
@code{@@ref} is nearly the same as @code{@@xref} except that it does
not generate a `See' in the printed output, just the reference itself.
This makes it useful as the last part of a sentence.@refill
@need 700
@noindent
For example,
@example
For more information, see @@ref@{Hurricanes@}.
@end example
@noindent
produces
@example
For more information, see *Note Hurricanes.
@end example
@noindent
and
@quotation
For more information, see Section 8.2 [Hurricanes], page 123.
@end quotation
The @code{@@ref} command sometimes leads writers to express themselves
in a manner that is suitable for a printed manual but looks awkward
in the Info format. Bear in mind that your audience will be using
both the printed and the Info format.@refill
@need 800
@noindent
For example,
@example
@group
Sea surges are described in @@ref@{Hurricanes@}.
@end group
@end example
@need 800
@noindent
produces
@quotation
Sea surges are described in Section 6.7 [Hurricanes], page 72.
@end quotation
@need 800
@noindent
in a printed document, and the following in Info:
@example
Sea surges are described in *Note Hurricanes::.
@end example
@quotation
@strong{Caution:} You @emph{must} write a period or comma immediately
after an @code{@@ref} command with two or more arguments. Otherwise,
Info will not find the end of the cross reference entry and its
attempt to follow the cross reference will fail. As a general rule,
you should write a period or comma after every @code{@@ref} command.
This looks best in both the printed and the Info output.@refill
@end quotation
@node pxref, inforef, ref, Cross References
@comment node-name, next, previous, up
@section @code{@@pxref}
@cindex Cross references using @code{@@pxref}
@cindex References using @code{@@pxref}
@findex pxref
The parenthetical reference command, @code{@@pxref}, is nearly the
same as @code{@@xref}, but you use it @emph{only} inside parentheses
and you do @emph{not} type a comma or period after the command's
closing brace. The command differs from @code{@@xref} in two
ways:@refill
@enumerate
@item
@TeX{} typesets the reference for the printed manual with a lower case
`see' rather than an upper case `See'.@refill
@item
The Info formatting commands automatically end the reference with a
closing colon or period.@refill
@end enumerate
Because one type of formatting automatically inserts closing
punctuation and the other does not, you should use @code{@@pxref}
@emph{only} inside parentheses as part of another sentence. Also, you
yourself should not insert punctuation after the reference, as you do
with @code{@@xref}.@refill
@code{@@pxref} is designed so that the output looks right and works
right between parentheses both in printed output and in an Info file.
In a printed manual, a closing comma or period should not follow a
cross reference within parentheses; such punctuation is wrong. But in
an Info file, suitable closing punctuation must follow the cross
reference so Info can recognize its end. @code{@@pxref} spares you
the need to use complicated methods to put a terminator into one form
of the output and not the other.@refill
@noindent
With one argument, a parenthetical cross reference looks like
this:@refill
@example
@dots{} storms cause flooding (@@pxref@{Hurricanes@}) @dots{}
@end example
@need 800
@noindent
which produces
@example
@group
@dots{} storms cause flooding (*Note Hurricanes::) @dots{}
@end group
@end example
@noindent
and
@quotation
@dots{} storms cause flooding (see Section 6.7 [Hurricanes], page 72) @dots{}
@end quotation
With two arguments, a parenthetical cross reference has this
template:@refill
@example
@dots{} (@@pxref@{@var{node-name}, @var{cross-reference-name}@}) @dots{}
@end example
@noindent
which produces
@example
@dots{} (*Note @var{cross-reference-name}: @var{node-name}.) @dots{}
@end example
@noindent
and
@need 1500
@quotation
@dots{} (see Section @var{nnn} [@var{node-name}], page @var{ppp}) @dots{}
@end quotation
@code{@@pxref} can be used with up to five arguments just like
@code{@@xref} (@pxref{xref, , @code{@@xref}}).@refill
@quotation
@strong{Please note:} Use @code{@@pxref} only as a parenthetical
reference. Do not try to use @code{@@pxref} as a clause in a sentence.
It will look bad in either the Info file, the printed output, or
both.@refill
Also, parenthetical cross references look best at the ends of sentences.
Although you may write them in the middle of a sentence, that location
breaks up the flow of text.@refill
@end quotation
@node inforef, , pxref, Cross References
@comment node-name, next, previous, up
@section @code{@@inforef}
@cindex Cross references using @code{@@inforef}
@cindex References using @code{@@inforef}
@findex inforef
@code{@@inforef} is used for cross references to Info files for which
there are no printed manuals. Even in a printed manual,
@code{@@inforef} generates a reference directing the user to look in
an Info file.@refill
The command takes either two or three arguments, in the following
order:@refill
@enumerate
@item
The node name.
@item
The cross reference name (optional).
@item
The Info file name.
@end enumerate
@noindent
Separate the arguments with commas, as with @code{@@xref}. Also, you
must terminate the reference with a comma or period after the
@samp{@}}, as you do with @code{@@xref}.@refill
@noindent
The template is:
@example
@@inforef@{@var{node-name}, @var{cross-reference-name}, @var{info-file-name}@},
@end example
@need 800
@noindent
Thus,
@example
@group
@@inforef@{Expert, Advanced Info commands, info@},
for more information.
@end group
@end example
@need 800
@noindent
produces
@example
@group
*Note Advanced Info commands: (info)Expert,
for more information.
@end group
@end example
@need 800
@noindent
and
@quotation
See Info file @file{info}, node @samp{Expert}, for more information.
@end quotation
@need 800
@noindent
Similarly,
@example
@group
@@inforef@{Expert, , info@}, for more information.
@end group
@end example
@need 800
@noindent
produces
@example
*Note (info)Expert::, for more information.
@end example
@need 800
@noindent
and
@quotation
See Info file @file{info}, node @samp{Expert}, for more information.
@end quotation
The converse of @code{@@inforef} is @code{@@cite}, which is used to
refer to printed works for which no Info form exists. @xref{cite, ,
@code{@@cite}}.@refill
@node Marking Text, Quotations and Examples, Cross References, Top
@comment node-name, next, previous, up
@chapter Marking Words and Phrases
@cindex Paragraph, marking text within
@cindex Marking words and phrases
@cindex Words and phrases, marking them
@cindex Marking text within a paragraph
In Texinfo, you can mark words and phrases in a variety of ways.
The Texinfo formatters use this information to determine how to
highlight the text.
You can specify, for example, whether a word or phrase is a
defining occurrence, a metasyntactic variable, or a symbol used in a
program. Also, you can emphasize text.@refill
@menu
* Indicating:: How to indicate definitions, files, etc.
* Emphasis:: How to emphasize text.
@end menu
@node Indicating, Emphasis, Marking Text, Marking Text
@comment node-name, next, previous, up
@section Indicating Definitions, Commands, etc.
@cindex Highlighting text
@cindex Indicating commands, definitions, etc.
Texinfo has commands for indicating just what kind of object a piece of
text refers to. For example, metasyntactic variables are marked by
@code{@@var}, and code by @code{@@code}. Since the pieces of text are
labelled by commands that tell what kind of object they are, it is easy
to change the way the Texinfo formatters prepare such text. (Texinfo is
an @emph{intentional} formatting language rather than a @emph{typesetting}
formatting language.)@refill
For example, in a printed manual,
code is usually illustrated in a typewriter font;
@code{@@code} tells @TeX{} to typeset this text in this font. But it
would be easy to change the way @TeX{} highlights code to use another
font, and this change would not effect how keystroke examples are
highlighted. If straight typesetting commands were used in the body
of the file and you wanted to make a change, you would need to check
every single occurrence to make sure that you were changing code and
not something else that should not be changed.@refill
@menu
* Useful Highlighting:: Highlighting provides useful information.
* code:: How to indicate code.
* kbd:: How to show keyboard input.
* key:: How to specify keys.
* samp:: How to show a literal sequence of characters.
* var:: How to indicate a metasyntactic variable.
* file:: How to indicate the name of a file.
* dfn:: How to specify a definition.
* cite:: How to refer to a book that is not in Info.
@end menu
@node Useful Highlighting, code, Indicating, Indicating
@ifinfo
@subheading Highlighting Commands are Useful
@end ifinfo
The highlighting commands can be used to generate useful information
from the file, such as lists of functions or file names. It is
possible, for example, to write a program in Emacs Lisp (or a keyboard
macro) to insert an index entry after every paragraph that contains
words or phrases marked by a specified command. You could do this to
construct an index of functions if you had not already made the
entries.@refill
The commands serve a variety of purposes:@refill
@table @code
@item @@code@{@var{sample-code}@}
Indicate text that is a literal example of a piece of a program.@refill
@item @@kbd@{@var{keyboard-characters}@}
Indicate keyboard input.@refill
@item @@key@{@var{key-name}@}
Indicate the conventional name for a key on a keyboard.@refill
@item @@samp@{@var{text}@}
Indicate text that is a literal example of a sequence of characters.@refill
@item @@var@{@var{metasyntactic-variable}@}
Indicate a metasyntactic variable.@refill
@item @@file@{@var{file-name}@}
Indicate the name of a file.@refill
@item @@dfn@{@var{term}@}
Indicate the introductory or defining use of a term.@refill
@item @@cite@{@var{reference}@}
Indicate the name of a book.@refill
@ignore
@item @@ctrl@{@var{ctrl-char}@}
Use for an @sc{ascii} control character.@refill
@end ignore
@end table
@node code, kbd, Useful Highlighting, Indicating
@comment node-name, next, previous, up
@subsection @code{@@code}@{@var{sample-code}@}
@findex code
Use the @code{@@code} command to indicate text that is a piece of a
program and which consists of entire syntactic tokens. Enclose the
text in braces.@refill
Thus, you should use @code{@@code} for an expression in a program, for
the name of a variable or function used in a program, or for a
keyword. Also, you should use @code{@@code} for the name of a
program, such as @code{diff}, that is a name used in the machine. (You
should write the name of a program in the ordinary text font if you
regard it as a new English word, such as `Emacs' or `Bison'.)@refill
Use @code{@@code} for environment variables such as @code{TEXINPUTS},
and other variables.@refill
Use @code{@@code} for command names in command languages that
resemble programming languages, such as Texinfo or the shell.
For example, @code{@@code} and @code{@@samp} are produced by writing
@samp{@@code@{@@@@code@}} and @samp{@@code@{@@@@samp@}} in the Texinfo
source, respectively.@refill
Note, however, that you should not use @code{@@code} for shell options
such as @samp{-c} when such options stand alone. (Use @code{@@samp}.)
Also, an entire shell command often looks better if written using
@code{@@samp} rather than @code{@@code}. In this case, the rule is to
choose the more pleasing format.@refill
It is incorrect to alter the case of a word inside an @code{@@code}
command when it appears at the beginning of a sentence. Most computer
languages are case sensitive. In C, for example, @code{Printf} is
different from the identifier @code{printf}, and most likely is a
misspelling of it. Even in languages which are not case sensitive, it
is confusing to a human reader to see identifiers spelled in different
ways. Pick one spelling and always use that. If you do not want to
start a sentence with a command written all in lower case, you should
rearrange the sentence.@refill
Do not use the @code{@@code} command for a string of characters shorter
than a syntactic token. If you are writing about @samp{TEXINPU}, which
is just a part of the name for the @code{TEXINPUTS} environment
variable, you should use @code{@@samp}.@refill
In particular, you should not use the @code{@@code} command when writing
about the characters used in a token; do not, for example, use
@code{@@code} when you are explaining what letters or printable symbols
can be used in the names of functions. (Use @code{@@samp}.) Also, you
should not use @code{@@code} to mark text that is considered input to
programs unless the input is written in a language that is like a
programming language. For example, you should not use @code{@@code} for
the keystroke commands of GNU Emacs (use @code{@@kbd} instead) although
you may use @code{@@code} for the names of the Emacs Lisp functions that
the keystroke commands invoke.@refill
In the printed manual, @code{@@code} causes @TeX{} to typeset the
argument in a typewriter face. In the Info file, it causes the Info
formatting commands to use single quotation marks around the text.
@need 700
For example,
@example
Use @@code@{diff@} to compare two files.
@end example
@noindent
produces this in the printed manual:@refill
@quotation
Use @code{diff} to compare two files.
@end quotation
@iftex
@noindent
and this in the Info file:@refill
@example
Use `diff' to compare two files.
@end example
@end iftex
@node kbd, key, code, Indicating
@comment node-name, next, previous, up
@subsection @code{@@kbd}@{@var{keyboard-characters}@}
@findex kbd
Use the @code{@@kbd} command for characters of input to be typed by
users. For example, to refer to the characters @kbd{M-a},
write@refill
@example
@@kbd@{M-a@}
@end example
@noindent
and to refer to the characters @kbd{M-x shell}, write@refill
@example
@@kbd@{M-x shell@}
@end example
The @code{@@kbd} command has the same effect as @code{@@code} in Info,
but may produce a different font in a printed manual.@refill
You can embed another @@-command inside the braces of an @code{@@kbd}
command. Here, for example, is the way to describe a command that
would be described more verbosely as ``press an @samp{r} and then
press the @key{RET} key'':@refill
@example
@@kbd@{r @@key@{RET@}@}
@end example
@noindent
This produces: @kbd{r @key{RET}}
You also use the @code{@@kbd} command if you are spelling out the letters
you type; for example:@refill
@example
To give the @@code@{logout@} command,
type the characters @@kbd@{l o g o u t @@key@{RET@}@}.
@end example
@noindent
This produces:
@quotation
To give the @code{logout} command,
type the characters @kbd{l o g o u t @key{RET}}.
@end quotation
(Also, this example shows that you can add spaces for clarity. If you
really want to mention a space character as one of the characters of
input, write @kbd{@@key@{SPC@}} for it.)@refill
@node key, samp, kbd, Indicating
@comment node-name, next, previous, up
@subsection @code{@@key}@{@var{key-name}@}
@findex key
Use the @code{@@key} command for the conventional name for a key on a
keyboard, as in:@refill
@example
@@key@{RET@}
@end example
You can use the @code{@@key} command within the argument of an
@code{@@kbd} command when the sequence of characters to be typed
includes one or more keys that are described by name.@refill
@need 700
For example, to produce @kbd{C-x @key{ESC}} you would type:@refill
@example
@@kbd@{C-x @@key@{ESC@}@}
@end example
@c bob: this next sentence looks weird, having a semi-colon followed by
@c a colon that ends the "sentence".. --mew
Here is a list of the recommended names for keys; they are all in
upper case:@refill
@cindex Recommended names for keys
@cindex Keys, recommended names
@cindex Names recommended for keys
@cindex Abbreviations for keys
@quotation
@table @t
@item SPC
Space
@item RET
Return
@item LFD
Linefeed
@item TAB
Tab
@item BS
Backspace
@item ESC
Escape
@item DEL
Delete
@item SFT
Shift
@item CTL
Control
@item META
Meta
@end table
@end quotation
There are subtleties to handling words like `meta' or `ctl' that are
names of shift keys. When mentioning a character in which the shift
key is used, such as @kbd{Meta-a}, use the @code{@@kbd} command alone;
do not use the @code{@@key} command; but when you are referring to the
shift key in isolation, use the @code{@@key} command. For example,
write @samp{@@kbd@{Meta-a@}} to produce @kbd{Meta-a} and
@samp{@@key@{META@}} to produce @key{META}. This is because
@kbd{Meta-a} refers to keys that you press on a keyboard, but
@key{META} refers to a key without implying that you press it. In
short, use @code{@@kbd} for what you do, and use @code{@@key} for what
you talk about: ``Press @code{@@kbd@{M-a@}} to move point to the
beginning of the sentence. The @code{@@key@{META@}} key is often in the
lower left of the keyboard.''@refill
@cindex META key
@node samp, var, key, Indicating
@comment node-name, next, previous, up
@subsection @code{@@samp}@{@var{text}@}
@findex samp
Use the @code{@@samp} command to indicate text that is a literal example
or `sample' of a sequence of characters in a file, string, pattern, etc.
Enclose the text in braces. The argument appears within single
quotation marks in both the Info file and the printed manual; in
addition, it is printed in a fixed-width font.@refill
@example
To match @@samp@{foo@} at the end of the line,
use the regexp @@samp@{foo$@}.
@end example
@noindent
produces
@quotation
To match @samp{foo} at the end of the line, use the regexp
@samp{foo$}.@refill
@end quotation
Any time you are referring to single characters, you should use
@code{@@samp} unless @code{@@kbd} is more appropriate. Use
@code{@@samp} for the names of command-line options. Also, you may use
@code{@@samp} for entire statements in C and for entire shell
commands---in this case, @code{@@samp} often looks better than
@code{@@code}. Basically, @code{@@samp} is a catchall for whatever is
not covered by @code{@@code}, @code{@@kbd}, or @code{@@key}.@refill
Only include punctuation marks within braces if they are part of the
string you are specifying. Write punctuation marks outside the braces
if those punctuation marks are part of the English text that surrounds
the string. In the following sentence, for example, the commas and
period are outside of the braces:@refill
@example
@group
In English, the vowels are @@samp@{a@}, @@samp@{e@},
@@samp@{i@}, @@samp@{o@}, @@samp@{u@}, and sometimes
@@samp@{y@}.
@end group
@end example
@noindent
This produces:
@quotation
In English, the vowels are @samp{a}, @samp{e},
@samp{i}, @samp{o}, @samp{u}, and sometimes
@samp{y}.
@end quotation
@node var, file, samp, Indicating
@comment node-name, next, previous, up
@subsection @code{@@var}@{@var{metasyntactic-variable}@}
@findex var
Use the @code{@@var} command to indicate metasyntactic variables. A
@dfn{metasyntactic variable} is something that stands for another piece of
text. For example, you should use a metasyntactic variable in the
documentation of a function to describe the arguments that are passed
to that function.@refill
Do not use @code{@@var} for the names of particular variables in
programming languages. These are specific names from a program, so
@code{@@code} is correct for them. For example, the Lisp variable
@code{texinfo-tex-command} is not a metasyntactic variable; it is
properly formatted using @code{@@code}.@refill
The effect of @code{@@var} in the Info file is to change the case of
the argument to all upper case; in the printed manual, to italicize it.
@need 700
For example,
@example
To delete file @@var@{filename@},
type @@code@{rm @@var@{filename@}@}.
@end example
@noindent
produces
@quotation
To delete file @var{filename}, type @code{rm @var{filename}}.
@end quotation
@noindent
(Note that @code{@@var} may appear inside @code{@@code},
@code{@@samp}, @code{@@file}, etc.)@refill
Write a metasyntactic variable all in lower case without spaces, and
use hyphens to make it more readable. Thus, the Texinfo source for
the illustration of how to begin a Texinfo manual looks like
this:@refill
@example
@group
\input texinfo
@@@@setfilename @@var@{info-file-name@}
@@@@settitle @@var@{name-of-manual@}
@end group
@end example
@noindent
This produces:
@example
@group
\input texinfo
@@setfilename @var{info-file-name}
@@settitle @var{name-of-manual}
@end group
@end example
In some documentation styles, metasyntactic variables are shown with
angle brackets, for example:@refill
@example
@dots{}, type rm
@end example
@noindent
However, that is not the style that Texinfo uses. (You can, of
course, modify the sources to @TeX{} and the Info formatting commands
to output the @code{<@dots{}>} format if you wish.)@refill
@node file, dfn, var, Indicating
@comment node-name, next, previous, up
@subsection @code{@@file}@{@var{file-name}@}
@findex file
Use the @code{@@file} command to indicate text that is the name of a
file, buffer, or directory, or is the name of a node in Info. You can
also use the command for file name suffixes. Do not use @code{@@file}
for symbols in a programming language; use @code{@@code}.
Currently, @code{@@file} is equivalent to @code{@@samp} in its effects.
For example,@refill
@example
The @@file@{.el@} files are in
the @@file@{/usr/local/emacs/lisp@} directory.
@end example
@noindent
produces
@quotation
The @file{.el} files are in
the @file{/usr/local/emacs/lisp} directory.
@end quotation
@node dfn, cite, file, Indicating
@comment node-name, next, previous, up
@subsection @code{@@dfn}@{@var{term}@}
@findex dfn
Use the @code{@@dfn} command to identify the introductory or defining
use of a technical term. Use the command only in passages whose
purpose is to introduce a term which will be used again or which the
reader ought to know. Mere passing mention of a term for the first
time does not deserve @code{@@dfn}. The command generates italics in
the printed manual, and double quotation marks in the Info file. For
example:@refill
@example
Getting rid of a file is called @@dfn@{deleting@} it.
@end example
@noindent
produces
@quotation
Getting rid of a file is called @dfn{deleting} it.
@end quotation
As a general rule, a sentence containing the defining occurrence of a
term should be a definition of the term. The sentence does not need
to say explicitly that it is a definition, but it should contain the
information of a definition---it should make the meaning clear.
@node cite, , dfn, Indicating
@comment node-name, next, previous, up
@subsection @code{@@cite}@{@var{reference}@}
@findex cite
Use the @code{@@cite} command for the name of a book that lacks a
companion Info file. The command produces italics in the printed
manual, and quotation marks in the Info file.@refill
(If a book is written in Texinfo, it is better to use a cross reference
command since a reader can easily follow such a reference in Info.
@xref{xref, , @code{@@xref}}.)@refill
@ignore
@c node ctrl, , cite, Indicating
@comment node-name, next, previous, up
@c subsection @code{@@ctrl}@{@var{ctrl-char}@}
@findex ctrl
The @code{@@ctrl} command is seldom used. It describes an @sc{ascii}
control character by inserting the actual character into the Info
file.
Usually, in Texinfo, you talk what you type as keyboard entry by
describing it with @code{@@kbd}: thus, @samp{@@kbd@{C-a@}} for
@kbd{C-a}. Use @code{@@kbd} in this way when talking about a control
character that is typed on the keyboard by the user. When talking
about a control character appearing in a file or a string, do not use
@code{@@kbd} since the control character is not typed. Also, do not
use @samp{C-} but spell out @code{control-}, as in @samp{control-a},
to make it easier for a reader to understand.@refill
@code{@@ctrl} is an idea from the beginnings of Texinfo which may not
really fit in to the scheme of things. But there may be times when
you want to use the command. The pattern is
@code{@@ctrl@{@var{ch}@}}, where @var{ch} is an @sc{ascii} character
whose control-equivalent is wanted. For example, to specify
@samp{control-f}, you would enter@refill
@example
@@ctrl@{f@}
@end example
@noindent
produces
@quotation
@ctrl{f}
@end quotation
In the Info file, this generates the specified control character, output
literally into the file. This is done so a user can copy the specified
control character (along with whatever else he or she wants) into another
Emacs buffer and use it. Since the `control-h',`control-i', and
`control-j' characters are formatting characters, they should not be
indicated with @code{@@ctrl}.@refill
In a printed manual, @code{@@ctrl} generates text to describe or
identify that control character: an uparrow followed by the character
@var{ch}.@refill
@end ignore
@node Emphasis, , Indicating, Marking Text
@comment node-name, next, previous, up
@section Emphasizing Text
@cindex Emphasizing text
Usually, Texinfo changes the font to mark words in the text according to
what category the words belong to; an example is the @code{@@code} command.
Most often, this is the best way to mark words.
However, sometimes you will want to emphasize text without indicating a
category. Texinfo has two commands to do this. Also, Texinfo has
several commands that specify the font in which @TeX{} will typeset
text. These commands have no affect on Info and only one of them,
the @code{@@r} command, has any regular use.@refill
@menu
* emph & strong:: How to emphasize text in Texinfo.
* Smallcaps:: How to use the small caps font.
* Fonts:: Various font commands for printed output.
* Customized Highlighting:: How to define highlighting commands.
@end menu
@node emph & strong, Smallcaps, Emphasis, Emphasis
@comment node-name, next, previous, up
@subsection @code{@@emph}@{@var{text}@} and @code{@@strong}@{@var{text}@}
@cindex Emphasizing text, font for
@findex emph
@findex strong
The @code{@@emph} and @code{@@strong} commands are for emphasis;
@code{@@strong} is stronger. In printed output, @code{@@emph}
produces @emph{italics} and @code{@@strong} produces
@strong{bold}.@refill
@need 800
For example,
@example
@group
@@quotation
@@strong@{Caution:@} @@code@{rm * .[^.]*@} removes @@emph@{all@}
files in the directory.
@@end quotation
@end group
@end example
@iftex
@noindent
produces the following in printed output:
@quotation
@strong{Caution}: @code{rm * .[^.]*} removes @emph{all}
files in the directory.
@end quotation
@noindent
and the following in Info:
@end iftex
@ifinfo
@noindent
produces:
@end ifinfo
@example
*Caution*: `rm * .[^.]*' removes *all*
files in the directory.
@end example
The @code{@@strong} command is seldom used except to mark what is, in
effect, a typographical element, such as the word `Caution' in the
preceding example.
In the Info file, both @code{@@emph} and @code{@@strong} put asterisks
around the text.@refill
@quotation
@strong{Caution:} Do not use @code{@@emph} or @code{@@strong} with the
word @samp{Note}; Info will mistake the combination for a cross
reference. Use a phrase such as @strong{Please note} or
@strong{Caution} instead.@refill
@end quotation
@node Smallcaps, Fonts, emph & strong, Emphasis
@subsection @code{@@sc}@{@var{text}@}: The Small Caps Font
@cindex Small caps font
@findex sc @r{(small caps font)}
@iftex
Use the @samp{@@sc} command to set text in the printed output in @sc{a
small caps font} and set text in the Info file in upper case letters.@refill
@end iftex
@ifinfo
Use the @samp{@@sc} command to set text in the printed output in a
small caps font and set text in the Info file in upper case letters.@refill
@end ifinfo
Write the text between braces in lower case, like this:@refill
@example
The @@sc@{acm@} and @@sc@{ieee@} are technical societies.
@end example
@noindent
This produces:
@display
The @sc{acm} and @sc{ieee} are technical societies.
@end display
@TeX{} typesets the small caps font in a manner that prevents the
letters from `jumping out at you on the page'. This makes small caps
text easier to read than text in all upper case. The Info formatting
commands set all small caps text in upper case.@refill
@ifinfo
If the text between the braces of an @code{@@sc} command is upper case,
@TeX{} typesets in full-size capitals. Use full-size capitals
sparingly.@refill
@end ifinfo
@iftex
If the text between the braces of an @code{@@sc} command is upper case,
@TeX{} typesets in @sc{FULL-SIZE CAPITALS}. Use full-size capitals
sparingly.@refill
@end iftex
You may also use the small caps font for a jargon word such as
@sc{ato} (a @sc{nasa} word meaning `abort to orbit').@refill
There are subtleties to using the small caps font with a jargon word
such as @sc{cdr}, a word used in Lisp programming. In this case, you
should use the small caps font when the word refers to the second and
subsequent elements of a list (the @sc{cdr} of the list), but you
should use @samp{@@code} when the word refers to the Lisp function of
the same spelling.@refill
@node Fonts, Customized Highlighting, Smallcaps, Emphasis
@comment node-name, next, previous, up
@subsection Fonts for Printing, Not Info
@cindex Fonts for printing, not for Info
@findex i @r{(italic font)}
@findex b @r{(bold font)}
@findex t @r{(typewriter font)}
@findex r @r{(Roman font)}
Texinfo provides four font commands that specify font changes in the
printed manual but have no effect in the Info file. @code{@@i}
requests @i{italic} font (in some versions of @TeX{}, a slanted font
is used), @code{@@b} requests @b{bold} face, @code{@@t} requests the
@t{fixed-width}, typewriter-style font used by @code{@@code}, and @code{@@r} requests a
@r{roman} font, which is the usual font in which text is printed. All
four commands apply to an argument that follows, surrounded by
braces.@refill
Only the @code{@@r} command has much use: in example programs, you
can use the @code{@@r} command to convert code comments from the
fixed-width font to a roman font. This looks better in printed
output.@refill
@need 700
For example,
@example
@group
@@lisp
(+ 2 2) ; @@r@{Add two plus two.@}
@@end lisp
@end group
@end example
@noindent
produces
@lisp
(+ 2 2) ; @r{Add two plus two.}
@end lisp
If possible, you should avoid using the other three font commands. If
you need to use one, it probably indicates a gap in the Texinfo
language.@refill
@node Customized Highlighting, , Fonts, Emphasis
@comment node-name, next, previous, up
@subsection Customized Highlighting
@findex @@definfoenclose
@cindex `Enclosure' command for Info
@cindex Highlighting, customized
@cindex Customized highlighting
You can use regular @TeX{} commands inside of @code{@@iftex} @dots{}
@code{@@end iftex} to create your own customized highlighting commands
for Texinfo. The easiest way to do this is to equate your customized
commands with pre-existing commands, such as those for italics. Such
new commands work only with @TeX{}.@refill
You can use the @code{@@definfoenclose} command inside of
@code{@@ifinfo} @dots{} @code{@@end ifinfo} to define commands for Info
with the same names as new commands for @TeX{}.
@code{@@definfoenclose} creates new commands for Info that mark text by
enclosing it in strings that precede and follow the text.
@footnote{Currently, @code{@@definfoenclose} works only with
@code{texinfo-format-buffer} and @code{texinfo-format-region}, not with
@code{makeinfo}.}@refill
Here is how to create a new @@-command called @code{@@phoo} that causes
@TeX{} to typeset its argument in italics and causes Info to display the
argument between @samp{//} and @samp{\\}.@refill
@need 1300
For @TeX{}, write the following to equate the @code{@@phoo} command with
the existing @code{@@i} italics command:@refill
@example
@group
@@iftex
@@global@@let@@phoo=@@i
@@end iftex
@end group
@end example
@noindent
This defines @code{@@phoo} as a command that causes @TeX{} to typeset
the argument to @code{@@phoo} in italics. @code{@@global@@let} tells
@TeX{} to equate the next argument with the argument that follows the
equals sign.
@need 1300
For Info, write the following to tell the Info formatters to enclose the
argument between @samp{//} and @samp{\\}:
@example
@group
@@ifinfo
@@definfoenclose phoo, //, \\
@@end ifinfo
@end group
@end example
@noindent
Write the @code{@@definfoenclose} command on a line and follow it with
three arguments separated by commas (commas are used as separators in an
@code{@@node} line in the same way).@refill
@itemize @bullet
@item
The first argument to @code{@@definfoenclose} is the @@-command name
@strong{without} the @samp{@@};
@item
the second argument is the Info start delimiter string; and,
@item
the third argument is the Info end delimiter string.
@end itemize
@noindent
The latter two arguments enclose the highlighted text in the Info file.
A delimiter string may contain spaces. Neither the start nor end
delimiter is required. However, if you do not provide a start
delimiter, you must follow the command name with two commas in a row;
otherwise, the Info formatting commands will misinterpret the end
delimiter string as a start delimiter string.@refill
After you have defined @code{@@phoo} both for @TeX{} and for Info, you
can then write @code{@@phoo@{bar@}} to see @samp{//bar\\}
in Info and see
@ifinfo
@samp{bar} in italics in printed output.
@end ifinfo
@iftex
@i{bar} in italics in printed output.
@end iftex
Note that each definition applies to its own formatter: one for @TeX{},
the other for Info.
@need 1200
Here is another example:
@example
@group
@@ifinfo
@@definfoenclose headword, , :
@@end ifinfo
@@iftex
@@global@@let@@headword=@@b
@@end iftex
@end group
@end example
@noindent
This defines @code{@@headword} as an Info formatting command that
inserts nothing before and a colon after the argument and as a @TeX{}
formatting command to typeset its argument in bold.
@node Quotations and Examples, Lists and Tables, Marking Text, Top
@comment node-name, next, previous, up
@chapter Quotations and Examples
Quotations and examples are blocks of text consisting of one or more
whole paragraphs that are set off from the bulk of the text and
treated differently. They are usually indented.@refill
In Texinfo, you always begin a quotation or example by writing an
@@-command at the beginning of a line by itself, and end it by writing
an @code{@@end} command that is also at the beginning of a line by
itself. For instance, you begin an example by writing @code{@@example}
by itself at the beginning of a line and end the example by writing
@code{@@end example} on a line by itself, at the beginning of that
line.@refill
@findex end
@menu
* Block Enclosing Commands:: Use different constructs for
different purposes.
* quotation:: How to write a quotation.
* example:: How to write an example in a fixed-width font.
* noindent:: How to prevent paragraph indentation.
* Lisp Example:: How to illustrate Lisp code.
* smallexample & smalllisp:: Forms for the @code{@@smallbook} option.
* display:: How to write an example in the current font.
* format:: How to write an example that does not narrow
the margins.
* exdent:: How to undo the indentation of a line.
* flushleft & flushright:: How to push text flushleft or flushright.
* cartouche:: How to draw cartouches around examples.
@end menu
@node Block Enclosing Commands, quotation, Quotations and Examples, Quotations and Examples
@section The Block Enclosing Commands
Here are commands for quotations and examples:@refill
@table @code
@item @@quotation
Indicate text that is quoted. The text is filled, indented, and
printed in a roman font by default.@refill
@item @@example
Illustrate code, commands, and the like. The text is printed
in a fixed-width font, and indented but not filled.@refill
@item @@lisp
Illustrate Lisp code. The text is printed in a fixed-width font,
and indented but not filled.@refill
@item @@smallexample
Illustrate code, commands, and the like. Similar to
@code{@@example}, except that in @TeX{} this command typesets text in
a smaller font for the smaller @code{@@smallbook} format than for the
8.5 by 11 inch format.@refill
@item @@smalllisp
Illustrate Lisp code. Similar to @code{@@lisp}, except that
in @TeX{} this command typesets text in a smaller font for the smaller
@code{@@smallbook} format than for the 8.5 by 11 inch format.@refill
@item @@display
Display illustrative text. The text is indented but not filled, and
no font is specified (so, by default, the font is roman).@refill
@item @@format
Print illustrative text. The text is not indented and not filled
and no font is specified (so, by default, the font is roman).@refill
@end table
The @code{@@exdent} command is used within the above constructs to
undo the indentation of a line.
The @code{@@flushleft} and @code{@@flushright} commands are used to line
up the left or right margins of unfilled text.@refill
The @code{@@noindent} command may be used after one of the above
constructs to prevent the following text from being indented as a new
paragraph.@refill
You can use the @code{@@cartouche} command within one of the above
constructs to highlight the example or quotation by drawing a box with
rounded corners around it. (The @code{@@cartouche} command affects
only the printed manual; it has no effect in the Info file; see
@ref{cartouche, , Drawing Cartouches Around Examples}.)@refill
@node quotation, example, Block Enclosing Commands, Quotations and Examples
@comment node-name, next, previous, up
@section @code{@@quotation}
@cindex Quotations
@findex quotation
The text of a quotation is
processed normally except that:@refill
@itemize @bullet
@item
the margins are closer to the center of the page, so the whole of the
quotation is indented;@refill
@item
the first lines of paragraphs are indented no more than other
lines;@refill
@item
in the printed output, interparagraph spacing is reduced.@refill
@end itemize
@quotation
This is an example of text written between an @code{@@quotation}
command and an @code{@@end quotation} command. An @code{@@quotation}
command is most often used to indicate text that is excerpted from
another (real or hypothetical) printed work.@refill
@end quotation
Write an @code{@@quotation} command as text on a line by itself. This
line will disappear from the output. Mark the end of the quotation
with a line beginning with and containing only @code{@@end quotation}.
The @code{@@end quotation} line will likewise disappear from the
output. Thus, the following,@refill
@example
@@quotation
This is
a foo.
@@end quotation
@end example
@noindent
produces
@quotation
This is a foo.
@end quotation
@node example, noindent, quotation, Quotations and Examples
@comment node-name, next, previous, up
@section @code{@@example}
@cindex Examples, formatting them
@cindex Formatting examples
@findex example
The @code{@@example} command is used to indicate an example that is
not part of the running text, such as computer input or output.@refill
@example
@group
This is an example of text written between an
@code{@@example} command
and an @code{@@end example} command.
The text is indented but not filled.
@end group
@group
In the printed manual, the text is typeset in a
fixed-width font, and extra spaces and blank lines are
significant. In the Info file, an analogous result is
obtained by indenting each line with five spaces.
@end group
@end example
Write an @code{@@example} command at the beginning of a line by itself.
This line will disappear from the output. Mark the end of the example
with an @code{@@end example} command, also written at the beginning of a
line by itself. The @code{@@end example} will disappear from the
output.@refill
@need 700
For example,
@example
@@example
mv foo bar
@@end example
@end example
@noindent
produces
@example
mv foo bar
@end example
Since the lines containing @code{@@example} and @code{@@end example}
will disappear, you should put a blank line before the
@code{@@example} and another blank line after the @code{@@end
example}. (Remember that blank lines between the beginning
@code{@@example} and the ending @code{@@end example} will appear in
the output.)@refill
@quotation
@strong{Caution:} Do not use tabs in the lines of an example (or anywhere
else in Texinfo, for that matter)! @TeX{} treats tabs as single
spaces, and that is not what they look like. This is a problem with
@TeX{}. (If necessary, in Emacs, you can use @kbd{M-x untabify} to
convert tabs in a region to multiple spaces.)@refill
@end quotation
Examples are often, logically speaking, ``in the middle'' of a
paragraph, and the text continues after an example should not be
indented. The @code{@@noindent} command prevents a piece of text from
being indented as if it were a new paragraph.
@ifinfo
(@xref{noindent}.)
@end ifinfo
(The @code{@@code} command is used for examples of code that are
embedded within sentences, not set off from preceding and following
text. @xref{code, , @code{@@code}}.)
@node noindent, Lisp Example, example, Quotations and Examples
@comment node-name, next, previous, up
@section @code{@@noindent}
@findex noindent
An example or other inclusion can break a paragraph into segments.
Ordinarily, the formatters indent text that follows an example as a new
paragraph. However, you can prevent this by writing @code{@@noindent}
at the beginning of a line by itself preceding the continuation
text.@refill
@need 1500
For example:
@example
@group
@@example
This is an example
@@end example
@@noindent
This line is not indented. As you can see, the
beginning of the line is fully flush left with the line
that follows after it. (This whole example is between
@@code@{@@@@display@} and @@code@{@@@@end display@}.)
@end group
@end example
@noindent
produces
@display
@example
This is an example
@end example
@tex
% Remove extra vskip; this is a kludge to counter the effect of display
\vskip-3.5\baselineskip
@end tex
@noindent
This line is not indented. As you can see, the
beginning of the line is fully flush left with the line
that follows after it. (This whole example is between
@code{@@display} and @code{@@end display}.)
@end display
To adjust the number of blank lines properly in the Info file output,
remember that the line containing @code{@@noindent} does not generate a
blank line, and neither does the @code{@@end example} line.@refill
In the Texinfo source file for this manual, each line that says
`produces' is preceded by a line containing @code{@@noindent}.@refill
Do not put braces after an @code{@@noindent} command; they are not
necessary, since @code{@@noindent} is a command used outside of
paragraphs (@pxref{Command Syntax}).@refill
@node Lisp Example, smallexample & smalllisp, noindent, Quotations and Examples
@comment node-name, next, previous, up
@section @code{@@lisp}
@cindex Lisp example
@findex lisp
The @code{@@lisp} command is used for Lisp code. It is synonymous
with the @code{@@example} command.
@lisp
This is an example of text written between an
@code{@@lisp} command and an @code{@@end lisp} command.
@end lisp
Use @code{@@lisp} instead of @code{@@example} so as to preserve
information regarding the nature of the example. This is useful, for
example, if you write a function that evaluates only and all the Lisp
code in a Texinfo file. Then you can use the Texinfo file as a Lisp
library.@footnote{It would be straightforward to extend Texinfo to
work in a similar fashion for C, @sc{fortran}, or other languages.}@refill
Mark the end of @code{@@lisp} with @code{@@end lisp} on a line by
itself.@refill
@node smallexample & smalllisp, display, Lisp Example, Quotations and Examples
@comment node-name, next, previous, up
@section @code{@@smallexample} and @code{@@smalllisp}
@cindex Small book example
@cindex Example for a small book
@cindex Lisp example for a small book
@findex smallexample
@findex smalllisp
In addition to the regular @code{@@example} and @code{@@lisp} commands,
Texinfo has two other ``example-style'' commands. These are the
@code{@@smallexample} and @code{@@smalllisp} commands. Both these
commands are designed for use with the @code{@@smallbook} command that
causes @TeX{} to produce a printed manual in a 7 by 9.25 inch format
rather than the regular 8.5 by 11 inch format.@refill
In @TeX{}, the @code{@@smallexample} and @code{@@smalllisp} commands
typeset text in a smaller font for the smaller @code{@@smallbook}
format than for the 8.5 by 11 inch format. Consequently, many examples
containing long lines fit in a narrower, @code{@@smallbook} page
without needing to be shortened. Both commands typeset in the normal
font size when you format for the 8.5 by 11 inch size; indeed,
in this situation, the @code{@@smallexample} and @code{@@smalllisp}
commands are defined to be the @code{@@example} and @code{@@lisp}
commands.@refill
In Info, the @code{@@smallexample} and @code{@@smalllisp} commands are
equivalent to the @code{@@example} and @code{@@lisp} commands, and work
exactly the same.@refill
Mark the end of @code{@@smallexample} or @code{@@smalllisp} with
@code{@@end smallexample} or @code{@@end smalllisp},
respectively.@refill
@iftex
Here is an example written in the small font used by the
@code{@@smallexample} and @code{@@smalllisp} commands:
@ifclear smallbook
@display
@tex
% Remove extra vskip; this is a kludge to counter the effect of display
\vskip-3\baselineskip
{\ninett
\dots{} to make sure that you have the freedom to
distribute copies of free software (and charge for
this service if you wish), that you receive source
code or can get it if you want it, that you can
change the software or use pieces of it in new free
programs; and that you know you can do these things.}
@end tex
@end display
@end ifclear
@end iftex
@ifset smallbook
@iftex
@smallexample
This is an example of text written between @code{@@smallexample} and
@code{@@end smallexample}. In Info and in an 8.5 by 11 inch manual,
this text appears in its normal size; but in a 7 by 9.25 inch manual,
this text appears in a smaller font.
@end smallexample
@end iftex
@end ifset
@ifinfo
@smallexample
This is an example of text written between @code{@@smallexample} and
@code{@@end smallexample}. In Info and in an 8.5 by 11 inch manual,
this text appears in its normal size; but in a 7 by 9.25 inch manual,
this text appears in a smaller font.
@end smallexample
@end ifinfo
The @code{@@smallexample} and @code{@@smalllisp} commands make it
easier to prepare smaller format manuals without forcing you to edit
examples by hand to fit them onto narrower pages.@refill
As a general rule, a printed document looks better if you write all the
examples in a chapter consistently in @code{@@example} or in
@code{@@smallexample}. Only occasionally should you mix the two
formats.@refill
@xref{smallbook, , Printing ``Small'' Books}, for more information
about the @code{@@smallbook} command.@refill
@node display, format, smallexample & smalllisp, Quotations and Examples
@comment node-name, next, previous, up
@section @code{@@display}
@cindex Display formatting
@findex display
The @code{@@display} command begins a kind of example. It is like the
@code{@@example} command
except that, in
a printed manual, @code{@@display} does not select the fixed-width
font. In fact, it does not specify the font at all, so that the text
appears in the same font it would have appeared in without the
@code{@@display} command.@refill
@display
This is an example of text written between an @code{@@display} command
and an @code{@@end display} command. The @code{@@display} command
indents the text, but does not fill it.
@end display
@node format, exdent, display, Quotations and Examples
@comment node-name, next, previous, up
@section @code{@@format}
@findex format
The @code{@@format} command is similar to @code{@@example} except
that, in the printed manual, @code{@@format} does not select the
fixed-width font and does not narrow the margins.@refill
@format
This is an example of text written between an @code{@@format} command
and an @code{@@end format} command. As you can see
from this example,
the @code{@@format} command does not fill the text.
@end format
@node exdent, flushleft & flushright, format, Quotations and Examples
@section @code{@@exdent}: Undoing a Line's Indentation
@cindex Indentation undoing
@findex exdent
The @code{@@exdent} command removes any indentation a line might have.
The command is written at the beginning of a line and applies only to
the text that follows the command that is on the same line. Do not use
braces around the text. In a printed manual, the text on an
@code{@@exdent} line is printed in the roman font.@refill
@code{@@exdent} is usually used within examples. Thus,@refill
@example
@group
@@example
This line follows an @@@@example command.
@@exdent This line is exdented.
This line follows the exdented line.
The @@@@end example comes on the next line.
@@end group
@end group
@end example
@noindent
produces
@example
@group
This line follows an @@example command.
@exdent This line is exdented.
This line follows the exdented line.
The @@end example comes on the next line.
@end group
@end example
In practice, the @code{@@exdent} command is rarely used.
Usually, you un-indent text by ending the example and
returning the page to its normal width.@refill
@node flushleft & flushright, cartouche, exdent, Quotations and Examples
@section @code{@@flushleft} and @code{@@flushright}
@findex flushleft
@findex flushright
The @code{@@flushleft} and @code{@@flushright} commands line up the
ends of lines on the left and right margins of a page,
but do not fill the text. The commands are written on lines of their
own, without braces. The @code{@@flushleft} and @code{@@flushright}
commands are ended by @code{@@end flushleft} and @code{@@end
flushright} commands on lines of their own.@refill
@need 1500
For example,
@example
@group
@@flushleft
This text is
written flushleft.
@@end flushleft
@end group
@end example
@noindent
produces
@quotation
@flushleft
This text is
written flushleft.
@end flushleft
@end quotation
Flushright produces the type of indentation often used in the return
address of letters.@refill
@need 1500
@noindent
For example,
@example
@group
@@flushright
Here is an example of text written
flushright. The @@code@{@@flushright@} command
right justifies every line but leaves the
left end ragged.
@@end flushright
@end group
@end example
@noindent
produces
@flushright
Here is an example of text written
flushright. The @code{@@flushright} command
right justifies every line but leaves the
left end ragged.
@end flushright
@node cartouche, , flushleft & flushright, Quotations and Examples
@section Drawing Cartouches Around Examples
@findex cartouche
@cindex Box with rounded corners
In a printed manual, the @code{@@cartouche} command draws a box with
rounded corners around its contents. You can use this command to
further highlight an example or quotation. For instance, you could
write a manual in which one type of example is surrounded by a cartouche
for emphasis.@refill
The @code{@@cartouche} command affects only the printed manual; it has
no effect in the Info file.@refill
@need 1500
For example,
@example
@group
@@example
@@cartouche
% pwd
/usr/local/lib/emacs/info
@@end cartouche
@@end example
@end group
@end example
@noindent
surrounds the two-line example with a box with rounded corners, in the
printed manual.
@iftex
In a printed manual, the example looks like this:@refill
@example
@group
@cartouche
% pwd
/usr/local/lib/emacs/info
@end cartouche
@end group
@end example
@end iftex
@node Lists and Tables, Indices, Quotations and Examples, Top
@comment node-name, next, previous, up
@chapter Making Lists and Tables
@cindex Making lists and tables
@cindex Lists and tables, making them
@cindex Tables and lists, making them
Texinfo has several ways of making lists and two-column tables. Lists can
be bulleted or numbered, while two-column tables can highlight the items in
the first column.@refill
@menu
* Introducing Lists:: Texinfo formats lists for you.
* itemize:: How to construct a simple list.
* enumerate:: How to construct a numbered list.
* Two-column Tables:: How to construct a two-column table.
@end menu
@ifinfo
@node Introducing Lists, itemize, Lists and Tables, Lists and Tables
@heading Introducing Lists
@end ifinfo
Texinfo automatically indents the text in lists or tables, and numbers
an enumerated list. This last feature is useful if you modify the
list, since you do not need to renumber it yourself.@refill
Numbered lists and tables begin with the appropriate @@-command at the
beginning of a line, and end with the corresponding @code{@@end}
command on a line by itself. The table and itemized-list commands
also require that you write formatting information on the same line as
the beginning @@-command.@refill
Begin an enumerated list, for example, with an @code{@@enumerate}
command and end the list with an @code{@@end enumerate} command.
Begin an itemized list with an @code{@@itemize} command, followed on
the same line by a formatting command such as @code{@@bullet}, and end
the list with an @code{@@end itemize} command.@refill
@findex end
Precede each element of a list with an @code{@@item} or @code{@@itemx}
command.@refill
@sp 1
@noindent
Here is an itemized list of the different kinds of table and lists:@refill
@itemize @bullet
@item
Itemized lists with and without bullets.
@item
Enumerated lists, using numbers or letters.
@item
Two-column tables with highlighting.
@end itemize
@sp 1
@noindent
Here is an enumerated list with the same items:@refill
@enumerate
@item
Itemized lists with and without bullets.
@item
Enumerated lists, using numbers or letters.
@item
Two-column tables with highlighting.
@end enumerate
@sp 1
@noindent
And here is a two-column table with the same items and their
@w{@@-commands}:@refill
@table @code
@item @@itemize
Itemized lists with and without bullets.
@item @@enumerate
Enumerated lists, using numbers or letters.
@item @@table
@itemx @@ftable
@itemx @@vtable
Two-column tables with highlighting.
@end table
@node itemize, enumerate, Introducing Lists, Lists and Tables
@comment node-name, next, previous, up
@section Making an Itemized List
@cindex Itemization
@findex itemize
The @code{@@itemize} command produces sequences of indented
paragraphs, with a bullet or other mark inside the left margin
at the beginning of each paragraph for which such a mark is desired.@refill
Begin an itemized list by writing @code{@@itemize} at the beginning of
a line. Follow the command, on the same line, with a character or a
Texinfo command that generates a mark. Usually, you will write
@code{@@bullet} after @code{@@itemize}, but you can use
@code{@@minus}, or any character or any special symbol that results in
a single character in the Info file. (When you write @code{@@bullet}
or @code{@@minus} after an @code{@@itemize} command, you may omit the
@samp{@{@}}.)@refill
Write the text of the indented paragraphs themselves after the
@code{@@itemize}, up to another line that says @code{@@end
itemize}.@refill
Before each paragraph for which a mark in the margin is desired, write
a line that says just @code{@@item}. Do not write any other text on this
line.@refill
@findex item
Usually, you should put a blank line before an @code{@@item}. This
puts a blank line in the Info file. (@TeX{} inserts the proper
interline whitespace in either case.) Except when the entries are
very brief, these blank lines make the list look better.@refill
Here is an example of the use of @code{@@itemize}, followed by the
output it produces. Note that @code{@@bullet} produces an @samp{*} in
Info and a round dot in @TeX{}.@refill
@example
@group
@@itemize @@bullet
@@item
Some text for foo.
@@item
Some text
for bar.
@@end itemize
@end group
@end example
@noindent
This produces:
@quotation
@itemize @bullet
@item
Some text for foo.
@item
Some text
for bar.
@end itemize
@end quotation
Itemized lists may be embedded within other itemized lists. Here is a
list marked with dashes embedded in a list marked with bullets:@refill
@example
@group
@@itemize @@bullet
@@item
First item.
@@itemize @@minus
@@item
Inner item.
@@item
Second inner item.
@@end itemize
@@item
Second outer item.
@@end itemize
@end group
@end example
@noindent
This produces:
@quotation
@itemize @bullet
@item
First item.
@itemize @minus
@item
Inner item.
@item
Second inner item.
@end itemize
@item
Second outer item.
@end itemize
@end quotation
@node enumerate, Two-column Tables, itemize, Lists and Tables
@comment node-name, next, previous, up
@section Making a Numbered or Lettered List
@cindex Enumeration
@findex enumerate
@code{@@enumerate} is like @code{@@itemize} except that the marks in
the left margin contain successive integers or letters.
(@xref{itemize, , @code{@@itemize}}.)@refill
Write the @code{@@enumerate} command at the beginning of a line.
The command does not require an argument, but accepts either a number or
a letter as an option.
Without an argument, @code{@@enumerate} starts the list
with the number 1. With a numeric argument, such as 3,
the command starts the list with that number.
With an upper or lower case letter, such as @kbd{a} or @kbd{A},
the command starts the list with that letter.@refill
Write the text of the enumerated list in the same way you write an
itemized list: put @code{@@item} on a line of its own before the start of
each paragraph that you want enumerated. Do not write any other text on
the line beginning with @code{@@item}.@refill
You should put a blank line between entries in the list.
This generally makes it easier to read the Info file.@refill
@need 1500
Here is an example of @code{@@enumerate} without an argument:@refill
@example
@group
@@enumerate
@@item
Underlying causes.
@@item
Proximate causes.
@@end enumerate
@end group
@end example
@noindent
This produces:
@enumerate
@item
Underlying causes.
@item
Proximate causes.
@end enumerate
@sp 1
Here is an example with an argument of @kbd{3}:@refill
@sp 1
@example
@group
@@enumerate 3
@@item
Predisposing causes.
@@item
Precipitating causes.
@@item
Perpetuating causes.
@@end enumerate
@end group
@end example
@noindent
This produces:
@enumerate 3
@item
Predisposing causes.
@item
Precipitating causes.
@item
Perpetuating causes.
@end enumerate
@sp 1
Here is a brief summary of the alternatives. The summary is constructed
using @code{@@enumerate} with an argument of @kbd{a}.@refill
@sp 1
@enumerate a
@item
@code{@@enumerate}
Without an argument, produce a numbered list, starting with the number
1.@refill
@item
@code{@@enumerate @var{positive-integer}}
With a (positive) numeric argument, start a numbered list with that
number. You can use this to continue a list that you interrupted with
other text.@refill
@item
@code{@@enumerate @var{upper-case-letter}}
With an upper case letter as argument, start a list
in which each item is marked
by a letter, beginning with that upper case letter.@refill
@item
@code{@@enumerate @var{lower-case-letter}}
With a lower case letter as argument, start a list
in which each item is marked by
a letter, beginning with that lower case letter.@refill
@end enumerate
You can also nest enumerated lists, as in an outline.@refill
@node Two-column Tables, , enumerate, Lists and Tables
@comment node-name, next, previous, up
@section Making a Two-column Table
@cindex Tables, making two-column
@findex table
@code{@@table} is similar to @code{@@itemize}, but the command allows
you to specify a name or heading line for each item. (@xref{itemize,
, @code{@@itemize}}.) The @code{@@table} command is used to produce
two-column tables, and is especially useful for glossaries and
explanatory exhibits.@refill
@menu
* table:: How to construct a two-column table.
* ftable vtable:: How to construct a two-column table
with automatic indexing.
* itemx:: How to put more entries in the first column.
@end menu
@ifinfo
@node table, ftable vtable, Two-column Tables, Two-column Tables
@subheading Using the @code{@@table} Command
Use the @code{@@table} command to produce two-column tables.@refill
@end ifinfo
Write the @code{@@table} command at the beginning of a line and follow
it on the same line with an argument that is a Texinfo command such as
@code{@@code}, @code{@@samp}, @code{@@var}, or @code{@@kbd}.
Although these commands are usually followed by arguments in braces,
in this case you use the command name without an argument because
@code{@@item} will supply the argument. This command will be applied
to the text that goes into the first column of each item and
determines how it will be highlighted. For example, @code{@@samp}
will cause the text in the first column to be highlighted with an
@code{@@samp} command.@refill
You may also choose to use the @code{@@asis} command as an argument to
@code{@@table}. @code{@@asis} is a command that does nothing; if you use this
command after @code{@@table}, @TeX{} and the Info formatting commands
output the first column entries without added highlighting (`as
is').@refill
(The @code{@@table} command may work with other commands besides those
listed here. However, you can only use commands
that normally take arguments in braces.)@refill
Begin each table entry with an @code{@@item} command at the beginning
of a line. Write the first column text on the same line as the
@code{@@item} command. Write the second column text on the line
following the @code{@@item} line and on subsequent lines. (You do not
need to type anything for an empty second column entry.) You may
write as many lines of supporting text as you wish, even several
paragraphs. But only text on the same line as the @code{@@item} will
be placed in the first column.@refill
@findex item
Normally, you should put a blank line before an @code{@@item} line.
This puts a blank like in the Info file. Except when the entries are
very brief, a blank line looks better.@refill
@need 1500
The following table, for example, highlights the text in the first
column with an @code{@@samp} command:@refill
@example
@group
@@table @@samp
@@item foo
This is the text for
@@samp@{foo@}.
@@item bar
Text for @@samp@{bar@}.
@@end table
@end group
@end example
@noindent
This produces:
@table @samp
@item foo
This is the text for
@samp{foo}.
@item bar
Text for @samp{bar}.
@end table
If you want to list two or more named items with a single block of
text, use the @code{@@itemx} command. (@xref{itemx, ,
@code{@@itemx}}.)@refill
@node ftable vtable, itemx, table, Two-column Tables
@comment node-name, next, previous, up
@subsection @code{@@ftable} and @code{@@vtable}
@cindex Tables with indexes
@cindex Indexing table entries automatically
@findex ftable
@findex vtable
The @code{@@ftable} and @code{@@vtable} commands are the same as the
@code{@@table} command except that @code{@@ftable} automatically enters
each of the items in the first column of the table into the index of
functions and @code{@@vtable} automatically enters each of the items in
the first column of the table into the index of variables. This
simplifies the task of creating indices. Only the items on the same
line as the @code{@@item} commands are indexed, and they are indexed in
exactly the form that they appear on that line. @xref{Indices, ,
Creating Indices}, for more information about indices.@refill
Begin a two-column table using @code{@@ftable} or @code{@@vtable} by
writing the @@-command at the beginning of a line, followed on the same
line by an argument that is a Texinfo command such as @code{@@code},
exactly as you would for an @code{@@table} command; and end the table
with an @code{@@end ftable} or @code{@@end vtable} command on a line by
itself.
@node itemx, , ftable vtable, Two-column Tables
@comment node-name, next, previous, up
@subsection @code{@@itemx}
@cindex Two named items for @code{@@table}
@findex itemx
Use the @code{@@itemx} command inside a table when you have two or
more first column entries for the same item, each of which should
appear on a line of its own. Use @code{@@itemx} for all but the first
entry. The @code{@@itemx} command works exactly like @code{@@item}
except that it does not generate extra vertical space above the first
column text.@refill
@need 1000
For example,
@example
@group
@@table @@code
@@item upcase
@@itemx downcase
These two functions accept a character or a string as
argument, and return the corresponding upper case (lower
case) character or string.
@@end table
@end group
@end example
@noindent
This produces:
@table @code
@item upcase
@itemx downcase
These two functions accept a character or a string as
argument, and return the corresponding upper case (lower
case) character or string.@refill
@end table
@noindent
(Note also that this example illustrates multi-line supporting text in
a two-column table.)@refill
@node Indices, Insertions, Lists and Tables, Top
@comment node-name, next, previous, up
@chapter Creating Indices
@cindex Indices
@cindex Creating indices
Using Texinfo, you can generate indices without having to sort and
collate entries manually. In an index, the entries are listed in
alphabetical order, together with information on how to find the
discussion of each entry. In a printed manual, this information
consists of page numbers. In an Info file, this information is a menu
entry leading to the first node referenced.@refill
Texinfo provides several predefined kinds of index: an index
for functions, an index for variables, an index for concepts, and so
on. You can combine indices or use them for other than their
canonical purpose. If you wish, you can define your own indices.@refill
@menu
* Index Entries:: Choose different words for index entries.
* Predefined Indices:: Use different indices for different kinds
of entry.
* Indexing Commands:: How to make an index entry.
* Combining Indices:: How to combine indices.
* New Indices:: How to define your own indices.
@end menu
@node Index Entries, Predefined Indices, Indices, Indices
@comment node-name, next, previous, up
@section Making Index Entries
@cindex Index entries, making
@cindex Entries, making index
When you are making index entries, it is good practice to think of the
different ways people may look for something. Different people
@emph{do not} think of the same words when they look something up. A
helpful index will have items indexed under all the different words
that people may use. For example, one reader may think it obvious that
the two-letter names for indices should be listed under ``Indices,
two-letter names'', since the word ``Index'' is the general concept.
But another reader may remember the specific concept of two-letter
names and search for the entry listed as ``Two letter names for
indices''. A good index will have both entries and will help both
readers.@refill
Like typesetting, the construction of an index is a highly skilled,
professional art, the subtleties of which are not appreciated until you
need to do it yourself.@refill
@xref{Printing Indices & Menus}, for information about printing an index
at the end of a book or creating an index menu in an Info file.@refill
@node Predefined Indices, Indexing Commands, Index Entries, Indices
@comment node-name, next, previous, up
@section Predefined Indices
Texinfo provides six predefined indices:@refill
@itemize @bullet
@item
A @dfn{concept index} listing concepts that are discussed.@refill
@item
A @dfn{function index} listing functions (such as entry points of
libraries).@refill
@item
A @dfn{variables index} listing variables (such as global variables
of libraries).@refill
@item
A @dfn{keystroke index} listing keyboard commands.@refill
@item
A @dfn{program index} listing names of programs.@refill
@item
A @dfn{data type index} listing data types (such as structures defined in
header files).@refill
@end itemize
@noindent
Not every manual needs all of these, and most manuals use two or three
of them. This manual has two indices: a
concept index and an @@-command index (that is actually the function
index but is called a command index in the chapter heading). Two or
more indices can be combined into one using the @code{@@synindex} or
@code{@@syncodeindex} commands. @xref{Combining Indices}.@refill
@node Indexing Commands, Combining Indices, Predefined Indices, Indices
@comment node-name, next, previous, up
@section Defining the Entries of an Index
@cindex Defining indexing entries
@cindex Index entries
@cindex Entries for an index
@cindex Specifying index entries
@cindex Creating index entries
The data to make an index come from many individual indexing commands
scattered throughout the Texinfo source file. Each command says to add
one entry to a particular index; after formatting, the index will give
the current page number or node name as the reference.@refill
An index entry consists of an indexing command at the beginning of a
line followed, on the rest of the line, by the entry.@refill
For example, this section begins with the following five entries for
the concept index:@refill
@example
@@cindex Defining indexing entries
@@cindex Index entries
@@cindex Entries for an index
@@cindex Specifying index entries
@@cindex Creating index entries
@end example
Each predefined index has its own indexing command---@code{@@cindex}
for the concept index, @code{@@findex} for the function index, and so
on.@refill
@cindex Writing index entries
@cindex Index entry writing
Concept index entries consist of text. The best way to write an index
is to choose entries that are terse yet clear. If you can do this,
the index often looks better if the entries are not capitalized, but
written just as they would appear in the middle of a sentence.
(Capitalize proper names and acronyms that always call for upper case
letters.) This is the case convention we use in most GNU manuals'
indices.
If you don't see how to make an entry terse yet clear, make it longer
and clear---not terse and confusing. If many of the entries are several
words long, the index may look better if you use a different convention:
to capitalize the first word of each entry. But do not capitalize a
case-sensitive name such as a C or Lisp function name or a shell
command; that would be a spelling error.
Whichever case convention you use, please use it consistently!
@ignore
Concept index entries consist of English text. The usual convention
is to capitalize the first word of each such index entry, unless that
word is the name of a function, variable, or other such entity that
should not be capitalized. However, if your concept index entries are
consistently short (one or two words each) it may look better for each
regular entry to start with a lower case letter, aside from proper
names and acronyms that always call for upper case letters. Whichever
convention you adapt, please be consistent!
@end ignore
Entries in indices other than the concept index are symbol names in
programming languages, or program names; these names are usually
case-sensitive, so use upper and lower case as required for them.
By default, entries for a concept index are printed in a small roman
font and entries for the other indices are printed in a small
@code{@@code} font. You may change the way part of an entry is
printed with the usual Texinfo commands, such as @code{@@file} for
file names and @code{@@emph} for emphasis (@pxref{Marking
Text}).@refill
@cindex Index font types
@cindex Predefined indexing commands
@cindex Indexing commands, predefined
The six indexing commands for predefined indices are:
@table @code
@item @@cindex @var{concept}
@findex cindex
Make an entry in the concept index for @var{concept}.@refill
@item @@findex @var{function}
@findex findex
Make an entry in the function index for @var{function}.@refill
@item @@vindex @var{variable}
@findex vindex
Make an entry in the variable index for @var{variable}.@refill
@item @@kindex @var{keystroke}
@findex kindex
Make an entry in the key index for @var{keystroke}.@refill
@item @@pindex @var{program}
@findex pindex
Make an entry in the program index for @var{program}.@refill
@item @@tindex @var{data type}
@findex tindex
Make an entry in the data type index for @var{data type}.@refill
@end table
@quotation
@strong{Caution:} Do not use a colon in an index entry. In Info, a
colon separates the menu entry name from the node name. An extra
colon confuses Info.
@xref{Menu Parts, , The Parts of a Menu},
for more information about the structure of a menu entry.@refill
@end quotation
If you write several identical index entries in different places in a
Texinfo file, the index in the printed manual will list all the pages to
which those entries refer. However, the index in the Info file will
list @strong{only} the node that references the @strong{first} of those
index entries. Therefore, it is best to write indices in which each
entry refers to only one place in the Texinfo file. Fortunately, this
constraint is a feature rather than a loss since it means that the index
will be easy to use. Otherwise, you could create an index that lists
several pages for one entry and your reader would not know to which page
to turn. If you have two identical entries for one topic, change the
topics slightly, or qualify them to indicate the difference.@refill
You are not actually required to use the predefined indices for their
canonical purposes. For example, suppose you wish to index some C
preprocessor macros. You could put them in the function index along
with actual functions, just by writing @code{@@findex} commands for
them; then, when you print the ``Function Index'' as an unnumbered
chapter, you could give it the title `Function and Macro Index' and
all will be consistent for the reader. Or you could put the macros in
with the data types by writing @code{@@tindex} commands for them, and
give that index a suitable title so the reader will understand.
(@xref{Printing Indices & Menus}.)@refill
@node Combining Indices, New Indices, Indexing Commands, Indices
@comment node-name, next, previous, up
@section Combining Indices
@cindex Combining indices
@cindex Indices, combining them
Sometimes you will want to combine two disparate indices such as functions
and concepts, perhaps because you have few enough of one of them that
a separate index for them would look silly.@refill
You could put functions into the concept index by writing
@code{@@cindex} commands for them instead of @code{@@findex} commands,
and produce a consistent manual by printing the concept index with the
title `Function and Concept Index' and not printing the `Function
Index' at all; but this is not a robust procedure. It works only if
your document is never included as part of another
document that is designed to have a separate function index; if your
document were to be included with such a document, the functions from
your document and those from the other would not end up together.
Also, to make your function names appear in the right font in the
concept index, you would need to enclose every one of them between
the braces of @code{@@code}.@refill
@menu
* syncodeindex:: How to merge two indices, using @code{@@code}
font for the merged-from index.
* synindex:: How to merge two indices, using the
default font of the merged-to index.
@end menu
@node syncodeindex, synindex, Combining Indices, Combining Indices
@subsection @code{@@syncodeindex}
@findex syncodeindex
When you want to combine functions and concepts into one index, you
should index the functions with @code{@@findex} and index the concepts
with @code{@@cindex}, and use the @code{@@syncodeindex} command to
redirect the function index entries into the concept index.@refill
@findex syncodeindex
The @code{@@syncodeindex} command takes two arguments; they are the name
of the index to redirect, and the name of the index to redirect it to.
The template looks like this:@refill
@example
@@syncodeindex @var{from} @var{to}
@end example
@cindex Predefined names for indices
@cindex Two letter names for indices
@cindex Indices, two letter names
@cindex Names for indices
For this purpose, the indices are given two-letter names:@refill
@table @samp
@item cp
concept index
@item fn
function index
@item vr
variable index
@item ky
key index
@item pg
program index
@item tp
data type index
@end table
Write an @code{@@syncodeindex} command before or shortly after the
end-of-header line at the beginning of a Texinfo file. For example,
to merge a function index with a concept index, write the
following:@refill
@example
@@syncodeindex fn cp
@end example
@noindent
This will cause all entries designated for the function index to merge
in with the concept index instead.@refill
To merge both a variables index and a function index into a concept
index, write the following:@refill
@example
@group
@@syncodeindex vr cp
@@syncodeindex fn cp
@end group
@end example
@cindex Fonts for indices
The @code{@@syncodeindex} command puts all the entries from the `from'
index (the redirected index) into the @code{@@code} font, overriding
whatever default font is used by the index to which the entries are
now directed. This way, if you direct function names from a function
index into a concept index, all the function names are printed in the
@code{@@code} font as you would expect.@refill
@node synindex, , syncodeindex, Combining Indices
@subsection @code{@@synindex}
@findex synindex
The @code{@@synindex} command is nearly the same as the
@code{@@syncodeindex} command, except that it does not put the
`from' index entries into the @code{@@code} font; rather it puts
them in the roman font. Thus, you use @code{@@synindex} when you
merge a concept index into a function index.@refill
@xref{Printing Indices & Menus}, for information about printing an index
at the end of a book or creating an index menu in an Info file.@refill
@node New Indices, , Combining Indices, Indices
@section Defining New Indices
@cindex Defining new indices
@cindex Indices, defining new
@cindex New index defining
@findex defindex
@findex defcodeindex
In addition to the predefined indices, you may use the
@code{@@defindex} and @code{@@defcodeindex} commands to define new
indices. These commands create new indexing @@-commands with which
you mark index entries. The @code{@@defindex }command is used like
this:@refill
@example
@@defindex @var{name}
@end example
The name of an index should be a two letter word, such as @samp{au}.
For example:@refill
@example
@@defindex au
@end example
This defines a new index, called the @samp{au} index. At the same
time, it creates a new indexing command, @code{@@auindex}, that you
can use to make index entries. Use the new indexing command just as
you would use a predefined indexing command.@refill
For example, here is a section heading followed by a concept index
entry and two @samp{au} index entries.@refill
@example
@@section Cognitive Semantics
@@cindex kinesthetic image schemas
@@auindex Johnson, Mark
@@auindex Lakoff, George
@end example
@noindent
(Evidently, @samp{au} serves here as an abbreviation for ``author''.)
Texinfo constructs the new indexing command by concatenating the name
of the index with @samp{index}; thus, defining an @samp{au} index
leads to the automatic creation of an @code{@@auindex} command.@refill
Use the @code{@@printindex} command to print the index, as you do with
the predefined indices. For example:@refill
@example
@group
@@node Author Index, Subject Index, , Top
@@unnumbered Author Index
@@printindex au
@end group
@end example
The @code{@@defcodeindex} is like the @code{@@defindex} command, except
that, in the printed output, it prints entries in an @code{@@code} font
instead of a roman font. Thus, it parallels the @code{@@findex} command
rather than the @code{@@cindex} command.@refill
You should define new indices within or right after the end-of-header
line of a Texinfo file, before any @code{@@synindex} or
@code{@@syncodeindex} commands (@pxref{Header}).@refill
@node Insertions, Glyphs, Indices, Top
@comment node-name, next, previous, up
@chapter Special Insertions
@cindex Inserting special characters and symbols
@cindex Special insertions
Texinfo provides several commands for formatting dimensions, for
inserting single characters that have special meaning in Texinfo, such
as braces, and for inserting special graphic symbols that do not
correspond to characters, such as dots and bullets.@refill
@iftex
These are:
@itemize @bullet
@item
Braces, @samp{@@} and periods.
@item
Format a dimension, such as @samp{12@dmn{pt}}.
@item
Dots and bullets.
@item
The @TeX{} logo and the copyright symbol.
@item
A minus sign.
@end itemize
@end iftex
@menu
* Braces Atsigns Periods:: How to insert braces, @samp{@@} and periods.
* dmn:: How to format a dimension.
* Dots Bullets:: How to insert dots and bullets.
* TeX and copyright:: How to insert the @TeX{} logo
and the copyright symbol.
* minus:: How to insert a minus sign.
* math:: How to format a mathematical expression.
@end menu
@node Braces Atsigns Periods, dmn, Insertions, Insertions
@comment node-name, next, previous, up
@section Inserting @samp{@@}, Braces, and Periods
@cindex Inserting @@, braces, and periods
@cindex Braces, inserting
@cindex Periods, inserting
@cindex Single characters, commands to insert
@cindex Commands to insert single characters
@samp{@@} and curly braces are special characters in Texinfo. To
insert these characters so they appear in text, you must put an @samp{@@} in front
of these characters to prevent Texinfo from misinterpreting them.@refill
Periods are also special. Depending on whether the period is inside
or at the end of a sentence, less or more space is inserted after a
period in a typeset manual. Since it is not always possible for
Texinfo to determine when a period ends a sentence and when it is used
in an abbreviation, special commands are needed in some circumstances.
(Usually, Texinfo can guess how to handle periods, so you do not need
to use the special commands; you just enter a period as you would if
you were using a typewriter, which means you put two spaces after the
period, question mark, or exclamation mark that ends a
sentence.)@refill
Do not put braces after any of these commands; they are not
necessary.@refill
@menu
* Inserting An Atsign::
* Inserting Braces:: How to insert @samp{@{} and @samp{@}}
* Controlling Spacing:: How to insert the right amount of space
after punctuation within a sentence.
@end menu
@node Inserting An Atsign, Inserting Braces, Braces Atsigns Periods, Braces Atsigns Periods
@comment node-name, next, previous, up
@subsection Inserting @samp{@@} with @@@@
@findex @@ @r{(single @samp{@@})}
@code{@@@@} stands for a single @samp{@@} in either printed or Info
output.@refill
Do not put braces after an @code{@@@@} command.@refill
@node Inserting Braces, Controlling Spacing, Inserting An Atsign, Braces Atsigns Periods
@comment node-name, next, previous, up
@subsection Inserting @samp{@{} and @samp{@}}with @@@{ and @@@}
@findex @{ @r{(single @samp{@{})}
@findex @} @r{(single @samp{@}})}
@code{@@@{} stands for a single @samp{@{} in either printed or Info
output.@refill
@code{@@@}} stands for a single @samp{@}} in either printed or Info
output.@refill
Do not put braces after either an @code{@@@{} or an @code{@@@}}
command.@refill
@node Controlling Spacing, , Inserting Braces, Braces Atsigns Periods
@comment node-name, next, previous, up
@subsection Spacing After Colons and Periods
@findex : @r{(suppress widening)}
Use the @code{@@:}@: command after a period, question mark,
exclamation mark, or colon that should not be followed by extra space.
For example, use @code{@@:}@: after periods that end abbreviations
which are not at the ends of sentences. @code{@@:}@: has no effect on
the Info file output.@refill
@need 700
For example,
@example
The s.o.p.@@: has three parts @dots{}
The s.o.p. has three parts @dots{}
@end example
@noindent
@ifinfo
produces
@end ifinfo
@iftex
produces the following. If you look carefully at this printed output,
you will see a little more whitespace after @samp{s.o.p.} in the second
line.@refill
@end iftex
@quotation
The s.o.p.@: has three parts @dots{}@*
The s.o.p. has three parts @dots{}
@end quotation
@noindent
@kbd{@@:} has no effect on the Info output. (@samp{s.o.p} is an acronym
for ``Standard Operating Procedure''.)
@findex . @r{(true end of sentence)}
Use @code{@@.}@: instead of a period at the end of a sentence that
ends with a single capital letter. Otherwise, @TeX{} will think the
letter is an abbreviation and will not insert the correct
end-of-sentence spacing. Here is an example:@refill
@example
Give it to M.I.B. and to M.E.W@@. Also, give it to R.J.C@@.
Give it to M.I.B. and to M.E.W. Also, give it to R.J.C.
@end example
@noindent
@ifinfo
produces
@end ifinfo
@iftex
produces the following. If you look carefully at this printed output,
you will see a little more whitespace after the @samp{W} in the first
line.@refill
@end iftex
@quotation
Give it to M.I.B. and to M.E.W@. Also, give it to R.J.C@.@*
Give it to M.I.B. and to M.E.W. Also, give it to R.J.C.
@end quotation
In the Info file output, @code{@@.}@: is equivalent to a simple
@samp{.}.@refill
The meanings of @code{@@:}@: and @code{@@.}@: in Texinfo are designed
to work well with the Emacs sentence motion commands. This made it
necessary for them to be incompatible with some other formatting
systems that use @@-commands.@refill
Do not put braces after either an @code{@@:} or an @code{@@.} command.@refill
@node dmn, Dots Bullets, Braces Atsigns Periods, Insertions
@section @code{@@dmn}@{@var{dimension}@}: Format a Dimension
@cindex Thin space between number, dimension
@cindex Dimension formatting
@cindex Format a dimension
@findex dmn
At times, you may want to write @samp{12@dmn{pt}} or
@samp{8.5@dmn{in}} with little or no space between the number and the
abbreviation for the dimension. You can use the @code{@@dmn} command
to do this. On seeing the command, @TeX{} inserts just enough space
for proper typesetting; the Info formatting commands insert no space
at all, since the Info file does not require it.@refill
To use the @code{@@dmn} command, write the number and then follow it
immediately, with no intervening space, by @code{@@dmn}, and then by
the dimension within braces.@refill
@need 700
@noindent
For example,
@example
A4 paper is 8.27@@dmn@{in@} wide.
@end example
@noindent
produces
@quotation
A4 paper is 8.27@dmn{in} wide.
@end quotation
Not everyone uses this style. Instead of writing
@w{@samp{8.27@@dmn@{in@}}} in the Texinfo file, you may write
@w{@samp{8.27 in.}} or @w{@samp{8.27 inches}}. (In these cases, the
formatters may insert a line break between the number and the
dimension. Also, if you write a period after an abbreviation within a
sentence, you should write @samp{@@:} after the period to prevent
@TeX{} from inserting extra whitespace. @xref{Controlling Spacing, ,
Spacing After Colons and Periods}.)@refill
@node Dots Bullets, TeX and copyright, dmn, Insertions
@comment node-name, next, previous, up
@section Inserting Ellipsis, Dots, and Bullets
@cindex Dots, inserting
@cindex Bullets, inserting
@cindex Ellipsis, inserting
@cindex Inserting ellipsis
@cindex Inserting dots
@cindex Special typesetting commands
@cindex Typesetting commands for dots, etc.
An @dfn{ellipsis} (a line of dots) is not typeset as a string of
periods, so a special command is used for ellipsis in Texinfo. The
@code{@@bullet} command is special, too. Each of these commands is
followed by a pair of braces, @samp{@{@}}, without any whitespace
between the name of the command and the braces. (You need to use braces
with these commands because you can use them next to other text; without
the braces, the formatters would be confused. @xref{Command Syntax, ,
@@-Command Syntax}, for further information.)@refill
@menu
* dots:: How to insert dots @dots{}
* bullet:: How to insert a bullet.
@end menu
@node dots, bullet, Dots Bullets, Dots Bullets
@comment node-name, next, previous, up
@subsection @code{@@dots}@{@}
@findex dots
@cindex Inserting dots
@cindex Dots, inserting
Use the @code{@@dots@{@}} command to generate an ellipsis, which is
three dots in a row, appropriately spaced, like this: `@dots{}'. Do
not simply write three periods in the input file; that would work for
the Info file output, but would produce the wrong amount of space
between the periods in the printed manual.@refill
Similarly, the @code{@@enddots@{@}} command helps you correctly set an
end-of-sentence ellipsis (four dots).
@iftex
Here is an ellipsis: @dots{}
Here are three periods in a row: ...
In printed output, the three periods in a row are closer together than
the dots in the ellipsis.
@end iftex
@node bullet, , dots, Dots Bullets
@comment node-name, next, previous, up
@subsection @code{@@bullet}@{@}
@findex bullet
Use the @code{@@bullet@{@}} command to generate a large round dot, or
the closest possible thing to one. In Info, an asterisk is used.@refill
Here is a bullet: @bullet{}
When you use @code{@@bullet} in @code{@@itemize}, you do not need to
type the braces, because @code{@@itemize} supplies them.
(@xref{itemize, , @code{@@itemize}}.)@refill
@node TeX and copyright, minus, Dots Bullets, Insertions
@comment node-name, next, previous, up
@section Inserting @TeX{} and the Copyright Symbol
The logo `@TeX{}' is typeset in a special fashion and it needs an
@@-command. The copyright symbol, `@copyright{}', is also special.
Each of these commands is followed by a pair of braces, @samp{@{@}},
without any whitespace between the name of the command and the
braces.@refill
@menu
* tex:: How to insert the @TeX{} logo.
* copyright symbol:: How to use @code{@@copyright}@{@}.
@end menu
@node tex, copyright symbol, TeX and copyright, TeX and copyright
@comment node-name, next, previous, up
@subsection @code{@@TeX}@{@}
@findex tex (command)
Use the @code{@@TeX@{@}} command to generate `@TeX{}'. In a printed
manual, this is a special logo that is different from three ordinary
letters. In Info, it just looks like @samp{TeX}. The
@code{@@TeX@{@}} command is unique among Texinfo commands in that the
@key{T} and the @key{X} are in upper case.@refill
@node copyright symbol, , tex, TeX and copyright
@comment node-name, next, previous, up
@subsection @code{@@copyright}@{@}
@findex copyright
Use the @code{@@copyright@{@}} command to generate `@copyright{}'. In
a printed manual, this is a @samp{c} inside a circle, and in Info,
this is @samp{(C)}.@refill
@node minus, math, TeX and copyright, Insertions
@section @code{@@minus}@{@}: Inserting a Minus Sign
@findex minus
Use the @code{@@minus@{@}} command to generate a minus sign. In a
fixed-width font, this is a single hyphen, but in a proportional font,
the symbol is the customary length for a minus sign---a little longer
than a hyphen.@refill
You can compare the two forms:
@display
@samp{@minus{}} is a minus sign generated with @samp{@@minus@{@}},
`-' is a hyphen generated with the character @samp{-}.
@end display
@noindent
In the fixed-width font used by Info, @code{@@minus@{@}} is the same
as a hyphen.@refill
You should not use @code{@@minus@{@}} inside @code{@@code} or
@code{@@example} because the width distinction is not made in the
fixed-width font they use.@refill
When you use @code{@@minus} to specify the mark beginning each entry in
an itemized list, you do not need to type the braces
(@pxref{itemize, , @code{@@itemize}}.)@refill
@node math, , minus, Insertions
@comment node-name, next, previous, up
@section @code{@@math}: Inserting Mathematical Expressions
@findex math
@cindex Mathematical expressions
You can write a short mathematical expression with the @code{@@math}
command. Write the mathematical expression between braces, like this:
@example
@@math@{(a + b)(a + b) = a^2 + 2ab + b^2@}
@end example
@iftex
@need 1000
@noindent
This produces the following in @TeX{}:
@display
@math{(a + b)(a + b) = a^2 + 2ab + b^2}
@end display
@noindent
and the following in Info:
@end iftex
@ifinfo
@noindent
This produces the following in Info:
@end ifinfo
@example
(a + b)(a + b) = a^2 + 2ab + b^2
@end example
The @code{@@math} command has no effect on the Info output. Currently,
it has limited effect on typeset output. However, this may change since
@TeX{} itself is designed for mathematical typesetting and does a
splendid job.
Certainly, for complex mathematical expressions, you could use @TeX{}
directly. @xref{Using Ordinary TeX Commands, , Using Ordinary @TeX{}
Commands}. When you use @TeX{} directly, remember to write the
mathematical expression between one or two @samp{$} (dollar-signs) as
appropriate.
@node Glyphs, Breaks, Insertions, Top
@comment node-name, next, previous, up
@chapter Glyphs for Examples
@cindex Glyphs
In Texinfo, code is often illustrated in examples that are delimited
by @code{@@example} and @code{@@end example}, or by @code{@@lisp} and
@code{@@end lisp}. In such examples, you can indicate the results of
evaluation or an expansion using @samp{@result{}} or
@samp{@expansion{}}. Likewise, there are commands to insert glyphs
to indicate
printed output, error messages, equivalence of expressions, and the
location of point.@refill
The glyph-insertion commands do not need to be used within an example, but
most often they are. Every glyph-insertion command is followed by a pair of
left- and right-hand braces.@refill
@menu
* Glyphs Summary::
* result:: How to show the result of expression.
* expansion:: How to indicate an expansion.
* Print Glyph:: How to indicate printed output.
* Error Glyph:: How to indicate an error message.
* Equivalence:: How to indicate equivalence.
* Point Glyph:: How to indicate the location of point.
@end menu
@node Glyphs Summary, result, Glyphs, Glyphs
@ifinfo
@heading Glyphs Summary
Here are the different glyph commands:@refill
@end ifinfo
@table @asis
@item @result{}
@code{@@result@{@}} points to the result of an expression.@refill
@item @expansion{}
@code{@@expansion@{@}} shows the results of a macro expansion.@refill
@item @print{}
@code{@@print@{@}} indicates printed output.@refill
@item @error{}
@code{@@error@{@}} indicates that the following text is an error
message.@refill
@item @equiv{}
@code{@@equiv@{@}} indicates the exact equivalence of two forms.@refill
@item @point{}
@code{@@point@{@}} shows the location of point.@refill
@end table
@node result, expansion, Glyphs Summary, Glyphs
@section @result{}: Indicating Evaluation
@cindex Result of an expression
@cindex Indicating evaluation
@cindex Evaluation glyph
@cindex Value of an expression, indicating
Use the @code{@@result@{@}} command to indicate the result of
evaluating an expression.@refill
@iftex
The @code{@@result@{@}} command is displayed as @samp{=>} in Info and
as @samp{@result{}} in the printed output.
@end iftex
@ifinfo
The @code{@@result@{@}} command is displayed as @samp{@result{}} in Info
and as a double stemmed arrow in the printed output.@refill
@end ifinfo
Thus, the following,
@lisp
(cdr '(1 2 3))
@result{} (2 3)
@end lisp
@noindent
may be read as ``@code{(cdr '(1 2 3))} evaluates to @code{(2 3)}''.
@node expansion, Print Glyph, result, Glyphs
@section @expansion{}: Indicating an Expansion
@cindex Expansion, indicating it
When an expression is a macro call, it expands into a new expression.
You can indicate the result of the expansion with the
@code{@@expansion@{@}} command.@refill
@iftex
The @code{@@expansion@{@}} command is displayed as @samp{==>} in Info and
as @samp{@expansion{}} in the printed output.
@end iftex
@ifinfo
The @code{@@expansion@{@}} command is displayed as @samp{@expansion{}}
in Info and as a long arrow with a flat base in the printed output.@refill
@end ifinfo
@need 700
For example, the following
@example
@group
@@lisp
(third '(a b c))
@@expansion@{@} (car (cdr (cdr '(a b c))))
@@result@{@} c
@@end lisp
@end group
@end example
@noindent
produces
@lisp
@group
(third '(a b c))
@expansion{} (car (cdr (cdr '(a b c))))
@result{} c
@end group
@end lisp
@noindent
which may be read as:
@quotation
@code{(third '(a b c))} expands to @code{(car (cdr (cdr '(a b c))))};
the result of evaluating the expression is @code{c}.
@end quotation
@noindent
Often, as in this case, an example looks better if the
@code{@@expansion@{@}} and @code{@@result@{@}} commands are indented
five spaces.@refill
@node Print Glyph, Error Glyph, expansion, Glyphs
@section @print{}: Indicating Printed Output
@cindex Printed output, indicating it
Sometimes an expression will print output during its execution. You
can indicate the printed output with the @code{@@print@{@}} command.@refill
@iftex
The @code{@@print@{@}} command is displayed as @samp{-|} in Info and
as @samp{@print{}} in the printed output.
@end iftex
@ifinfo
The @code{@@print@{@}} command is displayed as @samp{@print{}} in Info
and similarly, as a horizontal dash butting against a vertical bar, in
the printed output.@refill
@end ifinfo
In the following example, the printed text is indicated with
@samp{@print{}}, and the value of the expression follows on the
last line.@refill
@lisp
@group
(progn (print 'foo) (print 'bar))
@print{} foo
@print{} bar
@result{} bar
@end group
@end lisp
@noindent
In a Texinfo source file, this example is written as follows:
@lisp
@group
@@lisp
(progn (print 'foo) (print 'bar))
@@print@{@} foo
@@print@{@} bar
@@result@{@} bar
@@end lisp
@end group
@end lisp
@node Error Glyph, Equivalence, Print Glyph, Glyphs
@section @error{}: Indicating an Error Message
@cindex Error message, indicating it
A piece of code may cause an error when you evaluate it. You can
designate the error message with the @code{@@error@{@}} command.@refill
@iftex
The @code{@@error@{@}} command is displayed as @samp{error-->} in Info
and as @samp{@error{}} in the printed output.
@end iftex
@ifinfo
The @code{@@error@{@}} command is displayed as @samp{@error{}} in Info
and as the word `error' in a box in the printed output.@refill
@end ifinfo
@need 700
Thus,
@example
@@lisp
(+ 23 'x)
@@error@{@} Wrong type argument: integer-or-marker-p, x
@@end lisp
@end example
@noindent
produces
@lisp
(+ 23 'x)
@error{} Wrong type argument: integer-or-marker-p, x
@end lisp
@noindent
This indicates that the following error message is printed
when you evaluate the expression:
@lisp
Wrong type argument: integer-or-marker-p, x
@end lisp
Note that @samp{@error{}} itself is not part of the error
message.
@node Equivalence, Point Glyph, Error Glyph, Glyphs
@section @equiv{}: Indicating Equivalence
@cindex Equivalence, indicating it
Sometimes two expressions produce identical results. You can indicate the
exact equivalence of two forms with the @code{@@equiv@{@}} command.@refill
@iftex
The @code{@@equiv@{@}} command is displayed as @samp{==} in Info and
as @samp{@equiv{}} in the printed output.
@end iftex
@ifinfo
The @code{@@equiv@{@}} command is displayed as @samp{@equiv{}} in Info
and as a three parallel horizontal lines in the printed output.@refill
@end ifinfo
Thus,
@example
@@lisp
(make-sparse-keymap) @@equiv@{@} (list 'keymap)
@@end lisp
@end example
@noindent
produces
@lisp
(make-sparse-keymap) @equiv{} (list 'keymap)
@end lisp
@noindent
This indicates that evaluating @code{(make-sparse-keymap)} produces
identical results to evaluating @code{(list 'keymap)}.
@c Cannot write point command here because it causes trouble with TOC.
@node Point Glyph, , Equivalence, Glyphs
@section Indicating Point in a Buffer
@cindex Point, indicating it in a buffer
Sometimes you need to show an example of text in an Emacs buffer. In
such examples, the convention is to include the entire contents of the
buffer in question between two lines of dashes containing the buffer
name.@refill
You can use the @samp{@@point@{@}} command to show the location of point
in the text in the buffer. (The symbol for point, of course, is not
part of the text in the buffer; it indicates the place @emph{between}
two characters where point is located.)@refill
@iftex
The @code{@@point@{@}} command is displayed as @samp{-!-} in Info and
as @samp{@point{}} in the printed output.
@end iftex
@ifinfo
The @code{@@point@{@}} command is displayed as @samp{@point{}} in Info
and as a small five pointed star in the printed output.@refill
@end ifinfo
The following example shows the contents of buffer @file{foo} before
and after evaluating a Lisp command to insert the word @code{changed}.@refill
@example
@group
---------- Buffer: foo ----------
This is the @point{}contents of foo.
---------- Buffer: foo ----------
@end group
@end example
@example
@group
(insert "changed ")
@result{} nil
---------- Buffer: foo ----------
This is the changed @point{}contents of foo.
---------- Buffer: foo ----------
@end group
@end example
In a Texinfo source file, the example is written like this:@refill
@example
@@example
---------- Buffer: foo ----------
This is the @@point@{@}contents of foo.
---------- Buffer: foo ----------
(insert "changed ")
@@result@{@} nil
---------- Buffer: foo ----------
This is the changed @@point@{@}contents of foo.
---------- Buffer: foo ----------
@@end example
@end example
@node Breaks, Definition Commands, Glyphs, Top
@comment node-name, next, previous, up
@chapter Making and Preventing Breaks
@cindex Making line and page breaks
@cindex Preventing line and page breaks
Usually, a Texinfo file is processed both by @TeX{} and by one of the
Info formatting commands. Line, paragraph, or page breaks sometimes
occur in the `wrong' place in one or other form of output. You must
ensure that text looks right both in the printed manual and in the
Info file.@refill
For example, in a printed manual, page breaks may occur awkwardly in
the middle of an example; to prevent this, you can hold text together
using a grouping command that keeps the text from being split across
two pages. Conversely, you may want to force a page break where none
would occur normally. Fortunately, problems like these do not often
arise. When they do, use the break, break prevention, or pagination
commands.@refill
@menu
* Break Commands:: Cause and prevent splits.
* Line Breaks:: How to force a single line to use two lines.
* w:: How to prevent unwanted line breaks.
* sp:: How to insert blank lines.
* page:: How to force the start of a new page.
* group:: How to prevent unwanted page breaks.
* need:: Another way to prevent unwanted page breaks.
@end menu
@ifinfo
@node Break Commands, Line Breaks, Breaks, Breaks
@heading The Break Commands
@end ifinfo
@iftex
@sp 1
@end iftex
The break commands create line and paragraph breaks:@refill
@table @code
@item @@*
Force a line break.
@item @@sp @var{n}
Skip @var{n} blank lines.@refill
@end table
@iftex
@sp 1
@end iftex
The line-break-prevention command holds text together all on one
line:@refill
@table @code
@item @@w@{@var{text}@}
Prevent @var{text} from being split and hyphenated across two lines.@refill
@end table
@iftex
@sp 1
@end iftex
The pagination commands apply only to printed output, since Info
files do not have pages.@refill
@table @code
@item @@page
Start a new page in the printed manual.@refill
@item @@group
Hold text together that must appear on one printed page.@refill
@item @@need @var{mils}
Start a new printed page if not enough space on this one.@refill
@end table
@node Line Breaks, w, Break Commands, Breaks
@comment node-name, next, previous, up
@section @code{@@*}: Generate Line Breaks
@findex * @r{(force line break)}
@cindex Line breaks
@cindex Breaks in a line
The @code{@@*} command forces a line break in both the printed manual and
in Info.@refill
@need 700
For example,
@example
This line @@* is broken @@*in two places.
@end example
@noindent
produces
@example
@group
This line
is broken
in two places.
@end group
@end example
@noindent
(Note that the space after the first @code{@@*} command is faithfully
carried down to the next line.)@refill
@need 800
The @code{@@*} command is often used in a file's copyright page:@refill
@example
@group
This is edition 2.0 of the Texinfo documentation,@@*
and is for @dots{}
@end group
@end example
@noindent
In this case, the @code{@@*} command keeps @TeX{} from stretching the
line across the whole page in an ugly manner.@refill
@quotation
@strong{Please note:} Do not write braces after an @code{@@*} command;
they are not needed.@refill
Do not write an @code{@@refill} command at the end of a paragraph
containing an @code{@@*} command; it will cause the paragraph to be
refilled after the line break occurs, negating the effect of the line
break.@refill
@end quotation
@node w, sp, Line Breaks, Breaks
@comment node-name, next, previous, up
@section @code{@@w}@{@var{text}@}: Prevent Line Breaks
@findex w @r{(prevent line break)}
@cindex Line breaks, preventing
@code{@@w@{@var{text}@}} outputs @var{text} and prohibits line breaks
within @var{text}.@refill
You can use the @code{@@w} command to prevent @TeX{} from automatically
hyphenating a long name or phrase that accidentally falls near the end
of a line.@refill
@example
You can copy GNU software from @@w@{@@file@{prep.ai.mit.edu@}@}.
@end example
@noindent
produces
@quotation
You can copy GNU software from @w{@file{prep.ai.mit.edu}}.
@end quotation
In the Texinfo file, you must write the @code{@@w} command and its
argument (all the affected text) all on one line.@refill
@quotation
@strong{Caution:} Do not write an @code{@@refill} command at the end
of a paragraph containing an @code{@@w} command; it will cause the
paragraph to be refilled and may thereby negate the effect of the
@code{@@w} command.@refill
@end quotation
@node sp, page, w, Breaks
@comment node-name, next, previous, up
@section @code{@@sp} @var{n}: Insert Blank Lines
@findex sp @r{(line spacing)}
@cindex Spaces (blank lines)
@cindex Blank lines
@cindex Line spacing
A line beginning with and containing only @code{@@sp @var{n}}
generates @var{n} blank lines of space in both the printed manual and
the Info file. @code{@@sp} also forces a paragraph break. For
example,@refill
@example
@@sp 2
@end example
@noindent
generates two blank lines.
The @code{@@sp} command is most often used in the title page.@refill
@ignore
@c node br, page, sp, Breaks
@comment node-name, next, previous, up
@c section @code{@@br}: Generate Paragraph Breaks
@findex br @r{(paragraph breaks)}
@cindex Paragraph breaks
@cindex Breaks in a paragraph
The @code{@@br} command forces a paragraph break. It inserts a blank
line. You can use the command within or at the end of a line. If
used within a line, the @code{@@br@{@}} command must be followed by
left and right braces (as shown here) to mark the end of the
command.@refill
@need 700
For example,
@example
@group
This line @@br@{@}contains and is ended by paragraph breaks@@br
and is followed by another line.
@end group
@end example
@noindent
produces
@example
@group
This line
contains and is ended by paragraph breaks
and is followed by another line.
@end group
@end example
The @code{@@br} command is seldom used.
@end ignore
@node page, group, sp, Breaks
@comment node-name, next, previous, up
@section @code{@@page}: Start a New Page
@cindex Page breaks
@findex page
A line containing only @code{@@page} starts a new page in a printed
manual. The command has no effect on Info files since they are not
paginated. An @code{@@page} command is often used in the @code{@@titlepage}
section of a Texinfo file to start the copyright page.@refill
@node group, need, page, Breaks
@comment node-name, next, previous, up
@section @code{@@group}: Prevent Page Breaks
@cindex Group (hold text together vertically)
@cindex Holding text together vertically
@cindex Vertically holding text together
@findex group
The @code{@@group} command (on a line by itself) is used inside an
@code{@@example} or similar construct to begin an unsplittable vertical
group, which will appear entirely on one page in the printed output.
The group is terminated by a line containing only @code{@@end group}.
These two lines produce no output of their own, and in the Info file
output they have no effect at all.@refill
@c Once said that these environments
@c turn off vertical spacing between ``paragraphs''.
@c Also, quotation used to work, but doesn't in texinfo-2.72
Although @code{@@group} would make sense conceptually in a wide
variety of contexts, its current implementation works reliably only
within @code{@@example} and variants, and within @code{@@display},
@code{@@format}, @code{@@flushleft} and @code{@@flushright}.
@xref{Quotations and Examples}. (What all these commands have in
common is that each line of input produces a line of output.) In
other contexts, @code{@@group} can cause anomalous vertical
spacing.@refill
@need 750
This formatting requirement means that you should write:
@example
@group
@@example
@@group
@dots{}
@@end group
@@end example
@end group
@end example
@noindent
with the @code{@@group} and @code{@@end group} commands inside the
@code{@@example} and @code{@@end example} commands.
The @code{@@group} command is most often used to hold an example
together on one page. In this Texinfo manual, more than 100 examples
contain text that is enclosed between @code{@@group} and @code{@@end
group}.
If you forget to end a group, you may get strange and unfathomable
error messages when you run @TeX{}. This is because @TeX{} keeps
trying to put the rest of the Texinfo file onto the one page and does
not start to generate error messages until it has processed
considerable text. It is a good rule of thumb to look for a missing
@code{@@end group} if you get incomprehensible error messages in
@TeX{}.@refill
@node need, , group, Breaks
@comment node-name, next, previous, up
@section @code{@@need @var{mils}}: Prevent Page Breaks
@cindex Need space at page bottom
@findex need
A line containing only @code{@@need @var{n}} starts
a new page in a printed manual if fewer than @var{n} mils (thousandths
of an inch) remain on the current page. Do not use
braces around the argument @var{n}. The @code{@@need} command has no
effect on Info files since they are not paginated.@refill
@need 800
This paragraph is preceded by an @code{@@need} command that tells
@TeX{} to start a new page if fewer than 800 mils (eight-tenths
inch) remain on the page. It looks like this:@refill
@example
@group
@@need 800
This paragraph is preceded by @dots{}
@end group
@end example
The @code{@@need} command is useful for preventing orphans (single
lines at the bottoms of printed pages).@refill
@node Definition Commands, Footnotes, Breaks, Top
@chapter Definition Commands
@cindex Definition commands
The @code{@@deffn} command and the other @dfn{definition commands}
enable you to describe functions, variables, macros, commands, user
options, special forms and other such artifacts in a uniform
format.@refill
In the Info file, a definition causes the entity
category---`Function', `Variable', or whatever---to appear at the
beginning of the first line of the definition, followed by the
entity's name and arguments. In the printed manual, the command
causes @TeX{} to print the entity's name and its arguments on the left
margin and print the category next to the right margin. In both
output formats, the body of the definition is indented. Also, the
name of the entity is entered into the appropriate index:
@code{@@deffn} enters the name into the index of functions,
@code{@@defvr} enters it into the index of variables, and so
on.@refill
A manual need not and should not contain more than one definition for
a given name. An appendix containing a summary should use
@code{@@table} rather than the definition commands.@refill
@menu
* Def Cmd Template:: How to structure a description using a
definition command.
* Optional Arguments:: How to handle optional and repeated arguments.
* deffnx:: How to group two or more `first' lines.
* Def Cmds in Detail:: All the definition commands.
* Def Cmd Conventions:: Conventions for writing definitions.
* Sample Function Definition::
@end menu
@node Def Cmd Template, Optional Arguments, Definition Commands, Definition Commands
@section The Template for a Definition
@cindex Definition template
@cindex Template for a definition
The @code{@@deffn} command is used for definitions of entities that
resemble functions. To write a definition using the @code{@@deffn}
command, write the @code{@@deffn} command at the beginning of a line
and follow it on the same line by the category of the entity, the name
of the entity itself, and its arguments (if any). Then write the body
of the definition on succeeding lines. (You may embed examples in the
body.) Finally, end the definition with an @code{@@end deffn} command
written on a line of its own. (The other definition commands follow
the same format.)@refill
The template for a definition looks like this:
@example
@group
@@deffn @var{category} @var{name} @var{arguments}@dots{}
@var{body-of-definition}
@@end deffn
@end group
@end example
@need 700
@noindent
For example,
@example
@group
@@deffn Command forward-word count
This command moves point forward @@var@{count@} words
(or backward if @@var@{count@} is negative). @dots{}
@@end deffn
@end group
@end example
@noindent
produces
@quotation
@deffn Command forward-word count
This function moves point forward @var{count} words
(or backward if @var{count} is negative). @dots{}
@end deffn
@end quotation
Capitalize the category name like a title. If the name of the
category contains spaces, as in the phrase `Interactive Command',
write braces around it. For example:@refill
@example
@group
@@deffn @{Interactive Command@} isearch-forward
@dots{}
@@end deffn
@end group
@end example
@noindent
Otherwise, the second word will be mistaken for the name of the
entity.@refill
Some of the definition commands are more general than others. The
@code{@@deffn} command, for example, is the general definition command
for functions and the like---for entities that may take arguments. When
you use this command, you specify the category to which the entity
belongs. The @code{@@deffn} command possesses three predefined,
specialized variations, @code{@@defun}, @code{@@defmac}, and
@code{@@defspec}, that specify the category for you: ``Function'',
``Macro'', and ``Special Form'' respectively. The @code{@@defvr}
command also is accompanied by several predefined, specialized
variations for describing particular kinds of variables.@refill
The template for a specialized definition, such as @code{@@defun}, is
similar to the template for a generalized definition, except that you
do not need to specify the category:@refill
@example
@group
@@defun @var{name} @var{arguments}@dots{}
@var{body-of-definition}
@@end defun
@end group
@end example
@noindent
Thus,
@example
@group
@@defun buffer-end flag
This function returns @@code@{(point-min)@} if @@var@{flag@}
is less than 1, @@code@{(point-max)@} otherwise.
@dots{}
@@end defun
@end group
@end example
@noindent
produces
@quotation
@defun buffer-end flag
This function returns @code{(point-min)} if @var{flag} is less than 1,
@code{(point-max)} otherwise. @dots{}
@end defun
@end quotation
@noindent
@xref{Sample Function Definition, Sample Function Definition, A Sample
Function Definition}, for a more detailed example of a function
definition, including the use of @code{@@example} inside the
definition.@refill
The other specialized commands work like @code{@@defun}.@refill
@node Optional Arguments, deffnx, Def Cmd Template, Definition Commands
@section Optional and Repeated Arguments
@cindex Optional and repeated arguments
@cindex Repeated and optional arguments
@cindex Arguments, repeated and optional
@cindex Syntax, optional & repeated arguments
@cindex Meta-syntactic chars for arguments
Some entities take optional or repeated arguments, which may be
specified by a distinctive glyph that uses square brackets and
ellipses. For @w{example}, a special form often breaks its argument list
into separate arguments in more complicated ways than a
straightforward function.@refill
@iftex
An argument enclosed within square brackets is optional.
Thus, the phrase
@samp{@code{@r{[}@var{optional-arg}@r{]}}} means that
@var{optional-arg} is optional.
An argument followed by an ellipsis is optional
and may be repeated more than once.
@c This is consistent with Emacs Lisp Reference manual
Thus, @samp{@var{repeated-args}@dots{}} stands for zero or more arguments.
Parentheses are used when several arguments are grouped
into additional levels of list structure in Lisp.
@end iftex
@c The following looks better in Info (no `r', `samp' and `code'):
@ifinfo
An argument enclosed within square brackets is optional.
Thus, [@var{optional-arg}] means that @var{optional-arg} is optional.
An argument followed by an ellipsis is optional
and may be repeated more than once.
@c This is consistent with Emacs Lisp Reference manual
Thus, @var{repeated-args}@dots{} stands for zero or more arguments.
Parentheses are used when several arguments are grouped
into additional levels of list structure in Lisp.
@end ifinfo
Here is the @code{@@defspec} line of an example of an imaginary
special form:@refill
@quotation
@defspec foobar (@var{var} [@var{from} @var{to} [@var{inc}]]) @var{body}@dots{}
@end defspec
@tex
\vskip \parskip
@end tex
@end quotation
@noindent
In this example, the arguments @var{from} and @var{to} are optional,
but must both be present or both absent. If they are present,
@var{inc} may optionally be specified as well. These arguments are
grouped with the argument @var{var} into a list, to distinguish them
from @var{body}, which includes all remaining elements of the
form.@refill
In a Texinfo source file, this @code{@@defspec} line is written like
this (except it would not be split over two lines, as it is in this
example).@refill
@example
@group
@@defspec foobar (@@var@{var@} [@@var@{from@} @@var@{to@}
[@@var@{inc@}]]) @@var@{body@}@@dots@{@}
@end group
@end example
@noindent
The function is listed in the Command and Variable Index under
@samp{foobar}.@refill
@node deffnx, Def Cmds in Detail, Optional Arguments, Definition Commands
@section Two or More `First' Lines
@cindex Two `First' Lines for @code{@@deffn}
@cindex Grouping two definitions together
@cindex Definitions grouped together
@findex deffnx
To create two or more `first' or header lines for a definition, follow
the first @code{@@deffn} line by a line beginning with @code{@@deffnx}.
The @code{@@deffnx} command works exactly like @code{@@deffn}
except that it does not generate extra vertical white space between it
and the preceding line.@refill
@need 1000
For example,
@example
@group
@@deffn @{Interactive Command@} isearch-forward
@@deffnx @{Interactive Command@} isearch-backward
These two search commands are similar except @dots{}
@@end deffn
@end group
@end example
@noindent
produces
@deffn {Interactive Command} isearch-forward
@deffnx {Interactive Command} isearch-backward
These two search commands are similar except @dots{}
@end deffn
Each of the other definition commands has an `x' form: @code{@@defunx},
@code{@@defvrx}, @code{@@deftypefunx}, etc.
The `x' forms work just like @code{@@itemx}; see @ref{itemx, , @code{@@itemx}}.
@node Def Cmds in Detail, Def Cmd Conventions, deffnx, Definition Commands
@section The Definition Commands
Texinfo provides more than a dozen definition commands, all of which
are described in this section.@refill
The definition commands automatically enter the name of the entity in
the appropriate index: for example, @code{@@deffn}, @code{@@defun},
and @code{@@defmac} enter function names in the index of functions;
@code{@@defvr} and @code{@@defvar} enter variable names in the index
of variables.@refill
Although the examples that follow mostly illustrate Lisp, the commands
can be used for other programming languages.@refill
@menu
* Functions Commands:: Commands for functions and similar entities.
* Variables Commands:: Commands for variables and similar entities.
* Typed Functions:: Commands for functions in typed languages.
* Typed Variables:: Commands for variables in typed languages.
* Abstract Objects:: Commands for object-oriented programming.
* Data Types:: The definition command for data types.
@end menu
@node Functions Commands, Variables Commands, Def Cmds in Detail, Def Cmds in Detail
@subsection Functions and Similar Entities
This section describes the commands for describing functions and similar
entities:@refill
@table @code
@findex deffn
@item @@deffn @var{category} @var{name} @var{arguments}@dots{}
The @code{@@deffn} command is the general definition command for
functions, interactive commands, and similar entities that may take
arguments. You must choose a term to describe the category of entity
being defined; for example, ``Function'' could be used if the entity is
a function. The @code{@@deffn} command is written at the beginning of a
line and is followed on the same line by the category of entity being
described, the name of this particular entity, and its arguments, if
any. Terminate the definition with @code{@@end deffn} on a line of its
own.@refill
@need 750
For example, here is a definition:
@example
@group
@@deffn Command forward-char nchars
Move point forward @@var@{nchars@} characters.
@@end deffn
@end group
@end example
@noindent
This shows a rather terse definition for a ``command'' named
@code{forward-char} with one argument, @var{nchars}.
@code{@@deffn} prints argument names such as @var{nchars} in italics or
upper case, as if @code{@@var} had been used, because we think of these
names as metasyntactic variables---they stand for the actual argument
values. Within the text of the description, write an argument name
explicitly with @code{@@var} to refer to the value of the argument. In
the example above, we used @samp{@@var@{nchars@}} in this way.
The template for @code{@@deffn} is:
@example
@group
@@deffn @var{category} @var{name} @var{arguments}@dots{}
@var{body-of-definition}
@@end deffn
@end group
@end example
@findex defun
@item @@defun @var{name} @var{arguments}@dots{}
The @code{@@defun} command is the definition command for functions.
@code{@@defun} is equivalent to @samp{@@deffn Function
@dots{}}.@refill
@need 800
@noindent
For example,
@example
@group
@@defun set symbol new-value
Change the value of the symbol @@var@{symbol@}
to @@var@{new-value@}.
@@end defun
@end group
@end example
@noindent
shows a rather terse definition for a function @code{set} whose
arguments are @var{symbol} and @var{new-value}. The argument names on
the @code{@@defun} line automatically appear in italics or upper case as
if they were enclosed in @code{@@var}. Terminate the definition with
@code{@@end defun} on a line of its own.@refill
The template is:
@example
@group
@@defun @var{function-name} @var{arguments}@dots{}
@var{body-of-definition}
@@end defun
@end group
@end example
@code{@@defun} creates an entry in the index of functions.
@findex defmac
@item @@defmac @var{name} @var{arguments}@dots{}
The @code{@@defmac} command is the definition command for macros.
@code{@@defmac} is equivalent to @samp{@@deffn Macro @dots{}} and
works like @code{@@defun}.@refill
@findex defspec
@item @@defspec @var{name} @var{arguments}@dots{}
The @code{@@defspec} command is the definition command for special
forms. (In Lisp, a special form is an entity much like a function.)
@code{@@defspec} is equivalent to @samp{@@deffn @{Special Form@}
@dots{}} and works like @code{@@defun}.@refill
@end table
@node Variables Commands, Typed Functions, Functions Commands, Def Cmds in Detail
@subsection Variables and Similar Entities
Here are the commands for defining variables and similar
entities:@refill
@table @code
@findex defvr
@item @@defvr @var{category} @var{name}
The @code{@@defvr} command is a general definition command for
something like a variable---an entity that records a value. You must
choose a term to describe the category of entity being defined; for
example, ``Variable'' could be used if the entity is a variable.
Write the @code{@@defvr} command at the beginning of a line and
followed it on the same line by the category of the entity and the
name of the entity.@refill
Capitalize the category name like a title. If the name of the
category contains spaces, as in the name `User Option', write braces
around it. Otherwise, the second word will be mistaken for the name
of the entity, for example:
@example
@group
@@defvr @{User Option@} fill-column
This buffer-local variable specifies
the maximum width of filled lines.
@dots{}
@@end defvr
@end group
@end example
Terminate the definition with @code{@@end defvr} on a line of its
own.@refill
The template is:
@example
@group
@@defvr @var{category} @var{name}
@var{body-of-definition}
@@end defvr
@end group
@end example
@code{@@defvr} creates an entry in the index of variables for @var{name}.
@findex defvar
@item @@defvar @var{name}
The @code{@@defvar} command is the definition command for variables.
@code{@@defvar} is equivalent to @samp{@@defvr Variable
@dots{}}.@refill
@need 750
For example:
@example
@group
@@defvar kill-ring
@dots{}
@@end defvar
@end group
@end example
The template is:
@example
@group
@@defvar @var{name}
@var{body-of-definition}
@@end defvar
@end group
@end example
@code{@@defvar} creates an entry in the index of variables for
@var{name}.@refill
@findex defopt
@item @@defopt @var{name}
The @code{@@defopt} command is the definition command for user
options. @code{@@defopt} is equivalent to @samp{@@defvr @{User
Option@} @dots{}} and works like @code{@@defvar}.@refill
@end table
@node Typed Functions, Typed Variables, Variables Commands, Def Cmds in Detail
@subsection Functions in Typed Languages
The @code{@@deftypefn} command and its variations are for describing
functions in C or any other language in which you must declare types
of variables and functions.@refill
@table @code
@findex deftypefn
@item @@deftypefn @var{category} @var{data-type} @var{name} @var{arguments}@dots{}
The @code{@@deftypefn} command is the general definition command for
functions and similar entities that may take arguments and that are
typed. The @code{@@deftypefn} command is written at the beginning of
a line and is followed on the same line by the category of entity
being described, the type of the returned value, the name of this
particular entity, and its arguments, if any.@refill
@need 800
@noindent
For example,
@example
@group
@@deftypefn @{Library Function@} int foobar
(int @@var@{foo@}, float @@var@{bar@})
@dots{}
@@end deftypefn
@end group
@end example
@need 1000
@noindent
(where the text before the ``@dots{}'', shown above as two lines, would
actually be a single line in a real Texinfo file) produces the following
in Info:
@smallexample
@group
-- Library Function: int foobar (int FOO, float BAR)
@dots{}
@end group
@end smallexample
@iftex
In a printed manual, it produces:
@quotation
@deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
@dots{}
@end deftypefn
@end quotation
@end iftex
This means that @code{foobar} is a ``library function'' that returns an
@code{int}, and its arguments are @var{foo} (an @code{int}) and
@var{bar} (a @code{float}).@refill
The argument names that you write in @code{@@deftypefn} are not subject
to an implicit @code{@@var}---since the actual names of the arguments in
@code{@@deftypefn} are typically scattered among data type names and
keywords, Texinfo cannot find them without help. Instead, you must write
@code{@@var} explicitly around the argument names. In the example
above, the argument names are @samp{foo} and @samp{bar}.@refill
The template for @code{@@deftypefn} is:@refill
@example
@group
@@deftypefn @var{category} @var{data-type} @var{name} @var{arguments} @dots{}
@var{body-of-description}
@@end deftypefn
@end group
@end example
@noindent
Note that if the @var{category} or @var{data type} is more than one
word then it must be enclosed in braces to make it a single argument.@refill
If you are describing a procedure in a language that has packages,
such as Ada, you might consider using @code{@@deftypefn} in a manner
somewhat contrary to the convention described in the preceding
paragraphs.@refill
@need 800
@noindent
For example:
@example
@group
@@deftypefn stacks private push
(@@var@{s@}:in out stack;
@@var@{n@}:in integer)
@dots{}
@@end deftypefn
@end group
@end example
@noindent
(The @code{@@deftypefn} arguments are shown split into three lines, but
would be a single line in a real Texinfo file.)
In this instance, the procedure is classified as belonging to the
package @code{stacks} rather than classified as a `procedure' and its
data type is described as @code{private}. (The name of the procedure
is @code{push}, and its arguments are @var{s} and @var{n}.)@refill
@code{@@deftypefn} creates an entry in the index of functions for
@var{name}.@refill
@findex deftypefun
@item @@deftypefun @var{data-type} @var{name} @var{arguments}@dots{}
The @code{@@deftypefun} command is the specialized definition command
for functions in typed languages. The command is equivalent to
@samp{@@deftypefn Function @dots{}}.@refill
@need 800
@noindent
Thus,
@smallexample
@group
@@deftypefun int foobar (int @@var@{foo@}, float @@var@{bar@})
@dots{}
@@end deftypefun
@end group
@end smallexample
@noindent
produces the following in Info:
@example
@group
-- Function: int foobar (int FOO, float BAR)
@dots{}
@end group
@end example
@iftex
@need 800
@noindent
and the following in a printed manual:
@quotation
@deftypefun int foobar (int @var{foo}, float @var{bar})
@dots{}
@end deftypefun
@end quotation
@end iftex
@need 800
The template is:
@example
@group
@@deftypefun @var{type} @var{name} @var{arguments}@dots{}
@var{body-of-description}
@@end deftypefun
@end group
@end example
@code{@@deftypefun} creates an entry in the index of functions for
@var{name}.@refill
@end table
@node Typed Variables, Abstract Objects, Typed Functions, Def Cmds in Detail
@subsection Variables in Typed Languages
Variables in typed languages are handled in a manner similar to
functions in typed languages. @xref{Typed Functions}. The general
definition command @code{@@deftypevr} corresponds to
@code{@@deftypefn} and the specialized definition command
@code{@@deftypevar} corresponds to @code{@@deftypefun}.@refill
@table @code
@findex deftypevr
@item @@deftypevr @var{category} @var{data-type} @var{name}
The @code{@@deftypevr} command is the general definition command for
something like a variable in a typed language---an entity that records
a value. You must choose a term to describe the category of the
entity being defined; for example, ``Variable'' could be used if the
entity is a variable.@refill
The @code{@@deftypevr} command is written at the beginning of a line
and is followed on the same line by the category of the entity
being described, the data type, and the name of this particular
entity.@refill
@need 800
@noindent
For example:
@example
@group
@@deftypevr @{Global Flag@} int enable
@dots{}
@@end deftypevr
@end group
@end example
@noindent
produces the following in Info:
@example
@group
-- Global Flag: int enable
@dots{}
@end group
@end example
@iftex
@noindent
and the following in a printed manual:
@quotation
@deftypevr {Global Flag} int enable
@dots{}
@end deftypevr
@end quotation
@end iftex
@need 800
The template is:
@example
@@deftypevr @var{category} @var{data-type} @var{name}
@var{body-of-description}
@@end deftypevr
@end example
@code{@@deftypevr} creates an entry in the index of variables for
@var{name}.@refill
@findex deftypevar
@item @@deftypevar @var{data-type} @var{name}
The @code{@@deftypevar} command is the specialized definition command
for variables in typed languages. @code{@@deftypevar} is equivalent
to @samp{@@deftypevr Variable @dots{}}.@refill
@need 800
@noindent
For example:
@example
@group
@@deftypevar int fubar
@dots{}
@@end deftypevar
@end group
@end example
@noindent
produces the following in Info:
@example
@group
-- Variable: int fubar
@dots{}
@end group
@end example
@iftex
@need 800
@noindent
and the following in a printed manual:
@quotation
@deftypevar int fubar
@dots{}
@end deftypevar
@end quotation
@end iftex
@need 800
@noindent
The template is:
@example
@group
@@deftypevar @var{data-type} @var{name}
@var{body-of-description}
@@end deftypevar
@end group
@end example
@code{@@deftypevar} creates an entry in the index of variables for
@var{name}.@refill
@end table
@node Abstract Objects, Data Types, Typed Variables, Def Cmds in Detail
@subsection Object-Oriented Programming
Here are the commands for formatting descriptions about abstract
objects, such as are used in object-oriented programming. A class is
a defined type of abstract object. An instance of a class is a
particular object that has the type of the class. An instance
variable is a variable that belongs to the class but for which each
instance has its own value.@refill
In a definition, if the name of a class is truly a name defined in the
programming system for a class, then you should write an @code{@@code}
around it. Otherwise, it is printed in the usual text font.@refill
@table @code
@findex defcv
@item @@defcv @var{category} @var{class} @var{name}
The @code{@@defcv} command is the general definition command for
variables associated with classes in object-oriented programming. The
@code{@@defcv} command is followed by three arguments: the category of
thing being defined, the class to which it belongs, and its
name. Thus,@refill
@example
@group
@@defcv @{Class Option@} Window border-pattern
@dots{}
@@end defcv
@end group
@end example
@noindent
illustrates how you would write the first line of a definition of the
@code{border-pattern} class option of the class @code{Window}.@refill
The template is
@example
@group
@@defcv @var{category} @var{class} @var{name}
@dots{}
@@end defcv
@end group
@end example
@code{@@defcv} creates an entry in the index of variables.
@findex defivar
@item @@defivar @var{class} @var{name}
The @code{@@defivar} command is the definition command for instance
variables in object-oriented programming. @code{@@defivar} is
equivalent to @samp{@@defcv @{Instance Variable@} @dots{}}@refill
The template is:
@example
@group
@@defivar @var{class} @var{instance-variable-name}
@var{body-of-definition}
@@end defivar
@end group
@end example
@code{@@defivar} creates an entry in the index of variables.
@findex defop
@item @@defop @var{category} @var{class} @var{name} @var{arguments}@dots{}
The @code{@@defop} command is the general definition command for
entities that may resemble methods in object-oriented programming.
These entities take arguments, as functions do, but are associated
with particular classes of objects.@refill
For example, some systems have constructs called @dfn{wrappers} that
are associated with classes as methods are, but that act more like
macros than like functions. You could use @code{@@defop Wrapper} to
describe one of these.@refill
Sometimes it is useful to distinguish methods and @dfn{operations}.
You can think of an operation as the specification for a method.
Thus, a window system might specify that all window classes have a
method named @code{expose}; we would say that this window system
defines an @code{expose} operation on windows in general. Typically,
the operation has a name and also specifies the pattern of arguments;
all methods that implement the operation must accept the same
arguments, since applications that use the operation do so without
knowing which method will implement it.@refill
Often it makes more sense to document operations than methods. For
example, window application developers need to know about the
@code{expose} operation, but need not be concerned with whether a
given class of windows has its own method to implement this operation.
To describe this operation, you would write:@refill
@example
@@defop Operation windows expose
@end example
The @code{@@defop} command is written at the beginning of a line and
is followed on the same line by the overall name of the category of
operation, the name of the class of the operation, the name of the
operation, and its arguments, if any.@refill
@need 800
@noindent
The template is:
@example
@group
@@defop @var{category} @var{class} @var{name} @var{arguments}@dots{}
@var{body-of-definition}
@@end defop
@end group
@end example
@code{@@defop} creates an entry, such as `@code{expose} on
@code{windows}', in the index of functions.@refill
@findex defmethod
@item @@defmethod @var{class} @var{name} @var{arguments}@dots{}
The @code{@@defmethod} command is the definition command for methods
in object-oriented programming. A method is a kind of function that
implements an operation for a particular class of objects and its
subclasses. In the Lisp Machine, methods actually were functions, but
they were usually defined with @code{defmethod}.
@code{@@defmethod} is equivalent to @samp{@@defop Method @dots{}}.
The command is written at the beginning of a line and is followed by
the name of the class of the method, the name of the method, and its
arguments, if any.@refill
@need 800
@noindent
For example,
@example
@group
@@defmethod @code{bar-class} bar-method argument
@dots{}
@@end defmethod
@end group
@end example
@noindent
illustrates the definition for a method called @code{bar-method} of
the class @code{bar-class}. The method takes an argument.@refill
The template is:
@example
@group
@@defmethod @var{class} @var{method-name} @var{arguments}@dots{}
@var{body-of-definition}
@@end defmethod
@end group
@end example
@code{@@defmethod} creates an entry, such as `@code{bar-method} on
@code{bar-class}', in the index of functions.@refill
@end table
@node Data Types, , Abstract Objects, Def Cmds in Detail
@subsection Data Types
Here is the command for data types:@refill
@table @code
@findex deftp
@item @@deftp @var{category} @var{name} @var{attributes}@dots{}
The @code{@@deftp} command is the generic definition command for data
types. The command is written at the beginning of a line and is
followed on the same line by the category, by the name of the type
(which is a word like @code{int} or @code{float}), and then by names of
attributes of objects of that type. Thus, you could use this command
for describing @code{int} or @code{float}, in which case you could use
@code{data type} as the category. (A data type is a category of
certain objects for purposes of deciding which operations can be
performed on them.)@refill
In Lisp, for example, @dfn{pair} names a particular data
type, and an object of that type has two slots called the
@sc{car} and the @sc{cdr}. Here is how you would write the first line
of a definition of @code{pair}.@refill
@example
@group
@@deftp @{Data type@} pair car cdr
@dots{}
@@end deftp
@end group
@end example
@need 950
The template is:
@example
@group
@@deftp @var{category} @var{name-of-type} @var{attributes}@dots{}
@var{body-of-definition}
@@end deftp
@end group
@end example
@code{@@deftp} creates an entry in the index of data types.
@end table
@node Def Cmd Conventions, Sample Function Definition, Def Cmds in Detail, Definition Commands
@section Conventions for Writing Definitions
@cindex Definition conventions
@cindex Conventions for writing definitions
When you write a definition using @code{@@deffn}, @code{@@defun}, or
one of the other definition commands, please take care to use
arguments that indicate the meaning, as with the @var{count} argument
to the @code{forward-word} function. Also, if the name of an argument
contains the name of a type, such as @var{integer}, take care that the
argument actually is of that type.@refill
@node Sample Function Definition, , Def Cmd Conventions, Definition Commands
@section A Sample Function Definition
@cindex Function definitions
@cindex Command definitions
@cindex Macro definitions
@cindex Sample function definition
A function definition uses the @code{@@defun} and @code{@@end defun}
commands. The name of the function follows immediately after the
@code{@@defun} command and it is followed, on the same line, by the
parameter list.@refill
Here is a definition from @cite{The GNU Emacs Lisp Reference Manual}.
(@xref{Calling Functions, , Calling Functions, elisp, The GNU Emacs
Lisp Reference Manual}.)
@quotation
@defun apply function &rest arguments
@code{apply} calls @var{function} with @var{arguments}, just
like @code{funcall} but with one difference: the last of
@var{arguments} is a list of arguments to give to
@var{function}, rather than a single argument. We also say
that this list is @dfn{appended} to the other arguments.
@code{apply} returns the result of calling @var{function}.
As with @code{funcall}, @var{function} must either be a Lisp
function or a primitive function; special forms and macros
do not make sense in @code{apply}.
@example
(setq f 'list)
@result{} list
(apply f 'x 'y 'z)
@error{} Wrong type argument: listp, z
(apply '+ 1 2 '(3 4))
@result{} 10
(apply '+ '(1 2 3 4))
@result{} 10
(apply 'append '((a b c) nil (x y z) nil))
@result{} (a b c x y z)
@end example
An interesting example of using @code{apply} is found in the description
of @code{mapcar}.@refill
@end defun
@end quotation
@need 1200
In the Texinfo source file, this example looks like this:
@example
@group
@@defun apply function &rest arguments
@@code@{apply@} calls @@var@{function@} with
@@var@{arguments@}, just like @@code@{funcall@} but with one
difference: the last of @@var@{arguments@} is a list of
arguments to give to @@var@{function@}, rather than a single
argument. We also say that this list is @@dfn@{appended@}
to the other arguments.
@end group
@group
@@code@{apply@} returns the result of calling
@@var@{function@}. As with @@code@{funcall@},
@@var@{function@} must either be a Lisp function or a
primitive function; special forms and macros do not make
sense in @@code@{apply@}.
@end group
@group
@@example
(setq f 'list)
@@result@{@} list
(apply f 'x 'y 'z)
@@error@{@} Wrong type argument: listp, z
(apply '+ 1 2 '(3 4))
@@result@{@} 10
(apply '+ '(1 2 3 4))
@@result@{@} 10
(apply 'append '((a b c) nil (x y z) nil))
@@result@{@} (a b c x y z)
@@end example
@end group
@group
An interesting example of using @@code@{apply@} is found
in the description of @@code@{mapcar@}.@@refill
@@end defun
@end group
@end example
@noindent
In this manual, this function is listed in the Command and Variable
Index under @code{apply}.@refill
Ordinary variables and user options are described using a format like
that for functions except that variables do not take arguments.
@node Footnotes, Conditionals, Definition Commands, Top
@comment node-name, next, previous, up
@chapter Footnotes
@cindex Footnotes
@findex footnote
A @dfn{footnote} is for a reference that documents or elucidates the
primary text.@footnote{A footnote should complement or expand upon
the primary text, but a reader should not need to read a footnote to
understand the primary text. For a thorough discussion of footnotes,
see @cite{The Chicago Manual of Style}, which is published by the
University of Chicago Press.}@refill
@menu
* Footnote Commands:: How to write a footnote in Texinfo.
* Footnote Styles:: Controlling how footnotes appear in Info.
@end menu
@node Footnote Commands
@section Footnote Commands
In Texinfo, footnotes are created with the @code{@@footnote} command.
This command is followed immediately by a left brace, then by the text
of the footnote, and then by a terminating right brace. The template
is:
@example
@@footnote@{@var{text}@}
@end example
Footnotes may be of any length, but are usually short.@refill
For example, this clause is followed by a sample
footnote@footnote{Here is the sample footnote.}; in the Texinfo
source, it looks like this:@refill
@example
@dots{}a sample footnote @@footnote@{Here is the sample
footnote.@}; in the Texinfo source@dots{}
@end example
@strong{Warning:} Don't use footnotes in the argument of the
@code{@@item} command for a @code{@@table} table. This doesn't work;
because of limitations of @TeX{}, there is no way to fix it. To avoid
the problem, move the footnote into the body text of the table.
In a printed manual or book, the reference mark for a footnote is a
small, superscripted number; the text of the footnote appears at the
bottom of the page, below a horizontal line.@refill
In Info, the reference mark for a footnote is a pair of parentheses
with the footnote number between them, like this: @samp{(1)}.@refill
@node Footnote Styles
@section Footnote Styles
Info has two footnote styles, which determine where the text of the
footnote is located:@refill
@itemize @bullet
@cindex @samp{@r{End}} node footnote style
@item
In the `End' node style, all the footnotes for a single node
are placed at the end of that node. The footnotes are separated from
the rest of the node by a line of dashes with the word
@samp{Footnotes} within it. Each footnote begins with an
@samp{(@var{n})} reference mark.@refill
@need 700
@noindent
Here is an example of a single footnote in the end of node style:@refill
@example
@group
--------- Footnotes ---------
(1) Here is a sample footnote.
@end group
@end example
@cindex @samp{@r{Separate}} footnote style
@item
In the `Separate' node style, all the footnotes for a single
node are placed in an automatically constructed node of
their own. In this style, a ``footnote reference'' follows
each @samp{(@var{n})} reference mark in the body of the
node. The footnote reference is actually a cross reference
which you use to reach the footnote node.@refill
The name of the node containing the footnotes is constructed
by appending @w{@samp{-Footnotes}} to the name of the node
that contains the footnotes. (Consequently, the footnotes'
node for the @file{Footnotes} node is
@w{@file{Footnotes-Footnotes}}!) The footnotes' node has an
`Up' node pointer that leads back to its parent node.@refill
@noindent
Here is how the first footnote in this manual looks after being
formatted for Info in the separate node style:@refill
@smallexample
@group
File: texinfo.info Node: Overview-Footnotes, Up: Overview
(1) Note that the first syllable of "Texinfo" is
pronounced like "speck", not "hex". @dots{}
@end group
@end smallexample
@end itemize
A Texinfo file may be formatted into an Info file with either footnote
style.@refill
@findex footnotestyle
Use the @code{@@footnotestyle} command to specify an Info file's
footnote style. Write this command at the beginning of a line followed
by an argument, either @samp{end} for the end node style or
@samp{separate} for the separate node style.
@need 700
For example,
@example
@@footnotestyle end
@end example
@noindent
or
@example
@@footnotestyle separate
@end example
Write an @code{@@footnotestyle} command before or shortly after the
end-of-header line at the beginning of a Texinfo file. (If you
include the @code{@@footnotestyle} command between the start-of-header
and end-of-header lines, the region formatting commands will format
footnotes as specified.)@refill
If you do not specify a footnote style, the formatting commands use
their default style. Currently, @code{texinfo-format-buffer} and
@code{texinfo-format-region} use the `separate' style and
@code{makeinfo} uses the `end' style.@refill
@c !!! note: makeinfo's --footnote-style option overrides footnotestyle
@ignore
If you use @code{makeinfo} to create the Info file, the
@samp{--footnote-style} option determines which style is used,
@samp{end} for the end of node style or @samp{separate} for the
separate node style. Thus, to format the Texinfo manual in the
separate node style, you would use the following shell command:@refill
@example
makeinfo --footnote-style=separate texinfo.texi
@end example
@noindent
To format the Texinfo manual in the end of node style, you would
type:@refill
@example
makeinfo --footnote-style=end texinfo.texi
@end example
@end ignore
@ignore
If you use @code{texinfo-format-buffer} or
@code{texinfo-format-region} to create the Info file, the value of the
@code{texinfo-footnote-style} variable controls the footnote style.
It can be either @samp{"separate"} for the separate node style or
@samp{"end"} for the end of node style. (You can change the value of
this variable with the @kbd{M-x edit-options} command (@pxref{Edit
Options, , Editing Variable Values, emacs, The GNU Emacs Manual}), or
with the @kbd{M-x set-variable} command (@pxref{Examining, , Examining
and Setting Variables, emacs, The GNU Emacs Manual}).@refill
The @code{texinfo-footnote-style} variable also controls the style if
you use the @kbd{M-x makeinfo-region} or @kbd{M-x makeinfo-buffer}
command in Emacs.@refill
@end ignore
This chapter contains two footnotes.@refill
@node Conditionals, Format/Print Hardcopy, Footnotes, Top
@comment node-name, next, previous, up
@chapter Conditionally Visible Text
@cindex Conditionally visible text
@cindex Text, conditionally visible
@cindex Visibility of conditional text
@cindex If text conditionally visible
@findex ifinfo
@findex iftex
Sometimes it is good to use different text for a printed manual and
its corresponding Info file. In this case, you can use the
@dfn{conditional commands} to specify which text is for the printed manual
and which is for the Info file.@refill
@menu
* Conditional Commands:: How to specify text for Info or @TeX{}.
* Using Ordinary TeX Commands:: You can use any and all @TeX{} commands.
* set clear value:: How to designate which text to format (for
both Info and @TeX{}); and how to set a
flag to a string that you can insert.
@end menu
@node Conditional Commands, Using Ordinary TeX Commands, Conditionals, Conditionals
@ifinfo
@heading Using @code{@@ifinfo} and @code{@@iftex}
@end ifinfo
@code{@@ifinfo} begins segments of text that should be ignored
by @TeX{} when it
typesets the printed manual. The segment of text appears only
in the Info file.
The @code{@@ifinfo} command should appear on a line by itself; end
the Info-only text with a line containing @code{@@end ifinfo} by
itself. At the beginning of a Texinfo file, the Info permissions are
contained within a region marked by @code{@@ifinfo} and @code{@@end
ifinfo}. (@xref{Info Summary and Permissions}.)@refill
The @code{@@iftex} and @code{@@end iftex} commands are similar to the
@code{@@ifinfo} and @code{@@end ifinfo} commands, except that they
specify text that will appear in the printed manual but not in the Info
file.@refill
@need 700
For example,
@example
@@iftex
This text will appear only in the printed manual.
@@end iftex
@@ifinfo
However, this text will appear only in Info.
@@end ifinfo
@end example
@noindent
The preceding example produces the following line:
@iftex
This text will appear only in the printed manual.
@end iftex
@ifinfo
However, this text will appear only in Info.
@end ifinfo
@noindent
Note how you only see one of the two lines, depending on whether you
are reading the Info version or the printed version of this
manual.@refill
The @code{@@titlepage} command is a special variant of @code{@@iftex} that
is used for making the title and copyright pages of the printed
manual. (@xref{titlepage, , @code{@@titlepage}}.) @refill
@node Using Ordinary TeX Commands, set clear value, Conditional Commands, Conditionals
@comment node-name, next, previous, up
@section Using Ordinary @TeX{} Commands
@cindex @TeX{} commands, using ordinary
@cindex Ordinary @TeX{} commands, using
@cindex Commands using ordinary @TeX{}
@cindex Plain@TeX{}
Inside a region delineated by @code{@@iftex} and @code{@@end iftex},
you can embed some Plain@TeX{} commands. Info will ignore these
commands since they are only in that part of the file which is seen by
@TeX{}. You can write the @TeX{} commands as you would write them in
a normal @TeX{} file, except that you must replace the @samp{\} used
by @TeX{} with an @samp{@@}. For example, in the @code{@@titlepage}
section of a Texinfo file, you can use the @TeX{} command
@code{@@vskip} to format the copyright page. (The @code{@@titlepage}
command causes Info to ignore the region automatically, as it does
with the @code{@@iftex} command.)@refill
However, many features of Plain@TeX{} will not work, as they are
overridden by features of Texinfo.
@findex tex
You can enter Plain@TeX{} completely, and use @samp{\} in the @TeX{}
commands, by delineating a region with the @code{@@tex} and @code{@@end
tex} commands. (The @code{@@tex} command also causes Info to ignore the
region, like the @code{@@iftex}
command.)@refill
@cindex Mathematical expressions
For example, here is a mathematical expression written in
Plain@TeX{}:@refill
@example
@@tex
$$ \chi^2 = \sum_@{i=1@}^N
\left (y_i - (a + b x_i)
\over \sigma_i\right)^2 $$
@@end tex
@end example
@noindent
The output of this example will appear only in a printed manual. If
you are reading this in Info, you will not see anything after this
paragraph.
@iftex
In a printed manual, the above expression looks like
this:
@end iftex
@tex
$$ \chi^2 = \sum_{i=1}^N
\left(y_i - (a + b x_i)
\over \sigma_i\right)^2 $$
@end tex
@node set clear value, , Using Ordinary TeX Commands, Conditionals
@comment node-name, next, previous, up
@section @code{@@set}, @code{@@clear}, and @code{@@value}
You can direct the Texinfo formatting commands to format or ignore parts
of a Texinfo file with the @code{@@set}, @code{@@clear}, @code{@@ifset},
and @code{@@ifclear} commands.@refill
In addition, you can use the @code{@@set @var{flag}} command to set the
value of @var{flag} to a string of characters; and use
@code{@@value@{@var{flag}@}} to insert that string. You can use
@code{@@set}, for example, to set a date and use @code{@@value} to
insert the date in several places in the Texinfo file.@refill
@menu
* ifset ifclear:: Format a region if a flag is set.
* value:: Replace a flag with a string.
* value Example:: An easy way to update edition information.
@end menu
@node ifset ifclear, value, set clear value, set clear value
@subsection @code{@@ifset} and @code{@@ifclear}
@findex ifset
When a @var{flag} is set, the Texinfo formatting commands format text
between subsequent pairs of @code{@@ifset @var{flag}} and @code{@@end
ifset} commands. When the @var{flag} is cleared, the Texinfo formatting
commands do @emph{not} format the text.
Use the @code{@@set @var{flag}} command to turn on, or @dfn{set}, a
@var{flag}; a @dfn{flag} can be any single word. The format for the
command looks like this:@refill
@findex set
@example
@@set @var{flag}
@end example
Write the conditionally formatted text between @code{@@ifset @var{flag}}
and @code{@@end ifset} commands, like this:@refill
@example
@group
@@ifset @var{flag}
@var{conditional-text}
@@end ifset
@end group
@end example
For example, you can create one document that has two variants, such as
a manual for a `large' and `small' model:@refill
@example
You can use this machine to dig up shrubs
without hurting them.
@@set large
@@ifset large
It can also dig up fully grown trees.
@@end ifset
Remember to replant promptly @dots{}
@end example
@noindent
In the example, the formatting commands will format the text between
@code{@@ifset large} and @code{@@end ifset} because the @code{large}
flag is set.@refill
@findex clear
Use the @code{@@clear @var{flag}} command to turn off, or @dfn{clear},
a flag. Clearing a flag is the opposite of setting a flag. The
command looks like this:@refill
@example
@@clear @var{flag}
@end example
@noindent
Write the command on a line of its own.
When @var{flag} is cleared, the Texinfo formatting commands do
@emph{not} format the text between @code{@@ifset @var{flag}} and
@code{@@end ifset}; that text is ignored and does not appear in either
printed or Info output.@refill
For example, if you clear the flag of the preceding example by writing
an @code{@@clear large} command after the @code{@@set large} command
(but before the conditional text), then the Texinfo formatting commands
ignore the text between the @code{@@ifset large} and @code{@@end ifset}
commands. In the formatted output, that text does not appear; in both
printed and Info output, you see only the lines that say, ``You can use
this machine to dig up shrubs without hurting them. Remember to replant
promptly @dots{}''.
@findex ifclear
If a flag is cleared with an @code{@@clear @var{flag}} command, then
the formatting commands format text between subsequent pairs of
@code{@@ifclear} and @code{@@end ifclear} commands. But if the flag
is set with @code{@@set @var{flag}}, then the formatting commands do
@emph{not} format text between an @code{@@ifclear} and an @code{@@end
ifclear} command; rather, they ignore that text. An @code{@@ifclear}
command looks like this:@refill
@example
@@ifclear @var{flag}
@end example
@need 700
In brief, the commands are:@refill
@table @code
@item @@set @var{flag}
Tell the Texinfo formatting commands that @var{flag} is set.@refill
@item @@clear @var{flag}
Tell the Texinfo formatting commands that @var{flag} is cleared.@refill
@item @@ifset @var{flag}
If @var{flag} is set, tell the Texinfo formatting commands to format
the text up to the following @code{@@end ifset} command.@refill
If @var{flag} is cleared, tell the Texinfo formatting commands to
ignore text up to the following @code{@@end ifset} command.@refill
@item @@ifclear @var{flag}
If @var{flag} is set, tell the Texinfo formatting commands to ignore
the text up to the following @code{@@end ifclear} command.@refill
If @var{flag} is cleared, tell the Texinfo formatting commands to
format the text up to the following @code{@@end ifclear}
command.@refill
@end table
@node value, value Example, ifset ifclear, set clear value
@subsection @code{@@value}
@findex value
You can use the @code{@@set} command to specify a value for a flag,
which is expanded by the @code{@@value} command. The value is a string
a characters.
Write the @code{@@set} command like this:
@example
@@set foo This is a string.
@end example
@noindent
This sets the value of @code{foo} to ``This is a string.''
The Texinfo formatters replace an @code{@@value@{@var{flag}@}} command with
the string to which @var{flag} is set.@refill
Thus, when @code{foo} is set as shown above, the Texinfo formatters convert
@example
@group
@@value@{foo@}
@exdent @r{to}
This is a string.
@end group
@end example
You can write an @code{@@value} command within a paragraph; but you
must write an @code{@@set} command on a line of its own.
If you write the @code{@@set} command like this:
@example
@@set foo
@end example
@noindent
without specifying a string, the value of @code{foo} is an empty string.
If you clear a previously set flag with an @code{@@clear @var{flag}}
command, a subsequent @code{@@value@{flag@}} command is invalid and the
string is replaced with an error message that says @samp{@{No value for
"@var{flag}"@}}.
For example, if you set @code{foo} as follows:@refill
@example
@@set how-much very, very, very
@end example
@noindent
then the formatters transform
@example
@group
It is a @@value@{how-much@} wet day.
@exdent @r{into}
It is a very, very, very wet day.
@end group
@end example
If you write
@example
@@clear how-much
@end example
@noindent
then the formatters transform
@example
@group
It is a @@value@{how-much@} wet day.
@exdent @r{into}
It is a @{No value for "how-much"@} wet day.
@end group
@end example
@node value Example, , value, set clear value
@subsection @code{@@value} Example
You can use the @code{@@value} command to limit the number of places you
need to change when you record an update to a manual.
Here is how it is done in @cite{The GNU Make Manual}:
@need 1000
@noindent
Set the flags:
@example
@group
@@set EDITION 0.35 Beta
@@set VERSION 3.63 Beta
@@set UPDATED 14 August 1992
@@set UPDATE-MONTH August 1992
@end group
@end example
@need 750
@noindent
Write text for the first @code{@@ifinfo} section, for people reading the
Texinfo file:
@example
@group
This is Edition @@value@{EDITION@},
last updated @@value@{UPDATED@},
of @@cite@{The GNU Make Manual@},
for @@code@{make@}, Version @@value@{VERSION@}.
@end group
@end example
@need 1000
@noindent
Write text for the title page, for people reading the printed manual:
@c List only the month and the year since that looks less fussy on a
@c printed cover than a date that lists the day as well.
@example
@group
@@title GNU Make
@@subtitle A Program for Directing Recompilation
@@subtitle Edition @@value@{EDITION@}, @dots{}
@@subtitle @@value@{UPDATE-MONTH@}
@end group
@end example
@noindent
(On a printed cover, a date listing the month and the year looks less
fussy than a date listing the day as well as the month and year.)
@need 750
@noindent
Write text for the Top node, for people reading the Info file:
@example
@group
This is Edition @@value@{EDITION@}
of the @@cite@{GNU Make Manual@},
last updated @@value@{UPDATED@}
for @@code@{make@} Version @@value@{VERSION@}.
@end group
@end example
@need 950
After you format the manual, the text in the first @code{@@ifinfo}
section looks like this:
@example
@group
This is Edition 0.35 Beta, last updated 14 August 1992,
of `The GNU Make Manual', for `make', Version 3.63 Beta.
@end group
@end example
When you update the manual, change only the values of the flags; you do
not need to rewrite the three sections.
@node Format/Print Hardcopy, Create an Info File, Conditionals, Top
@comment node-name, next, previous, up
@chapter Format and Print Hardcopy
@cindex Format and print hardcopy
@cindex Hardcopy, printing it
@cindex Making a printed manual
@cindex Sorting indices
@cindex Indices, sorting
@cindex @TeX{} index sorting
@findex texindex
There are three major shell commands for making a printed manual from a
Texinfo file: one for converting the Texinfo file into a file that will be
printed, a second for sorting indices, and a third for printing the
formatted document. When you use the shell commands, you can either
work directly in the operating system shell or work within a shell
inside GNU Emacs.@refill
If you are using GNU Emacs, you can use commands provided by Texinfo
mode instead of shell commands. In addition to the three commands to
format a file, sort the indices, and print the result, Texinfo mode
offers key bindings for commands to recenter the output buffer, show the
print queue, and delete a job from the print queue.@refill
@menu
* Use TeX:: Use @TeX{} to format for hardcopy.
* Format with tex/texindex:: How to format in a shell.
* Format with texi2dvi:: A simpler way to use the shell.
* Print with lpr:: How to print.
* Within Emacs:: How to format and print from an Emacs shell.
* Texinfo Mode Printing:: How to format and print in Texinfo mode.
* Compile-Command:: How to print using Emacs's compile command.
* Requirements Summary:: @TeX{} formatting requirements summary.
* Preparing for TeX:: What you need to do to use @TeX{}.
* Overfull hboxes:: What are and what to do with overfull hboxes.
* smallbook:: How to print small format books and manuals.
* A4 Paper:: How to print on European A4 paper.
* Cropmarks and Magnification:: How to print marks to indicate the size
of pages and how to print scaled up output.
@end menu
@node Use TeX, Format with tex/texindex, Format/Print Hardcopy, Format/Print Hardcopy
@ifinfo
@heading Use @TeX{}
@end ifinfo
The typesetting program called @TeX{} is used for formatting a Texinfo
file. @TeX{} is a very powerful typesetting program and, if used right,
does an exceptionally good job. @xref{Obtaining TeX, , How to Obtain
@TeX{}}, for information on how to obtain @TeX{}.@refill
The @code{makeinfo}, @code{texinfo-format-region}, and
@code{texinfo-format-buffer} commands read the very same @@-commands
in the Texinfo file as does @TeX{}, but process them differently to
make an Info file; see @ref{Create an Info File}.@refill
@node Format with tex/texindex, Format with texi2dvi, Use TeX, Format/Print Hardcopy
@comment node-name, next, previous, up
@section Format using @code{tex} and @code{texindex}
@cindex Shell formatting with @code{tex} and @code{texindex}
@cindex Formatting with @code{tex} and @code{texindex}
@cindex DVI file
Format the Texinfo file with the shell command @code{tex} followed by
the name of the Texinfo file. This command produces a formatted
@sc{dvi} file as well as several auxiliary files containing indices,
cross references, etc. The @sc{dvi} file (for @dfn{DeVice Independent}
file) can be printed on a wide variety of printers.@refill
The @code{tex} formatting command itself does not sort the indices; it
writes an output file of unsorted index data. This is a misfeature of
@TeX{}. (The @code{texi2dvi} command automatically generates indices;
see @ref{Format with texi2dvi, , Format using @code{texi2dvi}}.) To
generate a printed index after running the @code{tex} command, you first
need a sorted index to work from. The @code{texindex} command sorts
indices. (The source file @file{texindex.c} comes as part of the
standard GNU distribution and is usually installed when Emacs is
installed.)@refill
@findex texindex
@ignore
Usage: texindex [-k] [-T tempdir] infile [-o outfile] ...
Each infile arg can optionally be followed by a `-o outfile' arg;
for each infile that is not followed by a -o arg, the infile name with
`s' (for `sorted') appended is used for the outfile.
-T dir is the directory to put temp files in, instead of /tmp.
-k means `keep tempfiles', for debugging.
@end ignore
The @code{tex} formatting command outputs unsorted index files under
names that obey a standard convention. These names are the name of
your main input file to the @code{tex} formatting command, with
everything after the first period thrown away, and the two letter
names of indices added at the end. For example, the raw index output
files for the input file @file{foo.texinfo} would be @file{foo.cp},
@file{foo.vr}, @file{foo.fn}, @file{foo.tp}, @file{foo.pg} and
@file{foo.ky}. Those are exactly the arguments to give to
@code{texindex}.@refill
@need 1000
Or else, you can use @samp{??} as ``wild-cards'' and give the command in
this form:@refill
@example
texindex foo.??
@end example
@noindent
This command will run @code{texindex} on all the unsorted index files,
including any that you have defined yourself using @code{@@defindex}
or @code{@@defcodeindex}. (You may execute @samp{texindex foo.??}
even if there are similarly named files with two letter extensions
that are not index files, such as @samp{foo.el}. The @code{texindex}
command reports but otherwise ignores such files.)@refill
For each file specified, @code{texindex} generates a sorted index file
whose name is made by appending @samp{s} to the input file name. The
@code{@@printindex} command knows to look for a file of that name.
@code{texindex} does not alter the raw index output file.@refill
After you have sorted the indices, you need to rerun the @code{tex}
formatting command on the Texinfo file. This regenerates a formatted
@sc{dvi} file with up-to-date index entries.@footnote{If you use more
than one index and have cross references to an index other than the
first, you must run @code{tex} @emph{three times} to get correct output:
once to generate raw index data; again (after @code{texindex}) to output
the text of the indices and determine their true page numbers; and a
third time to output correct page numbers in cross references to them.
However, cross references to indices are rare.}@refill
To summarize, this is a three step process:
@enumerate
@item
Run the @code{tex} formatting command on the Texinfo file. This
generates the formatted @sc{dvi} file as well as the raw index files
with two letter extensions.@refill
@item
Run the shell command @code{texindex} on the raw index files to sort
them. This creates the corresponding sorted index files.@refill
@item
Rerun the @code{tex} formatting command on the Texinfo file. This
regenerates a formatted @sc{dvi} file with the index entries in the
correct order. This second run also corrects the page numbers for
the cross references. (The tables of contents are always correct.)@refill
@end enumerate
You need not run @code{texindex} each time after you run the
@code{tex} formatting. If you do not, on the next run, the @code{tex}
formatting command will use whatever sorted index files happen to
exist from the previous use of @code{texindex}. This is usually
@sc{ok} while you are debugging.@refill
@node Format with texi2dvi, Print with lpr, Format with tex/texindex, Format/Print Hardcopy
@comment node-name, next, previous, up
@section Format using @code{texi2dvi}
@findex texi2dvi @r{(shell script)}
The @code{texi2dvi} command is a shell script that automatically runs
both @code{tex} and @code{texindex} as needed to produce a @sc{dvi} file
with up-to-date, sorted indices. It simplifies the
@code{tex}---@code{texindex}---@code{tex} sequence described in the
previous section.
@need 1000
The syntax for @code{texi2dvi} is like this (where @samp{%} is the
shell prompt):@refill
@example
% texi2dvi @var{filename}@dots{}
@end example
@node Print with lpr, Within Emacs, Format with texi2dvi, Format/Print Hardcopy
@comment node-name, next, previous, up
@section Shell Print Using @code{lpr -d}
@findex lpr @r{(@sc{dvi} print command)}
You can print a @sc{dvi} file with the @sc{dvi} print command. The
precise printing command to use depends on your system; @samp{lpr -d} is
common. The @sc{dvi} print command may require a file name without any
extension or with a @samp{.dvi} extension.@refill
@need 1200
The following commands, for example, sort the indices, format, and
print the @cite{Bison Manual} (where @samp{%} is the shell
prompt):@refill
@example
@group
% tex bison.texinfo
% texindex bison.??
% tex bison.texinfo
% lpr -d bison.dvi
@end group
@end example
@noindent
(Remember that the shell commands may be different at your site; but
these are commonly used versions.)@refill
@need 1000
Using the @code{texi2dvi} shell script, you simply need type:@refill
@example
@group
% texi2dvi bison.texinfo
% lpr -d bison.dvi
@end group
@end example
@node Within Emacs, Texinfo Mode Printing, Print with lpr, Format/Print Hardcopy
@comment node-name, next, previous, up
@section From an Emacs Shell @dots{}
@cindex Print, format from Emacs shell
@cindex Format, print from Emacs shell
@cindex Shell, format, print from
@cindex Emacs shell, format, print from
@cindex GNU Emacs shell, format, print from
You can give formatting and printing commands from a shell within GNU
Emacs. To create a shell within Emacs, type @kbd{M-x shell}. In this
shell, you can format and print the document. @xref{Format/Print
Hardcopy, , Format and Print Hardcopy}, for details.@refill
You can switch to and from the shell buffer while @code{tex} is
running and do other editing. If you are formatting a long document
on a slow machine, this can be very convenient.@refill
You can also use @code{texi2dvi} from an Emacs shell. For example,
here is how to use @code{texi2dvi} to format and print @cite{Using and
Porting GNU CC} from a shell within Emacs (where @samp{%} is the shell
prompt):@refill
@example
@group
% texi2dvi gcc.texinfo
% lpr -d gcc.dvi
@end group
@end example
@ifinfo
@xref{Texinfo Mode Printing}, for more information about formatting
and printing in Texinfo mode.@refill
@end ifinfo
@node Texinfo Mode Printing, Compile-Command, Within Emacs, Format/Print Hardcopy
@section Formatting and Printing in Texinfo Mode
@cindex Region printing in Texinfo mode
@cindex Format and print in Texinfo mode
@cindex Print and format in Texinfo mode
Texinfo mode provides several predefined key commands for @TeX{}
formatting and printing. These include commands for sorting indices,
looking at the printer queue, killing the formatting job, and
recentering the display of the buffer in which the operations
occur.@refill
@table @kbd
@item C-c C-t C-b
@itemx M-x texinfo-tex-buffer
Run @code{texi2dvi} on the current buffer.@refill
@item C-c C-t C-r
@itemx M-x texinfo-tex-region
Run @TeX{} on the current region.@refill
@item C-c C-t C-i
@itemx M-x texinfo-texindex
Sort the indices of a Texinfo file formatted with
@code{texinfo-tex-region}.@refill
@item C-c C-t C-p
@itemx M-x texinfo-tex-print
Print a @sc{dvi} file that was made with @code{texinfo-tex-region} or
@code{texinfo-tex-buffer}.@refill
@item C-c C-t C-q
@itemx M-x tex-show-print-queue
Show the print queue.@refill
@item C-c C-t C-d
@itemx M-x texinfo-delete-from-print-queue
Delete a job from the print queue; you will be prompted for the job
number shown by a preceding @kbd{C-c C-t C-q} command
(@code{texinfo-show-tex-print-queue}).@refill
@item C-c C-t C-k
@itemx M-x tex-kill-job
Kill the currently running @TeX{} job started by
@code{texinfo-tex-region} or @code{texinfo-tex-buffer}, or any other
process running in the Texinfo shell buffer.@refill
@item C-c C-t C-x
@itemx M-x texinfo-quit-job
Quit a @TeX{} formatting job that has stopped because of an error by
sending an @key{x} to it. When you do this, @TeX{} preserves a record
of what it did in a @file{.log} file.@refill
@item C-c C-t C-l
@itemx M-x tex-recenter-output-buffer
Redisplay the shell buffer in which the @TeX{} printing and formatting
commands are run to show its most recent output.@refill
@end table
@need 1000
Thus, the usual sequence of commands for formatting a buffer is as
follows (with comments to the right):@refill
@example
@group
C-c C-t C-b @r{Run @code{texi2dvi} on the buffer.}
C-c C-t C-p @r{Print the @sc{dvi} file.}
C-c C-t C-q @r{Display the printer queue.}
@end group
@end example
The Texinfo mode @TeX{} formatting commands start a subshell in Emacs
called the @file{*tex-shell*}. The @code{texinfo-tex-command},
@code{texinfo-texindex-command}, and @code{tex-dvi-print-command}
commands are all run in this shell.
You can watch the commands operate in the @samp{*tex-shell*} buffer,
and you can switch to and from and use the @samp{*tex-shell*} buffer
as you would any other shell buffer.@refill
@need 1500
The formatting and print commands depend on the values of several variables.
The default values are:@refill
@example
@group
@r{Variable} @r{Default value}
texinfo-texi2dvi-command "texi2dvi"
texinfo-tex-command "tex"
texinfo-texindex-command "texindex"
texinfo-delete-from-print-queue-command "lprm"
texinfo-tex-trailer "@@bye"
tex-start-of-header "%**start"
tex-end-of-header "%**end"
tex-dvi-print-command "lpr -d"
tex-show-queue-command "lpq"
@end group
@end example
You can change the values of these variables with the @kbd{M-x
edit-options} command (@pxref{Edit Options, , Editing Variable Values,
emacs, The GNU Emacs Manual}), with the @kbd{M-x set-variable} command
(@pxref{Examining, , Examining and Setting Variables, emacs, The GNU
Emacs Manual}), or with your @file{.emacs} initialization file
(@pxref{Init File, , , emacs, The GNU Emacs Manual}).@refill
@node Compile-Command, Requirements Summary, Texinfo Mode Printing, Format/Print Hardcopy
@comment node-name, next, previous, up
@section Using the Local Variables List
@cindex Local variables
@cindex Compile command for formatting
@cindex Format with the compile command
Yet another way to apply the @TeX{} formatting command to a Texinfo file
is to put that command in a @dfn{local variables list} at the end of the
Texinfo file. You can then specify the @code{tex} or @code{texi2dvi}
commands as a @code{compile-command} and have Emacs run it by typing
@kbd{M-x compile}. This creates a special shell called the
@file{*compilation*} buffer in which Emacs runs the compile command.
For example, at the end of the @file{gdb.texinfo} file, after the
@code{@@bye}, you could put the following:@refill
@example
@group
@@c Local Variables:
@@c compile-command: "texi2dvi gdb.texinfo"
@@c End:
@end group
@end example
@noindent
This technique is most often used by programmers who also compile programs
this way; see @ref{Compilation, , , emacs, The GNU Emacs Manual}.@refill
@node Requirements Summary, Preparing for TeX, Compile-Command, Format/Print Hardcopy
@comment node-name, next, previous, up
@section @TeX{} Formatting Requirements Summary
@cindex Requirements for formatting
@cindex Formatting requirements
Every Texinfo file that is to be input to @TeX{} must begin with a
@code{\input} command and contain an @code{@@settitle} command:@refill
@example
\input texinfo
@@settitle @var{name-of-manual}
@end example
@noindent
The first command instructs @TeX{} to load the macros it needs to
process a Texinfo file and the second command specifies the title of
printed manual.@refill
@need 1000
Every Texinfo file must end with a line that terminates @TeX{}
processing and forces out unfinished pages:@refill
@example
@@bye
@end example
Strictly speaking, these three lines are all a Texinfo file needs for
@TeX{}, besides the body. (The @code{@@setfilename} line is the only
line that a Texinfo file needs for Info formatting.)@refill
Usually, the file's first line contains an @samp{@@c -*-texinfo-*-}
comment that causes Emacs to switch to Texinfo mode when you edit the
file. In addition, the beginning usually includes an
@code{@@setfilename} for Info formatting, an @code{@@setchapternewpage}
command, a title page, a copyright page, and permissions. Besides an
@code{@@bye}, the end of a file usually includes indices and a table of
contents.@refill
@iftex
For more information, see
@ref{setchapternewpage, , @code{@@setchapternewpage}},
@ref{Headings, ,Page Headings},
@ref{Titlepage & Copyright Page},
@ref{Printing Indices & Menus}, and
@ref{Contents}.
@end iftex
@noindent
@ifinfo
For more information, see@*
@ref{setchapternewpage, , @code{@@setchapternewpage}},@*
@ref{Headings, ,Page Headings},@*
@ref{Titlepage & Copyright Page},@*
@ref{Printing Indices & Menus}, and@*
@ref{Contents}.
@end ifinfo
@node Preparing for TeX, Overfull hboxes, Requirements Summary, Format/Print Hardcopy
@comment node-name, next, previous, up
@section Preparing to Use @TeX{}
@cindex Preparing to use @TeX{}
@cindex @TeX{} input initialization
@cindex @code{TEXINPUTS} environment variable
@vindex TEXINPUTS
@cindex @b{.profile} initialization file
@cindex @b{.cshrc} initialization file
@cindex Initialization file for @TeX{} input
@TeX{} needs to know where to find the @file{texinfo.tex} file
that you have told it to input with the @samp{\input texinfo} command
at the beginning of the first line. The @file{texinfo.tex} file tells
@TeX{} how to handle @@-commands. (@file{texinfo.tex} is
included in the standard GNU distributions.)@refill
Usually, the @file{texinfo.tex} file is put in the default directory
that contains @TeX{} macros (the @file{/usr/lib/tex/macros}
directory) when GNU Emacs or other GNU software is installed.
In this case, @TeX{} will
find the file and you do not need to do anything special.
Alternatively, you can put @file{texinfo.tex} in the directory in
which the Texinfo source file is located, and @TeX{} will find it
there.@refill
However, you may want to specify the location of the @code{\input} file
yourself. One way to do this is to write the complete path for the file
after the @code{\input} command. Another way is to set the
@code{TEXINPUTS} environment variable in your @file{.cshrc} or
@file{.profile} file. The @code{TEXINPUTS} environment variable will tell
@TeX{} where to find the @file{texinfo.tex} file and any other file that
you might want @TeX{} to use.@refill
Whether you use a @file{.cshrc} or @file{.profile} file depends on
whether you use @code{csh}, @code{sh}, or @code{bash} for your shell
command interpreter. When you use @code{csh}, it looks to the
@file{.cshrc} file for initialization information, and when you use
@code{sh} or @code{bash}, it looks to the @file{.profile} file.@refill
@need 1000
In a @file{.cshrc} file, you could use the following @code{csh} command
sequence:@refill
@example
setenv TEXINPUTS .:/usr/me/mylib:/usr/lib/tex/macros
@end example
@need 1000
In a @file{.profile} file, you could use the following @code{sh} command
sequence:
@example
@group
TEXINPUTS=.:/usr/me/mylib:/usr/lib/tex/macros
export TEXINPUTS
@end group
@end example
@noindent
This would cause @TeX{} to look for @file{\input} file first in the current
directory, indicated by the @samp{.}, then in a hypothetical user's
@file{me/mylib} directory, and finally in the system library.@refill
@node Overfull hboxes, smallbook, Preparing for TeX, Format/Print Hardcopy
@comment node-name, next, previous, up
@section Overfull ``hboxes''
@cindex Overfull @samp{hboxes}
@cindex @samp{hboxes}, overfull
@cindex Final output
@TeX{} is sometimes unable to typeset a line without extending it into
the right margin. This can occur when @TeX{} comes upon what it
interprets as a long word that it cannot hyphenate, such as an
electronic mail network address or a very long title. When this
happens, @TeX{} prints an error message like this:@refill
@example
Overfull \hbox (20.76302pt too wide)
@end example
@noindent
(In @TeX{}, lines are in ``horizontal boxes'', hence the term, ``hbox''.
The backslash, @samp{\}, is the @TeX{} equivalent of @samp{@@}.)@refill
@TeX{} also provides the line number in the Texinfo source file and
the text of the offending line, which is marked at all the places that
@TeX{} knows how to hyphenate words.
@xref{Debugging with TeX, , Catching Errors with @TeX{} Formatting},
for more information about typesetting errors.@refill
If the Texinfo file has an overfull hbox, you can rewrite the sentence
so the overfull hbox does not occur, or you can decide to leave it. A
small excursion into the right margin often does not matter and may not
even be noticeable.@refill
@cindex Black rectangle in hardcopy
@cindex Rectangle, ugly, black in hardcopy
However, unless told otherwise, @TeX{} will print a large, ugly, black
rectangle beside the line that contains the overful hbox. This is so
you will notice the location of the problem if you are correcting a
draft.@refill
@need 1000
@findex finalout
To prevent such a monstrosity from marring your final printout, write
the following in the beginning of the Texinfo file on a line of its own,
before the @code{@@titlepage} command:@refill
@example
@@finalout
@end example
@node smallbook, A4 Paper, Overfull hboxes, Format/Print Hardcopy
@comment node-name, next, previous, up
@section Printing ``Small'' Books
@findex smallbook
@cindex Small book size
@cindex Book, printing small
@cindex Page sizes for books
@cindex Size of printed book
By default, @TeX{} typesets pages for printing in an 8.5 by 11 inch
format. However, you can direct @TeX{} to typeset a document in a 7 by
9.25 inch format that is suitable for bound books by inserting the
following command on a line by itself at the beginning of the Texinfo
file, before the title page:@refill
@example
@@smallbook
@end example
@noindent
(Since regular sized books are often about 7 by 9.25 inches, this
command might better have been called the @code{@@regularbooksize}
command, but it came to be called the @code{@@smallbook} command by
comparison to the 8.5 by 11 inch format.)@refill
If you write the @code{@@smallbook} command between the
start-of-header and end-of-header lines, the Texinfo mode @TeX{}
region formatting command, @code{texinfo-tex-region}, will format the
region in ``small'' book size (@pxref{Start of Header}).@refill
The Free Software Foundation distributes printed copies of @cite{The GNU
Emacs Manual} and other manuals in the ``small'' book size.
@xref{smallexample & smalllisp, , @code{@@smallexample} and
@code{@@smalllisp}}, for information about commands that make it easier
to produce examples for a smaller manual.@refill
@node A4 Paper, Cropmarks and Magnification, smallbook, Format/Print Hardcopy
@comment node-name, next, previous, up
@section Printing on A4 Paper
@cindex A4 paper, printing on
@cindex Paper size, European A4
@cindex European A4 paper
@findex afourpaper
You can tell @TeX{} to typeset a document for printing on European size
A4 paper with the @code{@@afourpaper} command. Write the command on a
line by itself between @code{@@iftex} and @code{@@end iftex} lines near
the beginning of the Texinfo file, before the title page:@refill
For example, this is how you would write the header for this manual:@refill
@example
@group
\input texinfo @@c -*-texinfo-*-
@@c %**start of header
@@setfilename texinfo
@@settitle Texinfo
@@syncodeindex vr fn
@@iftex
@@afourpaper
@@end iftex
@@c %**end of header
@end group
@end example
@node Cropmarks and Magnification, , A4 Paper, Format/Print Hardcopy
@comment node-name, next, previous, up
@section Cropmarks and Magnification
@findex cropmarks
@cindex Cropmarks for printing
@cindex Printing cropmarks
You can attempt to direct @TeX{} to print cropmarks at the corners of
pages with the @code{@@cropmarks} command. Write the @code{@@cropmarks}
command on a line by itself between @code{@@iftex} and @code{@@end
iftex} lines near the beginning of the Texinfo file, before the title
page, like this:@refill
@example
@group
@@iftex
@@cropmarks
@@end iftex
@end group
@end example
This command is mainly for printers that typeset several pages on one
sheet of film; but you can attempt to use it to mark the corners of a
book set to 7 by 9.25 inches with the @code{@@smallbook} command.
(Printers will not produce cropmarks for regular sized output that is
printed on regular sized paper.) Since different printing machines work
in different ways, you should explore the use of this command with a
spirit of adventure. You may have to redefine the command in the
@file{texinfo.tex} definitions file.@refill
@findex mag @r{(@TeX{} command)}
@cindex Magnified printing
@cindex Larger or smaller pages
You can attempt to direct @TeX{} to typeset pages larger or smaller than
usual with the @code{\mag} @TeX{} command. Everything that is typeset
is scaled proportionally larger or smaller. (@code{\mag} stands for
``magnification''.) This is @emph{not} a Texinfo @@-command, but is a
Plain@TeX{} command that is prefixed with a backslash. You have to
write this command between @code{@@tex} and @code{@@end tex}
(@pxref{Using Ordinary TeX Commands, , Using Ordinary @TeX{}
Commands}).@refill
Follow the @code{\mag} command with an @samp{=} and then a number that
is 1000 times the magnification you desire. For example, to print pages
at 1.2 normal size, write the following near the beginning of the
Texinfo file, before the title page:@refill
@example
@group
@@tex
\mag=1200
@@end tex
@end group
@end example
With some printing technologies, you can print normal-sized copies that
look better than usual by using a larger-than-normal master.@refill
Depending on your system, @code{\mag} may not work or may work only at
certain magnifications. Be prepared to experiment.@refill
@node Create an Info File, Install an Info File, Format/Print Hardcopy, Top
@comment node-name, next, previous, up
@chapter Creating an Info File
@cindex Creating an Info file
@cindex Info, creating an on-line file
@cindex Formatting a file for Info
@code{makeinfo} is a utility that converts a Texinfo file into an Info
file; @code{texinfo-format-region} and @code{texinfo-format-buffer} are
GNU Emacs functions that do the same.@refill
A Texinfo file must possess an @code{@@setfilename} line near its
beginning, otherwise the Info formatting commands will fail.@refill
For information on installing the Info file in the Info system, see
@ref{Install an Info File}.@refill
@menu
* makeinfo advantages:: @code{makeinfo} provides better error checking.
* Invoking makeinfo:: How to run @code{makeinfo} from a shell.
* makeinfo options:: Specify fill-column and other options.
* Pointer Validation:: How to check that pointers point somewhere.
* makeinfo in Emacs:: How to run @code{makeinfo} from Emacs.
* texinfo-format commands:: Two Info formatting commands written
in Emacs Lisp are an alternative
to @code{makeinfo}.
* Batch Formatting:: How to format for Info in Emacs Batch mode.
* Tag and Split Files:: How tagged and split files help Info
to run better.
@end menu
@node makeinfo advantages, Invoking makeinfo, Create an Info File, Create an Info File
@ifinfo
@heading @code{makeinfo} Preferred
@end ifinfo
The @code{makeinfo} utility creates an Info file from a Texinfo source
file more quickly than either of the Emacs formatting commands and
provides better error messages. We recommend it. @code{makeinfo} is a
C program that is independent of Emacs. You do not need to run Emacs to
use @code{makeinfo}, which means you can use @code{makeinfo} on machines
that are too small to run Emacs. You can run @code{makeinfo} in
any one of three ways: from an operating system shell, from a shell
inside Emacs, or by typing a key command in Texinfo mode in Emacs.
@refill
The @code{texinfo-format-region} and the @code{texinfo-format-buffer}
commands are useful if you cannot run @code{makeinfo}. Also, in some
circumstances, they format short regions or buffers more quickly than
@code{makeinfo}.@refill
@node Invoking makeinfo, makeinfo options, makeinfo advantages, Create an Info File
@section Running @code{makeinfo} from a Shell
To create an Info file from a Texinfo file, type @code{makeinfo}
followed by the name of the Texinfo file. Thus, to create the Info
file for Bison, type the following at the shell prompt (where @samp{%}
is the prompt):@refill
@example
% makeinfo bison.texinfo
@end example
(You can run a shell inside Emacs by typing @kbd{M-x
shell}.)@refill
@ifinfo
Sometimes you will want to specify options. For example, if you wish
to discover which version of @code{makeinfo} you are using,
type:@refill
@example
% makeinfo --version
@end example
@xref{makeinfo options}, for more information.
@end ifinfo
@node makeinfo options, Pointer Validation, Invoking makeinfo, Create an Info File
@comment node-name, next, previous, up
@section Options for @code{makeinfo}
@cindex @code{makeinfo} options
@cindex Options for @code{makeinfo}
The @code{makeinfo} command takes a number of options. Most often,
options are used to set the value of the fill column and specify the
footnote style. Each command line option is a word preceded by
@samp{--}@footnote{@samp{--} has replaced @samp{+}, the old introductory
character, to maintain POSIX.2 compatibility without losing long-named
options.} or a letter preceded by @samp{-}. You can use abbreviations
for the option names as long as they are unique.@refill
For example, you could use the following command to create an Info
file for @file{bison.texinfo} in which each line is filled to only 68
columns (where @samp{%} is the prompt):@refill
@example
% makeinfo --fill-column=68 bison.texinfo
@end example
You can write two or more options in sequence, like this:@refill
@example
% makeinfo --no-split --fill-column=70 @dots{}
@end example
@noindent
This would keep the Info file together as one possibly very long
file and would also set the fill column to 70.@refill
@iftex
If you wish to discover which version of @code{makeinfo}
you are using, type:@refill
@example
% makeinfo --version
@end example
@end iftex
The options are:@refill
@need 100
@table @code
@item -D @var{var}
Cause @var{var} to be defined. This is equivalent to
@code{@@set @var{var}} in the Texinfo file.
@need 150
@item --error-limit @var{limit}
Set the maximum number of errors that @code{makeinfo} will report
before exiting (on the assumption that continuing would be useless).
The default number of errors that can be reported before
@code{makeinfo} gives up is 100.@refill
@need 150
@item --fill-column @var{width}
Specify the maximum number of columns in a line; this is the right-hand
edge of a line. Paragraphs that are filled will be filled to this
width. (Filling is the process of breaking up and connecting lines so
that lines are the same length as or shorter than the number specified
as the fill column. Lines are broken between words.) The default value
for @code{fill-column} is 72.
@refill
@item --footnote-style @var{style}
Set the footnote style to @var{style}, either @samp{end} for the end
node style or @samp{separate} for the separate node style. The value
set by this option overrides the value set in a Texinfo file by an
@code{@@footnotestyle} command. When the footnote style is
@samp{separate}, @code{makeinfo} makes a new node containing the
footnotes found in the current node. When the footnote style is
@samp{end}, @code{makeinfo} places the footnote references at the end
of the current node.@refill
@need 150
@item -I @var{dir}
Add @code{dir} to the directory search list for finding files that are
included using the @code{@@include} command. By default,
@code{makeinfo} searches only the current directory.
@need 150
@item --no-headers
Do not include menus or node lines in the output. This results in an
@sc{ascii} file that you cannot read in Info since it does not contain
the requisite nodes or menus; but you can print such a file in a
single, typewriter-like font and produce acceptable output.
@need 150
@item --no-split
Suppress the splitting stage of @code{makeinfo}. Normally, large
output files (where the size is greater than 70k bytes) are split into
smaller subfiles, each one approximately 50k bytes. If you specify
@samp{--no-split}, @code{makeinfo} will not split up the output
file.@refill
@need 100
@item --no-pointer-validate
@item --no-validate
Suppress the pointer-validation phase of @code{makeinfo}. Normally,
after a Texinfo file is processed, some consistency checks are made to
ensure that cross references can be resolved, etc.
@xref{Pointer Validation}.@refill
@need 150
@item --no-warn
Suppress the output of warning messages. This does @emph{not}
suppress the output of error messages, only warnings. You might
want this if the file you are creating has examples of Texinfo cross
references within it, and the nodes that are referenced do not actually
exist.@refill
@item --no-number-footnotes
Suppress automatic footnote numbering. By default, @code{makeinfo}
numbers each footnote sequentially in a single node, resetting the
current footnote number to 1 at the start of each node.
@need 150
@item --output @var{file}
@itemx -o @var{file}
Specify that the output should be directed to @var{file} and not to the
file name specified in the @code{@@setfilename} command found in the Texinfo
source. @var{file} can be the special token @samp{-}, which specifies
standard output.
@need 150
@item --paragraph-indent @var{indent}
Set the paragraph indentation style to @var{indent}. The value set by
this option overrides the value set in a Texinfo file by an
@code{@@paragraphindent} command. The value of @var{indent} is
interpreted as follows:@refill
@itemize @bullet
@item
If the value of @var{indent} is @samp{asis}, do not change the
existing indentation at the starts of paragraphs.@refill
@item
If the value of @var{indent} is zero, delete any existing
indentation.@refill
@item
If the value of @var{indent} is greater than zero, indent each
paragraph by that number of spaces.@refill
@end itemize
@need 100
@item --reference-limit @var{limit}
Set the value of the number of references to a node that
@code{makeinfo} will make without reporting a warning. If a node has more
than this number of references in it, @code{makeinfo} will make the
references but also report a warning.@refill
@need 150
@item -U @var{var}
Cause @var{var} to be undefined. This is equivalent to
@code{@@clear @var{var}} in the Texinfo file.
@need 100
@item --verbose
Cause @code{makeinfo} to display messages saying what it is doing.
Normally, @code{makeinfo} only outputs messages if there are errors or
warnings.@refill
@need 100
@item --version
Report the version number of this copy of @code{makeinfo}.@refill
@end table
@node Pointer Validation, makeinfo in Emacs, makeinfo options, Create an Info File
@section Pointer Validation
@cindex Pointer validation with @code{makeinfo}
@cindex Validation of pointers
If you do not suppress pointer-validation, @code{makeinfo} will check
the validity of the final Info file. Mostly, this means ensuring that
nodes you have referenced really exist. Here is a complete list of what
is checked:@refill
@enumerate
@item
If a `Next', `Previous', or `Up' node reference is a reference to a
node in the current file and is not an external reference such as to
@file{(dir)}, then the referenced node must exist.@refill
@item
In every node, if the `Previous' node is different from the `Up' node,
then the `Previous' node must also be pointed to by a `Next' node.@refill
@item
Every node except the `Top' node must have an `Up' pointer.@refill
@item
The node referenced by an `Up' pointer must contain a reference to the
current node in some manner other than through a `Next' reference.
This includes menu entries and cross references.@refill
@item
If the `Next' reference of a node is not the same as the `Next' reference
of the `Up' reference, then the node referenced by the `Next' pointer
must have a `Previous' pointer that points back to the current node.
This rule allows the last node in a section to point to the first node
of the next chapter.@refill
@end enumerate
@node makeinfo in Emacs, texinfo-format commands, Pointer Validation, Create an Info File
@section Running @code{makeinfo} inside Emacs
@cindex Running @code{makeinfo} in Emacs
@cindex @code{makeinfo} inside Emacs
@cindex Shell, running @code{makeinfo} in
You can run @code{makeinfo} in GNU Emacs Texinfo mode by using either the
@code{makeinfo-region} or the @code{makeinfo-buffer} commands. In
Texinfo mode, the commands are bound to @kbd{C-c C-m C-r} and @kbd{C-c
C-m C-b} by default.@refill
@table @kbd
@item C-c C-m C-r
@itemx M-x makeinfo-region
Format the current region for Info.@refill
@findex makeinfo-region
@item C-c C-m C-b
@itemx M-x makeinfo-buffer
Format the current buffer for Info.@refill
@findex makeinfo-buffer
@end table
When you invoke either @code{makeinfo-region} or
@code{makeinfo-buffer}, Emacs prompts for a file name, offering the
name of the visited file as the default. You can edit the default
file name in the minibuffer if you wish, before typing @key{RET} to
start the @code{makeinfo} process.@refill
The Emacs @code{makeinfo-region} and @code{makeinfo-buffer} commands
run the @code{makeinfo} program in a temporary shell buffer. If
@code{makeinfo} finds any errors, Emacs displays the error messages in
the temporary buffer.@refill
@cindex Errors, parsing
@cindex Parsing errors
@findex next-error
You can parse the error messages by typing @kbd{C-x `}
(@code{next-error}). This causes Emacs to go to and position the
cursor on the line in the Texinfo source that @code{makeinfo} thinks
caused the error. @xref{Compilation, , Running @code{make} or
Compilers Generally, emacs, The GNU Emacs Manual}, for more
information about using the @code{next-error} command.@refill
In addition, you can kill the shell in which the @code{makeinfo}
command is running or make the shell buffer display its most recent
output.@refill
@table @kbd
@item C-c C-m C-k
@itemx M-x makeinfo-kill-job
@findex makeinfo-kill-job
Kill the current running @code{makeinfo} job created by
@code{makeinfo-region} or @code{makeinfo-buffer}.@refill
@item C-c C-m C-l
@itemx M-x makeinfo-recenter-output-buffer
@findex makeinfo-recenter-output-buffer
Redisplay the @code{makeinfo} shell buffer to display its most recent
output.@refill
@end table
@noindent
(Note that the parallel commands for killing and recentering a @TeX{}
job are @kbd{C-c C-t C-k} and @kbd{C-c C-t C-l}. @xref{Texinfo Mode
Printing}.)@refill
You can specify options for @code{makeinfo} by setting the
@code{makeinfo-options} variable with either the @kbd{M-x
edit-options} or the @kbd{M-x set-variable} command, or by setting the
variable in your @file{.emacs} initialization file.@refill
For example, you could write the following in your @file{.emacs} file:@refill
@example
@group
(setq makeinfo-options
"--paragraph-indent=0 --no-split
--fill-column=70 --verbose")
@end group
@end example
@c If you write these three cross references using xref, you see
@c three references to the same named manual, which looks strange.
@iftex
For more information, see @ref{makeinfo options, , Options for
@code{makeinfo}}, as well as ``Editing Variable Values,''``Examining and
Setting Variables,'' and ``Init File'' in the @cite{The GNU Emacs
Manual}.
@end iftex
@noindent
@ifinfo
For more information, see@*
@ref{Edit Options, , Editing Variable Values, emacs, The GNU Emacs Manual},@*
@ref{Examining, , Examining and Setting Variables, emacs, The GNU Emacs Manual},@*
@ref{Init File, , , emacs, The GNU Emacs Manual}, and@*
@ref{makeinfo options, , Options for @code{makeinfo}}.
@end ifinfo
@node texinfo-format commands, Batch Formatting, makeinfo in Emacs, Create an Info File
@comment node-name, next, previous, up
@section The @code{texinfo-format@dots{}} Commands
@findex texinfo-format-region
@findex texinfo-format-buffer
In GNU Emacs in Texinfo mode, you can format part or all of a Texinfo
file with the @code{texinfo-format-region} command. This formats the
current region and displays the formatted text in a temporary buffer
called @samp{*Info Region*}.@refill
Similarly, you can format a buffer with the
@code{texinfo-format-buffer} command. This command creates a new
buffer and generates the Info file in it. Typing @kbd{C-x C-s} will
save the Info file under the name specified by the
@code{@@setfilename} line which must be near the beginning of the
Texinfo file.@refill
@table @kbd
@item C-c C-e C-r
@itemx @code{texinfo-format-region}
Format the current region for Info.
@findex texinfo-format-region
@item C-c C-e C-b
@itemx @code{texinfo-format-buffer}
Format the current buffer for Info.
@findex texinfo-format-buffer
@end table
The @code{texinfo-format-region} and @code{texinfo-format-buffer}
commands provide you with some error checking, and other functions can
provide you with further help in finding formatting errors. These
procedures are described in an appendix; see @ref{Catching Mistakes}.
However, the @code{makeinfo} program is often faster and
provides better error checking (@pxref{makeinfo in Emacs}).@refill
@node Batch Formatting, Tag and Split Files, texinfo-format commands, Create an Info File
@comment node-name, next, previous, up
@section Batch Formatting
@cindex Batch formatting for Info
@cindex Info batch formatting
You can format Texinfo files for Info using @code{batch-texinfo-format}
and Emacs Batch mode. You can run Emacs in Batch mode from any shell,
including a shell inside of Emacs. (@xref{Command Switches, , Command
Line Switches and Arguments, emacs, The GNU Emacs Manual}.)@refill
Here is the command to format all the files that end in @file{.texinfo}
in the current directory (where @samp{%} is the shell prompt):@refill
@example
% emacs -batch -funcall batch-texinfo-format *.texinfo
@end example
@noindent
Emacs processes all the files listed on the command line, even if an
error occurs while attempting to format some of them.@refill
Run @code{batch-texinfo-format} only with Emacs in Batch mode as shown;
it is not interactive. It kills the Batch mode Emacs on completion.@refill
@code{batch-texinfo-format} is convenient if you lack @code{makeinfo}
and want to format several Texinfo files at once. When you use Batch
mode, you create a new Emacs process. This frees your current Emacs, so
you can continue working in it. (When you run
@code{texinfo-format-region} or @code{texinfo-format-buffer}, you cannot
use that Emacs for anything else until the command finishes.)@refill
@node Tag and Split Files, , Batch Formatting, Create an Info File
@comment node-name, next, previous, up
@section Tag Files and Split Files
@cindex Making a tag table automatically
@cindex Tag table, making automatically
If a Texinfo file has more than 30,000 bytes,
@code{texinfo-format-buffer} automatically creates a tag table
for its Info file; @code{makeinfo} always creates a tag table. With
a @dfn{tag table}, Info can jump to new nodes more quickly than it can
otherwise.@refill
@cindex Indirect subfiles
In addition, if the Texinfo file contains more than about 70,000
bytes, @code{texinfo-format-buffer} and @code{makeinfo} split the
large Info file into shorter @dfn{indirect} subfiles of about 50,000
bytes each. Big files are split into smaller files so that Emacs does
not need to make a large buffer to hold the whole of a large Info
file; instead, Emacs allocates just enough memory for the small, split
off file that is needed at the time. This way, Emacs avoids wasting
memory when you run Info. (Before splitting was implemented, Info
files were always kept short and @dfn{include files} were designed as
a way to create a single, large printed manual out of the smaller Info
files. @xref{Include Files}, for more information. Include files are
still used for very large documents, such as @cite{The Emacs Lisp
Reference Manual}, in which each chapter is a separate file.)@refill
When a file is split, Info itself makes use of a shortened version of
the original file that contains just the tag table and references to
the files that were split off. The split off files are called
@dfn{indirect} files.@refill
The split off files have names that are created by appending @w{@samp{-1}},
@w{@samp{-2}}, @w{@samp{-3}} and so on to the file name specified by the
@code{@@setfilename} command. The shortened version of the original file
continues to have the name specified by @code{@@setfilename}.@refill
At one stage in writing this document, for example, the Info file was saved
as @file{test-texinfo} and that file looked like this:@refill
@example
@group
Info file: test-texinfo, -*-Text-*-
produced by texinfo-format-buffer
from file: new-texinfo-manual.texinfo
^_
Indirect:
test-texinfo-1: 102
test-texinfo-2: 50422
@end group
@group
test-texinfo-3: 101300
^_^L
Tag table:
(Indirect)
Node: overview^?104
Node: info file^?1271
@end group
@group
Node: printed manual^?4853
Node: conventions^?6855
@dots{}
@end group
@end example
@noindent
(But @file{test-texinfo} had far more nodes than are shown here.) Each of
the split off, indirect files, @file{test-texinfo-1},
@file{test-texinfo-2}, and @file{test-texinfo-3}, is listed in this file
after the line that says @samp{Indirect:}. The tag table is listed after
the line that says @samp{Tag table:}. @refill
In the list of indirect files, the number following the file name
records the cumulative number of bytes in the preceding indirect files,
not counting the file list itself, the tag table, or the permissions
text in each file. In the tag table, the number following the node name
records the location of the beginning of the node, in bytes from the
beginning.@refill
If you are using @code{texinfo-format-buffer} to create Info files,
you may want to run the @code{Info-validate} command. (The
@code{makeinfo} command does such a good job on its own, you do not
need @code{Info-validate}.) However, you cannot run the @kbd{M-x
Info-validate} node-checking command on indirect files. For
information on how to prevent files from being split and how to
validate the structure of the nodes, see @ref{Using
Info-validate}.@refill
@node Install an Info File, Command List, Create an Info File, Top
@comment node-name, next, previous, up
@chapter Installing an Info File
@cindex Installing an Info file
@cindex Info file installation
@cindex @file{dir} directory for Info installation
Info files are usually kept in the @file{info} directory. You can read
Info files using the standalone Info program or the Info reader built
into Emacs. (@inforef{Top, info, info}, for an introduction to Info.)
@menu
* Directory file:: The top level menu for all Info files.
* New Info File:: Listing a new info file.
* Other Info Directories:: How to specify Info files that are
located in other directories.
@end menu
@node Directory file, New Info File, Install an Info File, Install an Info File
@ifinfo
@heading The @file{dir} File
@end ifinfo
For Info to work, the @file{info} directory must contain a file that
serves as a top level directory for the Info system. By convention,
this file is called @file{dir}. (You can find the location of this file
within Emacs by typing @kbd{C-h i} to enter Info and then typing
@kbd{C-x C-f} to see the pathname to the @file{info} directory.)
The @file{dir} file is itself an Info file. It contains the top level
menu for all the Info files in the system. The menu looks like
this:@refill
@example
@group
* Menu:
* Info: (info). Documentation browsing system.
* Emacs: (emacs). The extensible, self-documenting
text editor.
* Texinfo: (texinfo). With one source file, make
either a printed manual using
TeX or an Info file.
@dots{}
@end group
@end example
Each of these menu entries points to the `Top' node of the Info file
that is named in parentheses. (The menu entry does not need to
specify the `Top' node, since Info goes to the `Top' node if no node
name is mentioned. @xref{Other Info Files, , Nodes in Other Info
Files}.)@refill
Thus, the @samp{Info} entry points to the `Top' node of the
@file{info} file and the @samp{Emacs} entry points to the `Top' node
of the @file{emacs} file.@refill
In each of the Info files, the `Up' pointer of the `Top' node refers
back to the @code{dir} file. For example, the line for the `Top'
node of the Emacs manual looks like this in Info:@refill
@example
File: emacs Node: Top, Up: (DIR), Next: Distrib
@end example
@noindent
(Note that in this case, the @file{dir} file name is written in upper
case letters---it can be written in either upper or lower case. Info
has a feature that it will change the case of the file name to lower
case if it cannot find the name as written.)@refill
@c !!! Can any file name be written in upper or lower case,
@c or is dir a special case?
@c Yes, apparently so, at least with Gillespie's Info. --rjc 24mar92
@c
@node New Info File, Other Info Directories, Directory file, Install an Info File
@section Listing a New Info File
@cindex Adding a new info file
@cindex Listing a new info file
@cindex New info file, listing it in @file{dir} file
@cindex Info file, listing new one
@cindex @file{dir} file listing
To add a new Info file to your system, write a menu entry for it in the
menu in the @file{dir} file in the @file{info} directory. Also, move
the new Info file itself to the @file{info} directory. For example, if
you were adding documentation for GDB, you would write the following new
entry:@refill
@example
* GDB: (gdb). The source-level C debugger.
@end example
@noindent
The first part of the menu entry is the menu entry name, followed by a
colon. The second part is the name of the Info file, in parentheses,
followed by a period. The third part is the description.@refill
Conventionally, the name of an Info file has a @file{.info} extension.
Thus, you might list the name of the file like this:
@example
* GDB: (gdb.info). The source-level C debugger.
@end example
@noindent
However, Info will look for a file with a @file{.info} extension if it
does not find the file under the name given in the menu. This means
that you can refer to the file @file{gdb.info} as @file{gdb}, as shown
in the first example. This looks better.
@node Other Info Directories, , New Info File, Install an Info File
@comment node-name, next, previous, up
@section Info Files in Other Directories
@cindex Installing Info in another directory
@cindex Info installed in another directory
@cindex Another Info directory
If an Info file is not in the @file{info} directory, there are three
ways to specify its location:@refill
@itemize @bullet
@item
Write the pathname in the @file{dir} file as the second part of the
menu.@refill
@item
If you are using Emacs, list the name of the file in a second @file{dir}
file, in its directory; and then add the name of that directory to the
@code{Info-directory-list} variable in your personal or site
initialization file.
This tells Emacs's Info reader reader where to look for @file{dir}
files. Emacs merges the files named @file{dir} from each of the listed
directories. (In Emacs Version 18, you can set the
@code{Info-directory} variable to the name of only one
directory.)@refill
@item
Specify the @file{info} directory name in an environment variable in
your @file{.profile} or @file{.cshrc} initialization file. (Only you
and others who set this environment variable will be able to find Info
files whose location is specified this way.)@refill
@end itemize
For example, to reach a test file in the @file{~bob/manuals}
directory, you could add an entry like this to the menu in the
@file{dir} file:@refill
@example
* Test: (/usr/bob/manuals/info-test). Bob's own test file.
@end example
@noindent
In this case, the absolute file name of the @file{info-test} file is
written as the second part of the menu entry.@refill
@vindex Info-directory-list
Alternatively, you could write the following in your @file{.emacs}
file:@refill
@example
@group
(setq Info-directory-list
'("/usr/bob/manuals"
"/usr/local/emacs/info"))
@end group
@end example
@c reworded to avoid overfill hbox
This tells Emacs to merge the @file{dir} file from the
@file{/usr/bob/manuals} directory with the @file{dir} file from the
@file{"/usr/local/emacs/info}" directory. Info will list the
@file{/usr/bob/manuals/info-test} file as a menu entry in the
@file{/usr/bob/manuals/dir} file.@refill
@vindex INFOPATH
Finally, you can tell Info where to look by setting the
@code{INFOPATH} environment variable in your @file{.cshrc} or
@file{.profile} file.@refill
If you use @code{sh} or @code{bash} for your shell command interpreter,
you must set the @code{INFOPATH} environment variable in the
@file{.profile} initialization file; but if you use @code{csh}, you must
set the variable in the @file{.cshrc} initialization file. The two
files require slightly different command formats.@refill
@itemize @bullet
@item
In a @file{.cshrc} file, you could set the @code{INFOPATH}
variable as follows:@refill
@smallexample
setenv INFOPATH .:~bob/manuals:/usr/local/emacs/info
@end smallexample
@item
In a @file{.profile} file, you would achieve the same effect by
writing:@refill
@smallexample
INFOPATH=.:~bob/manuals:/usr/local/emacs/info
export INFOPATH
@end smallexample
@end itemize
@noindent
The @samp{.} indicates the current directory. Emacs uses the
@code{INFOPATH} environment variable to initialize the value of Emacs's
own @code{Info-directory-list} variable.
@c ================ Appendix starts here ================
@node Command List, Tips, Install an Info File, Top
@appendix @@-Command List
@cindex Alphabetical @@-command list
@cindex List of @@-commands
@cindex @@-command list
Here is an alphabetical list of the @@-commands in Texinfo. Square
brackets, @t{[}@w{ }@t{]}, indicate optional arguments; an ellipsis,
@samp{@dots{}}, indicates repeated text.@refill
@sp 1
@table @code
@item @@*
Force a line break. Do not end a paragraph that uses @code{@@*} with
an @code{@@refill} command. @xref{Line Breaks}.@refill
@item @@.
Stands for a period that really does end a sentence (usually after an
end-of-sentence capital letter). @xref{Controlling Spacing}.@refill
@item @@:
Indicate to @TeX{} that an immediately preceding period, question
mark, exclamation mark, or colon does not end a sentence. Prevent
@TeX{} from inserting extra whitespace as it does at the end of a
sentence. The command has no effect on the Info file output.
@xref{Controlling Spacing}.@refill
@item @@@@
Stands for @samp{@@}. @xref{Braces Atsigns Periods, , Inserting
@samp{@@}}.@refill
@item @@@{
Stands for a left-hand brace, @samp{@{}.@*
@xref{Braces Atsigns Periods, , Inserting @@ braces and periods}.@refill
@item @@@}
Stands for a right-hand brace, @samp{@}}.@*
@xref{Braces Atsigns Periods, , Inserting @@ braces and periods}.@refill
@item @@appendix @var{title}
Begin an appendix. The title appears in the table
of contents of a printed manual. In Info, the title is
underlined with asterisks. @xref{unnumbered & appendix, , The
@code{@@unnumbered} and @code{@@appendix} Commands}.@refill
@item @@appendixsec @var{title}
@itemx @@appendixsection @var{title}
Begin an appendix section within an appendix. The section title appears
in the table of contents of a printed manual. In Info, the title is
underlined with equal signs. @code{@@appendixsection} is a longer
spelling of the @code{@@appendixsec} command. @xref{unnumberedsec
appendixsec heading, , Section Commands}.@refill
@item @@appendixsubsec @var{title}
Begin an appendix subsection within an appendix. The title appears
in the table of contents of a printed manual. In Info, the title is
underlined with hyphens. @xref{unnumberedsubsec appendixsubsec
subheading, , Subsection Commands}.@refill
@item @@appendixsubsubsec @var{title}
Begin an appendix subsubsection within a subappendix. The title
appears in the table of contents of a printed manual. In Info, the
title is underlined with periods. @xref{subsubsection,, The `subsub'
Commands}.@refill
@item @@asis
Used following @code{@@table}, @code{@@ftable}, and @code{@@vtable} to
print the table's first column without highlighting (``as is'').
@xref{Two-column Tables, , Making a Two-column Table}.@refill
@item @@author @var{author}
Typeset @var{author} flushleft and underline it. @xref{title
subtitle author, , The @code{@@title} and @code{@@author}
Commands}.@refill
@item @@b@{@var{text}@}
Print @var{text} in @b{bold} font. No effect in Info. @xref{Fonts}.@refill
@ignore
@item @@br
Force a paragraph break. If used within a line, follow @code{@@br}
with braces. @xref{br, , @code{@@br}}.@refill
@end ignore
@item @@bullet@{@}
Generate a large round dot, or the closest possible
thing to one. @xref{bullet, , @code{@@bullet}}.@refill
@item @@bye
Stop formatting a file. The formatters do not see the contents of a
file following an @code{@@bye} command. @xref{Ending a File}.@refill
@item @@c @var{comment}
Begin a comment in Texinfo. The rest of the line does not appear in
either the Info file or the printed manual. A synonym for
@code{@@comment}. @xref{Comments, , Comments}.@refill
@item @@cartouche
Highlight an example or quotation by drawing a box with rounded
corners around it. Pair with @code{@@end cartouche}. No effect in
Info. @xref{cartouche, , Drawing Cartouches Around Examples}.)@refill
@item @@center @var{line-of-text}
Center the line of text following the command.
@xref{titlefont center sp, , @code{@@center}}.@refill
@item @@lowersections
Change subsequent chapters to sections, sections to subsections, and so
on. @xref{Raise/lower sections, , @code{@@raisesections} and
@code{@@lowersections}}.@refill
@item @@chapheading @var{title}
Print a chapter-like heading in the text, but not in the table of
contents of a printed manual. In Info, the title is underlined with
asterisks. @xref{majorheading & chapheading, , @code{@@majorheading}
and @code{@@chapheading}}.@refill
@item @@chapter @var{title}
Begin a chapter. The chapter title appears in the table of
contents of a printed manual. In Info, the title is underlined with
asterisks. @xref{chapter, , @code{@@chapter}}.@refill
@item @@cindex @var{entry}
Add @var{entry} to the index of concepts. @xref{Index Entries, ,
Defining the Entries of an Index}.@refill
@item @@cite@{@var{reference}@}
Highlight the name of a book or other reference that lacks a
companion Info file. @xref{cite, , @code{@@cite}}.@refill
@item @@clear @var{flag}
Unset @var{flag}, preventing the Texinfo formatting commands from
formatting text between subsequent pairs of @code{@@ifset @var{flag}}
and @code{@@end ifset} commands, and preventing
@code{@@value@{@var{flag}@}} from expanding to the value to which
@var{flag} is set.
@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
@item @@code@{@var{sample-code}@}
Highlight text that is an expression, a syntactically complete token
of a program, or a program name. @xref{code, , @code{@@code}}.@refill
@item @@comment @var{comment}
Begin a comment in Texinfo. The rest of the line does not appear in
either the Info file or the printed manual. A synonym for @code{@@c}.
@xref{Comments, , Comments}.@refill
@item @@contents
Print a complete table of contents. Has no effect in Info, which uses
menus instead. @xref{Contents, , Generating a Table of
Contents}.@refill
@item @@copyright@{@}
Generate a copyright symbol. @xref{copyright symbol, ,
@code{@@copyright}}.@refill
@ignore
@item @@ctrl@{@var{ctrl-char}@}
Describe an @sc{ascii} control character. Insert actual control character
into Info file. @xref{ctrl, , @code{@@ctrl}}.@refill
@end ignore
@item @@defcodeindex @var{index-name}
Define a new index and its indexing command. Print entries in an
@code{@@code} font. @xref{New Indices, , Defining New
Indices}.@refill
@item @@defcv @var{category} @var{class} @var{name}
Format a description for a variable associated with a class in
object-oriented programming. Takes three arguments: the category of
thing being defined, the class to which it belongs, and its name.
@xref{Definition Commands}.@refill
@item @@deffn @var{category} @var{name} @var{arguments}@dots{}
Format a description for a function, interactive command, or similar
entity that may take arguments. @code{@@deffn} takes as arguments the
category of entity being described, the name of this particular
entity, and its arguments, if any. @xref{Definition Commands}.@refill
@item @@defindex @var{index-name}
Define a new index and its indexing command. Print entries in a roman
font. @xref{New Indices, , Defining New Indices}.@refill
@item @@definfoenclose @var{new-command}, @var{before}, @var{after},
Create new @@-command for Info that marks text by enclosing it in
strings that precede and follow the text. Write definition inside of
@code{@@ifinfo} @dots{} @code{@@end ifinfo}. @xref{Customized
Highlighting}.@refill
@item @@defivar @var{class} @var{instance-variable-name}
This command formats a description for an instance variable in
object-oriented programming. The command is equivalent to @samp{@@defcv
@{Instance Variable@} @dots{}}. @xref{Definition Commands}.@refill
@item @@defmac @var{macro-name} @var{arguments}@dots{}
Format a description for a macro. The command is equivalent to
@samp{@@deffn Macro @dots{}}. @xref{Definition Commands}.@refill
@item @@defmethod @var{class} @var{method-name} @var{arguments}@dots{}
Format a description for a method in object-oriented programming. The
command is equivalent to @samp{@@defop Method @dots{}}. Takes as
arguments the name of the class of the method, the name of the
method, and its arguments, if any. @xref{Definition Commands}.@refill
@item @@defop @var{category} @var{class} @var{name} @var{arguments}@dots{}
Format a description for an operation in object-oriented programming.
@code{@@defop} takes as arguments the overall name of the category of
operation, the name of the class of the operation, the name of the
operation, and its arguments, if any. @xref{Definition
Commands}.@refill
@need 100
@item @@defopt @var{option-name}
Format a description for a user option. The command is equivalent to
@samp{@@defvr @{User Option@} @dots{}}. @xref{Definition Commands}.@refill
@need 100
@item @@defspec @var{special-form-name} @var{arguments}@dots{}
Format a description for a special form. The command is equivalent to
@samp{@@deffn @{Special Form@} @dots{}}. @xref{Definition Commands}.@refill
@need 200
@item @@deftp @var{category} @var{name-of-type} @var{attributes}@dots{}
Format a description for a data type. @code{@@deftp} takes as
arguments the category, the name of the type (which is a word like
@samp{int} or @samp{float}), and then the names of attributes of
objects of that
type. @xref{Definition Commands}.@refill
@item @@deftypefn @var{classification} @var{data-type} @var{name} @var{arguments}@dots{}
Format a description for a function or similar entity that may take
arguments and that is typed. @code{@@deftypefn} takes as arguments
the classification of entity being described, the type, the name of
the entity, and its arguments, if any. @xref{Definition
Commands}.@refill
@item @@deftypefun @var{data-type} @var{function-name} @var{arguments}@dots{}
Format a description for a function in a typed language.
The command is equivalent to @samp{@@deftypefn Function @dots{}}.
@xref{Definition Commands}.@refill
@item @@deftypevr @var{classification} @var{data-type} @var{name}
Format a description for something like a variable in a typed
language---an entity that records a value. Takes as arguments the
classification of entity being described, the type, and the name of
the entity. @xref{Definition Commands}.@refill
@item @@deftypevar @var{data-type} @var{variable-name}
Format a description for a variable in a typed language. The command is
equivalent to @samp{@@deftypevr Variable @dots{}}. @xref{Definition
Commands}.@refill
@item @@defun @var{function-name} @var{arguments}@dots{}
Format a description for functions. The command is equivalent to
@samp{@@deffn Function @dots{}}. @xref{Definition Commands}.@refill
@item @@defvar @var{variable-name}
Format a description for variables. The command is equivalent to
@samp{@@defvr Variable @dots{}}. @xref{Definition Commands}.@refill
@item @@defvr @var{category} @var{name}
Format a description for any kind of variable. @code{@@defvr} takes
as arguments the category of the entity and the name of the entity.
@xref{Definition Commands}.@refill
@item @@dfn@{@var{term}@}
Highlight the introductory or defining use of a term.
@xref{dfn, , @code{@@dfn}}.@refill
@need 100
@item @@display
Begin a kind of example. Indent text, do not fill, do not select a
new font. Pair with @code{@@end display}. @xref{display, ,
@code{@@display}}.@refill
@need 100
@item @@dmn@{@var{dimension}@}
Format a dimension. Cause @TeX{} to insert a narrow space before
@var{dimension}. No effect in Info. Use for writing a number
followed by an abbreviation of a dimension name, such as
@samp{12@dmn{pt}}, written as @samp{12@@dmn@{pt@}}, with no space
between the number and the @code{@@dmn} command. @xref{dmn, ,
@code{@@dmn}}.@refill
@need 100
@item @@dots@{@}
Insert an ellipsis: @samp{@dots{}}.
@xref{dots, , @code{@@dots}}.@refill
@need 100
@item @@emph@{@var{text}@}
Highlight @var{text}; text is displayed in @emph{italics} in printed
output, and surrounded by asterisks in Info. @xref{Emphasis, , Emphasizing Text}.@refill
@need 100
@item @@enumerate [@var{number-or-letter}]
Begin a numbered list, using @code{@@item} for each entry.
Optionally, start list with @var{number-or-letter}. Pair with
@code{@@end enumerate}. @xref{enumerate, ,
@code{@@enumerate}}.@refill
@need 100
@item @@equiv@{@}
Indicate to the reader the exact equivalence of two forms with a
glyph: @samp{@equiv{}}. @xref{Equivalence}.@refill
@item @@error@{@}
Indicate to the reader with a glyph that the following text is
an error message: @samp{@error{}}. @xref{Error Glyph}.@refill
@item @@evenfooting [@var{left}] @@| [@var{center}] @@| [@var{right}]
Specify page footings for even-numbered (left-hand) pages. Not relevant to
Info. @xref{Custom Headings, , How to Make Your Own Headings}.@refill
@item @@evenheading [@var{left}] @@| [@var{center}] @@| [@var{right}]
Specify page headings for even-numbered (left-hand) pages. Not relevant to
Info. @xref{Custom Headings, , How to Make Your Own Headings}.@refill
@item @@everyfooting [@var{left}] @@| [@var{center}] @@| [@var{right}]
Specify page footings for every page. Not relevant to Info. @xref{Custom
Headings, , How to Make Your Own Headings}.@refill
@item @@everyheading [@var{left}] @@| [@var{center}] @@| [@var{right}]
Specify page headings for every page. Not relevant to Info. @xref{Custom
Headings, , How to Make Your Own Headings}.@refill
@item @@example
Begin an example. Indent text, do not fill, and select fixed-width font.
Pair with @code{@@end example}. @xref{example, ,
@code{@@example}}.@refill
@item @@exdent @var{line-of-text}
Remove any indentation a line might have. @xref{exdent, ,
Undoing the Indentation of a Line}.@refill
@item @@expansion@{@}
Indicate the result of a macro expansion to the reader with a special
glyph: @samp{@expansion{}}.
@xref{expansion, , @expansion{} Indicating an Expansion}.@refill
@item @@file@{@var{filename}@}
Highlight the name of a file, buffer, node, or directory. @xref{file, ,
@code{@@file}}.@refill
@item @@finalout
Prevent @TeX{} from printing large black warning rectangles beside
over-wide lines. @xref{Overfull hboxes}.@refill
@need 100
@item @@findex @var{entry}
Add @var{entry} to the index of functions. @xref{Index Entries, ,
Defining the Entries of an Index}.@refill
@need 200
@item @@flushleft
Left justify every line but leave the right end ragged.
Leave font as is. Pair with @code{@@end flushleft}.
@xref{flushleft & flushright, , @code{@@flushleft} and
@code{@@flushright}}.@refill
@need 200
@item @@flushright
Right justify every line but leave the left end ragged.
Leave font as is. Pair with @code{@@end flushright}.
@xref{flushleft & flushright, , @code{@@flushleft} and
@code{@@flushright}}.@refill
@need 200
@item @@footnote@{@var{text-of-footnote}@}
Enter a footnote. Footnote text is printed at the bottom of the page
by @TeX{}; Info may format in either `End' node or `Separate' node style.
@xref{Footnotes}.@refill
@item @@footnotestyle @var{style}
Specify an Info file's footnote style, either @samp{end} for the end
node style or @samp{separate} for the separate node style.
@xref{Footnotes}.@refill
@item @@format
Begin a kind of example. Like @code{@@example} or @code{@@display},
but do not narrow the margins and do not select the fixed-width font.
Pair with @code{@@end format}. @xref{example, ,
@code{@@example}}.@refill
@item @@ftable @var{formatting-command}
Begin a two-column table, using @code{@@item} for each entry.
Automatically enter each of the items in the first column into the
index of functions. Pair with @code{@@end ftable}. The same as
@code{@@table}, except for indexing. @xref{ftable vtable, ,
@code{@@ftable} and @code{@@vtable}}.@refill
@item @@group
Hold text together that must appear on one printed page. Pair with
@code{@@end group}. Not relevant to Info. @xref{group, ,
@code{@@group}}.@refill
@item @@heading @var{title}
Print an unnumbered section-like heading in the text, but not in the
table of contents of a printed manual. In Info, the title is
underlined with equal signs. @xref{unnumberedsec appendixsec heading,
, Section Commands}.@refill
@item @@headings @var{on-off-single-double}
Turn page headings on or off, or specify single-sided or double-sided
page headings for printing. @code{@@headings on} is synonymous with
@code{@@headings double}. @xref{headings on off, , The
@code{@@headings} Command}.@refill
@item @@i@{@var{text}@}
Print @var{text} in @i{italic} font. No effect in Info.
@xref{Fonts}.@refill
@item @@ifclear @var{flag}
If @var{flag} is cleared, the Texinfo formatting commands format text
between @code{@@ifclear @var{flag}} and the following @code{@@end
ifclear} command.
@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
@item @@ifinfo
Begin a stretch of text that will be ignored by @TeX{} when it
typesets the printed manual. The text appears only in the Info file.
Pair with @code{@@end ifinfo}. @xref{Conditionals, , Conditionally
Visible Text}.@refill
@item @@ifset @var{flag}
If @var{flag} is set, the Texinfo formatting commands format text
between @code{@@ifset @var{flag}} and the following @code{@@end ifset}
command.
@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
@item @@iftex
Begin a stretch of text that will not appear in the Info file, but
will be processed only by @TeX{}. Pair with @code{@@end iftex}.
@xref{Conditionals, , Conditionally Visible Text}.@refill
@item @@ignore
Begin a stretch of text that will not appear in either the Info file
or the printed output. Pair with @code{@@end ignore}.
@xref{Comments, , Comments and Ignored Text}.@refill
@item @@include @var{filename}
Incorporate the contents of the file @var{filename} into the Info file
or printed document. @xref{Include Files}.@refill
@item @@inforef@{@var{node-name}, [@var{entry-name}], @var{info-file-name}@}
Make a cross reference to an Info file for which there is no printed
manual. @xref{inforef, , Cross references using
@code{@@inforef}}.@refill
@item \input @var{macro-definitions-file}
Use the specified macro definitions file. This command is used only
in the first line of a Texinfo file to cause @TeX{} to make use of the
@file{texinfo} macro definitions file. The backslash in @code{\input}
is used instead of an @code{@@} because @TeX{} does not properly
recognize @code{@@} until after it has read the definitions file.
@xref{Header, , The Texinfo File Header}.@refill
@item @@item
Indicate the beginning of a marked paragraph for @code{@@itemize} and
@code{@@enumerate}; indicate the beginning of the text of a first column
entry for @code{@@table}, @code{@@ftable}, and @code{@@vtable}.
@xref{Lists and Tables}.@refill
@item @@itemize @var{mark-generating-character-or-command}
Produce a sequence of indented paragraphs, with a mark inside the left
margin at the beginning of each paragraph. Pair with @code{@@end
itemize}. @xref{itemize, , @code{@@itemize}}.@refill
@item @@itemx
Like @code{@@item} but do not generate extra vertical space above the
item text. @xref{itemx, , @code{@@itemx}}.@refill
@item @@kbd@{@var{keyboard-characters}@}
Indicate text that consists of characters of input to be typed by
users. @xref{kbd, , @code{@@kbd}}.@refill
@item @@key@{@var{key-name}@}
Highlight @var{key-name}, a conventional name for a key on a keyboard.
@xref{key, , @code{@@key}}.@refill
@item @@kindex @var{entry}
Add @var{entry} to the index of keys. @xref{Index Entries, , Defining the
Entries of an Index}.@refill
@item @@global@@let@var{new-command}=@var{existing-command}
Equate a new highlighting command with an existing one. Only for
@TeX{}. Write definition inside of @code{@@iftex} @dots{} @code{@@end
iftex}. @xref{Customized Highlighting}.@refill
@item @@lisp
Begin an example of Lisp code. Indent text, do not fill, and select
fixed-width font. Pair with @code{@@end lisp}. @xref{Lisp Example, ,
@code{@@lisp}}.@refill
@item @@majorheading @var{title}
Print a chapter-like heading in the text, but not in the table of
contents of a printed manual. Generate more vertical whitespace before
the heading than the @code{@@chapheading} command. In Info, the chapter
heading line is underlined with asterisks. @xref{majorheading &
chapheading, , @code{@@majorheading} and @code{@@chapheading}}.@refill
@item @@math@{@var{mathematical-expression}@}
Format a mathematical expression.
@xref{math, , @code{@@math}: Inserting Mathematical Expressions}.
@item @@menu
Mark the beginning of a menu of nodes in Info. No effect in a printed
manual. Pair with @code{@@end menu}. @xref{Menus}.@refill
@item @@minus@{@}
Generate a minus sign. @xref{minus, , @code{@@minus}}.@refill
@item @@need @var{n}
Start a new page in a printed manual if fewer than @var{n} mils
(thousandths of an inch) remain on the current page. @xref{need, ,
@code{@@need}}.@refill
@item @@node @var{name, next, previous, up}
Define the beginning of a new node in Info, and serve as a locator for
references for @TeX{}. @xref{node, , @code{@@node}}.@refill
@need 200
@item @@noindent
Prevent text from being indented as if it were a new paragraph.
@xref{noindent, , @code{@@noindent}}.@refill
@item @@oddfooting [@var{left}] @@| [@var{center}] @@| [@var{right}]
Specify page footings for odd-numbered (right-hand) pages. Not relevant to
Info. @xref{Custom Headings, , How to Make Your Own Headings}.@refill
@item @@oddheading [@var{left}] @@| [@var{center}] @@| [@var{right}]
Specify page headings for odd-numbered (right-hand) pages. Not relevant to
Info. @xref{Custom Headings, , How to Make Your Own Headings}.@refill
@item @@page
Start a new page in a printed manual. No effect in Info.
@xref{page, , @code{@@page}}.@refill
@item @@paragraphindent @var{indent}
Indent paragraphs by @var{indent} number of spaces; delete indentation
if the value of @var{indent} is 0; and do not change indentation if
@var{indent} is @code{asis}. @xref{paragraphindent, , Paragraph
Indenting}.@refill
@item @@pindex @var{entry}
Add @var{entry} to the index of programs. @xref{Index Entries, , Defining
the Entries of an Index}.@refill
@item @@point@{@}
Indicate the position of point in a buffer to the reader with a
glyph: @samp{@point{}}. @xref{Point Glyph, , Indicating
Point in a Buffer}.@refill
@item @@print@{@}
Indicate printed output to the reader with a glyph:
@samp{@print{}}. @xref{Print Glyph}.@refill
@item @@printindex @var{index-name}
Print an alphabetized two-column index in a printed manual or generate
an alphabetized menu of index entries for Info. @xref{Printing
Indices & Menus}.@refill
@item @@pxref@{@var{node-name}, [@var{entry}], [@var{topic-or-title}], [@var{info-file}], [@var{manual}]@}
Make a reference that starts with a lower case `see' in a printed
manual. Use within parentheses only. Do not follow command with a
punctuation mark. The Info formatting commands automatically insert
terminating punctuation as needed, which is why you do not need to
insert punctuation. Only the first argument is mandatory.
@xref{pxref, , @code{@@pxref}}.@refill
@item @@quotation
Narrow the margins to indicate text that is quoted from another real
or imaginary work. Write command on a line of its own. Pair with
@code{@@end quotation}. @xref{quotation, ,
@code{@@quotation}}.@refill
@need 100
@item @@r@{@var{text}@}
Print @var{text} in @r{roman} font. No effect in Info.
@xref{Fonts}.@refill
@item @@raisesections
Change subsequent sections to chapters, subsections to sections, and so
on. @xref{Raise/lower sections, , @code{@@raisesections} and
@code{@@lowersections}}.@refill
@need 300
@item @@ref@{@var{node-name}, [@var{entry}], [@var{topic-or-title}], [@var{info-file}], [@var{manual}]@}
Make a reference. In a printed manual, the reference does not start
with a `See'. Follow command with a punctuation mark. Only the first
argument is mandatory. @xref{ref, , @code{@@ref}}.@refill
@need 300
@item @@refill
In Info, refill and indent the paragraph after all the other processing
has been done. No effect on @TeX{}, which always refills. This command
is no longer needed, since all formatters now automatically refill.
@xref{Refilling Paragraphs}.@refill
@need 300
@item @@result@{@}
Indicate the result of an expression to the reader with a special
glyph: @samp{@result{}}. @xref{result, , @code{@@result}}.@refill
@item @@samp@{@var{text}@}
Highlight @var{text} that is a literal example of a sequence of
characters. Used for single characters, for statements, and often for
entire shell commands. @xref{samp, , @code{@@samp}}.@refill
@item @@sc@{@var{text}@}
Set @var{text} in a printed output in @sc{the small caps font} and
set text in the Info file in uppercase letters.
@xref{Smallcaps}.@refill
@item @@section @var{title}
Begin a section within a chapter. In a printed manual, the section
title is numbered and appears in the table of contents. In Info, the
title is underlined with equal signs. @xref{section, ,
@code{@@section}}.@refill
@item @@set @var{flag} [@var{string}]
Make @var{flag} active, causing the Texinfo formatting commands to
format text between subsequent pairs of @code{@@ifset @var{flag}} and
@code{@@end ifset} commands. Optionally, set value of @var{flag} to
@var{string}.
@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
@item @@setchapternewpage @var{on-off-odd}
Specify whether chapters start on new pages, and if so, whether on
odd-numbered (right-hand) new pages. @xref{setchapternewpage, ,
@code{@@setchapternewpage}}.@refill
@c awkward wording prevents overfull hbox
@item @@setfilename @var{info-file-name}
Provide a name to be used by the Info file. @xref{setfilename, ,
@code{@@setfilename}}.@refill
@item @@settitle @var{title}
Provide a title for page headers in a printed manual.
@xref{settitle, , @code{@@settitle}}.@refill
@item @@shortcontents
Print a short table of contents. Not relevant to Info, which uses
menus rather than tables of contents. A synonym for
@code{@@summarycontents}. @xref{Contents, , Generating a Table of
Contents}.@refill
@need 400
@item @@smallbook
Cause @TeX{} to produce a printed manual in a 7 by 9.25 inch format
rather than the regular 8.5 by 11 inch format. @xref{smallbook, ,
Printing Small Books}. Also, see @ref{smallexample & smalllisp, ,
@code{@@smallexample} and @code{@@smalllisp}}.@refill
@need 400
@item @@smallexample
Indent text to indicate an example. Do not fill, select fixed-width
font. In @code{@@smallbook} format, print text in a smaller font than
with @code{@@example}. Pair with @code{@@end smallexample}.
@xref{smallexample & smalllisp, , @code{@@smallexample} and
@code{@@smalllisp}}.@refill
@need 400
@item @@smalllisp
Begin an example of Lisp code. Indent text, do not fill, select
fixed-width font. In @code{@@smallbook} format, print text in a
smaller font. Pair with @code{@@end smalllisp}. @xref{smallexample &
smalllisp, , @code{@@smallexample} and @code{@@smalllisp}}.@refill
@need 700
@item @@sp @var{n}
Skip @var{n} blank lines. @xref{sp, , @code{@@sp}}.@refill
@need 700
@item @@strong @var{text}
Emphasize @var{text} by typesetting it in a @strong{bold} font for the
printed manual and by surrounding it with asterisks for Info.
@xref{emph & strong, , Emphasizing Text}.@refill
@item @@subheading @var{title}
Print an unnumbered subsection-like heading in the text, but not in
the table of contents of a printed manual. In Info, the title is
underlined with hyphens. @xref{unnumberedsubsec appendixsubsec
subheading, , @code{@@unnumberedsubsec} @code{@@appendixsubsec}
@code{@@subheading}}.@refill
@item @@subsection @var{title}
Begin a subsection within a section. In a printed manual, the
subsection title is numbered and appears in the table of contents. In
Info, the title is underlined with hyphens. @xref{subsection, ,
@code{@@subsection}}.@refill
@item @@subsubheading @var{title}
Print an unnumbered subsubsection-like heading in the text, but not in
the table of contents of a printed manual. In Info, the title is
underlined with periods. @xref{subsubsection, , The `subsub'
Commands}.@refill
@item @@subsubsection @var{title}
Begin a subsubsection within a subsection. In a printed manual,
the subsubsection title is numbered and appears in the table of
contents. In Info, the title is underlined with periods.
@xref{subsubsection, , The `subsub' Commands}.@refill
@item @@subtitle @var{title}
In a printed manual, set a subtitle in a normal sized font flush to
the right-hand side of the page. Not relevant to Info, which does not
have title pages. @xref{title subtitle author, , @code{@@title}
@code{@@subtitle} and @code{@@author} Commands}.@refill
@item @@summarycontents
Print a short table of contents. Not relevant to Info, which uses
menus rather than tables of contents. A synonym for
@code{@@shortcontents}. @xref{Contents, , Generating a Table of
Contents}.@refill
@need 300
@item @@syncodeindex @var{from-index} @var{into-index}
Merge the index named in the first argument into the index named in
the second argument, printing the entries from the first index in
@code{@@code} font. @xref{Combining Indices}.@refill
@need 300
@item @@synindex @var{from-index} @var{into-index}
Merge the index named in the first argument into the index named in
the second argument. Do not change the font of @var{from-index}
entries. @xref{Combining Indices}.@refill
@need 100
@item @@t@{@var{text}@}
Print @var{text} in a @t{fixed-width}, typewriter-like font.
No effect in Info. @xref{Fonts}.@refill
@need 400
@item @@table @var{formatting-command}
Begin a two-column table, using @code{@@item} for each entry. Write
each first column entry on the same line as @code{@@item}. First
column entries are printed in the font resulting from
@var{formatting-command}. Pair with @code{@@end table}.
@xref{Two-column Tables, , Making a Two-column Table}.
Also see @ref{ftable vtable, , @code{@@ftable} and @code{@@vtable}},
and @ref{itemx, , @code{@@itemx}}.@refill
@item @@TeX@{@}
Insert the logo @TeX{}. @xref{TeX and copyright, , Inserting @TeX{}
and @copyright{}}.@refill
@item @@tex
Enter @TeX{} completely. Pair with @code{@@end tex}. @xref{Using
Ordinary TeX Commands, , Using Ordinary @TeX{} Commands}.@refill
@item @@thischapter
In a heading or footing, stands for the number and name of the current
chapter, in the format `Chapter 1: Title'. @xref{Custom
Headings, , How to Make Your Own Headings}.@refill
@item @@thischaptername
In a heading or footing, stands for the name of the current chapter.
@xref{Custom Headings, , How to Make Your Own Headings}.@refill
@item @@thisfile
In a heading or footing, stands for the name of the current
@code{@@include} file. Does not insert anything if not within an
@code{@@include} file. @xref{Custom Headings, , How to Make Your Own
Headings}.@refill
@item @@thispage
In a heading or footing, stands for the current page number.
@xref{Custom Headings, , How to Make Your Own Headings}.@refill
@ignore
@item @@thissection
In a heading or footing, stands for the title of the current section.
@xref{Custom Headings, , How to Make Your Own Headings}.@refill
@end ignore
@item @@thistitle
In a heading or footing, stands for the name of the document, as specified
by the @code{@@settitle} command. @xref{Custom Headings, , How to
Make Your Own Headings}.@refill
@item @@tindex @var{entry}
Add @var{entry} to the index of data types. @xref{Index Entries, ,
Defining the Entries of an Index}.@refill
@item @@title @var{title}
In a printed manual, set a title flush to the left-hand side of the
page in a larger than normal font and underline it with a black rule.
Not relevant to Info, which does not have title pages. @xref{title
subtitle author, , The @code{@@title} @code{@@subtitle} and
@code{@@author} Commands}.@refill
@need 400
@item @@titlefont@{@var{text}@}
In a printed manual, print @var{text} in a larger than normal font.
Not relevant to Info, which does not have title pages.
@xref{titlefont center sp, , The @code{@@titlefont} @code{@@center}
and @code{@@sp} Commands}.@refill
@need 300
@item @@titlepage
Indicate to Texinfo the beginning of the title page. Write command on
a line of its own. Pair with @code{@@end titlepage}. Nothing between
@code{@@titlepage} and @code{@@end titlepage} appears in Info.
@xref{titlepage, , @code{@@titlepage}}.@refill
@need 150
@item @@today@{@}
Insert the current date, in `1 Jan 1900' style. @xref{Custom
Headings, , How to Make Your Own Headings}.@refill
@item @@top @var{title}
In a Texinfo file to be formatted with @code{makeinfo}, identify the
topmost @code{@@node} line in the file, which must be written on the line
immediately preceding the @code{@@top} command. Used for
@code{makeinfo}'s node pointer insertion feature. The title is
underlined with asterisks. Both the @code{@@node} line and the @code{@@top}
line normally should be enclosed by @code{@@ifinfo} and @code{@@end
ifinfo}. In @TeX{} and @code{texinfo-format-buffer}, the @code{@@top}
command is merely a synonym for @code{@@unnumbered}. @xref{makeinfo
Pointer Creation, , Creating Pointers with @code{makeinfo}}.
@item @@unnumbered @var{title}
In a printed manual, begin a chapter that appears without chapter
numbers of any kind. The title appears in the table of contents of a
printed manual. In Info, the title is underlined with asterisks.
@xref{unnumbered & appendix, , @code{@@unnumbered} and
@code{@@appendix}}.@refill
@item @@unnumberedsec @var{title}
In a printed manual, begin a section that appears without section
numbers of any kind. The title appears in the table of contents of a
printed manual. In Info, the title is underlined with equal signs.
@xref{unnumberedsec appendixsec heading, , Section Commands}.@refill
@item @@unnumberedsubsec @var{title}
In a printed manual, begin an unnumbered subsection within a
chapter. The title appears in the table of contents of a printed
manual. In Info, the title is underlined with hyphens.
@xref{unnumberedsubsec appendixsubsec subheading, ,
@code{@@unnumberedsubsec} @code{@@appendixsubsec}
@code{@@subheading}}.@refill
@item @@unnumberedsubsubsec @var{title}
In a printed manual, begin an unnumbered subsubsection within a
chapter. The title appears in the table of contents of a printed
manual. In Info, the title is underlined with periods.
@xref{subsubsection, , The `subsub' Commands}.@refill
@item @@value@{@var{flag}@}
Replace @var{flag} with the value to which it is set by @code{@@set
@var{flag}}.
@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
@item @@var@{@var{metasyntactic-variable}@}
Highlight a metasyntactic variable, which is something that stands for
another piece of text. @xref{var, , Indicating Metasyntactic
Variables}.@refill
@need 400
@item @@vindex @var{entry}
Add @var{entry} to the index of variables. @xref{Index Entries, ,
Defining the Entries of an Index}.@refill
@need 400
@item @@vskip @var{amount}
In a printed manual, insert whitespace so as to push text on the
remainder of the page towards the bottom of the page. Used in
formatting the copyright page with the argument @samp{0pt plus
1filll}. (Note spelling of @samp{filll}.) @code{@@vskip} may be used
only in contexts ignored for Info. @xref{Copyright & Permissions, ,
The Copyright Page and Printed Permissions}.@refill
@need 400
@item @@vtable @var{formatting-command}
Begin a two-column table, using @code{@@item} for each entry.
Automatically enter each of the items in the first column into the
index of variables. Pair with @code{@@end vtable}. The same as
@code{@@table}, except for indexing. @xref{ftable vtable, ,
@code{@@ftable} and @code{@@vtable}}.@refill
@need 400
@item @@w@{@var{text}@}
Prevent @var{text} from being split across two lines. Do not end a
paragraph that uses @code{@@w} with an @code{@@refill} command.
In the Texinfo file, keep @var{text} on one line.
@xref{w, , @code{@@w}}.@refill
@need 400
@item @@xref@{@var{node-name}, [@var{entry}], [@var{topic-or-title}], [@var{info-file}], [@var{manual}]@}
Make a reference that starts with `See' in a printed manual. Follow
command with a punctuation mark. Only the first argument is
mandatory. @xref{xref, , @code{@@xref}}.@refill
@end table
@node Tips, Sample Texinfo File, Command List, Top
@comment node-name, next, previous, up
@appendix Tips and Hints
Here are some tips for writing Texinfo documentation:@refill
@cindex Tips
@cindex Usage tips
@cindex Hints
@itemize @bullet
@item
Write in the present tense, not in the past or the future.
@item
Write actively! For example, write ``We recommend that @dots{}'' rather
than ``It is recommended that @dots{}''.
@item
Use 70 or 72 as your fill column. Longer lines are hard to read.
@item
Include a copyright notice and copying permissions.
@end itemize
@subsubheading Index, index, index!
Write many index entries, in different ways.
Readers like indices; they are helpful and convenient.
Although it is easiest to write index entries as you write the body of
the text, some people prefer to write entries afterwards. In either
case, write an entry before the paragraph to which it applies. This
way, an index entry points to the first page of a paragraph that is
split across pages.
Here are more hints we have found valuable:
@itemize @bullet
@item
Write each index entry differently, so each entry refers to a different
place in the document. The index of an Info file lists only one
location for each entry.
@item
Write index entries only where a topic is discussed significantly. For
example, it is not useful to index ``debugging information'' in a
chapter on reporting bugs. Someone who wants to know about debugging
information will certainly not find it in that chapter.
@item
Consistently capitalize the first word of every concept index entry,
or else consistently use lower case. Terse entries often call for
lower case; longer entries for capitalization. Whichever case
convention you use, please use one or the other consistently! Mixing
the two styles looks bad.
@item
Always capitalize or use upper case for those words in an index for
which this is proper, such as names of countries or acronyms. Always
use the appropriate case for case-sensitive names, such as those in C or
Lisp.
@item
Write the indexing commands that refer to a whole section immediately
after the section command, and write the indexing commands that refer to
the paragraph before the paragraph.
@need 1000
In the example that follows, a blank line comes after the index
entry for ``Leaping'':
@example
@group
@@section The Dog and the Fox
@@cindex Jumping, in general
@@cindex Leaping
@@cindex Dog, lazy, jumped over
@@cindex Lazy dog jumped over
@@cindex Fox, jumps over dog
@@cindex Quick fox jumps over dog
The quick brown fox jumps over the lazy dog.
@end group
@end example
@noindent
(Note that the example shows entries for the same concept that are
written in different ways---@samp{Lazy dog}, and @samp{Dog, lazy}---so
readers can look up the concept in different ways.)
@end itemize
@subsubheading Blank lines
@itemize @bullet
@item
Insert a blank line between a sectioning command and the first following
sentence or paragraph, or between the indexing commands associated with
the sectioning command and the first following sentence or paragraph, as
shown in the tip on indexing. Otherwise, a formatter may fold title and
paragraph together.
@item
Always insert a blank line before an @code{@@table} command and after an
@code{@@end table} command; but never insert a blank line after an
@code{@@table} command or before an @code{@@end table} command.
@need 1000
For example,
@example
@group
Types of fox:
@@table @@samp
@@item Quick
Jump over lazy dogs.
@end group
@group
@@item Brown
Also jump over lazy dogs.
@@end table
@end group
@group
@@noindent
On the other hand, @dots{}
@end group
@end example
Insert blank lines before and after @code{@@itemize} @dots{} @code{@@end
itemize} and @code{@@enumerate} @dots{} @code{@@end enumerate} in the
same way.
@end itemize
@subsubheading Complete phrases
Complete phrases are easier to read than @dots{}
@itemize @bullet
@item
Write entries in an itemized list as complete sentences; or at least, as
complete phrases. Incomplete expressions @dots{} awkward @dots{} like
this.
@item
Write the prefatory sentence or phrase for a multi-item list or table as
a complete expression. Do not write ``You can set:''; instead, write
``You can set these variables:''. The former expression sounds cut off.
@end itemize
@subsubheading Editions, dates and versions
Write the edition and version numbers and date in three places in every
manual:
@enumerate
@item
In the first @code{@@ifinfo} section, for people reading the Texinfo file.
@item
In the @code{@@titlepage} section, for people reading the printed manual.
@item
In the `Top' node, for people reading the Info file.
@end enumerate
@noindent
Also, it helps to write a note before the first @code{@@ifinfo}
section to explain what you are doing.
@need 800
@noindent
For example:
@example
@group
@@c ===> NOTE! <==
@@c Specify the edition and version numbers and date
@@c in *three* places:
@@c 1. First ifinfo section 2. title page 3. top node
@@c To find the locations, search for !!set
@end group
@group
@@ifinfo
@@c !!set edition, date, version
This is Edition 4.03, January 1992,
of the @@cite@{GDB Manual@} for GDB Version 4.3.
@dots{}
@end group
@end example
@noindent
---or use @code{@@set} and @code{@@value}
(@pxref{value Example, , @code{@@value} Example}).
@subsubheading Definition Commands
Definition commands are @code{@@deffn}, @code{@@defun},
@code{@@defmac}, and the like, and enable you to write descriptions in
a uniform format.@refill
@itemize @bullet
@item
Write just one definition command for each entity you define with a
definition command. The automatic indexing feature creates an index
entry that leads the reader to the definition.
@item
Use @code{@@table} @dots{} @code{@@end table} in an appendix that
contains a summary of functions, not @code{@@deffn} or other definition
commands.
@end itemize
@subsubheading Capitalization
@itemize @bullet
@item
Capitalize @samp{Texinfo}; it is a name. Do not write the @samp{x} or
@samp{i} in upper case.
@item
Capitalize @samp{Info}; it is a name.
@item
Write @TeX{} using the @code{@@TeX@{@}} command. Note the uppercase
@samp{T} and @samp{X}. This command causes the formatters to
typeset the name according to the wishes of Donald Knuth, who wrote
@TeX{}.
@end itemize
@subsubheading Spaces
Do not use spaces to format a Texinfo file, except inside of
@code{@@example} @dots{} @code{@@end example} and similar commands.
@need 700
For example, @TeX{} fills the following:
@example
@group
@@kbd@{C-x v@}
@@kbd@{M-x vc-next-action@}
Perform the next logical operation
on the version-controlled file
corresponding to the current buffer.
@end group
@end example
@need 950
@noindent
so it looks like this:
@iftex
@quotation
@kbd{C-x v}
@kbd{M-x vc-next-action}
Perform the next logical operation on the version-controlled file
corresponding to the current buffer.
@end quotation
@end iftex
@ifinfo
@quotation
`C-x v' `M-x vc-next-action' Perform the next logical operation on the
version-controlled file corresponding to the current buffer.
@end quotation
@end ifinfo
@noindent
In this case, the text should be formatted with
@code{@@table}, @code{@@item}, and @code{@@itemx}, to create a table.
@subsubheading @@code, @@samp, @@var, and @samp{---}
@itemize @bullet
@item
Use @code{@@code} around Lisp symbols, including command names.
For example,
@example
The main function is @@code@{vc-next-action@}, @dots{}
@end example
@item
Avoid putting letters such as @samp{s} immediately after an
@samp{@@code}. Such letters look bad.
@item
Use @code{@@var} around meta-variables. Do not write angle brackets
around them.
@item
Use three hyphens in a row, @samp{---}, to indicate a long dash. @TeX{}
typesets these as a long dash and the Info formatters reduce three
hyphens to two.
@end itemize
@subsubheading Periods Outside of Quotes
Place periods and other punctuation marks @emph{outside} of quotations,
unless the punctuation is part of the quotation. This practice goes against
convention, but enables the reader to distinguish between the contents
of the quotation and the whole passage.
For example, you should write the following sentence with the period
outside the end quotation marks:
@example
Evidently, @samp{au} is an abbreviation for ``author''.
@end example
@noindent
since @samp{au} does @emph{not} serve as an abbreviation for
@samp{author.} (with a period following the word).
@subsubheading Introducing New Terms
@itemize @bullet
@item
Introduce new terms so that a user who does not know them can understand
them from context; or write a definition for the term.
For example, in the following, the terms ``check in'', ``register'' and
``delta'' are all appearing for the first time; the example sentence should be
rewritten so they are understandable.
@quotation
The major function assists you in checking in a file to your
version control system and registering successive sets of changes to
it as deltas.
@end quotation
@item
Use the @code{@@dfn} command around a word being introduced, to indicate
that the user should not expect to know the meaning already, and should
expect to learn the meaning from this passage.
@end itemize
@subsubheading @@pxref
@c !!! maybe include this in the tips on pxref
@ignore
By the way, it is okay to use pxref with something else in front of
it within the parens, as long as the pxref is followed by the close
paren, and the material inside the parents is not part of a larger
sentence. Also, you can use xref inside parens as part of a complete
sentence so long as you terminate the cross reference with punctuation.
@end ignore
Absolutely never use @code{@@pxref} except in the special context for
which it is designed: inside parentheses, with the closing parenthesis
following immediately after the closing brace. One formatter
automatically inserts closing punctuation and the other does not. This
means that the output looks right both in printed output and in an Info
file, but only when the command is used inside parentheses.
@subsubheading Invoking from a Shell
You can invoke programs such as Emacs, GCC, and GAWK from a shell.
The documentation for each program should contain a section that
describes this. Unfortunately, if the node names and titles for these
sections are all different, readers find it hard to search for the
section.@refill
Name such sections with a phrase beginning with the word
@w{`Invoking @dots{}'}, as in `Invoking Emacs'; this way
users can find the section easily.
@subsubheading @sc{ansi c} Syntax
When you use @code{@@example} to describe a C function's calling
conventions, use the @sc{ansi c} syntax, like this:@refill
@example
void dld_init (char *@@var@{path@});
@end example
@noindent
And in the subsequent discussion, refer to the argument values by
writing the same argument names, again highlighted with
@code{@@var}.@refill
@need 800
Avoid the obsolete style that looks like this:@refill
@example
#include
dld_init (path)
char *path;
@end example
Also, it is best to avoid writing @code{#include} above the
declaration just to indicate that the function is declared in a
header file. The practice may give the misimpression that the
@code{#include} belongs near the declaration of the function. Either
state explicitly which header file holds the declaration or, better
yet, name the header file used for a group of functions at the
beginning of the section that describes the functions.@refill
@subsubheading Bad Examples
Here are several examples of bad writing to avoid:
In this example, say, `` @dots{} you must @code{@@dfn}@{check
in@} the new version.'' That flows better.
@quotation
When you are done editing the file, you must perform a
@code{@@dfn}@{check in@}.
@end quotation
In the following example, say, ``@dots{} makes a unified interface such as VC
mode possible.''
@quotation
SCCS, RCS and other version-control systems all perform similar
functions in broadly similar ways (it is this resemblance which makes
a unified control mode like this possible).
@end quotation
And in this example, you should specify what `it' refers to:
@quotation
If you are working with other people, it assists in coordinating
everyone's changes so they do not step on each other.
@end quotation
@subsubheading And Finally @dots{}
@itemize @bullet
@item
Pronounce @TeX{} as if the @samp{X} were a Greek `chi', as the last
sound in the name `Bach'. But pronounce Texinfo as in `speck':
@samp{teckinfo}.
@item
Write notes for yourself at the very end of a Texinfo file after the
@code{@@bye}. None of the formatters process text after the
@code{@@bye}; it is as if the text were within @code{@@ignore} @dots{}
@code{@@end ignore}.
@end itemize
@node Sample Texinfo File, Sample Permissions, Tips, Top
@comment node-name, next, previous, up
@appendix A Sample Texinfo File
@cindex Sample Texinfo file, no comments
Here is a complete, short sample Texinfo file, without any commentary.
You can see this file, with comments, in the first chapter.
@xref{Short Sample, , A Short Sample Texinfo File}.
@sp 1
@example
\input texinfo @@c -*-texinfo-*-
@@c %**start of header
@@setfilename sample.info
@@settitle Sample Document
@@c %**end of header
@@setchapternewpage odd
@@ifinfo
This is a short example of a complete Texinfo file.
Copyright 1990 Free Software Foundation, Inc.
@@end ifinfo
@@titlepage
@@sp 10
@@comment The title is printed in a large font.
@@center @@titlefont@{Sample Title@}
@@c The following two commands start the copyright page.
@@page
@@vskip 0pt plus 1filll
Copyright @@copyright@{@} 1990 Free Software Foundation, Inc.
@@end titlepage
@@node Top, First Chapter, (dir), (dir)
@@comment node-name, next, previous, up
@@menu
* First Chapter:: The first chapter is the
only chapter in this sample.
* Concept Index:: This index has two entries.
@@end menu
@@node First Chapter, Concept Index, Top, Top
@@comment node-name, next, previous, up
@@chapter First Chapter
@@cindex Sample index entry
This is the contents of the first chapter.
@@cindex Another sample index entry
Here is a numbered list.
@@enumerate
@@item
This is the first item.
@@item
This is the second item.
@@end enumerate
The @@code@{makeinfo@} and @@code@{texinfo-format-buffer@}
commands transform a Texinfo file such as this into
an Info file; and @@TeX@{@} typesets it for a printed
manual.
@@node Concept Index, , First Chapter, Top
@@comment node-name, next, previous, up
@@unnumbered Concept Index
@@printindex cp
@@contents
@@bye
@end example
@node Sample Permissions, Include Files, Sample Texinfo File, Top
@appendix Sample Permissions
@cindex Permissions
@cindex Copying permissions
Texinfo files should contain sections that tell the readers that they
have the right to copy and distribute the Texinfo file, the Info file,
and the printed manual.@refill
Also, if you are writing a manual about software, you should explain
that the software is free and either include the GNU General Public
License (GPL) or provide a reference to it. @xref{Distrib, ,
Distribution, emacs, The GNU Emacs Manual}, for an example of the text
that could be used in the software ``Distribution'', ``General Public
License'', and ``NO WARRANTY'' sections of a document. @xref{Copying,
, Texinfo Copying Conditions}, for an example of a brief explanation
of how the copying conditions provide you with rights. @refill
@menu
* Inserting Permissions:: How to put permissions in your document.
* ifinfo Permissions:: Sample @samp{ifinfo} copying permissions.
* Titlepage Permissions:: Sample Titlepage copying permissions.
@end menu
@node Inserting Permissions, ifinfo Permissions, Sample Permissions, Sample Permissions
@ifinfo
@appendixsec Inserting Permissions
@end ifinfo
In a Texinfo file, the first @code{@@ifinfo} section usually begins
with a line that says what the file documents. This is what a person
reading the unprocessed Texinfo file or using the advanced Info
command @kbd{g *} sees first. @inforef{Expert, Advanced Info
commands, info}, for more information. (A reader using the regular
Info commands usually starts reading at the first node and skips
this first section, which is not in a node.)@refill
In the @code{@@ifinfo} section, the summary sentence is followed by a
copyright notice and then by the copying permission notice. One of
the copying permission paragraphs is enclosed in @code{@@ignore} and
@code{@@end ignore} commands. This paragraph states that the Texinfo
file can be processed through @TeX{} and printed, provided the printed
manual carries the proper copying permission notice. This paragraph
is not made part of the Info file since it is not relevant to the Info
file; but it is a mandatory part of the Texinfo file since it permits
people to process the Texinfo file in @TeX{} and print the
results.@refill
In the printed manual, the Free Software Foundation copying permission
notice follows the copyright notice and publishing information and is
located within the region delineated by the @code{@@titlepage} and
@code{@@end titlepage} commands. The copying permission notice is exactly
the same as the notice in the @code{@@ifinfo} section except that the
paragraph enclosed in @code{@@ignore} and @code{@@end ignore} commands is
not part of the notice.@refill
To make it simple to insert a permission notice into each section of
the Texinfo file, sample permission notices for each section are
reproduced in full below.@refill
Note that you may need to specify the correct name of a section
mentioned in the permission notice. For example, in @cite{The GDB
Manual}, the name of the section referring to the General Public
License is called the ``GDB General Public License'', but in the
sample shown below, that section is referred to generically as the
``GNU General Public License''. If the Texinfo file does not carry a
copy of the General Public License, leave out the reference to it, but
be sure to include the rest of the sentence.@refill
@node ifinfo Permissions, Titlepage Permissions, Inserting Permissions, Sample Permissions
@comment node-name, next, previous, up
@appendixsec @samp{ifinfo} Copying Permissions
@cindex @samp{ifinfo} permissions
In the @code{@@ifinfo} section of a Texinfo file, the standard Free
Software Foundation permission notice reads as follows:@refill
@example
This file documents @dots{}
Copyright 1992 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim
copies of this manual provided the copyright notice and
this permission notice are preserved on all copies.
@@ignore
Permission is granted to process this file through TeX
and print the results, provided the printed document
carries a copying permission notice identical to this
one except for the removal of this paragraph (this
paragraph not being relevant to the printed manual).
@@end ignore
Permission is granted to copy and distribute modified
versions of this manual under the conditions for
verbatim copying, provided also that the sections
entitled ``Copying'' and ``GNU General Public License''
are included exactly as in the original, and provided
that the entire resulting derived work is distributed
under the terms of a permission notice identical to this
one.
Permission is granted to copy and distribute
translations of this manual into another language,
under the above conditions for modified versions,
except that this permission notice may be stated in a
translation approved by the Free Software Foundation.
@end example
@node Titlepage Permissions, , ifinfo Permissions, Sample Permissions
@comment node-name, next, previous, up
@appendixsec Titlepage Copying Permissions
@cindex Titlepage permissions
In the @code{@@titlepage} section of a Texinfo file, the standard Free
Software Foundation copying permission notice follows the copyright
notice and publishing information. The standard phrasing is as
follows:@refill
@example
Permission is granted to make and distribute verbatim
copies of this manual provided the copyright notice and
this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified
versions of this manual under the conditions for
verbatim copying, provided also that the sections
entitled ``Copying'' and ``GNU General Public License''
are included exactly as in the original, and provided
that the entire resulting derived work is distributed
under the terms of a permission notice identical to this
one.
Permission is granted to copy and distribute
translations of this manual into another language,
under the above conditions for modified versions,
except that this permission notice may be stated in a
translation approved by the Free Software Foundation.
@end example
@node Include Files, Headings, Sample Permissions, Top
@comment node-name, next, previous, up
@appendix Include Files
@cindex Include files
When @TeX{} or an Info formatting command sees an @code{@@include}
command in a Texinfo file, it processes the contents of the file named
by the command and incorporates them into the @sc{dvi} or Info file being
created. Index entries from the included file are incorporated into
the indices of the output file.@refill
Include files let you keep a single large document as a collection of
conveniently small parts.@refill
@menu
* Using Include Files:: How to use the @code{@@include} command.
* texinfo-multiple-files-update:: How to create and update nodes and
menus when using included files.
* Include File Requirements:: What @code{texinfo-multiple-files-update} expects.
* Sample Include File:: A sample outer file with included files
within it; and a sample included file.
* Include Files Evolution:: How use of the @code{@@include} command
has changed over time.
@end menu
@node Using Include Files, texinfo-multiple-files-update, Include Files, Include Files
@appendixsec How to Use Include Files
@findex include
To include another file within a Texinfo file, write the
@code{@@include} command at the beginning of a line and follow it on
the same line by the name of a file to be included. For
example:@refill
@example
@@include buffers.texi
@end example
An included file should simply be a segment of text that you expect to
be included as is into the overall or @dfn{outer} Texinfo file; it
should not contain the standard beginning and end parts of a Texinfo
file. In particular, you should not start an included file with a
line saying @samp{\input texinfo}; if you do, that phrase is inserted
into the output file as is. Likewise, you should not end an included
file with an @code{@@bye} command; nothing after @code{@@bye} is
formatted.@refill
In the past, you were required to write an @code{@@setfilename} line at the
beginning of an included file, but no longer. Now, it does not matter
whether you write such a line. If an @code{@@setfilename} line exists
in an included file, it is ignored.@refill
Conventionally, an included file begins with an @code{@@node} line that
is followed by an @code{@@chapter} line. Each included file is one
chapter. This makes it easy to use the regular node and menu creating
and updating commands to create the node pointers and menus within the
included file. However, the simple Emacs node and menu creating and
updating commands do not work with multiple Texinfo files. Thus you
cannot use these commands to fill in the `Next', `Previous', and `Up'
pointers of the @code{@@node} line that begins the included file. Also,
you cannot use the regular commands to create a master menu for the
whole file. Either you must insert the menus and the `Next',
`Previous', and `Up' pointers by hand, or you must use the GNU Emacs
Texinfo mode command, @code{texinfo-multiple-files-update}, that is
designed for @code{@@include} files.@refill
@node texinfo-multiple-files-update, Include File Requirements, Using Include Files, Include Files
@appendixsec @code{texinfo-multiple-files-update}
@findex texinfo-multiple-files-update
GNU Emacs Texinfo mode provides the @code{texinfo-multiple-files-update}
command. This command creates or updates `Next', `Previous', and `Up'
pointers of included files as well as those in the outer or overall
Texinfo file, and it creates or updates a main menu in the outer file.
Depending whether you call it with optional arguments, the command
updates only the pointers in the first @code{@@node} line of the
included files or all of them:@refill
@table @kbd
@item M-x texinfo-multiple-files-update
Called without any arguments:@refill
@itemize @minus
@item
Create or update the `Next', `Previous', and `Up' pointers of the
first @code{@@node} line in each file included in an outer or overall
Texinfo file.@refill
@item
Create or update the `Top' level node pointers of the outer or
overall file.@refill
@item
Create or update a main menu in the outer file.@refill
@end itemize
@item C-u M-x texinfo-multiple-files-update
Called with @kbd{C-u} as a prefix argument:
@itemize @minus{}
@item
Create or update pointers in the first @code{@@node} line in each
included file.
@item
Create or update the `Top' level node pointers of the outer file.
@item
Create and insert a master menu in the outer file. The master menu
is made from all the menus in all the included files.@refill
@end itemize
@item C-u 8 M-x texinfo-multiple-files-update
Called with a numeric prefix argument, such as @kbd{C-u 8}:
@itemize @minus
@item
Create or update @strong{all} the `Next', `Previous', and `Up' pointers
of all the included files.@refill
@item
Create or update @strong{all} the menus of all the included
files.@refill
@item
Create or update the `Top' level node pointers of the outer or
overall file.@refill
@item
And then create a master menu in the outer file. This is similar to
invoking @code{texinfo-master-menu} with an argument when you are
working with just one file.@refill
@end itemize
@end table
Note the use of the prefix argument in interactive use: with a regular
prefix argument, just @w{@kbd{C-u}}, the
@code{texinfo-multiple-files-update} command inserts a master menu;
with a numeric prefix argument, such as @kbd{C-u 8}, the command
updates @strong{every} pointer and menu in @strong{all} the files and then inserts a
master menu.@refill
@node Include File Requirements, Sample Include File, texinfo-multiple-files-update, Include Files
@appendixsec Include File Requirements
@cindex Include file requirements
@cindex Requirements for include files
If you plan to use the @code{texinfo-multiple-files-update} command,
the outer Texinfo file that lists included files within it should
contain nothing but the beginning and end parts of a Texinfo file, and
a number of @code{@@include} commands listing the included files. It
should not even include indices, which should be listed in an included
file of their own.@refill
Moreover, each of the included files must contain exactly one highest
level node (conventionally, @code{@@chapter} or equivalent),
and this node must be the first node in the included file.
Furthermore, each of these highest level nodes in each included file
must be at the same hierarchical level in the file structure.
Usually, each is an @code{@@chapter}, an @code{@@appendix}, or an
@code{@@unnumbered} node. Thus, normally, each included file contains
one, and only one, chapter or equivalent-level node.@refill
The outer file should contain only @emph{one} node, the `Top' node. It
should @emph{not} contain any nodes besides the single `Top' node. The
@code{texinfo-multiple-files-update} command will not process
them.@refill
@node Sample Include File, Include Files Evolution, Include File Requirements, Include Files
@appendixsec Sample File with @code{@@include}
@cindex Sample @code{@@include} file
@cindex Include file sample
@cindex @code{@@include} file sample
Here is an example of a complete outer Texinfo file with @code{@@include} files
within it before running @code{texinfo-multiple-files-update}, which
would insert a main or master menu:@refill
@example
@group
\input texinfo @@c -*-texinfo-*-
@c %**start of header
@@setfilename include-example.info
@@settitle Include Example
@c %**end of header
@end group
@group
@@setchapternewpage odd
@@titlepage
@@sp 12
@@center @@titlefont@{Include Example@}
@@sp 2
@@center by Whom Ever
@end group
@group
@@page
@@vskip 0pt plus 1filll
Copyright @@copyright@{@} 1990 Free Software Foundation, Inc.
@@end titlepage
@end group
@group
@@ifinfo
@@node Top, First, (dir), (dir)
@@top Master Menu
@@end ifinfo
@end group
@group
@@include foo.texinfo
@@include bar.texinfo
@@include concept-index.texinfo
@end group
@group
@@summarycontents
@@contents
@@bye
@end group
@end example
An included file, such as @file{foo.texinfo}, might look like
this:@refill
@example
@group
@@node First, Second, , Top
@@chapter First Chapter
Contents of first chapter @dots{}
@end group
@end example
The full contents of @file{concept-index.texinfo} might be as simple as this:
@example
@group
@@node Concept Index, , Second, Top
@@unnumbered Concept Index
@@printindex cp
@end group
@end example
The outer Texinfo source file for @cite{The GNU Emacs Lisp Reference
Manual} is named @file{elisp.texi}. This outer file contains a master
menu with 417 entries and a list of 41 @code{@@include}
files.@refill
@node Include Files Evolution, , Sample Include File, Include Files
@comment node-name, next, previous, up
@appendixsec Evolution of Include Files
When Info was first created, it was customary to create many small
Info files on one subject. Each Info file was formatted from its own
Texinfo source file. This custom meant that Emacs did not need to
make a large buffer to hold the whole of a large Info file when
someone wanted information; instead, Emacs allocated just enough
memory for the small Info file that contained the particular
information sought. This way, Emacs could avoid wasting memory.@refill
References from one file to another were made by referring to the file
name as well as the node name. (@xref{Other Info Files, , Referring to
Other Info Files}. Also, see @ref{Four and Five Arguments, ,
@code{@@xref} with Four and Five Arguments}.)@refill
Include files were designed primarily as a way to create a single,
large printed manual out of several smaller Info files. In a printed
manual, all the references were within the same document, so @TeX{}
could automatically determine the references' page numbers. The Info
formatting commands used include files only for creating joint
indices; each of the individual Texinfo files had to be formatted for
Info individually. (Each, therefore, required its own
@code{@@setfilename} line.)@refill
However, because large Info files are now split automatically, it is
no longer necessary to keep them small.@refill
Nowadays, multiple Texinfo files are used mostly for large documents,
such as @cite{The GNU Emacs Lisp Reference Manual}, and for projects
in which several different people write different sections of a
document simultaneously.@refill
In addition, the Info formatting commands have been extended to work
with the @code{@@include} command so as to create a single large Info
file that is split into smaller files if necessary. This means that
you can write menus and cross references without naming the different
Texinfo files.@refill
@node Headings, Catching Mistakes, Include Files, Top
@comment node-name, next, previous, up
@appendix Page Headings
@cindex Headings
@cindex Footings
@cindex Page numbering
@cindex Page headings
@cindex Formatting headings and footings
Most printed manuals contain headings along the top of every page
except the title and copyright pages. Some manuals also contain
footings. (Headings and footings have no meaning to Info, which is
not paginated.)@refill
@menu
* Headings Introduced:: Conventions for using page headings.
* Heading Format:: Standard page heading formats.
* Heading Choice:: How to specify the type of page heading.
* Custom Headings:: How to create your own headings and footings.
@end menu
@node Headings Introduced, Heading Format, Headings, Headings
@ifinfo
@heading Headings Introduced
@end ifinfo
Texinfo provides standard page heading formats for manuals that are printed
on one side of each sheet of paper and for manuals that are printed on
both sides of the paper. Usually, you will use one or other of these
formats, but you can specify your own format, if you wish.@refill
In addition, you can specify whether chapters should begin on a new
page, or merely continue the same page as the previous chapter; and if
chapters begin on new pages, you can specify whether they must be
odd-numbered pages.@refill
By convention, a book is printed on both sides of each sheet of paper.
When you open a book, the right-hand page is odd-numbered, and
chapters begin on right-hand pages---a preceding left-hand page is
left blank if necessary. Reports, however, are often printed on just
one side of paper, and chapters begin on a fresh page immediately
following the end of the preceding chapter. In short or informal
reports, chapters often do not begin on a new page at all, but are
separated from the preceding text by a small amount of whitespace.@refill
The @code{@@setchapternewpage} command controls whether chapters begin
on new pages, and whether one of the standard heading formats is used.
In addition, Texinfo has several heading and footing commands that you
can use to generate your own heading and footing formats.@refill
In Texinfo, headings and footings are single lines at the tops and
bottoms of pages; you cannot create multiline headings or footings.
Each header or footer line is divided into three parts: a left part, a
middle part, and a right part. Any part, or a whole line, may be left
blank. Text for the left part of a header or footer line is set
flushleft; text for the middle part is centered; and, text for the
right part is set flushright.@refill
@node Heading Format, Heading Choice, Headings Introduced, Headings
@comment node-name, next, previous, up
@appendixsec Standard Heading Formats
Texinfo provides two standard heading formats, one for manuals printed
on one side of each sheet of paper, and the other for manuals printed
on both sides of the paper.
By default, nothing is specified for the footing of a Texinfo file,
so the footing remains blank.@refill
The standard format for single-sided printing consists of a header
line in which the left-hand part contains the name of the chapter, the
central part is blank, and the right-hand part contains the page
number.@refill
@need 950
A single-sided page looks like this:
@example
@group
_______________________
| |
| chapter page number |
| |
| Start of text ... |
| ... |
| |
@end group
@end example
The standard format for two-sided printing depends on whether the page
number is even or odd. By convention, even-numbered pages are on the
left- and odd-numbered pages are on the right. (@TeX{} will adjust the
widths of the left- and right-hand margins. Usually, widths are
correct, but during double-sided printing, it is wise to check that
pages will bind properly---sometimes a printer will produce output in
which the even-numbered pages have a larger right-hand margin than the
odd-numbered pages.)@refill
In the standard double-sided format, the left part of the left-hand
(even-numbered) page contains the page number, the central part is
blank, and the right part contains the title (specified by the
@code{@@settitle} command). The left part of the right-hand
(odd-numbered) page contains the name of the chapter, the central part
is blank, and the right part contains the page number.@refill
@need 750
Two pages, side by side as in an open book, look like this:@refill
@example
@group
_______________________ _______________________
| | | |
| page number title | | chapter page number |
| | | |
| Start of text ... | | More text ... |
| ... | | ... |
| | | |
@end group
@end example
@noindent
The chapter name is preceded by the word @samp{Chapter}, the chapter
number and a colon. This makes it easier to keep track of where you
are in the manual.@refill
@node Heading Choice, Custom Headings, Heading Format, Headings
@comment node-name, next, previous, up
@appendixsec Specifying the Type of Heading
@TeX{} does not begin to generate page headings for a standard Texinfo
file until it reaches the @code{@@end titlepage} command. Thus, the
title and copyright pages are not numbered. The @code{@@end
titlepage} command causes @TeX{} to begin to generate page headings
according to a standard format specified by the
@code{@@setchapternewpage} command that precedes the
@code{@@titlepage} section.@refill
@need 1000
There are four possibilities:@refill
@table @asis
@item No @code{@@setchapternewpage} command
Cause @TeX{} to specify the single-sided heading format, with chapters
on new pages. This is the same as @code{@@setchapternewpage on}.@refill
@item @code{@@setchapternewpage on}
Specify the single-sided heading format, with chapters on new pages.@refill
@item @code{@@setchapternewpage off}
Cause @TeX{} to start a new chapter on the same page as the last page of
the preceding chapter, after skipping some vertical whitespace. Also
cause @TeX{} to typeset for single-sided printing. (You can override
the headers format with the @code{@@headings double} command; see
@ref{headings on off, , The @code{@@headings} Command}.)@refill
@item @code{@@setchapternewpage odd}
Specify the double-sided heading format, with chapters on new pages.@refill
@end table
@noindent
Texinfo lacks an @code{@@setchapternewpage even} command.@refill
@node Custom Headings, , Heading Choice, Headings
@comment node-name, next, previous, up
@appendixsec How to Make Your Own Headings
You can use the standard headings provided with Texinfo or specify
your own.@refill
@c Following paragraph is verbose to prevent overfull hboxes.
Texinfo provides six commands for specifying headings and
footings. The @code{@@everyheading} command and
@code{@@everyfooting} command generate page headers and footers
that are the same for both even- and odd-numbered pages.
The @code{@@evenheading} command and @code{@@evenfooting}
command generate headers and footers for even-numbered
(left-hand) pages; and the @code{@@oddheading} command and
@code{@@oddfooting} command generate headers and footers for
odd-numbered (right-hand) pages.@refill
Write custom heading specifications in the Texinfo file immediately
after the @code{@@end titlepage} command. Enclose your specifications
between @code{@@iftex} and @code{@@end iftex} commands since the
@code{texinfo-format-buffer} command may not recognize them. Also,
you must cancel the predefined heading commands with the
@code{@@headings off} command before defining your own
specifications.@refill
@need 1000
Here is how to tell @TeX{} to place the chapter name at the left, the
page number in the center, and the date at the right of every header
for both even- and odd-numbered pages:@refill
@example
@group
@@iftex
@@headings off
@@everyheading @@thischapter @@| @@thispage @@| @@today@{@}
@@end iftex
@end group
@end example
@noindent
You need to divide the left part from the central part and the central
part from the right had part by inserting @samp{@@|} between parts.
Otherwise, the specification command will not be able to tell where
the text for one part ends and the next part begins.@refill
Each part can contain text or @@-commands. The text
is printed as if the part were within an ordinary paragraph in the
body of the page. The @@-commands replace
themselves with the page number, date, chapter name, or
whatever.@refill
@need 950
Here are the six heading and footing commands:@refill
@findex everyheading
@findex everyfooting
@table @code
@item @@everyheading @var{left} @@| @var{center} @@| @var{right}
@itemx @@everyfooting @var{left} @@| @var{center} @@| @var{right}
The `every' commands specify the format for both even- and odd-numbered
pages. These commands are for documents that are printed on one side
of each sheet of paper, or for documents in which you want symmetrical
headers or footers.@refill
@findex evenheading
@findex evenfooting
@findex oddheading
@findex oddfooting
@item @@evenheading @var{left} @@| @var{center} @@| @var{right}
@itemx @@oddheading @var{left} @@| @var{center} @@| @var{right}
@itemx @@evenfooting @var{left} @@| @var{center} @@| @var{right}
@itemx @@oddfooting @var{left} @@| @var{center} @@| @var{right}
The `even' and `odd' commands specify the format for even-numbered
pages and odd-numbered pages. These commands are for books and
manuals that are printed on both sides of each sheet of paper.@refill
@end table
Use the @samp{@@this@dots{}} series of @@-commands to
provide the names of chapters
and sections and the page number. You can use the
@samp{@@this@dots{}} commands in the left, center, or right portions
of headers and footers, or anywhere else in a Texinfo file so long as
they are between @code{@@iftex} and @code{@@end iftex} commands.@refill
@need 1000
Here are the @samp{@@this@dots{}} commands:@refill
@table @code
@findex thispage
@item @@thispage
Expands to the current page number.@refill
@c !!! Karl Berry says that `thissection' fails on page breaks.
@ignore
@item @@thissection
Expands to the name of the current section.@refill
@end ignore
@findex thischaptername
@item @@thischaptername
Expands to the name of the current chapter.@refill
@findex thischapter
@item @@thischapter
Expands to the number and name of the current
chapter, in the format `Chapter 1: Title'.@refill
@findex thistitle
@item @@thistitle
Expands to the name of the document, as specified by the
@code{@@settitle} command.@refill
@findex thisfile
@item @@thisfile
For @code{@@include} files only: expands to the name of the current
@code{@@include} file. If the current Texinfo source file is not an
@code{@@include} file, this command has no effect. This command does
@emph{not} provide the name of the current Texinfo source file unless
it is an @code{@@include} file. (@xref{Include Files}, for more
information about @code{@@include} files.)@refill
@end table
@noindent
You can also use the @code{@@today@{@}} command, which expands to the
current date, in `1 Jan 1900' format.@refill
@findex today
Other @@-commands and text are printed in a header or footer just as
if they were in the body of a page. It is useful to incorporate text,
particularly when you are writing drafts:@refill
@example
@group
@@iftex
@@headings off
@@everyheading @@emph@{Draft!@} @@| @@thispage @@| @@thischapter
@@everyfooting @@| @@| Version: 0.27: @@today@{@}
@@end iftex
@end group
@end example
Beware of overlong titles: they may overlap another part of the
header or footer and blot it out.@refill
@node Catching Mistakes, Refilling Paragraphs, Headings, Top
@comment node-name, next, previous, up
@appendix Formatting Mistakes
@cindex Structure, catching mistakes in
@cindex Nodes, catching mistakes
@cindex Catching mistakes
@cindex Correcting mistakes
@cindex Mistakes, catching
@cindex Problems, catching
@cindex Debugging the Texinfo structure
Besides mistakes in the content of your documentation, there
are two kinds of mistake you can make with Texinfo: you can make mistakes
with @@-commands, and you can make mistakes with the structure of the
nodes and chapters.@refill
Emacs has two tools for catching the @@-command mistakes and two for
catching structuring mistakes.@refill
For finding problems with @@-commands, you can run @TeX{} or a region
formatting command on the region that has a problem; indeed, you can
run these commands on each region as you write it.@refill
For finding problems with the structure of nodes and chapters, you can use
@kbd{C-c C-s} (@code{texinfo-show-structure}) and the related @code{occur}
command and you can use the @kbd{M-x Info-validate} command.@refill
@menu
* makeinfo preferred:: @code{makeinfo} finds errors.
* Debugging with Info:: How to catch errors with Info formatting.
* Debugging with TeX:: How to catch errors with @TeX{} formatting.
* Using texinfo-show-structure:: How to use @code{texinfo-show-structure}.
* Using occur:: How to list all lines containing a pattern.
* Running Info-Validate:: How to find badly referenced nodes.
@end menu
@node makeinfo preferred, Debugging with Info, Catching Mistakes, Catching Mistakes
@ifinfo
@heading @code{makeinfo} Find Errors
@end ifinfo
The @code{makeinfo} program does an excellent job of catching errors
and reporting them---far better than @code{texinfo-format-region} or
@code{texinfo-format-buffer}. In addition, the various functions for
automatically creating and updating node pointers and menus remove
many opportunities for human error.@refill
If you can, use the updating commands to create and insert pointers
and menus. These prevent many errors. Then use @code{makeinfo} (or
its Texinfo mode manifestations, @code{makeinfo-region} and
@code{makeinfo-buffer}) to format your file and check for other
errors. This is the best way to work with Texinfo. But if you
cannot use @code{makeinfo}, or your problem is very puzzling, then you
may want to use the tools described in this appendix.@refill
@node Debugging with Info, Debugging with TeX, makeinfo preferred, Catching Mistakes
@comment node-name, next, previous, up
@appendixsec Catching Errors with Info Formatting
@cindex Catching errors with Info formatting
@cindex Debugging with Info formatting
After you have written part of a Texinfo file, you can use the
@code{texinfo-format-region} or the @code{makeinfo-region} command to
see whether the region formats properly.@refill
Most likely, however, you are reading this section because for some
reason you cannot use the @code{makeinfo-region} command; therefore, the
rest of this section presumes that you are using
@code{texinfo-format-region}.@refill
If you have made a mistake with an @@-command,
@code{texinfo-format-region} will stop processing at or after the
error and display an error message. To see where in the buffer the
error occurred, switch to the @samp{*Info Region*} buffer; the cursor
will be in a position that is after the location of the error. Also,
the text will not be formatted after the place where the error
occurred (or more precisely, where it was detected).@refill
For example, if you accidentally end a menu with the command @code{@@end
menus} with an `s' on the end, instead of with @code{@@end menu}, you
will see an error message that says:@refill
@example
@@end menus is not handled by texinfo
@end example
@noindent
The cursor will stop at the point in the buffer where the error
occurs, or not long after it. The buffer will look like this:@refill
@example
@group
---------- Buffer: *Info Region* ----------
* Menu:
* Using texinfo-show-structure:: How to use
`texinfo-show-structure'
to catch mistakes.
* Running Info-Validate:: How to check for
unreferenced nodes.
@@end menus
@point{}
---------- Buffer: *Info Region* ----------
@end group
@end example
The @code{texinfo-format-region} command sometimes provides slightly
odd error messages. For example, the following cross reference fails to format:@refill
@example
(@@xref@{Catching Mistakes, for more info.)
@end example
@noindent
In this case, @code{texinfo-format-region} detects the missing closing
brace but displays a message that says @samp{Unbalanced parentheses}
rather than @samp{Unbalanced braces}. This is because the formatting
command looks for mismatches between braces as if they were
parentheses.@refill
Sometimes @code{texinfo-format-region} fails to detect mistakes. For
example, in the following, the closing brace is swapped with the
closing parenthesis:@refill
@example
(@@xref@{Catching Mistakes), for more info.@}
@end example
@noindent
Formatting produces:
@example
(*Note for more info.: Catching Mistakes)
@end example
The only way for you to detect this error is to realize that the
reference should have looked like this:@refill
@example
(*Note Catching Mistakes::, for more info.)
@end example
Incidentally, if you are reading this node in Info and type @kbd{f
@key{RET}} (@code{Info-follow-reference}), you will generate an error
message that says:
@example
No such node: "Catching Mistakes) The only way @dots{}
@end example
@noindent
This is because Info perceives the example of the error as the first
cross reference in this node and if you type a @key{RET} immediately
after typing the Info @kbd{f} command, Info will attempt to go to the
referenced node. If you type @kbd{f catch @key{TAB} @key{RET}}, Info
will complete the node name of the correctly written example and take
you to the `Catching Mistakes' node. (If you try this, you can return
from the `Catching Mistakes' node by typing @kbd{l}
(@code{Info-last}).)
@c !!! section on using Elisp debugger ignored.
@ignore
Sometimes @code{texinfo-format-region} will stop long after the
original error; this is because it does not discover the problem until
then. In this case, you will need to backtrack.@refill
@c menu
@c * Using the Emacs Lisp Debugger:: How to use the Emacs Lisp debugger.
@c end menu
@c node Using the Emacs Lisp Debugger
@c appendixsubsec Using the Emacs Lisp Debugger
@c index Using the Emacs Lisp debugger
@c index Emacs Lisp debugger
@c index Debugger, using the Emacs Lisp
If an error is especially elusive, you can turn on the Emacs Lisp
debugger and look at the backtrace; this tells you where in the
@code{texinfo-format-region} function the problem occurred. You can
turn on the debugger with the command:@refill
@example
M-x set-variable @key{RET} debug-on-error @key{RET} t @key{RET}
@end example
@noindent
and turn it off with
@example
M-x set-variable @key{RET} debug-on-error @key{RET} nil @key{RET}
@end example
Often, when you are using the debugger, it is easier to follow what is
going on if you use the Emacs Lisp files that are not byte-compiled.
The byte-compiled sources send octal numbers to the debugger that may
look mysterious. To use the uncompiled source files, load
@file{texinfmt.el} and @file{texinfo.el} with the @kbd{M-x load-file}
command.@refill
The debugger will not catch an error if @code{texinfo-format-region}
does not detect one. In the example shown above,
@code{texinfo-format-region} did not find the error when the whole
list was formatted, but only when part of the list was formatted.
When @code{texinfo-format-region} did not find an error, the debugger
did not find one either. @refill
However, when @code{texinfo-format-region} did report an error, it
invoked the debugger. This is the backtrace it produced:@refill
@example
---------- Buffer: *Backtrace* ----------
Signalling: (search-failed "[@},]")
re-search-forward("[@},]")
(while ...)
(let ...)
texinfo-format-parse-args()
(let ...)
texinfo-format-xref()
funcall(texinfo-format-xref)
(if ...)
(let ...)
(if ...)
(while ...)
texinfo-format-scan()
(save-excursion ...)
(let ...)
texinfo-format-region(103370 103631)
* call-interactively(texinfo-format-region)
---------- Buffer: *Backtrace* ----------
@end example
The backtrace is read from the bottom up.
@code{texinfo-format-region} was called interactively; and it, in
turn, called various functions, including @code{texinfo-format-scan},
@code{texinfo-format-xref} and @code{texinfo-format-parse-args}.
Inside the function @code{texinfo-format-parse-args}, the function
@code{re-search-forward} was called; it was this function that could
not find the missing right-hand brace.@refill
@xref{Lisp Debug, , Debugging Emacs Lisp, emacs, The GNU Emacs
Manual}, for more information.@refill
@end ignore
@node Debugging with TeX, Using texinfo-show-structure, Debugging with Info, Catching Mistakes
@comment node-name, next, previous, up
@appendixsec Catching Errors with @TeX{} Formatting
@cindex Catching errors with @TeX{} formatting
@cindex Debugging with @TeX{} formatting
You can also catch mistakes when you format a file with @TeX{}.@refill
Usually, you will want to do this after you have run
@code{texinfo-format-buffer} (or, better, @code{makeinfo-buffer}) on
the same file, because @code{texinfo-format-buffer} sometimes displays
error messages that make more sense than @TeX{}. (@xref{Debugging
with Info}, for more information.)@refill
For example, @TeX{} was run on a Texinfo file, part of which is shown
here:@refill
@example
---------- Buffer: texinfo.texi ----------
name of the Texinfo file as an extension. The
@@samp@{??@} are `wildcards' that cause the shell to
substitute all the raw index files. (@@xref@{sorting
indices, for more information about sorting
indices.)@@refill
---------- Buffer: texinfo.texi ----------
@end example
@noindent
(The cross reference lacks a closing brace.)
@TeX{} produced the following output, after which it stopped:@refill
@example
---------- Buffer: *tex-shell* ----------
Runaway argument?
@{sorting indices, for more information about sorting
indices.) @@refill @@ETC.
! Paragraph ended before @@xref was complete.
@@par
l.27
?
---------- Buffer: *tex-shell* ----------
@end example
In this case, @TeX{} produced an accurate and
understandable error message:
@example
Paragraph ended before @@xref was complete.
@end example
@noindent
@samp{@@par} is an internal @TeX{} command of no relevance to Texinfo.
@samp{l.27} means that @TeX{} detected the problem on line 27 of the
Texinfo file. The @samp{?} is the prompt @TeX{} uses in this
circumstance.@refill
Unfortunately, @TeX{} is not always so helpful, and sometimes you must
truly be a Sherlock Holmes to discover what went wrong.@refill
In any case, if you run into a problem like this, you can do one of three
things.@refill
@enumerate
@item
You can tell @TeX{} to continue running and ignore just this error by
typing @key{RET} at the @samp{?} prompt.@refill
@item
You can tell @TeX{} to continue running and to ignore all errors as best
it can by typing @kbd{r @key{RET}} at the @samp{?} prompt.@refill
This is often the best thing to do. However, beware: the one error
may produce a cascade of additional error messages as its consequences
are felt through the rest of the file. (To stop @TeX{} when it is
producing such an avalanche of error messages, type @kbd{C-d} (or
@kbd{C-c C-d}, if you are running a shell inside Emacs.))@refill
@item
You can tell @TeX{} to stop this run by typing @kbd{x @key{RET}}
at the @samp{?} prompt.@refill
@end enumerate
Please note that if you are running @TeX{} inside Emacs, you need to
switch to the shell buffer and line at which @TeX{} offers the @samp{?}
prompt.@refill
Sometimes @TeX{} will format a file without producing error messages even
though there is a problem. This usually occurs if a command is not ended
but @TeX{} is able to continue processing anyhow. For example, if you fail
to end an itemized list with the @code{@@end itemize} command, @TeX{} will
write a @sc{dvi} file that you can print out. The only error message that
@TeX{} will give you is the somewhat mysterious comment that@refill
@example
(@@end occurred inside a group at level 1)
@end example
@noindent
However, if you print the @sc{dvi} file, you will find that the text
of the file that follows the itemized list is entirely indented as if
it were part of the last item in the itemized list. The error message
is the way @TeX{} says that it expected to find an @code{@@end}
command somewhere in the file; but that it could not determine where
it was needed.@refill
Another source of notoriously hard-to-find errors is a missing
@code{@@end group} command. If you ever are stumped by
incomprehensible errors, look for a missing @code{@@end group} command
first.@refill
If the Texinfo file lacks header lines,
@TeX{} may stop in the
beginning of its run and display output that looks like the following.
The @samp{*} indicates that @TeX{} is waiting for input.@refill
@example
This is TeX, Version 2.0 for Berkeley UNIX
(preloaded format=plain-cm 87.10.25)
(test.texinfo [1])
*
@end example
@noindent
In this case, simply type @kbd{\end @key{RET}} after the asterisk. Then
write the header lines in the Texinfo file and run the @TeX{} command
again. (Note the use of the backslash, @samp{\}. @TeX{} uses @samp{\}
instead of @samp{@@}; and in this circumstance, you are working
directly with @TeX{}, not with Texinfo.)@refill
@node Using texinfo-show-structure, Using occur, Debugging with TeX, Catching Mistakes
@comment node-name, next, previous, up
@appendixsec Using @code{texinfo-show-structure}
@cindex Showing the structure of a file
@findex texinfo-show-structure
It is not always easy to keep track of the nodes, chapters, sections, and
subsections of a Texinfo file. This is especially true if you are revising
or adding to a Texinfo file that someone else has written.@refill
In GNU Emacs, in Texinfo mode, the @code{texinfo-show-structure}
command lists all the lines that begin with the @@-commands that
specify the structure: @code{@@chapter}, @code{@@section},
@code{@@appendix}, and so on. With an argument (@w{@kbd{C-u}}
as prefix argument, if interactive),
the command also shows the @code{@@node} lines. The
@code{texinfo-show-structure} command is bound to @kbd{C-c C-s} in
Texinfo mode, by default.@refill
The lines are displayed in a buffer called the @samp{*Occur*} buffer,
indented by hierarchical level. For example, here is a part of what was
produced by running @code{texinfo-show-structure} on this manual:@refill
@example
@group
Lines matching "^@@\\(chapter \\|sect\\|subs\\|subh\\|
unnum\\|major\\|chapheading \\|heading \\|appendix\\)"
in buffer texinfo.texi.
@dots{}
4177:@@chapter Nodes
4198: @@heading Two Paths
4231: @@section Node and Menu Illustration
4337: @@section The @@code@{@@@@node@} Command
4393: @@subheading Choosing Node and Pointer Names
4417: @@subsection How to Write an @@code@{@@@@node@} Line
4469: @@subsection @@code@{@@@@node@} Line Tips
@dots{}
@end group
@end example
This says that lines 4337, 4393, and 4417 of @file{texinfo.texi} begin
with the @code{@@section}, @code{@@subheading}, and @code{@@subsection}
commands respectively. If you move your cursor into the @samp{*Occur*}
window, you can position the cursor over one of the lines and use the
@kbd{C-c C-c} command (@code{occur-mode-goto-occurrence}), to jump to
the corresponding spot in the Texinfo file. @xref{Other Repeating
Search, , Using Occur, emacs, The GNU Emacs Manual}, for more
information about @code{occur-mode-goto-occurrence}.@refill
The first line in the @samp{*Occur*} window describes the @dfn{regular
expression} specified by @var{texinfo-heading-pattern}. This regular
expression is the pattern that @code{texinfo-show-structure} looks for.
@xref{Regexps, , Using Regular Expressions, emacs, The GNU Emacs Manual},
for more information.@refill
When you invoke the @code{texinfo-show-structure} command, Emacs will
display the structure of the whole buffer. If you want to see the
structure of just a part of the buffer, of one chapter, for example,
use the @kbd{C-x n n} (@code{narrow-to-region}) command to mark the
region. (@xref{Narrowing, , , emacs, The GNU Emacs Manual}.) This is
how the example used above was generated. (To see the whole buffer
again, use @kbd{C-x n w} (@code{widen}).)@refill
If you call @code{texinfo-show-structure} with a prefix argument by
typing @w{@kbd{C-u C-c C-s}}, it will list lines beginning with
@code{@@node} as well as the lines beginning with the @@-sign commands
for @code{@@chapter}, @code{@@section}, and the like.@refill
You can remind yourself of the structure of a Texinfo file by looking at
the list in the @samp{*Occur*} window; and if you have mis-named a node
or left out a section, you can correct the mistake.@refill
@node Using occur, Running Info-Validate, Using texinfo-show-structure, Catching Mistakes
@comment node-name, next, previous, up
@appendixsec Using @code{occur}
@cindex Occurrences, listing with @code{@@occur}
@findex occur
Sometimes the @code{texinfo-show-structure} command produces too much
information. Perhaps you want to remind yourself of the overall structure
of a Texinfo file, and are overwhelmed by the detailed list produced by
@code{texinfo-show-structure}. In this case, you can use the @code{occur}
command directly. To do this, type@refill
@example
@kbd{M-x occur}
@end example
@noindent
and then, when prompted, type a @dfn{regexp}, a regular expression for
the pattern you want to match. (@xref{Regexps, , Regular Expressions,
emacs, The GNU Emacs Manual}.) The @code{occur} command works from
the current location of the cursor in the buffer to the end of the
buffer. If you want to run @code{occur} on the whole buffer, place
the cursor at the beginning of the buffer.@refill
For example, to see all the lines that contain the word
@samp{@@chapter} in them, just type @samp{@@chapter}. This will
produce a list of the chapters. It will also list all the sentences
with @samp{@@chapter} in the middle of the line.@refill
If you want to see only those lines that start with the word
@samp{@@chapter}, type @samp{^@@chapter} when prompted by
@code{occur}. If you want to see all the lines that end with a word
or phrase, end the last word with a @samp{$}; for example,
@samp{catching mistakes$}. This can be helpful when you want to see
all the nodes that are part of the same chapter or section and
therefore have the same `Up' pointer.@refill
@xref{Other Repeating Search, , Using Occur, emacs , The GNU Emacs Manual},
for more information.@refill
@node Running Info-Validate, , Using occur, Catching Mistakes
@comment node-name, next, previous, up
@appendixsec Finding Badly Referenced Nodes
@findex Info-validate
@cindex Nodes, checking for badly referenced
@cindex Checking for badly referenced nodes
@cindex Looking for badly referenced nodes
@cindex Finding badly referenced nodes
@cindex Badly referenced nodes
You can use the @code{Info-validate} command to check whether any of
the `Next', `Previous', `Up' or other node pointers fail to point to a
node. This command checks that every node pointer points to an
existing node. The @code{Info-validate} command works only on Info
files, not on Texinfo files.@refill
The @code{makeinfo} program validates pointers automatically, so you
do not need to use the @code{Info-validate} command if you are using
@code{makeinfo}. You only may need to use @code{Info-validate} if you
are unable to run @code{makeinfo} and instead must create an Info file
using @code{texinfo-format-region} or @code{texinfo-format-buffer}, or
if you write an Info file from scratch.@refill
@menu
* Using Info-validate:: How to run @code{Info-validate}.
* Unsplit:: How to create an unsplit file.
* Tagifying:: How to tagify a file.
* Splitting:: How to split a file manually.
@end menu
@node Using Info-validate, Unsplit, Running Info-Validate, Running Info-Validate
@appendixsubsec Running @code{Info-validate}
@cindex Running @code{Info-validate}
@cindex Info validating a large file
@cindex Validating a large file
To use @code{Info-validate}, visit the Info file you wish to check and
type:@refill
@example
M-x Info-validate
@end example
@noindent
(Note that the @code{Info-validate} command requires an upper case
`I'. You may also need to create a tag table before running
@code{Info-validate}. @xref{Tagifying}.)@refill
If your file is valid, you will receive a message that says ``File appears
valid''. However, if you have a pointer that does not point to a node,
error messages will be displayed in a buffer called @samp{*problems in
info file*}.@refill
For example, @code{Info-validate} was run on a test file that contained
only the first node of this manual. One of the messages said:@refill
@example
In node "Overview", invalid Next: Texinfo Mode
@end example
@noindent
This meant that the node called @samp{Overview} had a `Next' pointer that
did not point to anything (which was true in this case, since the test file
had only one node in it).@refill
Now suppose we add a node named @samp{Texinfo Mode} to our test case
but we do not specify a `Previous' for this node. Then we will get
the following error message:@refill
@example
In node "Texinfo Mode", should have Previous: Overview
@end example
@noindent
This is because every `Next' pointer should be matched by a
`Previous' (in the node where the `Next' points) which points back.@refill
@code{Info-validate} also checks that all menu entries and cross references
point to actual nodes.@refill
Note that @code{Info-validate} requires a tag table and does not work
with files that have been split. (The @code{texinfo-format-buffer}
command automatically splits large files.) In order to use
@code{Info-validate} on a large file, you must run
@code{texinfo-format-buffer} with an argument so that it does not split
the Info file; and you must create a tag table for the unsplit
file.@refill
@node Unsplit, Tagifying, Using Info-validate, Running Info-Validate
@comment node-name, next, previous, up
@appendixsubsec Creating an Unsplit File
@cindex Creating an unsplit file
@cindex Unsplit file creation
You can run @code{Info-validate} only on a single Info file that has a
tag table. The command will not work on the indirect subfiles that
are generated when a master file is split. If you have a large file
(longer than 70,000 bytes or so), you need to run the
@code{texinfo-format-buffer} or @code{makeinfo-buffer} command in such
a way that it does not create indirect subfiles. You will also need
to create a tag table for the Info file. After you have done this,
you can run @code{Info-validate} and look for badly referenced
nodes.@refill
The first step is to create an unsplit Info file. To prevent
@code{texinfo-format-buffer} from splitting a Texinfo file into
smaller Info files, give a prefix to the @kbd{M-x
texinfo-format-buffer} command:@refill
@example
C-u M-x texinfo-format-buffer
@end example
@noindent
or else
@example
C-u C-c C-e C-b
@end example
@noindent
When you do this, Texinfo will not split the file and will not create
a tag table for it. @refill
@cindex Making a tag table manually
@cindex Tag table, making manually
@node Tagifying, Splitting, Unsplit, Running Info-Validate
@appendixsubsec Tagifying a File
After creating an unsplit Info file, you must create a tag table for
it. Visit the Info file you wish to tagify and type:@refill
@example
M-x Info-tagify
@end example
@noindent
(Note the upper case @key{I} in @code{Info-tagify}.) This creates an
Info file with a tag table that you can validate.@refill
The third step is to validate the Info file:@refill
@example
M-x Info-validate
@end example
@noindent
(Note the upper case @key{I} in @code{Info-validate}.)
In brief, the steps are:@refill
@example
@group
C-u M-x texinfo-format-buffer
M-x Info-tagify
M-x Info-validate
@end group
@end example
After you have validated the node structure, you can rerun
@code{texinfo-format-buffer} in the normal way so it will construct a
tag table and split the file automatically, or you can make the tag
table and split the file manually.@refill
@node Splitting, , Tagifying, Running Info-Validate
@comment node-name, next, previous, up
@appendixsubsec Splitting a File Manually
@cindex Splitting an Info file manually
@cindex Info file, splitting manually
You should split a large file or else let the
@code{texinfo-format-buffer} or @code{makeinfo-buffer} command do it
for you automatically. (Generally you will let one of the formatting
commands do this job for you. @xref{Create an Info File}.)@refill
The split-off files are called the indirect subfiles.@refill
Info files are split to save memory. With smaller files, Emacs does not
have make such a large buffer to hold the information.@refill
If an Info file has more than 30 nodes, you should also make a tag
table for it. @xref{Using Info-validate}, for information
about creating a tag table. (Again, tag tables are usually created
automatically by the formatting command; you only need to create a tag
table yourself if you are doing the job manually. Most likely, you
will do this for a large, unsplit file on which you have run
@code{Info-validate}.)@refill
@c Info-split is autoloaded in `loaddefs.el' in Emacs 18.51
@ignore
Before running @code{Info-split}, you need to load the @code{info} library
into Emacs by giving the command @kbd{M-x load-library @key{RET} info
@key{RET}}.
@end ignore
Visit the Info file you wish to tagify and split and type the two
commands:@refill
@example
M-x Info-tagify
M-x Info-split
@end example
@noindent
(Note that the @samp{I} in @samp{Info} is upper case.)@refill
When you use the @code{Info-split} command, the buffer is modified into a
(small) Info file which lists the indirect subfiles. This file should be
saved in place of the original visited file. The indirect subfiles are
written in the same directory the original file is in, with names generated
by appending @samp{-} and a number to the original file name.@refill
The primary file still functions as an Info file, but it contains just
the tag table and a directory of subfiles.@refill
@node Refilling Paragraphs, Command Syntax, Catching Mistakes, Top
@comment node-name, next, previous, up
@appendix Refilling Paragraphs
@cindex Refilling paragraphs
@cindex Filling paragraphs
@findex refill
The @code{@@refill} command refills and, optionally, indents the first
line of a paragraph.@footnote{Perhaps the command should have been
called the @code{@@refillandindent} command, but @code{@@refill} is
shorter and the name was chosen before indenting was possible.} The
@code{@@refill} command is no longer important, but we describe it here
because you once needed it. You will see it in many old Texinfo
files.@refill
Without refilling, paragraphs containing long @@-constructs may look
bad after formatting because the formatter removes @@-commands and
shortens some lines more than others. In the past, neither the
@code{texinfo-format-region} command nor the
@code{texinfo-format-buffer} command refilled paragraphs
automatically. The @code{@@refill} command had to be written at the
end of every paragraph to cause these formatters to fill them. (Both
@TeX{} and @code{makeinfo} have always refilled paragraphs
automatically.) Now, all the Info formatters automatically fill and
indent those paragraphs that need to be filled and indented.@refill
The @code{@@refill} command causes @code{texinfo-format-region} and
@code{texinfo-format-buffer} to refill a paragraph in the Info file
@emph{after} all the other processing has been done. For this reason,
you can not use @code{@@refill} with a paragraph containing either
@code{@@*} or @code{@@w@{ @dots{} @}} since the refilling action will
override those two commands.@refill
The @code{texinfo-format-region} and @code{texinfo-format-buffer}
commands now automatically append @code{@@refill} to the end of each
paragraph that should be filled. They do not append @code{@@refill} to
the ends of paragraphs that contain @code{@@*} or @w{@code{@@w@{ @dots{}@}}}
and therefore do not refill or indent them.@refill
@node Command Syntax, Obtaining TeX, Refilling Paragraphs, Top
@comment node-name, next, previous, up
@appendix @@-Command Syntax
@cindex @@-command syntax
The character @samp{@@} is used to start special Texinfo commands.
(It has the same meaning that @samp{\} has in Plain@TeX{}.) Texinfo
has four types of @@-command:@refill
@table @asis
@item 1. Non-alphabetic commands.
These commands consist of an @@ followed by a punctuation mark or other
character that is not part of the alphabet. Non-alphabetic commands
are almost always part of the text within a paragraph, and never take
any argument. The two characters (@@ and the other one) are complete
in themselves; none is followed by braces. The non-alphabetic
commands are: @code{@@.}, @code{@@:}, @code{@@*}, @code{@@@@},
@code{@@@{}, and @code{@@@}}.@refill
@item 2. Alphabetic commands that do not require arguments.
These commands start with @@ followed by a word followed by left- and
right-hand braces. These commands insert special symbols in the
document; they do not require arguments. For example,
@code{@@dots@{@}} @result{} @samp{@dots{}}, @code{@@equiv@{@}}
@result{} @samp{@equiv{}}, @code{@@TeX@{@}} @result{} `@TeX{}',
and @code{@@bullet@{@}} @result{} @samp{@bullet{}}.@refill
@item 3. Alphabetic commands that require arguments within braces.
These commands start with @@ followed by a letter or a word, followed by an
argument within braces. For example, the command @code{@@dfn} indicates
the introductory or defining use of a term; it is used as follows: @samp{In
Texinfo, @@@@-commands are @@dfn@{mark-up@} commands.}@refill
@item 4. Alphabetic commands that occupy an entire line.
These commands occupy an entire line. The line starts with @@,
followed by the name of the command (a word); for example, @code{@@center}
or @code{@@cindex}. If no argument is needed, the word is followed by
the end of the line. If there is an argument, it is separated from
the command name by a space. Braces are not used.@refill
@end table
@cindex Braces and argument syntax
Thus, the alphabetic commands fall into classes that have
different argument syntaxes. You cannot tell to which class a command
belongs by the appearance of its name, but you can tell by the
command's meaning: if the command stands for a glyph, it is in
class 2 and does not require an argument; if it makes sense to use the
command together with other text as part of a paragraph, the command
is in class 3 and must be followed by an argument in braces;
otherwise, it is in class 4 and uses the rest of the line as its
argument.@refill
The purpose of having a different syntax for commands of classes 3 and
4 is to make Texinfo files easier to read, and also to help the GNU
Emacs paragraph and filling commands work properly. There is only one
exception to this rule: the command @code{@@refill}, which is always
used at the end of a paragraph immediately following the final period
or other punctuation character. @code{@@refill} takes no argument and
does @emph{not} require braces. @code{@@refill} never confuses the
Emacs paragraph commands because it cannot appear at the beginning of
a line.@refill
@node Obtaining TeX, New Features, Command Syntax, Top
@appendix How to Obtain @TeX{}
@cindex Obtaining @TeX{}
@cindex @TeX{}, how to obtain
@c !!! Here is information about obtaining TeX. Update it whenever.
@c Last updated by RJC on 1 March 1995, conversation with Mackay.
@TeX{} is freely redistributable. You can obtain @TeX{} for Unix
systems via anonymous ftp or on tape or CD-ROM. The core material
consists of Karl Berry's @code{web2c} @TeX{} package.
On-line retrieval instructions are in @code{ftp.cs.umb.edu}
@t{[158.121.104.33]} in @file{pub/tex/unixtex.ftp}
The Free Software Foundation provides a core distribution on its
Source Code CD-ROM; the University of Washington maintains and
supports a tape distribution.
For the FSF Source Code CD-ROM, please contact:
@iftex
@display
@group
Free Software Foundation, Inc.
59 Temple Place Suite 330
Boston, MA @w{ } 02111-1307
USA
Telephone: @w{@t{+}1--617--542--5942}
Fax: (including Japan) @w{@t{+}1--617--542--2652}
Free Dial Fax (in Japan):
@w{ } @w{ } @w{ } 0031--13--2473 (KDD)
@w{ } @w{ } @w{ } 0066--3382--0158 (IDC)
Electronic mail: @code{gnu@@prep.ai.mit.edu}
@end group
@end display
@end iftex
@ifinfo
@display
@group
Free Software Foundation, Inc.
59 Temple Place Suite 330
Boston, MA @w{ } 02111-1307
USA
Telephone: @w{@t{+}1-617-542-5942}
Fax: (including Japan) @w{@t{+}1-617-542-2652}
Free Dial Fax (in Japan):
@w{ } @w{ } @w{ } 0031-13-2473 (KDD)
@w{ } @w{ } @w{ } 0066-3382-0158 (IDC)
Electronic mail: @code{gnu@@prep.ai.mit.edu}
@end group
@end display
@end ifinfo
To order a full distribution from the University of Washington on either a
1/4@dmn{inch} 4-track QIC-24 cartridge or a 4@dmn{mm} DAT cartridge, send
$210.00 to:
@iftex
@display
@group
Pierre A. MacKay
Department of Classics
DH-10, Denny Hall 218
University of Washington
Seattle, WA @w{ } 98195
USA
Telephone: @t{+}1--206--543--2268
Electronic mail: @code{mackay@@cs.washington.edu}
@end group
@end display
@end iftex
@ifinfo
@display
@group
Pierre A. MacKay
Department of Classics
DH-10, Denny Hall 218
University of Washington
Seattle, WA @w{ } 98195
USA
Telephone: @t{+}1-206-543-2268
Electronic mail: @code{mackay@@cs.washington.edu}
@end group
@end display
@end ifinfo
Please make checks payable to the University of Washington.
Checks must be in U.S.@: dollars, drawn on a U.S.@: bank.
Prepaid orders are the only orders that can now be handled. Overseas
sites: please add to the base cost, if desired, $20.00 for shipment
via air parcel post, or $30.00 for shipment via courier.
Please check with the above for current prices and formats.
@node New Features, Command and Variable Index, Obtaining TeX, Top
@appendix Second Edition Features
@tex
% Widen the space for the first column so three control-character
% strings fit in the first column. Switched back to default .8in
% value at end of chapter.
\global\tableindent=1.0in
@end tex
The second edition of the Texinfo manual describes more than 20 new
Texinfo mode commands and more than 50 previously undocumented Texinfo
@@-commands. This edition is more than twice the length of the first
edition.@refill
Here is a brief description of the new commands.@refill
@menu
* New Texinfo Mode Commands:: The updating commands are especially useful.
* New Commands:: Many newly described @@-commands.
@end menu
@node New Texinfo Mode Commands, New Commands, New Features, New Features
@appendixsec New Texinfo Mode Commands
Texinfo mode provides commands and features especially designed for
working with Texinfo files. More than 20 new commands have been
added, including commands for automatically creating and updating
both nodes and menus. This is a tedious task when done by hand.@refill
The keybindings are intended to be somewhat mnemonic.@refill
@subheading Update all nodes and menus
The @code{texinfo-master-menu} command is the primary command:
@table @kbd
@item C-c C-u m
@itemx M-x texinfo-master-menu
Create or update a master menu.
With @kbd{C-u} as a prefix argument,
first create or update all nodes
and regular menus.
@end table
@subheading Update Pointers
@noindent
Create or update `Next', `Previous', and `Up' node pointers.@refill
@noindent
@xref{Updating Nodes and Menus}.
@table @kbd
@item C-c C-u C-n
@itemx M-x texinfo-update-node
Update a node.
@item C-c C-u C-e
@itemx M-x texinfo-every-node-update
Update every node in the buffer.
@end table
@subheading Update Menus
@noindent
Create or update menus.@refill
@noindent
@xref{Updating Nodes and Menus}.
@table @kbd
@item C-c C-u C-m
@itemx M-x texinfo-make-menu
Make or update a menu.
@item C-c C-u C-a
@itemx M-x texinfo-all-menus-update
Make or update all the menus in a buffer.
With @kbd{C-u} as a prefix argument,
first update all the nodes.
@end table
@subheading Insert Title as Description
@noindent
Insert a node's chapter or section title in the space for the
description in a menu entry line; position point so you can edit the
insert. (This command works somewhat differently than the other
insertion commands, which insert only a predefined string.)@refill
@noindent
@xref{Inserting, Inserting Frequently Used Commands}.
@table @kbd
@item C-c C-c C-d
Insert title.
@end table
@subheading Format for Info
@noindent
Provide keybindings both for the Info formatting commands that are
written in Emacs Lisp and for @code{makeinfo} that is written in
C.@refill
@noindent
@xref{Info Formatting}.
@noindent
Use the Emacs lisp @code{texinfo-format@dots{}} commands:
@table @kbd
@item C-c C-e C-r
Format the region.
@item C-c C-e C-b
Format the buffer.
@end table
@noindent
Use @code{makeinfo}:
@table @kbd
@item C-c C-m C-r
Format the region.
@item C-c C-m C-b
Format the buffer.
@item C-c C-m C-l
Recenter the @code{makeinfo} output buffer.
@item C-c C-m C-k
Kill the @code{makeinfo} formatting job.
@end table
@subheading Typeset and Print
@noindent
Typeset and print Texinfo documents from within Emacs.@refill
@ifinfo
@noindent
@xref{Printing}.
@end ifinfo
@iftex
@noindent
@xref{Printing, , Formatting and Printing}.
@end iftex
@table @kbd
@item C-c C-t C-b
Run @code{texi2dvi} on the buffer.
@item C-c C-t C-r
Run @TeX{} on the region.
@item C-c C-t C-i
Run @code{texindex}.
@item C-c C-t C-p
Print the @sc{dvi} file.
@item C-c C-t C-q
Show the print queue.
@item C-c C-t C-d
Delete a job from the print queue.
@item C-c C-t C-k
Kill the current @TeX{} formatting job.
@item C-c C-t C-x
Quit a currently stopped @TeX{} formatting job.
@item C-c C-t C-l
Recenter the output buffer.
@end table
@subheading Other Updating Commands
@noindent
The ``other updating commands'' do not have standard keybindings because
they are used less frequently.@refill
@noindent
@xref{Other Updating Commands}.
@table @kbd
@item M-x texinfo-insert-node-lines
Insert missing @code{@@node} lines using
section titles as node names.
@item M-x texinfo-multiple-files-update
Update a multi-file document.
With a numeric prefix, such as @kbd{C-u 8},
update @strong{every} pointer and
menu in @strong{all} the files and
then insert a master menu.
@item M-x texinfo-indent-menu-description
Indent descriptions in menus.
@item M-x texinfo-sequential-node-update
Insert node pointers in strict sequence.
@end table
@node New Commands, , New Texinfo Mode Commands, New Features
@appendixsec New Texinfo @@-Commands
The second edition of the Texinfo manual describes more than 50
commands that were not described in the first edition. A third or so
of these commands existed in Texinfo but were not documented in the
manual; the others are new. Here is a listing, with brief
descriptions of them:@refill
@subheading Indexing
@noindent
Create your own index, and merge indices.@refill
@noindent
@xref{Indices}.
@table @kbd
@item @@defindex @var{index-name}
Define a new index and its indexing command.
See also the @code{@@defcodeindex} command.
@c written verbosely to avoid overful hbox
@item @@synindex @var{from-index} @var{into-index}
Merge the @var{from-index} index into the @var{into-index} index.
See also the @code{@@syncodeindex} command.
@end table
@subheading Definitions
@noindent
Describe functions, variables, macros,
commands, user options, special forms, and other such artifacts in a
uniform format.@refill
@noindent
@xref{Definition Commands}.
@table @kbd
@item @@deffn @var{category} @var{name} @var{arguments}@dots{}
Format a description for functions, interactive
commands, and similar entities.
@item @@defvr, @@defop, @dots{}
15 other related commands.
@end table
@subheading Glyphs
@noindent
Indicate the results of evaluation, expansion,
printed output, an error message, equivalence of expressions, and the
location of point.@refill
@noindent
@xref{Glyphs}.
@table @kbd
@item @@equiv@{@}
@itemx @equiv{}
Equivalence:
@item @@error@{@}
@itemx @error{}
Error message
@item @@expansion@{@}
@itemx @expansion{}
Macro expansion
@item @@point@{@}
@itemx @point{}
Position of point
@item @@print@{@}
@itemx @print{}
Printed output
@item @@result@{@}
@itemx @result{}
Result of an expression
@end table
@subheading Page Headings
@noindent
Customize page headings.
@noindent
@xref{Headings}.
@table @kbd
@item @@headings @var{on-off-single-double}
Headings on or off, single, or double-sided.
@item @@evenfooting [@var{left}] @@| [@var{center}] @@| [@var{right}]
Footings for even-numbered (left-hand) pages.
@item @@evenheading, @@everyheading, @@oddheading, @dots{}
Five other related commands.
@item @@thischapter
Insert name of chapter and chapter number.
@item @@thischaptername, @@thisfile, @@thistitle, @@thispage
Related commands.
@end table
@subheading Formatting
@noindent
Format blocks of text.
@noindent
@xref{Quotations and Examples}, and@*
@ref{Lists and Tables, , Making Lists and Tables}.
@table @kbd
@item @@cartouche
Draw rounded box surrounding text (not in Info).
@item @@enumerate @var{optional-arg}
Enumerate a list with letters or numbers.
@item @@exdent @var{line-of-text}
Remove indentation.
@item @@flushleft
Left justify.
@item @@flushright
Right justify.
@item @@format
Do not narrow nor change font.
@item @@ftable @var{formatting-command}
@itemx @@vtable @var{formatting-command}
Two-column table with indexing.
@item @@lisp
For an example of Lisp code.
@item @@smallexample
@itemx @@smalllisp
Like @@table and @@lisp @r{but for} @@smallbook.
@end table
@subheading Conditionals
@noindent
Conditionally format text.
@noindent
@xref{set clear value, , @code{@@set} @code{@@clear} @code{@@value}}.@refill
@table @kbd
@item @@set @var{flag} [@var{string}]
Set a flag. Optionally, set value
of @var{flag} to @var{string}.
@item @@clear @var{flag}
Clear a flag.
@item @@value@{@var{flag}@}
Replace with value to which @var{flag} is set.
@item @@ifset @var{flag}
Format, if @var{flag} is set.
@item @@ifclear @var{flag}
Ignore, if @var{flag} is set.
@end table
@subheading @@heading series for Titles
@noindent
Produce unnumbered headings that do not appear in a table of contents.
@noindent
@xref{Structuring}.
@table @kbd
@item @@heading @var{title}
Unnumbered section-like heading not listed
in the table of contents of a printed manual.
@item @@chapheading, @@majorheading, @@subheading, @@subsubheading
Related commands.
@end table
@need 1000
@subheading Font commands
@need 1000
@noindent
@xref{Smallcaps}, and @*
@ref{Fonts}.
@table @kbd
@item @@r@{@var{text}@}
Print in roman font.
@item @@sc@{@var{text}@}
Print in @sc{small caps} font.
@end table
@subheading Miscellaneous
@noindent
See @ref{title subtitle author, , @code{@@title} @code{@@subtitle} and @code{@@author} Commands},@*
see @ref{Customized Highlighting},@*
see @ref{Overfull hboxes},@*
see @ref{Footnotes},@*
see @ref{dmn, , Format a Dimension},@*
see @ref{Raise/lower sections, , @code{@@raisesections} and @code{@@lowersections}},@*
see @ref{math, , @code{@@math}: Inserting Mathematical Expressions}.@*
see @ref{minus, , Inserting a Minus Sign},@*
see @ref{paragraphindent, , Paragraph Indenting},@*
see @ref{Cross Reference Commands},@*
see @ref{title subtitle author, , @code{@@title} @code{@@subtitle} and @code{@@author}}, and@*
see @ref{Custom Headings, , How to Make Your Own Headings}.
@need 700
@table @kbd
@item @@author @var{author}
Typeset author's name.
@item @@definfoenclose @var{new-command}, @var{before}, @var{after},
Define a highlighting command for Info. (Info only.)
@item @@finalout
Produce cleaner printed output.
@item @@footnotestyle @var{end-or-separate}
Specify footnote style.
@item @@dmn@{@var{dimension}@}
Format a dimension.
@item @@global@@let@var{new-cmd}=@var{existing-cmd}
Define a highlighting command for @TeX{}. (@TeX{} only.)
@item @@lowersections
Reduce hierarchical level of sectioning commands.
@item @@math@{@var{mathematical-expression}@}
Format a mathematical expression.
@item @@minus@{@}
Generate a minus sign.
@item @@paragraphindent @var{asis-or-number}
Specify paragraph indentation.
@item @@raisesections
Raise hierarchical level of sectioning commands.
@item @@ref@{@var{node-name}, @r{[}@var{entry}@r{]}, @r{[}@var{topic-or-title}@r{]}, @r{[}@var{info-file}@r{]}, @r{[}@var{manual}@r{]}@}
Make a reference. In the printed manual, the
reference does not start with the word `see'.
@item @@title @var{title}
Typeset @var{title} in the alternative
title page format.
@item @@subtitle @var{subtitle}
Typeset @var{subtitle} in the alternative
title page format.
@item @@today@{@}
Insert the current date.
@end table
@tex
% Switch width of first column of tables back to default value
\global\tableindent=.8in
@end tex
@node Command and Variable Index, Concept Index, New Features, Top
@comment node-name, next, previous, up
@unnumbered Command and Variable Index
This is an alphabetical list of all the @@-commands and several
variables. To make the list easier to use, the commands are listed
without their preceding @samp{@@}.@refill
@printindex fn
@node Concept Index, , Command and Variable Index, Top
@comment node-name, next, previous, up
@unnumbered Concept Index
@printindex cp
@summarycontents
@contents
@bye