NetBSD/gnu/dist/texinfo/info/dir.c
wiz ccaa2ac97b Import of texinfo-4.7, as prepared by texinfo2netbsd.
Changes since 4.6:

4.7 (9 April 2004)
* Language:
  . new commands @float, @caption, @shortcaption, @listoffloats for
    initial implementation of floating material (figures, tables, etc).
    Ironically, they do not yet actually float anywhere.
  . new commands @docbook, @ifdocbook, @ifnotdocbook for conditional Docbook.
  . new commands @ordf{} and @ordm{} for Spanish feminine/masculine ordinals.
  . new commands @deftypecv[x] for class variables in typed OO languages.
  . new command @registeredsymbol for the r-in-a-circle symbol.
  . new command @headitem to make a heading row in @multitable.
  . new command @LaTeX{} for the LaTeX logo.
  . new command @comma{} to avoid comma-parsing problems.
  . @url is now a synonym for @uref; new command @indicateurl has the
    old meaning of just displaying a url as text.
  . @quotation now accepts an optional argument for labelling the text
      as a `Note', `Tip', etc.
  . @defun (et al.) heading lines can now be continued with a lone @.
  . @acronym accepts an optional argument for the meaning of the acronym.
* makeinfo:
  . New environment variable TEXINFO_OUTPUT_FORMAT determines the output
    format at runtime, if no options are specified.
  . New option --plaintext, equivalent to --no-headers with Info output.
  . All outputs:
    - sections are numbered by default.
  . Info output:
    - punctuation is inserted after @pxref and @ref, if needed to make
      cross-references valid.
    - line numbers included in index menus, so Info readers can go to
      the exact line of an entry, not just a node.  Also in plaintext output.
    - ^@^H[index^@^H] cookie included in index menus, so Info readers
      can handle the ] etc. commands better.
  . HTML output:
    - new algorithm for cross-references to other manuals, for maximum
      portability and stability.
    - include node name in <title> with split output.
    - @multicolumn fractions become percentages.
    - entities used for bullets, quotes, dashes, and others.
    - index entries are links to the exact locations.
    - <h4> and <h5> used for @sub and @subsubsections again.
    - accented dotless i supported.
  . XML output: many new tags and structure to preserve more source features.
  . Docbook output:
    - upgraded DTD to Docbook XML 4.2, no longer using Docbook SGML.
    - improved translation in general, for instance:
    - line annotations and marked quotations.
* texi2dvi:
  . if available, use etex (pdfetex if --pdf) by default.
  . if the input file includes thumbpdf.sty (for LaTeX), then run thumbpdf.
  . more output if --debug.
* texinfo.tex:
  . @defun names are now printed in typewriter (instead of bold), and
    within the arguments, @var text is printed in slanted typewriter.
  . @tex code is executed inside a TeX group, so that any changes must
    be prefixed with \global (or the equivalent) to be effective.  (This
    change was actually made years ago, but never made it into the NEWS.)
* info:
  . new option --where (aka --location, -w) to report where an Info file
    would be found, instead of reading it.
  . by default, output ANSI terminal escape sequences as-is; new option
    --no-raw-escapes overrides this.
  . use the newly-generated index line numbers.
* Distribution:
  . new script gendocs.sh (not installed), for use by GNU maintainers in
    getting their manuals on the GNU web site.  Documented in
    maintain.texi (http://www.gnu.org/prep/maintain_toc.html).
  . Most code uses ANSI C prototypes, to some extent.
  . New translation: nb.
  . automake 1.8.3, autoconf 2.59, gettext 0.14.1.
2004-07-12 23:26:33 +00:00

293 lines
9.1 KiB
C

/* $NetBSD: dir.c,v 1.1.1.4 2004/07/12 23:26:56 wiz Exp $ */
/* dir.c -- how to build a special "dir" node from "localdir" files.
Id: dir.c,v 1.3 2004/03/14 00:57:29 karl Exp
Copyright (C) 1993, 1997, 1998, 2004 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Written by Brian Fox (bfox@ai.mit.edu). */
#include "info.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 named in the array
dirs_to_add which are found in INFOPATH. */
static void add_menu_to_file_buffer (char *contents, long int size,
FILE_BUFFER *fb);
static void insert_text_into_fb_at_binding (FILE_BUFFER *fb,
SEARCH_BINDING *binding, char *text, int textlen);
void maybe_build_dir_node (char *dirname);
static char *dirs_to_add[] = {
"dir", "localdir", (char *)NULL
};
/* Return zero if the file represented in the stat structure TEST has
already been seen, nonzero else. */
typedef struct
{
unsigned long device;
unsigned long inode;
} dir_file_list_entry_type;
static int
new_dir_file_p (struct stat *test)
{
static unsigned dir_file_list_len = 0;
static dir_file_list_entry_type *dir_file_list = NULL;
unsigned i;
for (i = 0; i < dir_file_list_len; i++)
{
dir_file_list_entry_type entry;
entry = dir_file_list[i];
if (entry.device == test->st_dev && entry.inode == test->st_ino)
return 0;
}
dir_file_list_len++;
dir_file_list = xrealloc (dir_file_list,
dir_file_list_len * sizeof (dir_file_list_entry_type));
dir_file_list[dir_file_list_len - 1].device = test->st_dev;
dir_file_list[dir_file_list_len - 1].inode = test->st_ino;
return 1;
}
void
maybe_build_dir_node (char *dirname)
{
int path_index, update_tags;
char *this_dir;
FILE_BUFFER *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;
/* Initialize the list we use to avoid reading the same dir file twice
with the dir file just found. */
new_dir_file_p (&dir_buffer->finfo);
path_index = update_tags = 0;
/* Using each element of the path, check for one of the files in
DIRS_TO_ADD. Do not check for "localdir.info.Z" or anything else.
Only files explictly named are eligible. This is a design decision.
There can be an info file name "localdir.info" which contains
information on the setting up of "localdir" files. */
while ((this_dir = extract_colon_unit (infopath, &path_index)))
{
register int da_index;
char *from_file;
/* Expand a leading tilde if one is present. */
if (*this_dir == '~')
{
char *tilde_expanded_dirname;
tilde_expanded_dirname = tilde_expand_word (this_dir);
if (tilde_expanded_dirname != this_dir)
{
free (this_dir);
this_dir = tilde_expanded_dirname;
}
}
/* For every different file named in DIRS_TO_ADD found in the
search path, add that file's menu to our "dir" node. */
for (da_index = 0; (from_file = dirs_to_add[da_index]); da_index++)
{
struct stat finfo;
int statable;
int namelen = strlen (from_file);
char *fullpath = xmalloc (3 + strlen (this_dir) + namelen);
strcpy (fullpath, this_dir);
if (!IS_SLASH (fullpath[strlen (fullpath) - 1]))
strcat (fullpath, "/");
strcat (fullpath, from_file);
statable = (stat (fullpath, &finfo) == 0);
/* Only add this file if we have not seen it before. */
if (statable && S_ISREG (finfo.st_mode) && new_dir_file_p (&finfo))
{
long filesize;
int compressed;
char *contents = filesys_read_info_file (fullpath, &filesize,
&finfo, &compressed);
if (contents)
{
update_tags++;
add_menu_to_file_buffer (contents, filesize, dir_buffer);
free (contents);
}
}
free (fullpath);
}
free (this_dir);
}
if (update_tags)
build_tags_and_nodes (dir_buffer);
/* Flag that the dir buffer has been built. */
dir_buffer->flags |= N_CannotGC;
}
/* Given CONTENTS and FB (a file buffer), add the menu found in CONTENTS
to the menu found in FB->contents. Second argument SIZE is the total
size of CONTENTS. */
static void
add_menu_to_file_buffer (char *contents, long int size, FILE_BUFFER *fb)
{
SEARCH_BINDING contents_binding, fb_binding;
long contents_offset, fb_offset;
contents_binding.buffer = contents;
contents_binding.start = 0;
contents_binding.end = size;
contents_binding.flags = S_FoldCase | S_SkipDest;
fb_binding.buffer = fb->contents;
fb_binding.start = 0;
fb_binding.end = fb->filesize;
fb_binding.flags = S_FoldCase | S_SkipDest;
/* Move to the start of the menus in CONTENTS and FB. */
contents_offset = search_forward (INFO_MENU_LABEL, &contents_binding);
fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
/* If there is no menu in CONTENTS, quit now. */
if (contents_offset == -1)
return;
/* There is a menu in CONTENTS, and contents_offset points to the first
character following the menu starter string. Skip all whitespace
and newline characters. */
contents_offset += skip_whitespace_and_newlines (contents + contents_offset);
/* If there is no menu in FB, make one. */
if (fb_offset == -1)
{
/* Find the start of the second node in this file buffer. If there
is only one node, we will be adding the contents to the end of
this node. */
fb_offset = find_node_separator (&fb_binding);
/* If not even a single node separator, give up. */
if (fb_offset == -1)
return;
fb_binding.start = fb_offset;
fb_binding.start +=
skip_node_separator (fb_binding.buffer + fb_binding.start);
/* Try to find the next node separator. */
fb_offset = find_node_separator (&fb_binding);
/* If found one, consider that the start of the menu. Otherwise, the
start of this menu is the end of the file buffer (i.e., fb->size). */
if (fb_offset != -1)
fb_binding.start = fb_offset;
else
fb_binding.start = fb_binding.end;
insert_text_into_fb_at_binding
(fb, &fb_binding, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL));
fb_binding.buffer = fb->contents;
fb_binding.start = 0;
fb_binding.end = fb->filesize;
fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
if (fb_offset == -1)
abort ();
}
/* CONTENTS_OFFSET and FB_OFFSET point to the starts of the menus that
appear in their respective buffers. Add the remainder of CONTENTS
to the end of FB's menu. */
fb_binding.start = fb_offset;
fb_offset = find_node_separator (&fb_binding);
if (fb_offset != -1)
fb_binding.start = fb_offset;
else
fb_binding.start = fb_binding.end;
/* Leave exactly one blank line between directory entries. */
{
int num_found = 0;
while ((fb_binding.start > 0) &&
(whitespace_or_newline (fb_binding.buffer[fb_binding.start - 1])))
{
num_found++;
fb_binding.start--;
}
/* Optimize if possible. */
if (num_found >= 2)
{
fb_binding.buffer[fb_binding.start++] = '\n';
fb_binding.buffer[fb_binding.start++] = '\n';
}
else
{
/* Do it the hard way. */
insert_text_into_fb_at_binding (fb, &fb_binding, "\n\n", 2);
fb_binding.start += 2;
}
}
/* Insert the new menu. */
insert_text_into_fb_at_binding
(fb, &fb_binding, contents + contents_offset, size - contents_offset);
}
static void
insert_text_into_fb_at_binding (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;
}