This commit was generated by cvs2svn to compensate for changes in r2726,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
gclarkii 1994-09-13 13:51:34 +00:00
commit 52038e4d67
94 changed files with 68956 additions and 0 deletions

View File

@ -0,0 +1,8 @@
#
# Bmake file for texinfo
#
SUBDIR= info info-files makedoc makeinfo texindex
.include <bsd.subdir.mk>

View File

@ -0,0 +1,7 @@
#
#
#
INFODIR= /usr/share/info

View File

@ -0,0 +1,18 @@
#
# Makefile for INFO files
#
INFOFILES+= dir info.info makeinfo.info texi.info texi.info-1 texi.inf-2
INFOFILES+= texi.info-3 texi.info-4 texi.info-5 texi.info-6 texi.info-7
INFOFILES+= texi.info-8 texi.info-9 texi.info-10 texi.info-11
install:
mkdir -p ${INFODIR}
install -g ${BINGRP} -o ${BINOWN} -m 444 ${INFOFILES} ${INFODIR}
clean:
cleandir:
obj:
.include <bsd.prog.mk>

View File

@ -0,0 +1,18 @@
-*- Text -*-
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<Return>" visits Texinfo topic,
etc.
--- PLEASE ADD DOCUMENTATION TO THIS TREE. (See INFO topic first.) ---
* Menu: The list of major topics begins on the next line.
* Info: (info). Documentation browsing system.
* Texi: (texi). TexInfo guide.
* Makeinfo: (makeinfo). Makeinfo guide.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,777 @@
This is Info file info.info, produced by Makeinfo-1.55 from the input
file info.texi.
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.
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.

File: info.info, Node: Top, Next: Getting Started, Prev: (dir), Up: (dir)
Info: An Introduction
*********************
Info is a program for reading documentation, which you are using now.
To learn how to use Info, type the command `h'. It brings you to a
programmed instruction sequence.
To learn advanced Info commands, type `n' twice. This brings you to
`Info for Experts', skipping over the . `Getting Started' chapter.
* Menu:
* Getting Started::
* Advanced Info::
* Create an Info File::

File: info.info, Node: Getting Started, Next: Advanced Info, Prev: Top, Up: Top
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.
* 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

File: info.info, Node: Help-Small-Screen, Next: Help, Up: Getting Started
Starting Info on a Small Screen
===============================
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 `--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 `--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, SPC. To move back up, press
the key labeled `Rubout' or `Delete' or DEL.
Here are 40 lines of junk, so you can try SPC and DEL 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 DEL, and
come back here again, then you understand SPC and DEL. So now type an
`n'--just one character; do not type the quotes and do not type the
Return key, RET, afterward--to get to the normal start of the course.

File: info.info, Node: Help, Next: Help-P, Prev: Help-Small-Screen, Up: Getting Started
How to use Info
===============
You are talking to the program Info, for reading documentation.
Right now you are looking at one "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 "header". This node's header (look at
it now) says that it is the node named `Help' in the file `info'. It
says that the `Next' node after this one is the node called `Help-P'.
An advanced Info command lets you go to any node whose name you know.
Besides a `Next', a node can have a `Previous' or an `Up'. This
node has a `Previous' but no `Up', as you can see.
Now it is time to move on to the `Next' node, named `Help-P'.
>> Type `n' to move there. Type just one character; do not type
the quotes and do not type a RET afterward.
`>>' in the margin means it is really time to try a command.

File: info.info, Node: Help-P, Next: Help-^L, Prev: Help, Up: Getting Started
Returning to the Previous node
==============================
This node is called `Help-P'. The `Previous' node, as you see, is
`Help', which is the one you just came from using the `n' command.
Another `n' command now would take you to the next node, `Help-^L'.
>> But do not do that yet. First, try the `p' command, which takes
you to the `Previous' node. When you get there, you can do an `n'
again to return here.
This all probably seems insultingly simple so far, but *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 `n' to get to the node `Help-^L' and learn more.

File: info.info, Node: Help-^L, Next: Help-M, Prev: Help-P, Up: Getting Started
The Space, Rubout, B and ^L commands.
=====================================
This node's header tells you that you are now at node `Help-^L', and
that `p' would get you back to `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 `--Top-----' rather than `--All----' near the bottom right
corner of the screen.
The SPC, DEL and `b' commands exist to allow you to "move around" in
a node that does not all fit on the screen at once. SPC moves forward,
to show what was below the bottom of the screen. DEL 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 SPC (afterward, type a DEL to return here).
When you type the SPC, the two lines that were at the bottom of the
screen appear at the top, followed by more lines. DEL takes the two
lines from the top and moves them to the bottom, *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 a SPC when there is no more to see, it rings the bell
and otherwise does nothing. The same goes for a DEL 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 `C-l' (`Control-L', that is--hold down "Control" and
type an L or `l').
>> Type `C-l' now.
To move back to the beginning of the node you are on, you can type a
lot of DELs. You can also type simply `b' for beginning.
>> Try that now. (I have put in enough verbiage to make sure you are
not on the first screenful now). Then come back, typing SPC
several times.
You have just learned a considerable number of commands. If you
want to use one but have trouble remembering which, you should type a ?
which prints out a brief list of commands. When you are finished
looking at the list, make it go away by typing a SPC.
>> Type a ? now. After it finishes, type a 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 SPC and DEL 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 `n' to see the description of the `m' command.

File: info.info, Node: Help-M, Next: Help-Adv, Prev: Help-^L, Up: Getting Started
Menus
=====
Menus and the `m' command
With only the `n' and `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 `* 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 `*'
identifies one subtopic. The line usually contains a brief name for
the subtopic (followed by a `:'), 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 `*' have no special
meaning--they are only for the human reader's benefit and do not define
additional subtopics. Here is an example:
* Foo: FOO's Node This tells about FOO
The subtopic name is Foo, and the node describing it is `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 `* 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:
* Foo:: This tells about FOO
This means that the subtopic name and node name are the same; they are
both `Foo'.
>> Now use SPCs to find the menu in this node, then come back to
the front with a `b'. 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 `m' command is not available.
The command to go to one of the subnodes is `m'--but *do not do it
yet!* Before you use `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 `m' command is different: it
is incomplete without the "name of the subtopic". Once you have typed
`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 `n' or `b'
or SPC or `m'. If that line contains text ending in a colon, it mean
Info is trying to read the "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 `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 `m'. After you type
the `m', the line at the bottom of the screen says `Menu item: '. You
must then type the name of the subtopic you want, and end it with a 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.
Here is a menu to give you a chance to practice.
* Menu: The menu starts here.
This menu givs 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 `m' and see what happens:
Now you are "inside" an `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 `m' by typing Control-g.
>> Try that now; notice the bottom line clear.
>> Then type another `m'.
>> Now type `BAR' item name. Do not type RET yet.
While you are typing the item name, you can use the DEL character to
cancel one character at a time if you make a mistake.
>> Type one to cancel the `R'. You could type another `R' to
replace it. You do not have to, since `BA' is a valid abbreviation.
>> Now you are ready to go. Type a RET.
After visiting Help-FOO, you should return here.
>> Type `n' to see more commands.
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::

File: info.info, Node: Help-FOO, Up: Help-M
The `u' command
---------------
Congratulations! This is the node `Help-FOO'. Unlike the other
nodes you have seen, this one has an `Up': `Help-M', the node you just
came from via the `m' command. This is the usual convention--the nodes
you reach from a menu have `Up' nodes that lead back to the menu.
Menus move Down in the tree, and `Up' moves Up. `Previous', on the
other hand, is usually used to "stay on the same level but go backwards"
You can go back to the node `Help-M' by typing the command `u' for
"Up". That puts you at the *front* of the node--to get back to where
you were reading you have to type some SPCs.
>> Now type `u' to move back up to `Help-M'.

File: info.info, Node: Help-Adv, Next: Help-Q, Prev: Help-M, Up: Getting Started
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 `l' command (`l' for "last") will do that, one
node at a time. If you have been following directions, an `l' command
now will get you back to `Help-M'. Another `l' command would undo the
`u' and get you back to `Help-FOO'. Another `l' would undo the `m' and
get you back to `Help-M'.
>> Try typing three `l''s, pausing in between to see what each
`l' does.
Then follow directions again and you will end up back here.
Note the difference between `l' and `p': `l' moves to where *you*
last were, whereas `p' always moves to the node which the header says
is the `Previous' node (from this node, to `Help-M').
The `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 `d', then do an `l' to return here (yes, *do*
return).
Sometimes, in Info documentation, you will see a cross reference.
Cross references look like this: *Note Cross: Help-Cross. That is a
real, live cross reference which is named `Cross' and points at the
node named `Help-Cross'.
If you wish to follow a cross reference, you must use the `f'
command. The `f' must be followed by the cross reference name (in this
case, `Cross'). You can use DEL to edit the name, and if you change
your mind about following any reference you can use `Control-g' to
cancel the command.
Completion is available in the `f' command; you can complete among
all the cross reference names in the current node.
>> Type `f', followed by `Cross', and a RET.
To get a list of all the cross references in the current node, you
can type `?' after an `f'. The `f' continues to await a cross
reference name even after printing the list, so if you do not actually
want to follow a reference you should type a `Control-g' to cancel the
`f'.
>> Type "f?" to get a list of the footnotes in this node. Then type
a `Control-g' and see how the `f' gives up.
>> Now type `n' to see the last node of the course.

File: info.info, Node: Help-Cross, Up: Help-Adv
The node reached by the cross reference in Info
-----------------------------------------------
This is the node reached by the cross reference named `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 `Next', `Previous' or `Up' pointing back to where
you came from. In general, the `l' (el) command is the only way to get
back there.
>> Type `l' to return to the node where the cross reference was.

File: info.info, Node: Help-Q, Prev: Help-Adv, Up: Getting Started
Quitting Info
=============
To get out of Info, back to what you were doing before, type `q' for
"Quit".
This is the end of the course on using Info. There are some other
commands that are not essential or are meant for experienced users;
they are useful, and you can find them by looking in the directory for
documentation on Info. Finding them will be a good exercise in using
Info in the usual manner.
>> Type `d' to go to the Info directory node; then type `mInfo'
and RET, to get to the node about Info and see what other help is
available.

File: info.info, Node: Advanced Info, Next: Create an Info File, Prev: Getting Started, Up: Top
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 *both* to
generate an Info file and to make a printed manual. *Note Overview of
Texinfo: (texinfo)Top.)
* 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

File: info.info, Node: Expert, Next: Add, Up: Advanced Info
Advanced Info Commands
======================
`g', `s', `1', - `5', and `e'
If you know a node's name, you can go there by typing `g', the name,
and RET. Thus, `gTopRET' would go to the node called `Top' in this
file (its directory node). `gExpertRET' would come back here.
Unlike `m', `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,
`g(dir)TopRET' would go to the Info Directory node, which is node `Top'
in the file `dir'.
The node name `*' specifies the whole file. So you can look at all
of the current file by typing `g*RET' or all of any other file with
`g(FILENAME)RET'.
The `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 `s'
followed by the string to search for, terminated by RET. To search for
the same string again, just `s' followed by 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 `next' pointers. But normally the two orders
are not very different. In any case, you can always do a `b' to find
out what node you have reached, if the header is not visible (this can
happen, because `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 `1', `2', `3', `4', and `5'. They are
short for the `m' command together with an argument. "1", "2", "3",
"4", and "5". `1' goes through the first item in the current node's
menu; `2' goes through the second item, etc. Note that numbers larger
than 5 are not allowed. If the item you want is that far down, you are
better off using an abbreviation for its name than counting.
The Info command `e' changes from Info mode to an ordinary Emacs
editing mode, so that you can edit the text of the current node. Type
`C-c C-c' to switch back to Info. The `e' command is allowed only if
the variable `Info-enable-edit' is non-`nil'.

File: info.info, Node: Add, Next: Menus, Prev: Expert, Up: Advanced Info
Adding a new node to Info
=========================
To add a new topic to the list in the directory, you must:
1. Create a node, in some file, to document that topic.
2. Put that topic in the menu in the directory. *Note Menu: Menus.
The new node can live in an existing documentation file, or in a new
one. It must have a ^_ character before it (invisible to the user;
this node has one but you cannot see it), and it ends with either a ^_,
a ^L, or the end of file. Note: If you put in a ^L to end a new node,
be sure that there is a ^_ after it to start the next one, since ^L
cannot *start* a node. Also, a nicer way to make a node boundary be a
page boundary as well is to put a ^L *right after* the ^_.
The ^_ starting a node must be followed by a newline or a ^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 `Next', `Previous', and `Up' nodes (if there are any). As you
can see, this node's `Up' node is the node `Top', which points at all
the documentation for Info. The `Next' node is `Menus'.
The keywords "Node", "Previous", "Up" and "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 `Node: ' in that node's first line. For
example, this node's name is `Add'. A node in another file is named by
`(FILENAME)NODE-WITHIN-FILE', as in `(info)Add' for this node. If the
file name is relative, it is taken starting from the standard Info file
directory of your site. The name `(FILENAME)Top' can be abbreviated to
just `(FILENAME)'. By convention, the name `Top' is used for the
"highest" node in any single file--the node whose `Up' points out of
the file. The Directory node is `(dir)'. The `Top' node of a document
file listed in the Directory should have an `Up: (dir)' in it.
The node name `*' is special: it refers to the entire file. Thus,
`g*' shows you the whole current file. The use of the node `*' is to
make it possible to make old-fashioned, unstructured files into nodes
of the tree.
The `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 `Next', `Previous' and `Up' names may
contain them. In this node, since the `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.

File: info.info, Node: Menus, Next: Cross-refs, Prev: Add, Up: Advanced Info
How to Create Menus
===================
Any node in the Info hierarchy may have a "menu"--a list of subnodes.
The `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 `* Menu:'. The rest of the
line is a comment. After the starting line, every line that begins
with a `* ' lists a single topic. The name of the topic-the argument
that the user must give to the `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 `Next', `Previous' and `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, than rather than
giving the name twice, the abbreviation `* 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 `Up:' pointing at the
superior. It is often useful to arrange all or most of the subnodes in
a sequence of `Next' and `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 `(dir)Top'--that
is, node `Top' in file `.../info/dir'. You can put new entries in that
menu just like any other menu. The Info Directory is *not* the same as
the file directory called `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 *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
`Top'; the other contains the node `Help' which the `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.

File: info.info, Node: Cross-refs, Next: Tags, Prev: Menus, Up: Advanced Info
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 `*note' instead of `*'. It
*cannot* be terminated by a `)', because `)''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:
*Note details: commands. (See *note 3: Full Proof.)
They are just examples. The places they "lead to" do not really
exist!

File: info.info, Node: Tags, Next: Checking, Prev: Cross-refs, Up: Advanced Info
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 `M-x Info-tagify'. Then you must use `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 `Info-tagify' command again.
An Info file tag table appears at the end of the file and looks like
this:
^_
Tag Table:
File: info, Node: Cross-refs^?21419
File: info, Node: Tags^?22145
^_
End Tag Table
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 DEL
character, and the character position in the file of the beginning of
the node.

File: info.info, Node: Checking, Prev: Tags, Up: Advanced Info
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 `Next', `Previous', and `Up' is
checked, as is every menu item and every cross reference. In addition,
any `Next' which does not have a `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 `M-x Info-validate' while looking at any
node of the file with Emacs Info mode.

File: info.info, Node: Create an Info File, Prev: Advanced Info, Up: Top
Creating an Info File from a Makeinfo file
******************************************
`makeinfo' is a utility that converts a Texinfo file into an Info
file; `texinfo-format-region' and `texinfo-format-buffer' are GNU Emacs
functions that do the same.
*Note Creating an Info File: (texinfo)Create an Info File, to learn
how to create an Info file from a Texinfo file.
*Note Overview of Texinfo: (texinfo)Top, to learn how to write a
Texinfo file.

Tag Table:
Node: Top913
Node: Getting Started1431
Node: Help-Small-Screen2179
Node: Help3921
Node: Help-P4949
Node: Help-^L5811
Node: Help-M8462
Node: Help-FOO14030
Node: Help-Adv14766
Node: Help-Cross17148
Node: Help-Q17794
Node: Advanced Info18434
Node: Expert19330
Node: Add21601
Node: Menus24635
Node: Cross-refs27509
Node: Tags28211
Node: Checking29510
Node: Create an Info File30434

End Tag Table

View File

@ -0,0 +1,224 @@
This is Info file makeinfo.info, produced by Makeinfo-1.55 from the
input file makeinfo.texi.
This file is an extract from the `Texinfo' manual.
It documents `makeinfo', a program that converts Texinfo files into
Info files.
Copyright (C) 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.
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.

File: makeinfo.info, Node: Top, Next: What is makeinfo, Prev: (dir), Up: (dir)
`makeinfo'
**********
This file documents the use of the `makeinfo' program, versions 1.51
and later. It is an extract from the `Texinfo' manual.
* Menu:
* What is makeinfo::

File: makeinfo.info, Node: What is makeinfo, Prev: Top, Up: Top
What is `makeinfo'?
*******************
`makeinfo' is a program for converting "Texinfo" files into "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 `info' to learn
about Info. *Note Texinfo: (texinfo.texi)Top, to learn about the
Texinfo documentation system.
* Menu:
* Formatting Control::
* Options::
* Pointer Validation::

File: makeinfo.info, Node: Formatting Control, Next: Options, Up: What is makeinfo
Controlling Paragraph Formats
=============================
In general, `makeinfo' "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:
* The width of each paragraph (the "fill-column").
* The amount of indentation that the first line of each paragraph
receives (the "paragraph-indentation").

File: makeinfo.info, Node: Options, Next: Pointer Validation, Prev: Formatting Control, Up: What is makeinfo
Command Line Options
====================
The following command line options are available for `makeinfo'.
`-D VAR'
Cause VAR to be defined. This is equivalent to `@set VAR' in the
Texinfo file.
`--error-limit 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.
`--fill-column 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 `fill-column' is 72.
`--footnote-style STYLE'
Set the footnote style to STYLE, either `end' for the end node
style or `separate' for the separate node style. The value set by
this option overrides the value set in a Texinfo file by an
`@footnotestyle' command. When the footnote style is `separate',
`makeinfo' makes a new node containing the footnotes found in the
current node. When the footnote style is `end', `makeinfo' places
the footnote references at the end of the current node.
`-I DIR'
Add `dir' to the directory search list for finding files that are
included using the `@include' command. By default, `makeinfo'
searches only the current directory.
`--no-headers'
Do not include menus or node lines in the output. This results in
an 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.
`--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 `--no-split', `makeinfo' will not split up the output file.
`--no-pointer-validate'
`--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. *Note
Pointer Validation::.
`--no-warn'
Suppress the output of warning messages. This does *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.
`--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.
`--output FILE'
`-o FILE'
Specify that the output should be directed to FILE and not to the
file name specified in the `@setfilename' command found in the
Texinfo source. FILE can be the special token `-', which specifies
standard output.
`--paragraph-indent INDENT'
Set the paragraph indentation style to INDENT. The value set by
this option overrides the value set in a Texinfo file by an
`@paragraphindent' command. The value of INDENT is interpreted as
follows:
* If the value of INDENT is `asis', do not change the existing
indentation at the starts of paragraphs.
* If the value of INDENT is zero, delete any existing
indentation.
* If the value of INDENT is greater than zero, indent each
paragraph by that number of spaces.
`--reference-limit 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.
`-U VAR'
Cause VAR to be undefined. This is equivalent to `@clear VAR' in
the Texinfo file.
`--verbose'
Cause `makeinfo' to display messages saying what it is doing.
Normally, `makeinfo' only outputs messages if there are errors or
warnings.
`--version'
Report the version number of this copy of `makeinfo'.

File: makeinfo.info, Node: Pointer Validation, Prev: Options, Up: What is makeinfo
Pointer Validation
==================
If you do not suppress pointer-validation (by using the
`--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:
1. 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 `(dir)', then the referenced node must exist.
2. 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.
3. Every node except the `Top' node must have an `Up' pointer.
4. 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.
5. 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.

Tag Table:
Node: Top949
Node: What is makeinfo1215
Node: Formatting Control1758
Node: Options2377
Node: Pointer Validation6743

End Tag Table

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,861 @@
\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::
* Advanced Info::
* Create an Info File::
@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{Rubout} or @samp{Delete} or
@key{DEL}.
@ifinfo
Here are 40 lines of junk, so you can try @key{SPC} and @key{DEL} 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
@key{DEL}, and come back here again, then you understand @key{SPC} and
@key{DEL}. So now type an @kbd{n}---just one character; do not type
the quotes and do not type the Return key, @key{RET}, 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, Rubout, 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 @key{SPC}, @key{DEL} and @kbd{b} commands exist to allow you to ``move
around'' in a node that does not all fit on the screen at once.
@key{SPC} moves forward, to show what was below the bottom of the screen.
@key{DEL} 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 @key{SPC} (afterward, type a @key{DEL} to return here).
When you type the @key{SPC}, the two lines that were at the bottom
of the screen appear at the top, followed by more lines. @key{DEL}
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 a @key{SPC} when there is no more to see, it rings the
bell and otherwise does nothing. The same goes for a @key{DEL} 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 @key{DEL}s. You can also type simply @kbd{b} for beginning.
>> Try that now. (I have put in enough verbiage to make sure you are
not on the first screenful now). Then come back, typing @key{SPC}
several times.
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 @key{SPC} and @key{DEL} 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 @key{SPC}s to find the menu in this node, then come back to
the front with a @kbd{b}. 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 @key{SPC} 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.
Here is a menu to give you a chance to practice.
* Menu: The menu starts here.
This menu givs 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 @key{RET} yet.
While you are typing the item name, you can use the @key{DEL}
character 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 at a time. If you have been following directions,
an @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}). You can use @key{DEL} to edit the name,
and 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.
>> 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 do not
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 footnotes 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 not essential or are meant for experienced users;
they are useful, and you can find them by looking in the directory 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 @key{RET}, 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
@end menu
@node Expert, Add, , Advanced Info
@comment node-name, next, previous, up
@section Advanced Info Commands
@kbd{g}, @kbd{s}, @kbd{1}, -- @kbd{5}, 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}, and
@kbd{5}. They are short for the @kbd{m} command together with an
argument. "1", "2", "3", "4", and "5". @kbd{1} goes through the
first item in the current node's menu; @kbd{2} goes through the second
item, etc. Note that numbers larger than 5 are not allowed. If the
item you want is that far down, you are better off using an
abbreviation for its name than counting.
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 directory, you must:
@enumerate
@item
Create a node, in some file, to document that topic.
@item
Put that topic in the menu in the directory. @xref{Menus, Menu}.
@end enumerate
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 is relative, it is
taken 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, than 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 @key{DEL} character, and the character position in the file of the
beginning of the node.
@node Checking, , 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 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

View File

@ -0,0 +1,285 @@
\input texinfo @c -*-texinfo-*-
@comment %**start of header
@setfilename makeinfo.info
@set VERSION 1.51
@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 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 Makeinfo
@author Brian J. Fox and Robert J. Chassell
@page
@vskip 0pt plus 1filll
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.
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, What is makeinfo, (dir), (dir)
@unnumbered @code{makeinfo}
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 ifinfo
@menu
* What is makeinfo::
@end menu
@node What is makeinfo, , Top, Top
@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.texi, Texinfo},
@end ifinfo
@iftex
See the @cite{Texinfo} manual,
@end iftex
to learn about the Texinfo documentation system.
@menu
* Formatting Control::
* Options::
* Pointer Validation::
@end menu
@node Formatting Control, Options, , What is makeinfo
@section Controlling Paragraph Formats
In general, @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, Pointer Validation, Formatting Control, What is makeinfo
@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
@end table
@node Pointer Validation, , Options, What is makeinfo
@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
@bye

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,297 @@
This is Info file texi.info, produced by Makeinfo-1.55 from the input
file texi.texi.
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 Free Software Foundation,
Inc.
This is the second edition of the Texinfo documentation,
and is consistent with version 2 of `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.
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.

Indirect:
texi.info-1: 1096
texi.info-2: 50585
texi.info-3: 100344
texi.info-4: 149083
texi.info-5: 197497
texi.info-6: 247275
texi.info-7: 296490
texi.info-8: 346023
texi.info-9: 387598
texi.info-10: 433598
texi.info-11: 476101

Tag Table:
(Indirect)
Node: Top1096
Node: Copying21758
Node: Overview23766
Node: Using Texinfo25673
Node: Info Files28165
Node: Printed Books32225
Node: Formatting Commands35110
Node: Conventions38551
Node: Comments40811
Node: Minimum42233
Node: Six Parts44386
Node: Short Sample45896
Node: Acknowledgements50027
Node: Texinfo Mode50585
Node: Texinfo Mode Overview51956
Node: Emacs Editing52709
Node: Inserting54839
Node: Showing the Structure59115
Node: Updating Nodes and Menus61634
Node: Updating Commands62706
Node: Updating Requirements68741
Node: Other Updating Commands71042
Node: Info Formatting74311
Node: Printing75635
Node: Texinfo Mode Summary77399
Node: Beginning a File82167
Node: Four Parts83056
Node: Sample Beginning84502
Node: Header86125
Node: First Line87476
Node: Start of Header88448
Node: setfilename89163
Node: settitle90763
Node: setchapternewpage92646
Node: paragraphindent95412
Node: End of Header96877
Node: Info Summary and Permissions97717
Node: Titlepage & Copyright Page98738
Node: titlepage100344
Node: titlefont center sp102665
Node: title subtitle author103895
Node: Copyright & Permissions106171
Node: end titlepage108176
Node: headings on off109881
Node: The Top Node111707
Node: Title of Top Node112862
Node: Master Menu Parts114099
Node: Software Copying Permissions116150
Node: Ending a File117318
Node: Printing Indices & Menus118165
Node: Contents120448
Node: File End122790
Node: Structuring123462
Node: Tree Structuring125043
Node: Structuring Command Types126467
Node: makeinfo top128792
Node: chapter129323
Node: unnumbered & appendix130147
Node: majorheading & chapheading130986
Node: section131808
Node: unnumberedsec appendixsec heading132573
Node: subsection133560
Node: unnumberedsubsec appendixsubsec subheading134131
Node: subsubsection135083
Node: Nodes136603
Node: Two Paths137538
Node: Node Menu Illustration138810
Node: node142510
Node: Node Names145206
Node: Writing a Node146271
Node: Node Line Tips148291
Node: Node Line Requirements149083
Node: First Node150691
Node: makeinfo top command151811
Node: Top Node Summary153591
Node: makeinfo Pointer Creation154728
Node: Menus155977
Node: Menu Location157220
Node: Writing a Menu158884
Node: Menu Parts159850
Node: Less Cluttered Menu Entry160848
Node: Menu Example161473
Node: Other Info Files162995
Node: Cross References164855
Node: References165734
Node: Cross Reference Commands167458
Node: Cross Reference Parts168509
Node: xref171238
Node: Reference Syntax172035
Node: One Argument173679
Node: Two Arguments174690
Node: Three Arguments175804
Node: Four and Five Arguments178189
Node: Top Node Naming180602
Node: ref181610
Node: pxref182998
Node: inforef185382
Node: Marking Text186662
Node: Indicating187283
Node: Useful Highlighting189014
Node: code190199
Node: kbd193243
Node: key194431
Node: samp195985
Node: var197497
Node: file199287
Node: dfn199893
Node: cite200802
Node: Emphasis201243
Node: emph & strong202071
Node: Smallcaps203041
Node: Fonts204371
Node: Quotations and Examples205427
Node: Block Enclosing Commands207048
Node: quotation209043
Node: example210132
Node: noindent212190
Node: Lisp Example213657
Node: smallexample & smalllisp214488
Node: display216516
Node: format217146
Node: exdent217605
Node: flushleft & flushright218684
Node: cartouche219946
Node: Lists and Tables220716
Node: Introducing Lists221311
Node: itemize222953
Node: enumerate225104
Node: Two-column Tables227594
Node: table228287
Node: ftable vtable230601
Node: itemx231644
Node: Indices232604
Node: Index Entries233753
Node: Predefined Indices234870
Node: Indexing Commands235865
Node: Combining Indices239873
Node: syncodeindex241235
Node: synindex242874
Node: New Indices243398
Node: Insertions245227
Node: Braces Atsigns Periods245985
Node: Inserting An Atsign247275
Node: Inserting Braces247533
Node: Controlling Spacing247932
Node: dmn249490
Node: Dots Bullets250719
Node: dots251525
Node: bullet251920
Node: TeX and copyright252297
Node: tex252861
Node: copyright symbol253233
Node: minus253479
Node: Glyphs254350
Node: Glyphs Summary255461
Node: result255973
Node: expansion256430
Node: Print Glyph257352
Node: Error Glyph258203
Node: Equivalence259021
Node: Point Glyph259683
Node: Breaks261206
Node: Break Commands262558
Node: Line Breaks263246
Node: w264248
Node: sp265066
Node: page265474
Node: group265851
Node: need267596
Node: Definition Commands268326
Node: Def Cmd Template269897
Node: Optional Arguments272807
Node: deffnx274396
Node: Def Cmds in Detail275352
Node: Functions Commands276462
Node: Variables Commands279391
Node: Typed Functions281340
Node: Typed Variables284875
Node: Abstract Objects286856
Node: Data Types291752
Node: Def Cmd Conventions293005
Node: Sample Function Definition293566
Node: Footnotes296490
Node: Conditionals300343
Node: Conditional Commands301099
Node: Using Ordinary TeX Commands302508
Node: set clear value303956
Node: ifset ifclear304761
Node: value307921
Node: value Example309339
Node: Format/Print Hardcopy310917
Node: Use TeX312719
Node: Shell Format & Print313310
Node: Within Emacs317908
Node: Texinfo Mode Printing318896
Node: Compile-Command322646
Node: Requirements Summary323554
Node: Preparing for TeX324974
Node: Overfull hboxes326989
Node: smallbook328549
Node: A4 Paper329782
Node: Cropmarks and Magnification330484
Node: Create an Info File332460
Node: makeinfo advantages333764
Node: Invoking makeinfo334651
Node: makeinfo options335363
Node: Pointer Validation340823
Node: makeinfo in Emacs342207
Node: texinfo-format commands344752
Node: Batch Formatting346023
Node: Tag and Split Files347269
Node: Install an Info File350626
Node: Directory file351276
Node: New Info File352956
Node: Other Info Directories354095
Node: Command List355961
Node: Tips387598
Node: Sample Texinfo File399031
Node: Sample Permissions401147
Node: Inserting Permissions402188
Node: ifinfo Permissions404469
Node: Titlepage Permissions406088
Node: Include Files407348
Node: Using Include Files408434
Node: texinfo-multiple-files-update410368
Node: Include File Requirements412759
Node: Sample Include File414004
Node: Include Files Evolution415532
Node: Headings417509
Node: Headings Introduced418144
Node: Heading Format420033
Node: Heading Choice422489
Node: Custom Headings423860
Node: Catching Mistakes428069
Node: makeinfo preferred429359
Node: Debugging with Info430260
Node: Debugging with TeX433598
Node: Using texinfo-show-structure437940
Node: Using occur441040
Node: Running Info-Validate442579
Node: Using Info-validate443639
Node: Unsplit445454
Node: Tagifying446502
Node: Splitting447361
Node: Refilling Paragraphs448981
Node: Command Syntax450800
Node: Obtaining TeX453731
Node: New Features454842
Node: New Texinfo Mode Commands455424
Node: New Commands458894
Node: Command and Variable Index463543
Node: Concept Index476101

End Tag Table

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,451 @@
This is Info file texi.info, produced by Makeinfo-1.55 from the input
file texi.texi.
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 Free Software Foundation,
Inc.
This is the second edition of the Texinfo documentation,
and is consistent with version 2 of `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.
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.

File: texi.info, Node: Concept Index, Prev: Command and Variable Index, Up: Top
Concept Index
*************
* Menu:
* @-command in nodename: Node Line Requirements.
* @-command list: Command List.
* @-command syntax: Command Syntax.
* @-commands: Formatting Commands.
* .cshrc initialization file: Preparing for TeX.
* .profile initialization file: Preparing for TeX.
* @include file sample: Sample Include File.
* @menu parts: Menu Parts.
* @node line writing: Writing a Node.
* makeinfo inside Emacs: makeinfo in Emacs.
* makeinfo options: makeinfo options.
* TEXINPUTS environment variable: Preparing for TeX.
* dir directory for Info installation: Install an Info File.
* dir file listing: New Info File.
* End node footnote style: Footnotes.
* Separate footnote style: Footnotes.
* Top node: The Top Node.
* Top node is first: First Node.
* Top node naming for references: Top Node Naming.
* Top node summary: Top Node Summary.
* hboxes, overfull: Overfull hboxes.
* ifinfo permissions: ifinfo Permissions.
* TeX commands, using ordinary: Using Ordinary TeX Commands.
* TeX index sorting: Format/Print Hardcopy.
* TeX input initialization: Preparing for TeX.
* TeX, how to obtain: Obtaining TeX.
* A4 paper, printing on: A4 Paper.
* Abbreviations for keys: key.
* Adding a new info file: New Info File.
* Alphabetical @-command list: Command List.
* Another Info directory: Other Info Directories.
* Apostrophe in nodename: Node Line Requirements.
* Arguments, repeated and optional: Optional Arguments.
* Automatic pointer creation with makeinfo: makeinfo Pointer Creation.
* Automatically insert nodes, menus: Updating Nodes and Menus.
* Badly referenced nodes: Running Info-Validate.
* Batch formatting for Info: Batch Formatting.
* Beginning a Texinfo file: Beginning a File.
* Beginning line of a Texinfo file: First Line.
* Black rectangle in hardcopy: Overfull hboxes.
* Blank lines: sp.
* Book characteristics, printed: Printed Books.
* Book, printing small: smallbook.
* Box with rounded corners: cartouche.
* Braces and argument syntax: Command Syntax.
* Braces, inserting: Braces Atsigns Periods.
* Braces, when to use: Formatting Commands.
* Breaks in a line: Line Breaks.
* Buffer formatting and printing: Printing.
* Bullets, inserting: Dots Bullets.
* Capitalizing index entries: Indexing Commands.
* Case in nodename: Node Line Requirements.
* Catching errors with TeX formatting: Debugging with TeX.
* Catching errors with Info formatting: Debugging with Info.
* Catching mistakes: Catching Mistakes.
* Chapter structuring: Structuring.
* Characteristics, printed books or manuals: Printed Books.
* Checking for badly referenced nodes: Running Info-Validate.
* Colon in nodename: Node Line Requirements.
* Combining indices: Combining Indices.
* Comma in nodename: Node Line Requirements.
* Command definitions: Sample Function Definition.
* Commands to insert single characters: Braces Atsigns Periods.
* Commands using ordinary TeX: Using Ordinary TeX Commands.
* Commands, inserting them: Inserting.
* Comments: Comments.
* Compile command for formatting: Compile-Command.
* Conditionally visible text: Conditionals.
* Conditions for copying Texinfo: Copying.
* Contents, Table of: Contents.
* Contents-like outline of file structure: Showing the Structure.
* Conventions for writing definitions: Def Cmd Conventions.
* Conventions, syntactic: Conventions.
* Copying conditions: Copying.
* Copying permissions: Sample Permissions.
* Copying software: Software Copying Permissions.
* Copyright page: Copyright & Permissions.
* Correcting mistakes: Catching Mistakes.
* Create nodes, menus automatically: Updating Nodes and Menus.
* Creating an Info file: Create an Info File.
* Creating an unsplit file: Unsplit.
* Creating index entries: Indexing Commands.
* Creating indices: Indices.
* Creating pointers with makeinfo: makeinfo Pointer Creation.
* Cropmarks for printing: Cropmarks and Magnification.
* Cross reference parts: Cross Reference Parts.
* Cross references: Cross References.
* Cross references using @inforef: inforef.
* Cross references using @pxref: pxref.
* Cross references using @ref: ref.
* Cross references using @xref: xref.
* Debugging the Texinfo structure: Catching Mistakes.
* Debugging with TeX formatting: Debugging with TeX.
* Debugging with Info formatting: Debugging with Info.
* Defining indexing entries: Indexing Commands.
* Defining new indices: New Indices.
* Definition commands: Definition Commands.
* Definition conventions: Def Cmd Conventions.
* Definition template: Def Cmd Template.
* Definitions grouped together: deffnx.
* Description for menu, start: Inserting.
* Different cross reference commands: Cross Reference Commands.
* Dimension formatting: dmn.
* Display formatting: display.
* Distribution: Software Copying Permissions.
* Dots, inserting: dots.
* Dots, inserting: Dots Bullets.
* Double-colon menu entries: Less Cluttered Menu Entry.
* DVI file: Shell Format & Print.
* Ellipsis, inserting: Dots Bullets.
* Emacs: Texinfo Mode.
* Emacs shell, format, print from: Within Emacs.
* Emphasizing text: Emphasis.
* Emphasizing text, font for: emph & strong.
* End of header line: End of Header.
* End titlepage starts headings: end titlepage.
* Ending a Texinfo file: Ending a File.
* Entries for an index: Indexing Commands.
* Entries, making index: Index Entries.
* Enumeration: enumerate.
* Equivalence, indicating it: Equivalence.
* Error message, indicating it: Error Glyph.
* Errors, parsing: makeinfo in Emacs.
* European A4 paper: A4 Paper.
* Evaluation glyph: result.
* Example for a small book: smallexample & smalllisp.
* Example menu: Menu Example.
* Examples, formatting them: example.
* Expansion, indicating it: expansion.
* File beginning: Beginning a File.
* File ending: Ending a File.
* File section structure, showing it: Showing the Structure.
* Filling paragraphs: Refilling Paragraphs.
* Final output: Overfull hboxes.
* Finding badly referenced nodes: Running Info-Validate.
* First line of a Texinfo file: First Line.
* First node: First Node.
* Fonts for indices: syncodeindex.
* Fonts for printing, not for Info: Fonts.
* Footings: Headings.
* Footnotes: Footnotes.
* Format a dimension: dmn.
* Format and print hardcopy: Format/Print Hardcopy.
* Format and print in Texinfo mode: Texinfo Mode Printing.
* Format with the compile command: Compile-Command.
* Format, print from Emacs shell: Within Emacs.
* Formatting a file for Info: Create an Info File.
* Formatting commands: Formatting Commands.
* Formatting examples: example.
* Formatting for Info: Info Formatting.
* Formatting for printing: Printing.
* Formatting headings and footings: Headings.
* Formatting requirements: Requirements Summary.
* Frequently used commands, inserting: Inserting.
* Function definitions: Sample Function Definition.
* General syntactic conventions: Conventions.
* Generating menus with indices: Printing Indices & Menus.
* Glyphs: Glyphs.
* GNU Emacs: Texinfo Mode.
* GNU Emacs shell, format, print from: Within Emacs.
* Going to other Info files' nodes: Other Info Files.
* Group (hold text together vertically): group.
* Grouping two definitions together: deffnx.
* Hardcopy, printing it: Format/Print Hardcopy.
* Header for Texinfo files: Header.
* Header of a Texinfo file: First Line.
* Headings: Headings.
* Headings, page, begin to appear: end titlepage.
* Highlighting text: Indicating.
* Hints: Tips.
* Holding text together vertically: group.
* If text conditionally visible: Conditionals.
* Ignored text: Comments.
* Include file requirements: Include File Requirements.
* Include file sample: Sample Include File.
* Include files: Include Files.
* Indentation undoing: exdent.
* Indenting paragraphs: paragraphindent.
* Index entries: Indexing Commands.
* Index entries, making: Index Entries.
* Index entry capitalization: Indexing Commands.
* Index font types: Indexing Commands.
* Indexing commands, predefined: Indexing Commands.
* Indexing table entries automatically: ftable vtable.
* Indicating commands, definitions, etc.: Indicating.
* Indicating evaluation: result.
* Indices: Indices.
* Indices, combining them: Combining Indices.
* Indices, defining new: New Indices.
* Indices, printing and menus: Printing Indices & Menus.
* Indices, sorting: Format/Print Hardcopy.
* Indices, two letter names: syncodeindex.
* Indirect subfiles: Tag and Split Files.
* Info batch formatting: Batch Formatting.
* Info file installation: Install an Info File.
* Info file requires @setfilename: setfilename.
* Info file, listing new one: New Info File.
* Info file, splitting manually: Splitting.
* Info files: Info Files.
* Info formatting: Info Formatting.
* Info installed in another directory: Other Info Directories.
* Info validating a large file: Using Info-validate.
* Info, creating an on-line file: Create an Info File.
* Info; other files' nodes: Other Info Files.
* Initialization file for TeX input: Preparing for TeX.
* Insert nodes, menus automatically: Updating Nodes and Menus.
* Inserting @, braces, and periods: Braces Atsigns Periods.
* Inserting dots: Dots Bullets.
* Inserting dots: dots.
* Inserting ellipsis: Dots Bullets.
* Inserting frequently used commands: Inserting.
* Inserting special characters and symbols: Insertions.
* Installing an Info file: Install an Info File.
* Installing Info in another directory: Other Info Directories.
* Introduction, as part of file: Software Copying Permissions.
* Itemization: itemize.
* Keys, recommended names: key.
* Larger or smaller pages: Cropmarks and Magnification.
* Less cluttered menu entry: Less Cluttered Menu Entry.
* License agreement: Software Copying Permissions.
* Line breaks: Line Breaks.
* Line breaks, preventing: w.
* Line spacing: sp.
* Lisp example: Lisp Example.
* Lisp example for a small book: smallexample & smalllisp.
* List of @-commands: Command List.
* Listing a new info file: New Info File.
* Lists and tables, making them: Lists and Tables.
* Local variables: Compile-Command.
* Location of menus: Menu Location.
* Looking for badly referenced nodes: Running Info-Validate.
* Macro definitions: Sample Function Definition.
* Magnified printing: Cropmarks and Magnification.
* Making a printed manual: Format/Print Hardcopy.
* Making a tag table automatically: Tag and Split Files.
* Making a tag table manually: Unsplit.
* Making cross references: Cross References.
* Making line and page breaks: Breaks.
* Making lists and tables: Lists and Tables.
* Manual characteristics, printed: Printed Books.
* Marking text within a paragraph: Marking Text.
* Marking words and phrases: Marking Text.
* Master menu: The Top Node.
* Master menu parts: Master Menu Parts.
* Mathematical expressions: Using Ordinary TeX Commands.
* Menu description, start: Inserting.
* Menu entries with two colons: Less Cluttered Menu Entry.
* Menu example: Menu Example.
* Menu location: Menu Location.
* Menu parts: Menu Parts.
* Menu writing: Writing a Menu.
* Menus: Menus.
* Menus generated with indices: Printing Indices & Menus.
* META key: key.
* Meta-syntactic chars for arguments: Optional Arguments.
* Minimal Texinfo file (requirements): Minimum.
* Mistakes, catching: Catching Mistakes.
* Mode, using Texinfo: Texinfo Mode.
* Must have in Texinfo file: Minimum.
* Names for indices: syncodeindex.
* Names recommended for keys: key.
* Naming a `Top' Node in references: Top Node Naming.
* Need space at page bottom: need.
* New index defining: New Indices.
* New info file, listing it in dir file: New Info File.
* Node line requirements: Node Line Requirements.
* Node line writing: Writing a Node.
* Node, defined: node.
* Node, `Top': The Top Node.
* Nodename must be unique: Node Line Requirements.
* Nodename, cannot contain: Node Line Requirements.
* Nodes for menus are short: Menu Location.
* Nodes in other Info files: Other Info Files.
* Nodes, catching mistakes: Catching Mistakes.
* Nodes, checking for badly referenced: Running Info-Validate.
* Obtaining TeX: Obtaining TeX.
* Occurrences, listing with @occur: Using occur.
* Optional and repeated arguments: Optional Arguments.
* Options for makeinfo: makeinfo options.
* Ordinary TeX commands, using: Using Ordinary TeX Commands.
* Other Info files' nodes: Other Info Files.
* Outline of file structure, showing it: Showing the Structure.
* Overfull hboxes: Overfull hboxes.
* Overview of Texinfo: Overview.
* Page breaks: page.
* Page delimiter in Texinfo mode: Showing the Structure.
* Page headings: Headings.
* Page numbering: Headings.
* Page sizes for books: smallbook.
* Pages, starting odd: setchapternewpage.
* Paper size, European A4: A4 Paper.
* Paragraph indentation: paragraphindent.
* Paragraph, marking text within: Marking Text.
* Parsing errors: makeinfo in Emacs.
* Part of file formatting and printing: Printing.
* Parts of a cross reference: Cross Reference Parts.
* Parts of a master menu: Master Menu Parts.
* Parts of a menu: Menu Parts.
* Periods, inserting: Braces Atsigns Periods.
* Permissions: Sample Permissions.
* Permissions, printed: Copyright & Permissions.
* PlainTeX: Using Ordinary TeX Commands.
* Point, indicating it in a buffer: Point Glyph.
* Pointer creation with makeinfo: makeinfo Pointer Creation.
* Pointer validation with makeinfo: Pointer Validation.
* Predefined indexing commands: Indexing Commands.
* Predefined names for indices: syncodeindex.
* Preparing to use TeX: Preparing for TeX.
* Preventing line and page breaks: Breaks.
* Print and format in Texinfo mode: Texinfo Mode Printing.
* Print, format from Emacs shell: Within Emacs.
* Printed book and manual characteristics: Printed Books.
* Printed output, indicating it: Print Glyph.
* Printed permissions: Copyright & Permissions.
* Printing a region or buffer: Printing.
* Printing an index: Printing Indices & Menus.
* Printing cropmarks: Cropmarks and Magnification.
* Problems, catching: Catching Mistakes.
* Quotations: quotation.
* Recommended names for keys: key.
* Rectangle, ugly, black in hardcopy: Overfull hboxes.
* References: Cross References.
* References using @inforef: inforef.
* References using @pxref: pxref.
* References using @ref: ref.
* References using @xref: xref.
* Referring to other Info files: Other Info Files.
* Refilling paragraphs: Refilling Paragraphs.
* Region formatting and printing: Printing.
* Region printing in Texinfo mode: Texinfo Mode Printing.
* Repeated and optional arguments: Optional Arguments.
* Required in Texinfo file: Minimum.
* Requirements for formatting: Requirements Summary.
* Requirements for include files: Include File Requirements.
* Requirements for updating commands: Updating Requirements.
* Result of an expression: result.
* Running Info-validate: Using Info-validate.
* Running makeinfo in Emacs: makeinfo in Emacs.
* Running an Info formatter: Info Formatting.
* Sample @include file: Sample Include File.
* Sample function definition: Sample Function Definition.
* Sample Texinfo file: Short Sample.
* Sample Texinfo file, no comments: Sample Texinfo File.
* Section structure of a file, showing it: Showing the Structure.
* Shell, format, print from: Within Emacs.
* Shell, running makeinfo in: makeinfo in Emacs.
* Short nodes for menus: Menu Location.
* Showing the section structure of a file: Showing the Structure.
* Showing the structure of a file: Using texinfo-show-structure.
* Single characters, commands to insert: Braces Atsigns Periods.
* Size of printed book: smallbook.
* Small book example: smallexample & smalllisp.
* Small book size: smallbook.
* Small caps font: Smallcaps.
* Software copying permissions: Software Copying Permissions.
* Sorting indices: Format/Print Hardcopy.
* Spaces (blank lines): sp.
* Special insertions: Insertions.
* Special typesetting commands: Dots Bullets.
* Specifying index entries: Indexing Commands.
* Splitting an Info file manually: Splitting.
* Start of header line: Start of Header.
* Starting chapters: setchapternewpage.
* Structure of a file, showing it: Showing the Structure.
* Structure, catching mistakes in: Catching Mistakes.
* Structuring of chapters: Structuring.
* Subsection-like commands: unnumberedsubsec appendixsubsec subheading.
* Subsub commands: subsubsection.
* Syntactic conventions: Conventions.
* Syntax, optional & repeated arguments: Optional Arguments.
* Table of contents: Contents.
* Tables and lists, making them: Lists and Tables.
* Tables with indexes: ftable vtable.
* Tables, making two-column: Two-column Tables.
* Tabs; don't use!: Conventions.
* Tag table, making automatically: Tag and Split Files.
* Tag table, making manually: Unsplit.
* Template for a definition: Def Cmd Template.
* Texinfo file beginning: Beginning a File.
* Texinfo file ending: Ending a File.
* Texinfo file header: Header.
* Texinfo file minimum: Minimum.
* Texinfo file section structure, showing it: Showing the Structure.
* Texinfo mode: Texinfo Mode.
* Texinfo overview: Overview.
* Texinfo printed book characteristics: Printed Books.
* Text, conditionally visible: Conditionals.
* Thin space between number, dimension: dmn.
* Tips: Tips.
* Title page: titlepage.
* Titlepage end starts headings: end titlepage.
* Titlepage permissions: Titlepage Permissions.
* Tree structuring: Tree Structuring.
* Two letter names for indices: syncodeindex.
* Two named items for @table: itemx.
* Two part menu entry: Less Cluttered Menu Entry.
* Two `First' Lines for @deffn: deffnx.
* Typesetting commands for dots, etc.: Dots Bullets.
* Uncluttered menu entry: Less Cluttered Menu Entry.
* Unique nodename requirement: Node Line Requirements.
* Unprocessed text: Comments.
* Unsplit file creation: Unsplit.
* Updating nodes and menus: Updating Nodes and Menus.
* Updating requirements: Updating Requirements.
* Usage tips: Tips.
* Validating a large file: Using Info-validate.
* Validation of pointers: Pointer Validation.
* Value of an expression, indicating: result.
* Vertical whitespace (vskip): Copyright & Permissions.
* Vertically holding text together: group.
* Visibility of conditional text: Conditionals.
* Words and phrases, marking them: Marking Text.
* Writing a menu: Writing a Menu.
* Writing an @node line: Writing a Node.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
#
# Bmakefile for GNU info
#
# $id$
#
PROG= info
SRCS+= dir.c display.c dribble.c echo_area.c filesys.c info-utils.c info.c
SRCS+= infodoc.c infomap.c m-x.c nodes.c search.c session.c signals.c
SRCS+= terminal.c tilde.c window.c indices.c doc.c nodemenu.c
SRCS+= footnotes.c variables.c gc.c xmalloc.c getopt1.c getopt.c
CFLAGS=
CFLAGS+= -I${.CURDIR}
CFLAGS+= -DNAMED_FUNCTIONS=1 -DSTDC_HEADERS=1
CFLAGS+= -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1
CFLAGS+= -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1
CFLAGS+= -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
CFLAGS+= -DHAVE_SYS_TIME_H=1 -DDEFAULT_INFOPATH='"${INFODIR}"'
LDADD+= -ltermcap
DPADD+= ${LIBTERMCAP}
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View File

@ -0,0 +1,224 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/errno.h>
#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 called "localdir" found in
INFOPATH. */
static void add_menu_to_file_buffer (), insert_text_into_fb_at_binding ();
void
maybe_build_dir_node (dirname, from_files_named)
char *dirname;
char *from_files_named;
{
FILE_BUFFER *dir_buffer;
/* See if the file has already been loaded and exists. */
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;
dir_buffer->flags |= N_CannotGC;
/* For every file named FROM_FILES_NAMED in the search path, add the
contents of that file's menu to our "dir" node. */
{
struct stat finfo;
char *this_dir;
int namelen, path_index;
int update_tags = 0;
namelen = strlen (from_files_named);
path_index = 0;
/* Using each element of the path, check for "localdir". Do not check
for "localdir.info.Z" or anything else. Only files explictly named
"localdir" 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))
{
char *fullpath;
int statable;
/* Expand a leading tilde if one is present. */
if (*this_dir == '~')
{
char *tilde_expanded_dirname;
tilde_expanded_dirname = tilde_expand_word (this_dir);
free (this_dir);
this_dir = tilde_expanded_dirname;
}
fullpath = (char *)xmalloc (3 + strlen (this_dir) + namelen);
strcpy (fullpath, this_dir);
if (fullpath[strlen (fullpath) - 1] != '/')
strcat (fullpath, "/");
strcat (fullpath, from_files_named);
statable = (stat (fullpath, &finfo) == 0);
if (statable && S_ISREG (finfo.st_mode))
{
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);
}
}
/* 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;
/* 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;
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;
}

View File

@ -0,0 +1,561 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#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);
}

View File

@ -0,0 +1,76 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

View File

@ -0,0 +1,128 @@
/* doc.c -- Generated structure containing function names and doc strings.
This file was automatically made from various source files with the
command "./makedoc". DO NOT EDIT THIS FILE, only "./makedoc.c".
Source files groveled to make this file include:
./session.c
./echo_area.c
./infodoc.c
./m-x.c
./indices.c
./nodemenu.c
./footnotes.c
./variables.c
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,
a string which is the user-visible name of the function,
and a string which documents its purpose. */
#include "doc.h"
#include "funs.h"
FUNCTION_DOC function_doc_array[] = {
/* Commands found in "./session.c". */
{ info_next_line, "next-line", "Move down to the next line" },
{ info_prev_line, "prev-line", "Move up to the previous line" },
{ info_end_of_line, "end-of-line", "Move to the end of the line" },
{ info_beginning_of_line, "beginning-of-line", "Move to the start of the line" },
{ info_forward_char, "forward-char", "Move forward a character" },
{ info_backward_char, "backward-char", "Move backward a character" },
{ info_forward_word, "forward-word", "Move forward a word" },
{ info_backward_word, "backward-word", "Move backward a word" },
{ info_global_next_node, "global-next-node", "Move forwards or down through node structure" },
{ info_global_prev_node, "global-prev-node", "Move backwards or up through node structure" },
{ info_scroll_forward, "scroll-forward", "Scroll forward in this window" },
{ info_scroll_backward, "scroll-backward", "Scroll backward in this window" },
{ info_beginning_of_node, "beginning-of-node", "Move to the start of this node" },
{ info_end_of_node, "end-of-node", "Move to the end of this node" },
{ info_next_window, "next-window", "Select the next window" },
{ info_prev_window, "prev-window", "Select the previous window" },
{ info_split_window, "split-window", "Split the current window" },
{ info_delete_window, "delete-window", "Delete the current window" },
{ info_keep_one_window, "keep-one-window", "Delete all other windows" },
{ info_scroll_other_window, "scroll-other-window", "Scroll the other window" },
{ info_grow_window, "grow-window", "Grow (or shrink) this window" },
{ info_tile_windows, "tile-windows", "Divide the available screen space among the visible windows" },
{ info_toggle_wrap, "toggle-wrap", "Toggle the state of line wrapping in the current window" },
{ info_next_node, "next-node", "Select the `Next' node" },
{ info_prev_node, "prev-node", "Select the `Prev' node" },
{ info_up_node, "up-node", "Select the `Up' node" },
{ info_last_node, "last-node", "Select the last node in this file" },
{ info_first_node, "first-node", "Select the first node in this file" },
{ info_history_node, "history-node", "Select the most recently selected node" },
{ info_last_menu_item, "last-menu-item", "Select the last item in this node's menu" },
{ info_menu_digit, "menu-digit", "Select this menu item" },
{ info_menu_item, "menu-item", "Read a menu item and select its node" },
{ info_xref_item, "xref-item", "Read a footnote or cross reference and select its node" },
{ info_find_menu, "find-menu", "Move to the start of this node's menu" },
{ info_visit_menu, "visit-menu", "Visit as many menu items at once as possible" },
{ info_goto_node, "goto-node", "Read a node name and select it" },
{ info_top_node, "top-node", "Select the node `Top' in this file" },
{ info_dir_node, "dir-node", "Select the node `(dir)'" },
{ info_kill_node, "kill-node", "Kill this node" },
{ info_view_file, "view-file", "Read the name of a file and select it" },
{ info_print_node, "print-node", "Pipe the contents of this node through INFO_PRINT_COMMAND" },
{ info_search, "search", "Read a string and search for it" },
{ isearch_forward, "isearch-forward", "Search interactively for a string as you type it" },
{ isearch_backward, "isearch-backward", "Search interactively for a string as you type it" },
{ info_move_to_prev_xref, "move-to-prev-xref", "Move to the previous cross reference" },
{ info_move_to_next_xref, "move-to-next-xref", "Move to the next cross reference" },
{ info_select_reference_this_line, "select-reference-this-line", "Select reference or menu item appearing on this line" },
{ info_abort_key, "abort-key", "Cancel current operation" },
{ info_move_to_window_line, "move-to-window-line", "Move to the cursor to a specific line of the window" },
{ info_redraw_display, "redraw-display", "Redraw the display" },
{ info_quit, "quit", "Quit using Info" },
{ info_do_lowercase_version, "do-lowercase-version", "" },
{ info_add_digit_to_numeric_arg, "add-digit-to-numeric-arg", "Add this digit to the current numeric argument" },
{ info_universal_argument, "universal-argument", "Start (or multiply by 4) the current numeric argument" },
{ info_numeric_arg_digit_loop, "numeric-arg-digit-loop", "" },
/* Commands found in "./echo_area.c". */
{ ea_forward, "echo-area-forward", "Move forward a character" },
{ ea_backward, "echo-area-backward", "Move backward a character" },
{ ea_beg_of_line, "echo-area-beg-of-line", "Move to the start of this line" },
{ ea_end_of_line, "echo-area-end-of-line", "Move to the end of this line" },
{ ea_forward_word, "echo-area-forward-word", "Move forward a word" },
{ ea_backward_word, "echo-area-backward-word", "Move backward a word" },
{ ea_delete, "echo-area-delete", "Delete the character under the cursor" },
{ ea_rubout, "echo-area-rubout", "Delete the character behind the cursor" },
{ ea_abort, "echo-area-abort", "Cancel or quit operation" },
{ ea_newline, "echo-area-newline", "Accept (or force completion of) this line" },
{ ea_quoted_insert, "echo-area-quoted-insert", "Insert next character verbatim" },
{ ea_insert, "echo-area-insert", "Insert this character" },
{ ea_tab_insert, "echo-area-tab-insert", "Insert a TAB character" },
{ ea_transpose_chars, "echo-area-transpose-chars", "Transpose characters at point" },
{ ea_yank, "echo-area-yank", "Yank back the contents of the last kill" },
{ ea_yank_pop, "echo-area-yank-pop", "Yank back a previous kill" },
{ ea_kill_line, "echo-area-kill-line", "Kill to the end of the line" },
{ ea_backward_kill_line, "echo-area-backward-kill-line", "Kill to the beginning of the line" },
{ ea_kill_word, "echo-area-kill-word", "Kill the word following the cursor" },
{ ea_backward_kill_word, "echo-area-backward-kill-word", "Kill the word preceding the cursor" },
{ ea_possible_completions, "echo-area-possible-completions", "List possible completions" },
{ ea_complete, "echo-area-complete", "Insert completion" },
{ ea_scroll_completions_window, "echo-area-scroll-completions-window", "Scroll the completions window" },
/* Commands found in "./infodoc.c". */
{ info_get_help_window, "get-help-window", "Display help message" },
{ info_get_info_help_node, "get-info-help-node", "Visit Info node `(info)Help'" },
{ describe_key, "describe-key", "Print documentation for KEY" },
{ info_where_is, "where-is", "Show what to type to execute a given command" },
/* Commands found in "./m-x.c". */
{ describe_command, "describe-command", "Read the name of an Info command and describe it" },
{ info_execute_command, "execute-command", "Read a command name in the echo area and execute it" },
{ set_screen_height, "set-screen-height", "Set the height of the displayed window" },
/* Commands found in "./indices.c". */
{ info_index_search, "index-search", "Look up a string in the index for this file" },
{ info_next_index_match, "next-index-match", "Go to the next matching index item from the last `\\[index-search]' command" },
{ info_index_apropos, "index-apropos", "Grovel all known info file's indices for a string and build a menu" },
/* Commands found in "./nodemenu.c". */
{ list_visited_nodes, "list-visited-nodes", "Make a window containing a menu of all of the currently visited nodes" },
{ select_visited_node, "select-visited-node", "Select a node which has been previously visited in a visible window" },
/* Commands found in "./footnotes.c". */
{ info_show_footnotes, "show-footnotes", "Show the footnotes associated with this node in another window" },
/* Commands found in "./variables.c". */
{ describe_variable, "describe-variable", "Explain the use of a variable" },
{ set_variable, "set-variable", "Set the value of an Info variable" },
{ (VFunction *)NULL, (char *)NULL, (char *)NULL }
};

View File

@ -0,0 +1,58 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

View File

@ -0,0 +1,71 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include <stdio.h>
#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);
}

View File

@ -0,0 +1,41 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,63 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

View File

@ -0,0 +1,624 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/errno.h>
#include "general.h"
#include "tilde.h"
#include "filesys.h"
#if !defined (O_RDONLY)
#if defined (HAVE_SYS_FCNTL_H)
#include <sys/fcntl.h>
#else /* !HAVE_SYS_FCNTL_H */
#include <fcntl.h>
#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" },
{ (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 = savestring (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 = (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 = savestring (filename);
new->expansion = expansion ? savestring (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 = savestring (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;
{
*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. */
contents = (char *)xmalloc (1 + finfo->st_size);
if ((read (descriptor, contents, finfo->st_size)) != finfo->st_size)
{
filesys_error_number = errno;
close (descriptor);
free (contents);
return ((char *)NULL);
}
close (descriptor);
*filesize = finfo->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;
#if !defined (HAVE_STRERROR)
extern const char * const sys_errlist[];
extern int sys_nerr;
char *
strerror (num)
int num;
{
if (num >= sys_nerr)
return ("");
else
return (sys_errlist[num]);
}
#endif /* !HAVE_STRERROR */
/* 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);
}

View File

@ -0,0 +1,84 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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/gnu/info:/local/gnu/info:/usr/gnu/lib/info:/usr/gnu/lib/emacs/info:/usr/local/gnu/info:/usr/local/gnu/lib/info:/usr/local/gnu/lib/emacs/info:/usr/local/lib/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_ */

View File

@ -0,0 +1,264 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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 (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;
}
}
}

View File

@ -0,0 +1,46 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

View File

@ -0,0 +1,110 @@
/* funs.h -- Generated declarations for Info commands. */
/* Functions declared in "./session.c". */
extern void info_next_line ();
extern void info_prev_line ();
extern void info_end_of_line ();
extern void info_beginning_of_line ();
extern void info_forward_char ();
extern void info_backward_char ();
extern void info_forward_word ();
extern void info_backward_word ();
extern void info_global_next_node ();
extern void info_global_prev_node ();
extern void info_scroll_forward ();
extern void info_scroll_backward ();
extern void info_beginning_of_node ();
extern void info_end_of_node ();
extern void info_next_window ();
extern void info_prev_window ();
extern void info_split_window ();
extern void info_delete_window ();
extern void info_keep_one_window ();
extern void info_scroll_other_window ();
extern void info_grow_window ();
extern void info_tile_windows ();
extern void info_toggle_wrap ();
extern void info_next_node ();
extern void info_prev_node ();
extern void info_up_node ();
extern void info_last_node ();
extern void info_first_node ();
extern void info_history_node ();
extern void info_last_menu_item ();
extern void info_menu_digit ();
extern void info_menu_item ();
extern void info_xref_item ();
extern void info_find_menu ();
extern void info_visit_menu ();
extern void info_goto_node ();
extern void info_top_node ();
extern void info_dir_node ();
extern void info_kill_node ();
extern void info_view_file ();
extern void info_print_node ();
extern void info_search ();
extern void isearch_forward ();
extern void isearch_backward ();
extern void info_move_to_prev_xref ();
extern void info_move_to_next_xref ();
extern void info_select_reference_this_line ();
extern void info_abort_key ();
extern void info_move_to_window_line ();
extern void info_redraw_display ();
extern void info_quit ();
extern void info_do_lowercase_version ();
extern void info_add_digit_to_numeric_arg ();
extern void info_universal_argument ();
extern void info_numeric_arg_digit_loop ();
/* Functions declared in "./echo_area.c". */
extern void ea_forward ();
extern void ea_backward ();
extern void ea_beg_of_line ();
extern void ea_end_of_line ();
extern void ea_forward_word ();
extern void ea_backward_word ();
extern void ea_delete ();
extern void ea_rubout ();
extern void ea_abort ();
extern void ea_newline ();
extern void ea_quoted_insert ();
extern void ea_insert ();
extern void ea_tab_insert ();
extern void ea_transpose_chars ();
extern void ea_yank ();
extern void ea_yank_pop ();
extern void ea_kill_line ();
extern void ea_backward_kill_line ();
extern void ea_kill_word ();
extern void ea_backward_kill_word ();
extern void ea_possible_completions ();
extern void ea_complete ();
extern void ea_scroll_completions_window ();
/* Functions declared in "./infodoc.c". */
extern void info_get_help_window ();
extern void info_get_info_help_node ();
extern void describe_key ();
extern void info_where_is ();
/* Functions declared in "./m-x.c". */
extern void describe_command ();
extern void info_execute_command ();
extern void set_screen_height ();
/* Functions declared in "./indices.c". */
extern void info_index_search ();
extern void info_next_index_match ();
extern void info_index_apropos ();
/* Functions declared in "./nodemenu.c". */
extern void list_visited_nodes ();
extern void select_visited_node ();
/* Functions declared in "./footnotes.c". */
extern void info_show_footnotes ();
/* Functions declared in "./variables.c". */
extern void describe_variable ();
extern void set_variable ();

View File

@ -0,0 +1,95 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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;
}

View File

@ -0,0 +1,36 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

View File

@ -0,0 +1,81 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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 <unistd.h>
#endif /* HAVE_UNISTD_H */
#if defined (HAVE_STRING_H)
# include <string.h>
#else
# include <strings.h>
#endif /* !HAVE_STRING_H */
#if !defined (savestring)
# define savestring(x) (char *)strcpy ((char *)xmalloc (1 + strlen (x)), x)
#endif /* !savestring */
#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 ();
#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 (HAVE_BZERO)
# define zero_mem(mem, length) memset (mem, 0, length)
#else
# define zero_mem(mem, length) bzero (mem, length)
#endif /* !BZERO_MISSING */
#endif /* !_GENERAL_H_ */

View File

@ -0,0 +1,731 @@
/* 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* NOTE!!! AIX requires this to be the first thing in the file.
Do not put ANYTHING before it! */
#if !defined (__GNUC__) && defined (_AIX)
#pragma alloca
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* not __GNUC__ */
#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
#include <alloca.h>
#else
#ifndef _AIX
char *alloca ();
#endif
#endif /* alloca.h */
#endif /* not __GNUC__ */
#if !__STDC__ && !defined(const) && IN_GCC
#define const
#endif
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
#ifndef _NO_PROTO
#define _NO_PROTO
#endif
#include <stdio.h>
/* 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__
#undef alloca
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
#include <stdlib.h>
#else /* Not GNU C library. */
#define __alloca alloca
#endif /* GNU C library. */
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
long-named option. Because this is not POSIX.2 compliant, it is
being phased out. */
/* #define GETOPT_COMPAT */
/* 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 = 0;
/* 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;
#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 <string.h>
#define my_index strchr
#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
#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;
}
static void
my_bcopy (from, to, size)
const char *from;
char *to;
int size;
{
int i;
for (i = 0; i < size; i++)
to[i] = from[i];
}
#endif /* GNU C 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 nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
char **temp = (char **) __alloca (nonopts_size);
/* Interchange the two blocks of data in ARGV. */
my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
(optind - last_nonopt) * sizeof (char *));
my_bcopy ((char *) temp,
(char *) &argv[first_nonopt + optind - last_nonopt],
nonopts_size);
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* 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;
{
int option_index;
optarg = 0;
/* Initialize the internal data when the first call is made.
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. */
if (optind == 0)
{
first_nonopt = last_nonopt = optind = 1;
nextchar = NULL;
/* 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 (getenv ("POSIXLY_CORRECT") != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
}
if (nextchar == NULL || *nextchar == '\0')
{
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;
/* Now skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
optind++;
last_nonopt = optind;
}
/* 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')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Start decoding its characters. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
if (longopts != NULL
&& ((argv[optind][0] == '-'
&& (argv[optind][1] == '-' || long_only))
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
))
{
const struct option *p;
char *s = nextchar;
int exact = 0;
int ambig = 0;
const struct option *pfound = NULL;
int indfound;
while (*s && *s != '=')
s++;
/* Test all options for either exact match or abbreviated matches. */
for (p = longopts, option_index = 0; p->name;
p++, option_index++)
if (!strncmp (p->name, nextchar, s - nextchar))
{
if (s - 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 nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous\n",
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*s)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = s + 1;
else
{
if (opterr)
{
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
"%s: option `--%s' doesn't allow an argument\n",
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
"%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, "%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] == '-'
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, "%s: unrecognized option `--%s'\n",
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
return '?';
}
}
/* Look at and handle the next 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 0
if (c < 040 || c >= 0177)
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
argv[0], c);
else
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
#else
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
#endif
}
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 = 0;
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)
{
#if 0
fprintf (stderr, "%s: option `-%c' requires an argument\n",
argv[0], c);
#else
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: option requires an argument -- %c\n",
argv[0], c);
#endif
}
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 */

View File

@ -0,0 +1,129 @@
/* Declarations for getopt.
Copyright (C) 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, 675 Mass Ave, Cambridge, MA 02139, 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 __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 __STDC__
#if defined(__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 /* not __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 /* not __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H */

View File

@ -0,0 +1,176 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987, 88, 89, 90, 91, 92, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "getopt.h"
#if !__STDC__ && !defined(const) && IN_GCC
#define const
#endif
#include <stdio.h>
/* 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 <stdlib.h>
#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 <stdio.h>
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 */

View File

@ -0,0 +1,667 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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 = savestring (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 = savestring (file_buffer->filename);
initial_index_nodename = savestring (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 = savestring (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 = savestring (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 = savestring (dir_node->parent);
else
this_item->filename = savestring (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 = savestring (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);
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 ();
}

View File

@ -0,0 +1,39 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,653 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include <stdio.h> /* For "NULL". Yechhh! */
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "info-utils.h"
/* 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;
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 = (stricmp (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 = savestring (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 = savestring (info_parsed_filename);
if (info_parsed_nodename)
entry->nodename = savestring (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;
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 *)rindex (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 (node &&
(node->filename && !*node->filename) &&
!node->parent && node->nodename)
return (1);
else
return (0);
}
/* 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 = (WINDOW *)NULL;
for (win = windows; win; win = win->next)
if (internal_info_node_p (win->node) &&
(strcmp (win->node->nodename, name) == 0))
break;
return (win);
}

View File

@ -0,0 +1,144 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _INFO_UTILS_H_
#define _INFO_UTILS_H_
#if !defined (HAVE_RINDEX)
#undef index
#undef rindex
#define index strchr
#define rindex strrchr
#endif
#if !defined (HAVE_BCOPY)
#undef bcopy
#define bcopy(source, dest, count) memcpy(dest, source, count)
#endif
#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_ */

View File

@ -0,0 +1,229 @@
.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 INFOPATHS
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

View File

@ -0,0 +1,511 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include "info.h"
#include "dribble.h"
#include "getopt.h"
/* The version numbers of this version of Info. */
int info_major_version = 2;
int info_minor_version = 10;
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. */
#if defined (NeXT) && defined (NOTDEF)
malloc_debug (0x0ffffffff);
#endif /* NeXT && NOTDEF */
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 = savestring (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 = savestring (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 = savestring (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 user specified --version, then show the version and exit. */
if (print_version_p)
{
printf ("GNU Info, Version %s.\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);
else
info_add_path (DEFAULT_INFOPATH);
}
/* 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 = savestring (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;
/* Remember the name of the menu entry we want. */
arg = argv[optind++];
/* 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)
{
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;
for (i = 0; entry = menu[i]; i++)
if (strnicmp (entry->label, arg, strlen (arg)) == 0)
break;
}
/* 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.";
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 = savestring (initial_node->parent);
else
entry->filename = savestring (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 (!node && entry->nodename &&
(strcmp (entry->label, entry->nodename) == 0))
node = info_get_node (entry->label, "Top");
if (node)
{
free (initial_node);
initial_node = node;
info_free_references (menu);
}
else
{
char *temp = savestring (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 = savestring (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);
}

View File

@ -0,0 +1,96 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _INFO_H_
#define _INFO_H_
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.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.9". */
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_ */

View File

@ -0,0 +1,777 @@
This is Info file info.info, produced by Makeinfo-1.55 from the input
file info.texi.
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.
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.

File: info.info, Node: Top, Next: Getting Started, Prev: (dir), Up: (dir)
Info: An Introduction
*********************
Info is a program for reading documentation, which you are using now.
To learn how to use Info, type the command `h'. It brings you to a
programmed instruction sequence.
To learn advanced Info commands, type `n' twice. This brings you to
`Info for Experts', skipping over the . `Getting Started' chapter.
* Menu:
* Getting Started::
* Advanced Info::
* Create an Info File::

File: info.info, Node: Getting Started, Next: Advanced Info, Prev: Top, Up: Top
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.
* 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

File: info.info, Node: Help-Small-Screen, Next: Help, Up: Getting Started
Starting Info on a Small Screen
===============================
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 `--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 `--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, SPC. To move back up, press
the key labeled `Rubout' or `Delete' or DEL.
Here are 40 lines of junk, so you can try SPC and DEL 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 DEL, and
come back here again, then you understand SPC and DEL. So now type an
`n'--just one character; do not type the quotes and do not type the
Return key, RET, afterward--to get to the normal start of the course.

File: info.info, Node: Help, Next: Help-P, Prev: Help-Small-Screen, Up: Getting Started
How to use Info
===============
You are talking to the program Info, for reading documentation.
Right now you are looking at one "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 "header". This node's header (look at
it now) says that it is the node named `Help' in the file `info'. It
says that the `Next' node after this one is the node called `Help-P'.
An advanced Info command lets you go to any node whose name you know.
Besides a `Next', a node can have a `Previous' or an `Up'. This
node has a `Previous' but no `Up', as you can see.
Now it is time to move on to the `Next' node, named `Help-P'.
>> Type `n' to move there. Type just one character; do not type
the quotes and do not type a RET afterward.
`>>' in the margin means it is really time to try a command.

File: info.info, Node: Help-P, Next: Help-^L, Prev: Help, Up: Getting Started
Returning to the Previous node
==============================
This node is called `Help-P'. The `Previous' node, as you see, is
`Help', which is the one you just came from using the `n' command.
Another `n' command now would take you to the next node, `Help-^L'.
>> But do not do that yet. First, try the `p' command, which takes
you to the `Previous' node. When you get there, you can do an `n'
again to return here.
This all probably seems insultingly simple so far, but *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 `n' to get to the node `Help-^L' and learn more.

File: info.info, Node: Help-^L, Next: Help-M, Prev: Help-P, Up: Getting Started
The Space, Rubout, B and ^L commands.
=====================================
This node's header tells you that you are now at node `Help-^L', and
that `p' would get you back to `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 `--Top-----' rather than `--All----' near the bottom right
corner of the screen.
The SPC, DEL and `b' commands exist to allow you to "move around" in
a node that does not all fit on the screen at once. SPC moves forward,
to show what was below the bottom of the screen. DEL 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 SPC (afterward, type a DEL to return here).
When you type the SPC, the two lines that were at the bottom of the
screen appear at the top, followed by more lines. DEL takes the two
lines from the top and moves them to the bottom, *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 a SPC when there is no more to see, it rings the bell
and otherwise does nothing. The same goes for a DEL 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 `C-l' (`Control-L', that is--hold down "Control" and
type an L or `l').
>> Type `C-l' now.
To move back to the beginning of the node you are on, you can type a
lot of DELs. You can also type simply `b' for beginning.
>> Try that now. (I have put in enough verbiage to make sure you are
not on the first screenful now). Then come back, typing SPC
several times.
You have just learned a considerable number of commands. If you
want to use one but have trouble remembering which, you should type a ?
which prints out a brief list of commands. When you are finished
looking at the list, make it go away by typing a SPC.
>> Type a ? now. After it finishes, type a 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 SPC and DEL 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 `n' to see the description of the `m' command.

File: info.info, Node: Help-M, Next: Help-Adv, Prev: Help-^L, Up: Getting Started
Menus
=====
Menus and the `m' command
With only the `n' and `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 `* 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 `*'
identifies one subtopic. The line usually contains a brief name for
the subtopic (followed by a `:'), 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 `*' have no special
meaning--they are only for the human reader's benefit and do not define
additional subtopics. Here is an example:
* Foo: FOO's Node This tells about FOO
The subtopic name is Foo, and the node describing it is `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 `* 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:
* Foo:: This tells about FOO
This means that the subtopic name and node name are the same; they are
both `Foo'.
>> Now use SPCs to find the menu in this node, then come back to
the front with a `b'. 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 `m' command is not available.
The command to go to one of the subnodes is `m'--but *do not do it
yet!* Before you use `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 `m' command is different: it
is incomplete without the "name of the subtopic". Once you have typed
`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 `n' or `b'
or SPC or `m'. If that line contains text ending in a colon, it mean
Info is trying to read the "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 `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 `m'. After you type
the `m', the line at the bottom of the screen says `Menu item: '. You
must then type the name of the subtopic you want, and end it with a 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.
Here is a menu to give you a chance to practice.
* Menu: The menu starts here.
This menu givs 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 `m' and see what happens:
Now you are "inside" an `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 `m' by typing Control-g.
>> Try that now; notice the bottom line clear.
>> Then type another `m'.
>> Now type `BAR' item name. Do not type RET yet.
While you are typing the item name, you can use the DEL character to
cancel one character at a time if you make a mistake.
>> Type one to cancel the `R'. You could type another `R' to
replace it. You do not have to, since `BA' is a valid abbreviation.
>> Now you are ready to go. Type a RET.
After visiting Help-FOO, you should return here.
>> Type `n' to see more commands.
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::

File: info.info, Node: Help-FOO, Up: Help-M
The `u' command
---------------
Congratulations! This is the node `Help-FOO'. Unlike the other
nodes you have seen, this one has an `Up': `Help-M', the node you just
came from via the `m' command. This is the usual convention--the nodes
you reach from a menu have `Up' nodes that lead back to the menu.
Menus move Down in the tree, and `Up' moves Up. `Previous', on the
other hand, is usually used to "stay on the same level but go backwards"
You can go back to the node `Help-M' by typing the command `u' for
"Up". That puts you at the *front* of the node--to get back to where
you were reading you have to type some SPCs.
>> Now type `u' to move back up to `Help-M'.

File: info.info, Node: Help-Adv, Next: Help-Q, Prev: Help-M, Up: Getting Started
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 `l' command (`l' for "last") will do that, one
node at a time. If you have been following directions, an `l' command
now will get you back to `Help-M'. Another `l' command would undo the
`u' and get you back to `Help-FOO'. Another `l' would undo the `m' and
get you back to `Help-M'.
>> Try typing three `l''s, pausing in between to see what each
`l' does.
Then follow directions again and you will end up back here.
Note the difference between `l' and `p': `l' moves to where *you*
last were, whereas `p' always moves to the node which the header says
is the `Previous' node (from this node, to `Help-M').
The `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 `d', then do an `l' to return here (yes, *do*
return).
Sometimes, in Info documentation, you will see a cross reference.
Cross references look like this: *Note Cross: Help-Cross. That is a
real, live cross reference which is named `Cross' and points at the
node named `Help-Cross'.
If you wish to follow a cross reference, you must use the `f'
command. The `f' must be followed by the cross reference name (in this
case, `Cross'). You can use DEL to edit the name, and if you change
your mind about following any reference you can use `Control-g' to
cancel the command.
Completion is available in the `f' command; you can complete among
all the cross reference names in the current node.
>> Type `f', followed by `Cross', and a RET.
To get a list of all the cross references in the current node, you
can type `?' after an `f'. The `f' continues to await a cross
reference name even after printing the list, so if you do not actually
want to follow a reference you should type a `Control-g' to cancel the
`f'.
>> Type "f?" to get a list of the footnotes in this node. Then type
a `Control-g' and see how the `f' gives up.
>> Now type `n' to see the last node of the course.

File: info.info, Node: Help-Cross, Up: Help-Adv
The node reached by the cross reference in Info
-----------------------------------------------
This is the node reached by the cross reference named `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 `Next', `Previous' or `Up' pointing back to where
you came from. In general, the `l' (el) command is the only way to get
back there.
>> Type `l' to return to the node where the cross reference was.

File: info.info, Node: Help-Q, Prev: Help-Adv, Up: Getting Started
Quitting Info
=============
To get out of Info, back to what you were doing before, type `q' for
"Quit".
This is the end of the course on using Info. There are some other
commands that are not essential or are meant for experienced users;
they are useful, and you can find them by looking in the directory for
documentation on Info. Finding them will be a good exercise in using
Info in the usual manner.
>> Type `d' to go to the Info directory node; then type `mInfo'
and RET, to get to the node about Info and see what other help is
available.

File: info.info, Node: Advanced Info, Next: Create an Info File, Prev: Getting Started, Up: Top
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 *both* to
generate an Info file and to make a printed manual. *Note Overview of
Texinfo: (texinfo)Top.)
* 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

File: info.info, Node: Expert, Next: Add, Up: Advanced Info
Advanced Info Commands
======================
`g', `s', `1', - `5', and `e'
If you know a node's name, you can go there by typing `g', the name,
and RET. Thus, `gTopRET' would go to the node called `Top' in this
file (its directory node). `gExpertRET' would come back here.
Unlike `m', `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,
`g(dir)TopRET' would go to the Info Directory node, which is node `Top'
in the file `dir'.
The node name `*' specifies the whole file. So you can look at all
of the current file by typing `g*RET' or all of any other file with
`g(FILENAME)RET'.
The `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 `s'
followed by the string to search for, terminated by RET. To search for
the same string again, just `s' followed by 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 `next' pointers. But normally the two orders
are not very different. In any case, you can always do a `b' to find
out what node you have reached, if the header is not visible (this can
happen, because `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 `1', `2', `3', `4', and `5'. They are
short for the `m' command together with an argument. "1", "2", "3",
"4", and "5". `1' goes through the first item in the current node's
menu; `2' goes through the second item, etc. Note that numbers larger
than 5 are not allowed. If the item you want is that far down, you are
better off using an abbreviation for its name than counting.
The Info command `e' changes from Info mode to an ordinary Emacs
editing mode, so that you can edit the text of the current node. Type
`C-c C-c' to switch back to Info. The `e' command is allowed only if
the variable `Info-enable-edit' is non-`nil'.

File: info.info, Node: Add, Next: Menus, Prev: Expert, Up: Advanced Info
Adding a new node to Info
=========================
To add a new topic to the list in the directory, you must:
1. Create a node, in some file, to document that topic.
2. Put that topic in the menu in the directory. *Note Menu: Menus.
The new node can live in an existing documentation file, or in a new
one. It must have a ^_ character before it (invisible to the user;
this node has one but you cannot see it), and it ends with either a ^_,
a ^L, or the end of file. Note: If you put in a ^L to end a new node,
be sure that there is a ^_ after it to start the next one, since ^L
cannot *start* a node. Also, a nicer way to make a node boundary be a
page boundary as well is to put a ^L *right after* the ^_.
The ^_ starting a node must be followed by a newline or a ^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 `Next', `Previous', and `Up' nodes (if there are any). As you
can see, this node's `Up' node is the node `Top', which points at all
the documentation for Info. The `Next' node is `Menus'.
The keywords "Node", "Previous", "Up" and "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 `Node: ' in that node's first line. For
example, this node's name is `Add'. A node in another file is named by
`(FILENAME)NODE-WITHIN-FILE', as in `(info)Add' for this node. If the
file name is relative, it is taken starting from the standard Info file
directory of your site. The name `(FILENAME)Top' can be abbreviated to
just `(FILENAME)'. By convention, the name `Top' is used for the
"highest" node in any single file--the node whose `Up' points out of
the file. The Directory node is `(dir)'. The `Top' node of a document
file listed in the Directory should have an `Up: (dir)' in it.
The node name `*' is special: it refers to the entire file. Thus,
`g*' shows you the whole current file. The use of the node `*' is to
make it possible to make old-fashioned, unstructured files into nodes
of the tree.
The `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 `Next', `Previous' and `Up' names may
contain them. In this node, since the `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.

File: info.info, Node: Menus, Next: Cross-refs, Prev: Add, Up: Advanced Info
How to Create Menus
===================
Any node in the Info hierarchy may have a "menu"--a list of subnodes.
The `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 `* Menu:'. The rest of the
line is a comment. After the starting line, every line that begins
with a `* ' lists a single topic. The name of the topic-the argument
that the user must give to the `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 `Next', `Previous' and `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, than rather than
giving the name twice, the abbreviation `* 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 `Up:' pointing at the
superior. It is often useful to arrange all or most of the subnodes in
a sequence of `Next' and `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 `(dir)Top'--that
is, node `Top' in file `.../info/dir'. You can put new entries in that
menu just like any other menu. The Info Directory is *not* the same as
the file directory called `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 *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
`Top'; the other contains the node `Help' which the `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.

File: info.info, Node: Cross-refs, Next: Tags, Prev: Menus, Up: Advanced Info
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 `*note' instead of `*'. It
*cannot* be terminated by a `)', because `)''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:
*Note details: commands. (See *note 3: Full Proof.)
They are just examples. The places they "lead to" do not really
exist!

File: info.info, Node: Tags, Next: Checking, Prev: Cross-refs, Up: Advanced Info
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 `M-x Info-tagify'. Then you must use `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 `Info-tagify' command again.
An Info file tag table appears at the end of the file and looks like
this:
^_
Tag Table:
File: info, Node: Cross-refs^?21419
File: info, Node: Tags^?22145
^_
End Tag Table
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 DEL
character, and the character position in the file of the beginning of
the node.

File: info.info, Node: Checking, Prev: Tags, Up: Advanced Info
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 `Next', `Previous', and `Up' is
checked, as is every menu item and every cross reference. In addition,
any `Next' which does not have a `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 `M-x Info-validate' while looking at any
node of the file with Emacs Info mode.

File: info.info, Node: Create an Info File, Prev: Advanced Info, Up: Top
Creating an Info File from a Makeinfo file
******************************************
`makeinfo' is a utility that converts a Texinfo file into an Info
file; `texinfo-format-region' and `texinfo-format-buffer' are GNU Emacs
functions that do the same.
*Note Creating an Info File: (texinfo)Create an Info File, to learn
how to create an Info file from a Texinfo file.
*Note Overview of Texinfo: (texinfo)Top, to learn how to write a
Texinfo file.

Tag Table:
Node: Top913
Node: Getting Started1431
Node: Help-Small-Screen2179
Node: Help3921
Node: Help-P4949
Node: Help-^L5811
Node: Help-M8462
Node: Help-FOO14030
Node: Help-Adv14766
Node: Help-Cross17148
Node: Help-Q17794
Node: Advanced Info18434
Node: Expert19330
Node: Add21601
Node: Menus24635
Node: Cross-refs27509
Node: Tags28211
Node: Checking29510
Node: Create an Info File30434

End Tag Table

View File

@ -0,0 +1,689 @@
/* infohelp.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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include "info.h"
/* **************************************************************** */
/* */
/* 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;
/* 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
};
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;
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);
{
char *message;
message = replace_in_documentation
("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n");
printf_to_message_buffer ("%s", message);
}
internal_info_help_node = message_buffer_to_node ();
add_gcable_pointer (internal_info_help_node->contents);
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;
help_window = get_internal_info_window (info_help_nodename);
/* If we couldn't find the help window, then make it. */
if (!help_window)
{
WINDOW *window, *eligible = (WINDOW *)NULL;
int max = 0;
for (window = windows; window; window = window->next)
{
if (window->height > max)
{
max = window->height;
eligible = window;
}
}
if (!eligible)
return ((WINDOW *)NULL);
else
{
/* Make a new node containing the help text. Split the largest
window into 2 windows, and show the help text in that window. */
if (!internal_info_help_node)
create_internal_info_help_node ();
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;
}
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 &&
(stricmp
(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. */
static char *where_is (), *where_is_internal ();
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);
}

View File

@ -0,0 +1,269 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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;
}

View File

@ -0,0 +1,82 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

View File

@ -0,0 +1,195 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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 = savestring (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);
}

View File

@ -0,0 +1,321 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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 (savestring (line_buffer));
}
/* Little string comparison routine for qsort (). */
static int
compare_strings (string1, string2)
char **string1, **string2;
{
return (stricmp (*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. */
qsort (lines, lines_index, sizeof (char *), compare_strings);
/* Delete duplicates. */
{
register int j, newlen;
char **temp;
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
("Here is a menu of nodes you could select with info-history-node:\n");
printf_to_message_buffer ("%s\n", nodemenu_format_info ());
for (i = 0; i < lines_index; i++)
{
printf_to_message_buffer ("%s\n", lines[i]);
free (lines[i]);
}
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 ();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,164 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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. */
/* **************************************************************** */
/* */
/* 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;
#endif /* !_NODES_H_ */

View File

@ -0,0 +1,566 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#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 = savestring (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 = savestring (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;
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);
}
/* Unix doesn't have stricmp () functions. */
int
stricmp (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
strnicmp (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);
}
/* **************************************************************** */
/* */
/* 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);
}

View File

@ -0,0 +1,78 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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. */
#ifndef _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 ();
/* Unix doesn't have stricmp () functions. */
/* strcmp (), but caseless. */
extern int stricmp ();
/* Compare at most COUNT characters from STRING1 to STRING2. Case
doesn't matter. */
extern int strnicmp ();
/* 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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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 `builddoc', 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_ */

View File

@ -0,0 +1,177 @@
/* 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 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.
Written by Brian Fox (bfox@ai.mit.edu). */
#include "info.h"
#include "signals.h"
/* **************************************************************** */
/* */
/* Pretending That We Have POSIX Signals */
/* */
/* **************************************************************** */
#if !defined (_POSIX_VERSION)
/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
static void
sigprocmask (operation, newset, oldset)
int operation, *newset, *oldset;
{
switch (operation)
{
case SIG_UNBLOCK:
#if defined (HAVE_SIGSETMASK)
sigsetmask (sigblock (0) & ~(*newset));
#endif /* HAVE_SIGSETMASK */
break;
case SIG_BLOCK:
*oldset = sigblock (*newset);
break;
case SIG_SETMASK:
#if defined (HAVE_SIGSETMASK)
sigsetmask (*newset);
#endif /* HAVE_SIGSETMASK */
break;
default:
abort ();
}
}
#endif /* !_POSIX_VERSION */
/* **************************************************************** */
/* */
/* 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 */
}
}

View File

@ -0,0 +1,85 @@
/* 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 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.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _SIGNALS_H_
#define _SIGNALS_H_
#include <signal.h>
#define HAVE_SIGSETMASK
#if !defined (_POSIX_VERSION) && !defined (sigmask)
# define sigmask(x) (1 << ((x)-1))
#endif /* !POSIX && !sigmask */
#if !defined (_POSIX_VERSION)
# 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 /* !_POSIX_VERSION */
/* 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)
#endif /* !_SIGNALS_H_ */

View File

@ -0,0 +1,64 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#if defined (HAVE_SYS_FCNTL_H)
#include <sys/fcntl.h>
#else
#include <fcntl.h>
#endif /* !HAVE_SYS_FCNTL_H */
#if defined (HAVE_TERMIO_H)
#include <termio.h>
#include <string.h>
#if defined (HAVE_SYS_PTEM_H)
#if !defined (M_XENIX)
#include <sys/stream.h>
#include <sys/ptem.h>
#undef TIOCGETC
#else /* M_XENIX */
#define tchars tc
#endif /* M_XENIX */
#endif /* HAVE_SYS_PTEM_H */
#else /* !HAVE_TERMIO_H */
#include <sys/file.h>
#include <sgtty.h>
#include <strings.h>
#endif /* !HAVE_TERMIO_H */
#if defined (HAVE_SYS_TTOLD_H)
#include <sys/ttold.h>
#endif /* HAVE_SYS_TTOLD_H */
#if !defined (HAVE_RINDEX)
#undef index
#undef rindex
#define index strchr
#define rindex strrchr
#endif
#if !defined (HAVE_BCOPY)
#undef bcopy
#define bcopy(source, dest, count) memcpy(dest, source, count)
#endif
/* eof */

View File

@ -0,0 +1,745 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include <stdio.h>
#include <sys/types.h>
#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 ();
}

View File

@ -0,0 +1,126 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

View File

@ -0,0 +1,379 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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 <alloca.h>
# endif /* HAVE_ALLOCA_H */
# endif /* !AIX */
#endif /* !__GNUC__ */
#include "tilde.h"
#include <pwd.h>
#if !defined (savestring)
#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
#endif /* !savestring */
#if !defined (NULL)
# define NULL 0x0
#endif
#if defined (TEST) || defined (STATIC_MALLOC)
static char *xmalloc (), *xrealloc ();
#else
extern char *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. */
Function *tilde_expansion_failure_hook = (Function *)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 ? savestring (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)
{
/* extern struct passwd *getpwuid (); */
struct passwd *entry;
entry = 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 = savestring (temp_name);
}
else
{
struct passwd *getpwnam (), *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 = 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 =
(char *)(*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 = savestring (temp_name);
}
endpwent ();
}
}
return (dirname);
}
#if defined (TEST)
#undef NULL
#include <stdio.h>
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 char *
xmalloc (bytes)
int bytes;
{
char *temp = (char *)malloc (bytes);
if (!temp)
memory_error_and_abort ();
return (temp);
}
static char *
xrealloc (pointer, bytes)
char *pointer;
int bytes;
{
char *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 ();
}
/*
* Local variables:
* compile-command: "gcc -g -DTEST -o tilde tilde.c"
* end:
*/
#endif /* TEST */

View File

@ -0,0 +1,62 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _TILDE_H_
#define _TILDE_H_
/* Function pointers can be declared as (Function *)foo. */
#if !defined (__FUNCTION_DEF)
# define __FUNCTION_DEF
typedef int Function ();
typedef void VFunction ();
#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 Function *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 ();
#endif

View File

@ -0,0 +1,272 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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 = savestring (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 = savestring (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);
}

View File

@ -0,0 +1,64 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,229 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#ifndef _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_ */

View File

@ -0,0 +1,78 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#if !defined (ALREADY_HAVE_XMALLOC)
#include <stdio.h>
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 = (void *)malloc (bytes);
if (!temp)
memory_error_and_abort ("xmalloc");
return (temp);
}
void *
xrealloc (pointer, bytes)
void *pointer;
int bytes;
{
void *temp;
if (!pointer)
temp = (void *)malloc (bytes);
else
temp = (void *)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 */

View File

@ -0,0 +1,20 @@
#
# Bmakefile for GNU info
#
# $id$
#
PROG= makedoc
SRCS+= makedoc.c xmalloc.c
CFLAGS+= -I${.CURDIR}/../info -I${.CURDIR}
CFLAGS+= -DNAMED_FUNCTIONS=1 -DSTDC_HEADERS=1
CFLAGS+= -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1
CFLAGS+= -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1
CFLAGS+= -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
CFLAGS+= -DHAVE_SYS_TIME_H=1 -DDEFAULT_INFOPATH='"${INFODIR}"'
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View File

@ -0,0 +1,477 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, 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 <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include "general.h"
#if !defined (O_RDONLY)
#if defined (HAVE_SYS_FCNTL_H)
#include <sys/fcntl.h>
#else /* !HAVE_SYS_FCNTL_H */
#include <fcntl.h>
#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 = savestring (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;
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);
buffer = (char *)xmalloc (1 + finfo.st_size);
read (descriptor, buffer, finfo.st_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 < (finfo.st_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 < finfo.st_size)
{
if (buffer[point] == '\n')
{
line_number++;
line_start = point + 1;
}
else if (buffer[point] == '(')
break;
point++;
}
while (point++ < finfo.st_size)
{
if (!whitespace_or_newline (buffer[point]))
break;
else if (buffer[point] == '\n')
{
line_number++;
line_start = point + 1;
}
}
if (point >= finfo.st_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 = savestring (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 < finfo.st_size)
{
if (buffer[point] == '\n')
{
line_number++;
line_start = point + 1;
}
if (buffer[point] == '"')
break;
else
point++;
}
offset = point + 1;
while (offset < finfo.st_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 >= finfo.st_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);
}

View File

@ -0,0 +1,78 @@
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#if !defined (ALREADY_HAVE_XMALLOC)
#include <stdio.h>
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 = (void *)malloc (bytes);
if (!temp)
memory_error_and_abort ("xmalloc");
return (temp);
}
void *
xrealloc (pointer, bytes)
void *pointer;
int bytes;
{
void *temp;
if (!pointer)
temp = (void *)malloc (bytes);
else
temp = (void *)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 */

View File

@ -0,0 +1,21 @@
#
# Bmakefile for GNU info
#
# $id$
#
PROG= makeinfo
SRCS+= makeinfo.c getopt1.c getopt.c
.PATH: ${.CURDIR}/../info
CFLAGS+= -I${.CURDIR}/../info -I${.CURDIR}
CFLAGS+= -DNAMED_FUNCTIONS=1 -DSTDC_HEADERS=1
CFLAGS+= -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1
CFLAGS+= -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1
CFLAGS+= -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
CFLAGS+= -DHAVE_SYS_TIME_H=1 -DDEFAULT_INFOPATH='"${INFODIR}"'
.include "../../Makefile.inc"
.include <bsd.prog.mk>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
# Generated automatically from Makefile.in by configure.
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#### Start of system configuration section. ####
srcdir = .
VPATH = $(srcdir):$(common)
common = $(srcdir)/../libtxi
CC = gcc
INSTALL = /usr/bin/install -c
INSTALL_PROGRAM = $(INSTALL)
INSTALL_DATA = $(INSTALL) -m 644
LN = ln
RM = rm -f
TAR = tar
MKDIR = mkdir
DEFS = -DSTDC_HEADERS=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1 -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
LIBS = -L../libtxi -ltxi
LOADLIBES = $(LIBS)
SHELL = /bin/sh
CFLAGS = -g
LDFLAGS = -g
prefix = /usr/local
exec_prefix = $(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:

View File

@ -0,0 +1,95 @@
# 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., 675 Mass Ave, Cambridge, MA 02139, 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 = -g
LDFLAGS = -g
prefix = /usr/local
exec_prefix = $(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:

View File

@ -0,0 +1,171 @@
This release of Info is version 2.8. Please read the file README.
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.

View File

@ -0,0 +1,54 @@
Please Emacs, use -*- text -*- mode when editing this file.
* The file RELEASE contains information about what has changed
since the last release.
* The file INSTALL contains instructions on how to install Info.
(Type "./configure" and then "make".)
This is the README file GNU Info version 2.8. This marks the first
non-beta release.
Thu Jan 21 14:50:52 1993
----------------------------------------
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
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.
So, please send your comments, bug reports, and suggestions to
bfox@ai.mit.edu
Thanks for beta testing this software.

View File

@ -0,0 +1,238 @@
/*
* 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 <stdio.h>
#include <ctype.h>
#include <errno.h>
/* 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;
}

View File

@ -0,0 +1,84 @@
#!/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

View File

@ -0,0 +1,35 @@
#!/bin/sh
# Make directory hierarchy.
# Written by Noah Friedman <friedman@prep.ai.mit.edu>
# Public domain.
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
errstatus=0
for file in ${1+"$@"} ; do
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${file} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
for d in ${1+"$@"} ; do
pathcomp="${pathcomp}${d}"
if test ! -d "${pathcomp}"; then
echo "mkdir $pathcomp" 1>&2
mkdir "${pathcomp}" || errstatus=$?
fi
pathcomp="${pathcomp}/"
done
done
exit $errstatus
# eof

View File

@ -0,0 +1,71 @@
#!/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

263
gnu/usr.bin/texinfo/misc/texi2dvi Executable file
View File

@ -0,0 +1,263 @@
#!/bin/sh
# texi2dvi -- smartly produce DVI files from texinfo sources
#
# Copyright (C) 1992, 1993 Free Software Foundation.
#
# 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:
#
# Free Software Foundation, Inc.
# 675 Mass Ave.
# Cambridge, MA 02139, USA.
#
# 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.
#
# Version 0.4
# Last modified 26-Mar-93
#
# Please note that 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 as
# portable as possible.
#
# Among the more interesting lossages I noticed with some bourne shells
# are:
# 1) Some don't have an `unset' builtin
# 2) In some implementations the `shift' builtin can't take a
# numerical argument.
progname=`basename $0`
usage="Usage: ${progname} {-D} {-h} [file1] {file2} {...}
{--debug} {--help}
Options in braces are optional. Those in brackets are required.
"
if test $# -eq 0 ; then
echo "${usage}" 1>&2;
exit 1
fi
backup_extension=".bak"
texindex="texindex"
tex="tex"
bq="\`" # To prevent hairy quoting and escaping later.
eq="'"
orig_pwd="`pwd`"
if test "z${TEXINDEX}" != "z" ; then
texindex="${TEXINDEX}"
fi
if test "z${TEX}" != "z" ; then
tex="${TEX}"
fi
# Save this so we can construct a new TEXINPUTS path for each file to be
# processed.
TEXINPUTS_orig="${TEXINPUTS}"
export TEXINPUTS
# Parse command line options
# "unset" option variables to make sure they weren't accidentally
# exported
debug=""
# If you add new commands be sure to change the wildcards below to make
# sure they are unambiguous (i.e. only match one possible long option)
# Be sure to show at least one instance of the full long option name to
# document what the long option is canonically called.
while test $# -gt 0 ; do
case z$1 in
z-D | z--debug | z--d* )
debug="t"
shift
;;
z-h | z--help | z--h* )
echo "${usage}" 1>&2
exit 1
;;
z-- )
shift
break
;;
z-* )
echo "${progname}: ${bq}${1}${eq} is not a valid option." 1>&2
echo "" 1>&2
echo "${usage}" 1>&2
exit 1
;;
* )
break
;;
esac
done
# See if there are any command line args left (which will be interpreted as
# filename arguments)
if test $# -eq 0 ; then
echo "${progname}: at least one file name is required as an argument." 1>&2
echo "" 1>&2
echo "${usage}" 1>&2
exit 1
fi
test "z${debug}" = "zt" && set -x
# 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
#
# eof
#

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
#
# Bmakefile for GNU info
#
# $id$
#
PROG= texindex
SRCS+= texindex.c getopt1.c getopt.c
.PATH: ${.CURDIR}/../info
CFLAGS+= -I${.CURDIR}/../info -I${.CURDIR}
CFLAGS+= -DNAMED_FUNCTIONS=1 -DSTDC_HEADERS=1
CFLAGS+= -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_VARARGS_H=1
CFLAGS+= -DHAVE_SYS_FCNTL_H=1 -DHAVE_SETVBUF=1 -DHAVE_GETCWD=1 -DHAVE_BZERO=1
CFLAGS+= -DHAVE_RINDEX=1 -DHAVE_VFPRINTF=1 -DHAVE_VSPRINTF=1
CFLAGS+= -DHAVE_SYS_TIME_H=1 -DDEFAULT_INFOPATH='"${INFODIR}"'
.include "../../Makefile.inc"
.include <bsd.prog.mk>

File diff suppressed because it is too large Load Diff