diff options
author | ru <ru@FreeBSD.org> | 2000-01-17 10:39:58 +0000 |
---|---|---|
committer | ru <ru@FreeBSD.org> | 2000-01-17 10:39:58 +0000 |
commit | 05f7b4b96773cc26ff78d5e68babd66861aa07a8 (patch) | |
tree | 523981ba621cd82428ac347585e7631052314d54 /contrib/texinfo/info | |
parent | 15da023077f02380356169c9b5f4a62a6dc51f63 (diff) | |
download | FreeBSD-src-05f7b4b96773cc26ff78d5e68babd66861aa07a8.zip FreeBSD-src-05f7b4b96773cc26ff78d5e68babd66861aa07a8.tar.gz |
Virgin import of GNU texinfo 4.0
Diffstat (limited to 'contrib/texinfo/info')
32 files changed, 2715 insertions, 1217 deletions
diff --git a/contrib/texinfo/info/README b/contrib/texinfo/info/README index 7e1ab32..5cc0791 100644 --- a/contrib/texinfo/info/README +++ b/contrib/texinfo/info/README @@ -14,11 +14,6 @@ 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. diff --git a/contrib/texinfo/info/dir.c b/contrib/texinfo/info/dir.c index 651e48a..94380f5 100644 --- a/contrib/texinfo/info/dir.c +++ b/contrib/texinfo/info/dir.c @@ -1,7 +1,7 @@ -/* dir.c -- How to build a special "dir" node from "localdir" files. - $Id: dir.c,v 1.6 1997/07/27 21:09:20 karl Exp $ +/* dir.c -- how to build a special "dir" node from "localdir" files. + $Id: dir.c,v 1.7 1998/06/28 19:51:36 karl Exp $ - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98 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 @@ -125,7 +125,7 @@ maybe_build_dir_node (dirname) char *fullpath = xmalloc (3 + strlen (this_dir) + namelen); strcpy (fullpath, this_dir); - if (fullpath[strlen (fullpath) - 1] != '/') + if (!IS_SLASH (fullpath[strlen (fullpath) - 1])) strcat (fullpath, "/"); strcat (fullpath, from_file); @@ -135,8 +135,9 @@ maybe_build_dir_node (dirname) 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); + &finfo, &compressed); if (contents) { update_tags++; diff --git a/contrib/texinfo/info/doc.c b/contrib/texinfo/info/doc.c index 6738396..e9756e4e 100644 --- a/contrib/texinfo/info/doc.c +++ b/contrib/texinfo/info/doc.c @@ -35,21 +35,28 @@ FUNCTION_DOC function_doc_array[] = { { 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_forward_set_window, "scroll-forward-set-window", "Scroll forward in this window and set default window size" }, { info_scroll_backward, "scroll-backward", "Scroll backward in this window" }, + { info_scroll_backward_set_window, "scroll-backward-set-window", "Scroll backward in this window and set default window size" }, { 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_down_line, "down-line", "Scroll down by lines" }, + { info_up_line, "up-line", "Scroll up by lines" }, + { info_scroll_half_screen_down, "scroll-half-screen-down", "Scroll down by half screen size" }, + { info_scroll_half_screen_up, "scroll-half-screen-up", "Scroll up by half screen size" }, { 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_scroll_other_window_backward, "scroll-other-window-backward", "Scroll the other window backward" }, { 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_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_last_menu_item, "last-menu-item", "Select the last item in this node's menu" }, @@ -59,6 +66,8 @@ FUNCTION_DOC function_doc_array[] = { { 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_menu_sequence, "menu-sequence", "Read a list of menus starting from dir and follow them" }, + { info_goto_invocation_node, "goto-invocation-node", "Find the node describing program invocation" }, { info_man, "man", "Read a manpage reference and select it" }, { info_top_node, "top-node", "Select the node `Top' in this file" }, { info_dir_node, "dir-node", "Select the node `(dir)'" }, @@ -66,14 +75,18 @@ FUNCTION_DOC function_doc_array[] = { { 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_case_sensitively, "search-case-sensitively", "Read a string and search for it case-sensitively" }, { info_search, "search", "Read a string and search for it" }, + { info_search_backward, "search-backward", "Read a string and search backward for it" }, + { info_search_next, "search-next", "Repeat last search in the same direction" }, + { info_search_previous, "search-previous", "Repeat last search in the reverse direction" }, { 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_move_to_window_line, "move-to-window-line", "Move 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", "" }, diff --git a/contrib/texinfo/info/dribble.c b/contrib/texinfo/info/dribble.c index d1d5848..c4b5b9f 100644 --- a/contrib/texinfo/info/dribble.c +++ b/contrib/texinfo/info/dribble.c @@ -1,9 +1,6 @@ -/* dribble.c -- Dribble files for Info. */ +/* 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. + Copyright (C) 1993, 98 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 @@ -37,7 +34,8 @@ open_dribble_file (name) /* Perhaps close existing dribble file. */ close_dribble_file (); - info_dribble_file = fopen (name, "w"); + /* Keystrokes can be non-printable characters, so we need binary I/O. */ + info_dribble_file = fopen (name, FOPEN_WBIN); #if defined (HAVE_SETVBUF) if (info_dribble_file) diff --git a/contrib/texinfo/info/echo-area.c b/contrib/texinfo/info/echo-area.c index 0d409e8..7500523 100644 --- a/contrib/texinfo/info/echo-area.c +++ b/contrib/texinfo/info/echo-area.c @@ -1,7 +1,7 @@ -/* echo-area.c -- How to read a line in the echo area. - $Id: echo-area.c,v 1.10 1998/02/26 22:47:02 karl Exp $ +/* echo-area.c -- how to read a line in the echo area. + $Id: echo-area.c,v 1.12 1999/03/03 22:22:14 karl Exp $ - Copyright (C) 1993, 97, 98 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -940,7 +940,8 @@ DECLARE_INFO_COMMAND (ea_possible_completions, _("List possible completions")) initialize_message_buffer (); printf_to_message_buffer (completions_found_index == 1 ? _("One completion:\n") - : _("%d completions:\n")); + : _("%d completions:\n"), + completions_found_index); /* Find the maximum length of a label. */ for (i = 0; i < completions_found_index; i++) @@ -1462,7 +1463,7 @@ echo_area_stack_contains_completions_p () static void pause_or_input () { -#if defined (FD_SET) +#ifdef FD_SET struct timeval timer; fd_set readfds; int ready; @@ -1470,14 +1471,14 @@ pause_or_input () FD_ZERO (&readfds); FD_SET (fileno (stdin), &readfds); timer.tv_sec = 2; - timer.tv_usec = 750; + timer.tv_usec = 0; ready = select (fileno (stdin) + 1, &readfds, (fd_set *) NULL, (fd_set *) NULL, &timer); #endif /* FD_SET */ } /* Print MESSAGE right after the end of the current line, and wait - for input or 2.75 seconds, whichever comes first. Then flush the + for input or a couple of seconds, whichever comes first. Then flush the informational message that was printed. */ void inform_in_echo_area (message) @@ -1487,8 +1488,9 @@ inform_in_echo_area (message) char *text; text = xstrdup (message); - for (i = 0; text[i] && text[i] != '\n'; i++); - text[i] = '\0'; + for (i = 0; text[i] && text[i] != '\n'; i++) + ; + text[i] = 0; echo_area_initialize_node (); sprintf (&input_line[input_line_end], "%s[%s]\n", diff --git a/contrib/texinfo/info/filesys.c b/contrib/texinfo/info/filesys.c index eb93fdf..96f0ed9 100644 --- a/contrib/texinfo/info/filesys.c +++ b/contrib/texinfo/info/filesys.c @@ -1,5 +1,5 @@ -/* filesys.c -- File system specific functions for hacking this system. - $Id: filesys.c,v 1.6 1998/02/21 22:52:46 karl Exp $ +/* filesys.c -- filesystem specific functions. + $Id: filesys.c,v 1.10 1998/12/06 21:58:30 karl Exp $ Copyright (C) 1993, 97, 98 Free Software Foundation, Inc. @@ -26,6 +26,7 @@ /* Local to this file. */ static char *info_file_in_path (), *lookup_info_filename (); +static char *info_absolute_file (); static void remember_info_filename (), maybe_initialize_infopath (); typedef struct @@ -35,18 +36,29 @@ typedef struct } COMPRESSION_ALIST; static char *info_suffixes[] = { - "", ".info", "-info", "/index", - (char *)NULL + ".inf", /* 8+3 file on filesystem which supports long file names */ +#ifdef __MSDOS__ + /* 8+3 file names strike again... */ + ".in", /* for .inz, .igz etc. */ + ".i", +#endif + "", + NULL }; static COMPRESSION_ALIST compress_suffixes[] = { + { ".gz", "gunzip" }, + { ".bz2", "bunzip2" }, + { ".z", "gunzip" }, { ".Z", "uncompress" }, { ".Y", "unyabba" }, - { ".z", "gunzip" }, - { ".gz", "gunzip" }, +#ifdef __MSDOS__ + { "gz", "gunzip" }, + { "z", "gunzip" }, +#endif { (char *)NULL, (char *)NULL } }; @@ -86,21 +98,22 @@ info_find_fullpath (partial) /* 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, "/"); + if (IS_ABSOLUTE (partial)) + temp = info_absolute_file (partial); else if (initial_character == '~') { expansion = tilde_expand_word (partial); - if (*expansion == '/') + if (IS_ABSOLUTE (expansion)) { - temp = info_file_in_path (expansion + 1, "/"); + temp = info_absolute_file (expansion); free (expansion); } else temp = expansion; } else if (initial_character == '.' && - (partial[1] == '/' || (partial[1] == '.' && partial[2] == '/'))) + (IS_SLASH (partial[1]) || + (partial[1] == '.' && IS_SLASH (partial[2])))) { if (local_temp_filename_size < 1024) local_temp_filename = (char *)xrealloc @@ -117,7 +130,9 @@ info_find_fullpath (partial) strcat (local_temp_filename, "/"); strcat (local_temp_filename, partial); - return (local_temp_filename); + temp = info_absolute_file (local_temp_filename); /* try extensions */ + if (!temp) + partial = local_temp_filename; } else temp = info_file_in_path (partial, infopath); @@ -167,7 +182,7 @@ info_file_in_path (filename, path) temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename)); strcpy (temp, temp_dirname); - if (temp[(strlen (temp)) - 1] != '/') + if (!IS_SLASH (temp[(strlen (temp)) - 1])) strcat (temp, "/"); strcat (temp, filename); @@ -229,8 +244,26 @@ info_file_in_path (filename, path) 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. +/* Assume FNAME is an absolute file name, and check whether it is + a regular file. If it is, return it as a new string; otherwise + return a NULL pointer. We do it by taking the file name apart + into its directory and basename parts, and calling info_file_in_path.*/ +static char * +info_absolute_file (fname) + char *fname; +{ + char *containing_dir = xstrdup (fname); + char *base = filename_non_directory (containing_dir); + + if (base > containing_dir) + base[-1] = '\0'; + + return info_file_in_path (filename_non_directory (fname), containing_dir); +} + +/* Given a string containing units of information separated by + the PATH_SEP character, 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) @@ -243,7 +276,7 @@ extract_colon_unit (string, idx) if ((i >= strlen (string)) || !string) return ((char *) NULL); - while (string[i] && string[i] != ':') + while (string[i] && string[i] != PATH_SEP[0]) i++; if (i == start) { @@ -285,7 +318,7 @@ lookup_info_filename (filename) register int i; for (i = 0; names_and_files[i]; i++) { - if (strcmp (names_and_files[i]->filename, filename) == 0) + if (FILENAME_CMP (names_and_files[i]->filename, filename) == 0) return (names_and_files[i]->expansion); } } @@ -354,14 +387,14 @@ info_add_path (path, where) strcpy (infopath, path); else if (where == INFOPATH_APPEND) { - strcat (infopath, ":"); + strcat (infopath, PATH_SEP); strcat (infopath, path); } else if (where == INFOPATH_PREPEND) { char *temp = xstrdup (infopath); strcpy (infopath, path); - strcat (infopath, ":"); + strcat (infopath, PATH_SEP); strcat (infopath, temp); free (temp); } @@ -378,28 +411,70 @@ zap_infopath () infopath_size = 0; } +/* Given a chunk of text and its length, convert all CRLF pairs at every + end-of-line into a single Newline character. Return the length of + produced text. + + This is required because the rest of code is too entrenched in having + a single newline at each EOL; in particular, searching for various + Info headers and cookies can become extremely tricky if that assumption + breaks. + + FIXME: this could also support Mac-style text files with a single CR + at the EOL, but what about random CR characters in non-Mac files? Can + we afford converting them into newlines as well? Maybe implement some + heuristics here, like in Emacs 20. + + FIXME: is it a good idea to show the EOL type on the modeline? */ +long +convert_eols (text, textlen) + char *text; + long textlen; +{ + register char *s = text; + register char *d = text; + + while (textlen--) + { + if (*s == '\r' && textlen && s[1] == '\n') + { + s++; + textlen--; + } + *d++ = *s++; + } + + return (long)(d - text); +} + /* 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 turns out to be compressed, set IS_COMPRESSED to non-zero. If the file cannot be read, return a NULL pointer. */ char * -filesys_read_info_file (pathname, filesize, finfo) +filesys_read_info_file (pathname, filesize, finfo, is_compressed) char *pathname; long *filesize; struct stat *finfo; + int *is_compressed; { long st_size; *filesize = filesys_error_number = 0; if (compressed_filename_p (pathname)) - return (filesys_read_compressed (pathname, filesize, finfo)); + { + *is_compressed = 1; + return (filesys_read_compressed (pathname, filesize, finfo)); + } else { int descriptor; char *contents; - descriptor = open (pathname, O_RDONLY, 0666); + *is_compressed = 0; + descriptor = open (pathname, O_RDONLY | O_BINARY, 0666); /* If the file couldn't be opened, give up. */ if (descriptor < 0) @@ -413,15 +488,24 @@ filesys_read_info_file (pathname, filesize, finfo) contents = (char *)xmalloc (1 + st_size); if ((read (descriptor, contents, st_size)) != st_size) { - filesys_error_number = errno; - close (descriptor); - free (contents); - return ((char *)NULL); + filesys_error_number = errno; + close (descriptor); + free (contents); + return ((char *)NULL); } close (descriptor); - *filesize = st_size; + /* Convert any DOS-style CRLF EOLs into Unix-style NL. + Seems like a good idea to have even on Unix, in case the Info + files are coming from some Windows system across a network. */ + *filesize = convert_eols (contents, st_size); + + /* EOL conversion can shrink the text quite a bit. We don't + want to waste storage. */ + if (*filesize < st_size) + contents = (char *)xrealloc (contents, 1 + *filesize); + return (contents); } } @@ -449,8 +533,11 @@ filesys_read_compressed (pathname, filesize, finfo) if (!decompressor) return ((char *)NULL); - command = (char *)xmalloc (10 + strlen (pathname) + strlen (decompressor)); - sprintf (command, "%s < %s", decompressor, pathname); + command = (char *)xmalloc (15 + strlen (pathname) + strlen (decompressor)); + /* Explicit .exe suffix makes the diagnostics of `popen' + better on systems where COMMAND.COM is the stock shell. */ + sprintf (command, "%s%s < %s", + decompressor, STRIP_DOT_EXE ? ".exe" : "", pathname); #if !defined (BUILDING_LIBRARY) if (info_windows_initialized_p) @@ -464,7 +551,7 @@ filesys_read_compressed (pathname, filesize, finfo) } #endif /* !BUILDING_LIBRARY */ - stream = popen (command, "r"); + stream = popen (command, FOPEN_RBIN); free (command); /* Read chunks from this file until there are none left to read. */ @@ -493,9 +580,18 @@ filesys_read_compressed (pathname, filesize, finfo) } free (chunk); - pclose (stream); - contents = (char *)xrealloc (contents, offset + 1); - *filesize = offset; + if (pclose (stream) == -1) + { + if (contents) + free (contents); + contents = (char *)NULL; + filesys_error_number = errno; + } + else + { + *filesize = convert_eols (contents, offset); + contents = (char *)xrealloc (contents, 1 + *filesize); + } } else { @@ -547,9 +643,19 @@ filesys_decompressor_for_file (filename) return ((char *)NULL); for (i = 0; compress_suffixes[i].suffix; i++) - if (strcmp (extension, compress_suffixes[i].suffix) == 0) + if (FILENAME_CMP (extension, compress_suffixes[i].suffix) == 0) return (compress_suffixes[i].decompressor); +#if defined (__MSDOS__) + /* If no other suffix matched, allow any extension which ends + with `z' to be decompressed by gunzip. Due to limited 8+3 DOS + file namespace, we can expect many such cases, and supporting + every weird suffix thus produced would be a pain. */ + if (extension[strlen (extension) - 1] == 'z' || + extension[strlen (extension) - 1] == 'Z') + return "gunzip"; +#endif + return ((char *)NULL); } @@ -582,3 +688,26 @@ filesys_error_string (filename, error_num) return (errmsg_buf); } + +/* Check for FILENAME eq "dir" first, then all the compression + suffixes. */ + +int +is_dir_name (filename) + char *filename; +{ + unsigned i; + if (strcasecmp (filename, "dir") == 0) + return 1; + + for (i = 0; compress_suffixes[i].suffix; i++) + { + char dir_compressed[50]; /* can be short */ + strcpy (dir_compressed, "dir"); + strcat (dir_compressed, compress_suffixes[i].suffix); + if (strcasecmp (filename, dir_compressed) == 0) + return 1; + } + + return 0; +} diff --git a/contrib/texinfo/info/filesys.h b/contrib/texinfo/info/filesys.h index 440eb9b..06573ef 100644 --- a/contrib/texinfo/info/filesys.h +++ b/contrib/texinfo/info/filesys.h @@ -1,10 +1,7 @@ -/* filesys.h -- External declarations of functions and vars in filesys.c. - $Id: filesys.h,v 1.3 1997/07/15 18:39:08 karl Exp $ +/* filesys.h -- external declarations for filesys.c. + $Id: filesys.h,v 1.5 1998/07/21 22:25:44 karl Exp $ - This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98 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 @@ -46,6 +43,11 @@ extern void info_add_path (); If it can't find the file, it returns NULL. */ extern char *info_find_fullpath (); +/* Given a chunk of text and its length, convert all CRLF pairs at the + EOLs into a single Newline character. Return the length of produced + text. */ +long convert_eols (); + /* 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. @@ -69,6 +71,9 @@ extern int filesys_error_number; Advance IDX to the character after the colon. */ extern char *extract_colon_unit (); +/* Return true if FILENAME is `dir', with a possible compression suffix. */ +extern int is_dir_name (); + /* The default value of INFOPATH. */ #if !defined (DEFAULT_INFOPATH) # define DEFAULT_INFOPATH "/usr/local/info:/usr/info:/usr/local/lib/info:/usr/lib/info:/usr/local/gnu/info:/usr/local/gnu/lib/info:/usr/gnu/info:/usr/gnu/lib/info:/opt/gnu/info:/usr/share/info:/usr/share/lib/info:/usr/local/share/info:/usr/local/share/lib/info:/usr/gnu/lib/emacs/info:/usr/local/gnu/lib/emacs/info:/usr/local/lib/emacs/info:/usr/local/emacs/info:." diff --git a/contrib/texinfo/info/footnotes.c b/contrib/texinfo/info/footnotes.c index b646743..c891e39 100644 --- a/contrib/texinfo/info/footnotes.c +++ b/contrib/texinfo/info/footnotes.c @@ -1,7 +1,7 @@ /* footnotes.c -- Some functions for manipulating footnotes. - $Id: footnotes.c,v 1.4 1997/07/24 21:23:33 karl Exp $ + $Id: footnotes.c,v 1.9 1999/09/25 16:10:04 karl Exp $ - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ make_footnotes_node (node) /* See if this node contains the magic footnote label. */ fn_start = - info_search_in_node (FOOTNOTE_LABEL, node, 0, (WINDOW *)NULL, 1); + info_search_in_node (FOOTNOTE_LABEL, node, 0, (WINDOW *)NULL, 1, 0); /* If it doesn't, check to see if it has an associated footnotes node. */ if (fn_start == -1) @@ -73,16 +73,21 @@ make_footnotes_node (node) { register int i; char *refname; + int reflen = strlen ("-Footnotes") + strlen (node->nodename); - refname = (char *)xmalloc - (1 + strlen ("-Footnotes") + strlen (node->nodename)); + refname = (char *)xmalloc (reflen + 1); strcpy (refname, node->nodename); strcat (refname, "-Footnotes"); for (i = 0; refs[i]; i++) if ((refs[i]->nodename != (char *)NULL) && - (strcmp (refs[i]->nodename, refname) == 0)) + /* Support both the older "foo-Footnotes" and the new + style "foo-Footnote-NN" references. */ + (strcmp (refs[i]->nodename, refname) == 0 || + (strncmp (refs[i]->nodename, refname, reflen - 1) == 0 && + refs[i]->nodename[reflen - 1] == '-' && + isdigit (refs[i]->nodename[reflen])))) { char *filename; @@ -110,6 +115,7 @@ make_footnotes_node (node) /* Make the new node. */ result = (NODE *)xmalloc (sizeof (NODE)); result->flags = 0; + result->display_pos = 0; /* Get the size of the footnotes appearing within this node. */ { @@ -250,11 +256,11 @@ DECLARE_INFO_COMMAND (info_show_footnotes, switch (result) { case FN_UNFOUND: - info_error (NO_FOOT_NODE); + info_error (msg_no_foot_node); break; case FN_UNABLE: - info_error (WIN_TOO_SMALL); + info_error (msg_win_too_small); break; } } diff --git a/contrib/texinfo/info/footnotes.h b/contrib/texinfo/info/footnotes.h index 3406bcb..a0d4fb0 100644 --- a/contrib/texinfo/info/footnotes.h +++ b/contrib/texinfo/info/footnotes.h @@ -1,10 +1,7 @@ /* footnotes.h -- Some functions for manipulating footnotes. - $Id: footnotes.h,v 1.3 1997/07/15 18:40:27 karl Exp $ + $Id: footnotes.h,v 1.4 1998/11/29 21:44:49 karl Exp $ - This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98 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 @@ -26,7 +23,7 @@ #define INFO_FOOTNOTES_H /* Magic string which indicates following text is footnotes. */ -#define FOOTNOTE_LABEL _("---------- Footnotes ----------") +#define FOOTNOTE_LABEL N_("---------- Footnotes ----------") #define FN_FOUND 0 #define FN_UNFOUND 1 diff --git a/contrib/texinfo/info/funs.h b/contrib/texinfo/info/funs.h index 32d80d5..f5c4d33 100644 --- a/contrib/texinfo/info/funs.h +++ b/contrib/texinfo/info/funs.h @@ -12,15 +12,22 @@ 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_forward_set_window (); extern void info_scroll_backward (); +extern void info_scroll_backward_set_window (); extern void info_beginning_of_node (); extern void info_end_of_node (); +extern void info_down_line (); +extern void info_up_line (); +extern void info_scroll_half_screen_down (); +extern void info_scroll_half_screen_up (); 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_scroll_other_window_backward (); extern void info_grow_window (); extern void info_tile_windows (); extern void info_toggle_wrap (); @@ -36,6 +43,8 @@ extern void info_xref_item (); extern void info_find_menu (); extern void info_visit_menu (); extern void info_goto_node (); +extern void info_menu_sequence (); +extern void info_goto_invocation_node (); extern void info_man (); extern void info_top_node (); extern void info_dir_node (); @@ -43,7 +52,11 @@ extern void info_history_node (); extern void info_kill_node (); extern void info_view_file (); extern void info_print_node (); +extern void info_search_case_sensitively (); extern void info_search (); +extern void info_search_backward (); +extern void info_search_next (); +extern void info_search_previous (); extern void isearch_forward (); extern void isearch_backward (); extern void info_move_to_prev_xref (); diff --git a/contrib/texinfo/info/indices.c b/contrib/texinfo/info/indices.c index 37e9b03..6583da1 100644 --- a/contrib/texinfo/info/indices.c +++ b/contrib/texinfo/info/indices.c @@ -1,7 +1,7 @@ -/* indices.c -- Commands for dealing with an Info file Index. - $Id: indices.c,v 1.6 1997/07/24 21:25:53 karl Exp $ +/* indices.c -- deal with an Info file index. + $Id: indices.c,v 1.14 1999/09/25 16:10:04 karl Exp $ - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -199,7 +199,7 @@ do_info_index_search (window, count, search_string) 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)) + (FILENAME_CMP (initial_index_filename, fb->filename) != 0)) { info_free_references (index_index); window_message_in_echo_area (_("Finding index entries...")); @@ -296,7 +296,7 @@ index_entry_exists (window, string) fb = file_buffer_of_window (window); if (!initial_index_filename - || (strcmp (initial_index_filename, fb->filename) != 0)) + || (FILENAME_CMP (initial_index_filename, fb->filename) != 0)) { info_free_references (index_index); index_index = info_indices_of_file_buffer (fb); @@ -439,15 +439,12 @@ DECLARE_INFO_COMMAND (info_next_index_match, if (!node) { - info_error (CANT_FILE_NODE, + info_error (msg_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); - + info_set_node_of_window (1, window, node); /* Try to find an occurence of LABEL in this node. */ { @@ -497,11 +494,13 @@ apropos_in_all_indices (search_string, inform) REFERENCE **this_index, *this_item; NODE *this_node; FILE_BUFFER *this_fb; + int dir_node_duplicated = 0; this_item = dir_menu[dir_index]; if (!this_item->filename) { + dir_node_duplicated = 1; if (dir_node->parent) this_item->filename = xstrdup (dir_node->parent); else @@ -517,7 +516,11 @@ apropos_in_all_indices (search_string, inform) this_node = info_get_node (this_item->label, "Top"); if (!this_node) - continue; + { + if (dir_node_duplicated) + free (this_item->filename); + continue; + } /* Get the file buffer associated with this node. */ { @@ -529,6 +532,19 @@ apropos_in_all_indices (search_string, inform) this_fb = info_find_file (files_name); + /* If we already scanned this file, don't do that again. + In addition to being faster, this also avoids having + multiple identical entries in the *Apropos* menu. */ + for (i = 0; i < dir_index; i++) + if (FILENAME_CMP (this_fb->filename, dir_menu[i]->filename) == 0) + break; + if (i < dir_index) + { + if (dir_node_duplicated) + free (this_item->filename); + continue; + } + if (this_fb && inform) message_in_echo_area (_("Scanning indices of \"%s\"..."), files_name); @@ -584,7 +600,7 @@ apropos_in_all_indices (search_string, inform) } #define APROPOS_NONE \ - _("No available info files reference \"%s\" in their indices.") + N_("No available info files have \"%s\" in their indices.") void info_apropos (string) @@ -596,7 +612,7 @@ info_apropos (string) if (!apropos_list) { - info_error (APROPOS_NONE, string); + info_error (_(APROPOS_NONE), string); } else { @@ -604,7 +620,7 @@ info_apropos (string) REFERENCE *entry; for (i = 0; (entry = apropos_list[i]); i++) - fprintf (stderr, "\"(%s)%s\" -- %s\n", + fprintf (stdout, "\"(%s)%s\" -- %s\n", entry->filename, entry->nodename, entry->label); } info_free_references (apropos_list); @@ -638,7 +654,7 @@ DECLARE_INFO_COMMAND (info_index_apropos, if (!apropos_list) { - info_error (APROPOS_NONE, line); + info_error (_(APROPOS_NONE), line); } else { @@ -653,10 +669,14 @@ DECLARE_INFO_COMMAND (info_index_apropos, for (i = 0; apropos_list[i]; i++) { int len; - sprintf (line_buffer, "* (%s)%s::", + /* The label might be identical to that of another index + entry in another Info file. Therefore, we make the file + name part of the menu entry, to make them all distinct. */ + sprintf (line_buffer, "* %s [%s]: ", + apropos_list[i]->label, apropos_list[i]->filename); + len = pad_to (40, line_buffer); + sprintf (line_buffer + len, "(%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); diff --git a/contrib/texinfo/info/info-utils.c b/contrib/texinfo/info/info-utils.c index d9ab9a0..a19c950 100644 --- a/contrib/texinfo/info/info-utils.c +++ b/contrib/texinfo/info/info-utils.c @@ -1,9 +1,7 @@ -/* info-utils.c -- Useful functions for manipulating Info file quirks. */ +/* info-utils.c -- miscellanous. + $Id: info-utils.c,v 1.7 1998/08/10 18:07:47 karl Exp $ -/* This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993 Free Software Foundation, Inc. + Copyright (C) 1993, 98 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 @@ -29,7 +27,7 @@ /* When non-zero, various display and input functions handle ISO Latin character sets correctly. */ -int ISO_Latin_p = 0; +int ISO_Latin_p = 1; /* Variable which holds the most recent filename parsed as a result of calling info_parse_xxx (). */ @@ -300,8 +298,8 @@ info_references_internal (label, binding) return (refs); } -/* Get the entry associated with LABEL in MENU. Return a pointer to the - REFERENCE if found, or NULL. */ +/* Get the entry associated with LABEL in REFERENCES. Return a pointer + to the ENTRY if found, or NULL. */ REFERENCE * info_get_labeled_reference (label, references) char *label; @@ -444,19 +442,10 @@ printed_representation (character, hpos) 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)) + int printable_limit = ISO_Latin_p ? 255 : 127; + + /* Show CTRL-x as ^X. */ + if (iscntrl (character) && character < 127) { switch (character) { @@ -480,17 +469,23 @@ printed_representation (character, hpos) the_rep[i++] = (character | 0x40); } } + /* Show META-x as 0370. */ else if (character > printable_limit) { sprintf (the_rep + i, "\\%0o", character); i = strlen (the_rep); } + else if (character == DEL) + { + the_rep[i++] = '^'; + the_rep[i++] = '?'; + } else the_rep[i++] = character; - the_rep[i] = '\0'; + the_rep[i] = 0; - return (the_rep); + return the_rep; } @@ -604,14 +599,13 @@ char * filename_non_directory (pathname) char *pathname; { - char *filename; + register char *filename = pathname + strlen (pathname); - filename = (char *) strrchr (pathname, '/'); + if (HAVE_DRIVE (pathname)) + pathname += 2; - if (filename) - filename++; - else - filename = pathname; + while (filename > pathname && !IS_SLASH (filename[-1])) + filename--; return (filename); } @@ -663,3 +657,17 @@ get_internal_info_window (name) return (win); } + +/* Return a window displaying the node NODE. */ +WINDOW * +get_window_of_node (node) + NODE *node; +{ + WINDOW *win = (WINDOW *)NULL; + + for (win = windows; win; win = win->next) + if (win->node == node) + break; + + return (win); +} diff --git a/contrib/texinfo/info/info-utils.h b/contrib/texinfo/info/info-utils.h index 879587c..24cc482 100644 --- a/contrib/texinfo/info/info-utils.h +++ b/contrib/texinfo/info/info-utils.h @@ -1,10 +1,7 @@ -/* info-utils.h -- Exported functions and variables from info-util.c. - $Id: info-utils.h,v 1.3 1997/07/15 18:42:20 karl Exp $ +/* info-utils.h -- Exported functions and variables from info-utils.c. + $Id: info-utils.h,v 1.5 1998/08/10 18:07:28 karl Exp $ - This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 96 Free Software Foundation, Inc. + Copyright (C) 1993, 96, 98 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 @@ -25,13 +22,6 @@ #ifndef INFO_UTILS_H #define INFO_UTILS_H -#if !defined (HAVE_STRCHR) -# undef strchr -# undef strrchr -# define strchr index -# define strrchr rindex -#endif /* !HAVE_STRCHR */ - #include "nodes.h" #include "window.h" #include "search.h" @@ -118,22 +108,22 @@ extern void name_internal_node (); Info window. */ extern WINDOW *get_internal_info_window (); +/* Return a window displaying the node NODE. */ +extern WINDOW *get_window_of_node (); + /* 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 globals `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) \ + if (!info_parsed_nodename && !info_parsed_filename) \ info_parse_label (INFO_ALTPREV_LABEL, n); \ } while (0) diff --git a/contrib/texinfo/info/info.c b/contrib/texinfo/info/info.c index 81ab460..4f4999c 100644 --- a/contrib/texinfo/info/info.c +++ b/contrib/texinfo/info/info.c @@ -1,7 +1,7 @@ /* info.c -- Display nodes of Info files in multiple windows. - $Id: info.c,v 1.18 1998/02/27 21:37:27 karl Exp $ + $Id: info.c,v 1.41 1999/09/25 16:10:04 karl Exp $ - Copyright (C) 1993, 96, 97, 98 Free Software Foundation, Inc. + Copyright (C) 1993, 96, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,12 +27,7 @@ # include "man.h" #endif /* HANDLE_MAN_PAGES */ -/* The version numbers of this version of Info. */ -int info_major_version = 2; -int info_minor_version = 18; - -/* basename (argv[0]) */ -static char *program_name = NULL; +static char *program_name = "info"; /* Non-zero means search all indices for APROPOS_SEARCH_STRING. */ static int apropos_p = 0; @@ -44,8 +39,13 @@ static char *apropos_search_string = (char *)NULL; apropos, this puts the user at the node, running info. */ static int index_search_p = 0; +/* Non-zero means look for the node which describes the invocation + and command-line options of the program, and start the info + session at that node. */ +static int goto_invocation_p = 0; + /* Variable containing the string to search for when index_search_p is - non-zero. */ + non-zero. */ static char *index_search_string = (char *)NULL; /* Non-zero means print version info only. */ @@ -73,6 +73,18 @@ static char *user_output_filename = (char *)NULL; dumped in the order encountered. This basically can print a book. */ int dump_subnodes = 0; +/* Non-zero means make default keybindings be loosely modeled on vi(1). */ +int vi_keys_p = 0; + +#ifdef __MSDOS__ +/* Non-zero indicates that screen output should be made 'speech-friendly'. + Since on MSDOS the usual behavior is to write directly to the video + memory, speech synthesizer software cannot grab the output. Therefore, + we provide a user option which tells us to avoid direct screen output + and use stdout instead (which loses the color output). */ +int speech_friendly = 0; +#endif + /* 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. */ @@ -87,22 +99,33 @@ static struct option long_options[] = { { "file", 1, 0, 'f' }, { "subnodes", 0, &dump_subnodes, 1 }, { "output", 1, 0, 'o' }, + { "show-options", 0, 0, 'O' }, + { "usage", 0, 0, 'O' }, + { "vi-keys", 0, &vi_keys_p, 1 }, { "help", 0, &print_help_p, 1 }, { "version", 0, &print_version_p, 1 }, { "dribble", 1, 0, DRIBBLE_OPTION }, { "restore", 1, 0, RESTORE_OPTION }, +#ifdef __MSDOS__ + { "speech-friendly", 0, &speech_friendly, 1 }, +#endif { "index-search", 1, 0, IDXSRCH_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"; +#ifdef __MSDOS__ +static char *short_options = "d:n:f:o:Osb"; +#else +static char *short_options = "d:n:f:o:Os"; +#endif /* When non-zero, the Info window system has been initialized. */ int info_windows_initialized_p = 0; /* Some "forward" declarations. */ static void info_short_help (), remember_info_program_name (); +static void init_messages (); /* **************************************************************** */ @@ -119,8 +142,6 @@ main (argc, argv) int getopt_long_index; /* Index returned by getopt_long (). */ NODE *initial_node; /* First node loaded by Info. */ - remember_info_program_name (argv[0]); - #ifdef HAVE_SETLOCALE /* Set locale via LC_ALL. */ setlocale (LC_ALL, ""); @@ -130,6 +151,8 @@ main (argc, argv) bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); + init_messages (); + while (1) { int option_character; @@ -177,12 +200,25 @@ main (argc, argv) user_output_filename = xstrdup (optarg); break; + /* User has specified that she wants to find the "Options" + or "Invocation" node for the program. */ + case 'O': + goto_invocation_p = 1; + break; + /* User is specifying that she wishes to dump the subnodes of the node that she is dumping. */ case 's': dump_subnodes = 1; break; +#ifdef __MSDOS__ + /* User specifies that she wants speech-friendly output. */ + case 'b': + speech_friendly = 1; + break; +#endif /* __MSDOS__ */ + /* User has specified a string to search all indices for. */ case APROPOS_OPTION: apropos_p = 1; @@ -209,8 +245,8 @@ main (argc, argv) break; default: - fprintf (stderr, _("Try --help for more information.")); - exit (1); + fprintf (stderr, _("Try --help for more information.\n")); + xexit (1); } } @@ -226,23 +262,23 @@ main (argc, argv) /* If the user specified --version, then show the version and exit. */ if (print_version_p) { - printf ("%s (GNU %s %s) %s\n", program_name, PACKAGE, VERSION, - version_string ()); + printf ("%s (GNU %s) %s\n", program_name, PACKAGE, VERSION); + puts (""); printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\ There is NO warranty. You may redistribute this software\n\ under the terms of the GNU General Public License.\n\ For more information about these matters, see the files named COPYING.\n"), - "1998"); - exit (0); + "1999"); + xexit (0); } /* If the `--help' option was present, show the help and exit. */ if (print_help_p) { info_short_help (); - exit (0); + xexit (0); } - + /* If the user hasn't specified a path for Info files, default it. Lowest priority is our messy hardwired list in filesys.h. Then comes the user's INFODIR from the Makefile. @@ -255,7 +291,7 @@ For more information about these matters, see the files named COPYING.\n"), { unsigned len = strlen (path_from_env); /* Trailing : on INFOPATH means insert the default path. */ - if (len && path_from_env[len - 1] == ':') + if (len && path_from_env[len - 1] == PATH_SEP[0]) { path_from_env[len - 1] = 0; info_add_path (DEFAULT_INFOPATH, INFOPATH_PREPEND); @@ -283,7 +319,14 @@ For more information about these matters, see the files named COPYING.\n"), if (temp != directory_name) { - *temp = 0; + if (HAVE_DRIVE (directory_name) && temp == directory_name + 2) + { + /* The directory of "d:foo" is stored as "d:.", to avoid + mixing it with "d:/" when a slash is appended. */ + *temp = '.'; + temp += 2; + } + temp[-1] = 0; info_add_path (directory_name, INFOPATH_PREPEND); } @@ -295,13 +338,13 @@ For more information about these matters, see the files named COPYING.\n"), if (apropos_p) { info_apropos (apropos_search_string); - exit (0); + xexit (0); } /* Get the initial Info node. It is either "(dir)Top", or what the user specifed with values in user_filename and user_nodenames. */ initial_node = info_get_node (user_filename, - user_nodenames ? user_nodenames[0] : NULL); + user_nodenames ? user_nodenames[0] : 0); /* If we couldn't get the initial node, this user is in trouble. */ if (!initial_node) @@ -309,9 +352,9 @@ For more information about these matters, see the files named COPYING.\n"), 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); + info_error (msg_cant_find_node, + user_nodenames ? user_nodenames[0] : "Top"); + xexit (1); } /* Special cases for when the user specifies multiple nodes. If we @@ -328,228 +371,112 @@ For more information about these matters, see the files named COPYING.\n"), else begin_multiple_window_info_session (user_filename, user_nodenames); - exit (0); - } - - /* If the user specified `--index-search=STRING', start the info - session in the node corresponding to the first match. */ - if (index_search_p) - { - int status = 0; - - initialize_info_session (initial_node, 0); - - if (index_entry_exists (windows, index_search_string)) - { - terminal_clear_screen (); - terminal_prep_terminal (); - display_update_display (windows); - info_last_executed_command = (VFunction *)NULL; - - do_info_index_search (windows, 0, index_search_string); - - info_read_and_dispatch (); - - terminal_unprep_terminal (); - - /* On program exit, leave the cursor at the bottom of the - window, and restore the terminal IO. */ - terminal_goto_xy (0, screenheight - 1); - terminal_clear_to_eol (); - fflush (stdout); - } - else - { - fputs (_("no entries found\n"), stderr); - status = 2; - } - - close_dribble_file (); - exit (status); + xexit (0); } /* If there are arguments remaining, they are the names of menu items in sequential info files starting from the first one loaded. That file name is either "dir", or the contents of user_filename if one was specified. */ - while (optind != argc) - { - REFERENCE **menu; - REFERENCE *entry; - NODE *node; - char *arg; - static char *first_arg = (char *)NULL; - - /* Remember the name of the menu entry we want. */ - arg = argv[optind++]; - - if (!first_arg) - first_arg = arg; - - /* Build and return a list of the menu items in this node. */ - menu = info_menu_of_node (initial_node); - - /* If there wasn't a menu item in this node, stop here, but let - the user continue to use Info. Perhaps they wanted this node - and didn't realize it. */ - if (!menu) - { -#if defined (HANDLE_MAN_PAGES) - if (first_arg == arg) - { - node = make_manpage_node (first_arg); - if (node) - goto maybe_got_node; - } -#endif /* HANDLE_MAN_PAGES */ - begin_info_session_with_error - (initial_node, _("There is no menu in this node.")); - exit (0); - } - - /* Find the specified menu item. */ - entry = info_get_labeled_reference (arg, menu); - - /* If the item wasn't found, search the list sloppily. Perhaps this - user typed "buffer" when they really meant "Buffers". */ - if (!entry) - { - register int i; - int best_guess = -1; - - for (i = 0; (entry = menu[i]); i++) - { - if (strcasecmp (entry->label, arg) == 0) - break; - else - if (strncasecmp (entry->label, arg, strlen (arg)) == 0) - best_guess = i; - } - - if (!entry && best_guess != -1) - entry = menu[best_guess]; - } - - /* If we failed to find the reference, start Info with the current - node anyway. It is probably a misspelling. */ - if (!entry) - { - char *error_message = _("There is no menu item \"%s\" in this node."); - -#if defined (HANDLE_MAN_PAGES) - if (first_arg == arg) - { - node = make_manpage_node (first_arg); - if (node) - goto maybe_got_node; - } -#endif /* HANDLE_MAN_PAGES */ - - info_free_references (menu); - - /* If we were supposed to dump this node, complain. */ - if (user_output_filename) - info_error (error_message, arg); - else - begin_info_session_with_error (initial_node, error_message, arg); - - exit (0); - } - - /* We have found the reference that the user specified. Clean it - up a little bit. */ - if (!entry->filename) - { - if (initial_node->parent) - entry->filename = xstrdup (initial_node->parent); - else - entry->filename = xstrdup (initial_node->filename); - } - - /* Find this node. If we can find it, then turn the initial_node - into this one. If we cannot find it, try using the label of the - entry as a file (i.e., "(LABEL)Top"). Otherwise the Info file is - malformed in some way, and we will just use the current value of - initial node. */ - node = info_get_node (entry->filename, entry->nodename); - -#if defined (HANDLE_MAN_PAGES) - if ((first_arg == arg) && !node) - { - node = make_manpage_node (first_arg); - if (node) - goto maybe_got_node; - } -#endif /* HANDLE_MAN_PAGES */ - - if (!node && entry->nodename && - (strcmp (entry->label, entry->nodename) == 0)) - node = info_get_node (entry->label, "Top"); - - maybe_got_node: - if (node) - { - free (initial_node); - initial_node = node; - info_free_references (menu); - } - else - { - char *temp = xstrdup (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); - } - return (vstring); + { + char *errstr, *errarg1, *errarg2; + NODE *new_initial_node = info_follow_menus (initial_node, argv + optind, + &errstr, &errarg1, &errarg2); + if (new_initial_node && new_initial_node != initial_node) + initial_node = new_initial_node; + + /* If the user specified that this node should be output, then do that + now. Otherwise, start the Info session with this node. Or act + accordingly if the initial node was not found. */ + if (user_output_filename) + { + if (!errstr) + dump_node_to_file (initial_node, user_output_filename, + dump_subnodes); + else + info_error (errstr, errarg1, errarg2); + } + else + { + + if (errstr) + begin_info_session_with_error (initial_node, errstr, + errarg1, errarg2); + /* If the user specified `--index-search=STRING' or + --show-options, start the info session in the node + corresponding to what they want. */ + else if (index_search_p || goto_invocation_p) + { + int status = 0; + + initialize_info_session (initial_node, 0); + + if (goto_invocation_p + || index_entry_exists (windows, index_search_string)) + { + terminal_prep_terminal (); + terminal_clear_screen (); + info_last_executed_command = (VFunction *)NULL; + + if (index_search_p) + do_info_index_search (windows, 0, index_search_string); + else + { + /* If they said "info --show-options foo bar baz", + the last of the arguments is the program whose + options they want to see. */ + char **p = argv + optind; + char *program; + + if (*p) + { + while (p[1]) + p++; + program = xstrdup (*p); + } + else if (user_filename) + /* If there's no command-line arguments to + supply the program name, use the Info file + name (sans extension and leading directories) + instead. */ + program = program_name_from_file_name (user_filename); + else + program = xstrdup (""); + + info_intuit_options_node (windows, initial_node, program); + free (program); + } + + info_read_and_dispatch (); + + /* On program exit, leave the cursor at the bottom of the + window, and restore the terminal IO. */ + terminal_goto_xy (0, screenheight - 1); + terminal_clear_to_eol (); + fflush (stdout); + terminal_unprep_terminal (); + } + else + { + fprintf (stderr, _("no index entries found for `%s'\n"), + index_search_string); + status = 2; + } + + close_dribble_file (); + xexit (status); + } + else + begin_info_session (initial_node); + } + + xexit (0); + } } /* Error handling. */ -static void -remember_info_program_name (fullpath) - char *fullpath; -{ - char *filename; - - filename = filename_non_directory (fullpath); - program_name = xstrdup (filename); -} - /* Non-zero if an error has been signalled. */ int info_error_was_printed = 0; @@ -595,33 +522,99 @@ info_error (format, arg1, arg2) } } + /* Produce a scaled down description of the available options to Info. */ static void info_short_help () { printf (_("\ -Usage: %s [OPTION]... [INFO-FILE [MENU-ITEM...]]\n\ +Usage: %s [OPTION]... [MENU-ITEM...]\n\ \n\ Read documentation in Info format.\n\ -For more complete documentation on how to use Info, run `info info options'.\n\ \n\ Options:\n\ ---directory DIR add DIR to INFOPATH.\n\ ---dribble FILENAME remember user keystrokes in FILENAME.\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\ ---restore FILENAME read initial keystrokes from FILENAME.\n\ ---subnodes recursively output menu items.\n\ ---help display this help and exit.\n\ ---version display version information and exit.\n\ + --apropos=SUBJECT look up SUBJECT in all indices of all manuals.\n\ + --directory=DIR add DIR to INFOPATH.\n\ + --dribble=FILENAME remember user keystrokes in FILENAME.\n\ + --file=FILENAME specify Info file to visit.\n\ + --help display this help and exit.\n\ + --index-search=STRING go to node pointed by index entry STRING.\n\ + --node=NODENAME specify nodes in first visited Info file.\n\ + --output=FILENAME output selected nodes to FILENAME.\n\ + --restore=FILENAME read initial keystrokes from FILENAME.\n\ + --show-options, --usage go to command-line options node.\n\ + --subnodes recursively output menu items.\n%s\ + --vi-keys use vi-like and less-like key bindings.\n\ + --version display version information and exit.\n\ \n\ -The first argument, if present, is the name of the Info file to read.\n\ +The first non-option argument, if present, is the menu entry to start from;\n\ +it is searched for in all `dir' files along INFOPATH.\n\ +If it is not present, info merges all `dir' files and shows the result.\n\ Any remaining arguments are treated as the names of menu\n\ -items in the initial node visited. For example, `info emacs buffers'\n\ -moves to the node `buffers' in the info file `emacs'.\n\ +items relative to the initial node visited.\n\ +\n\ +Examples:\n\ + info show top-level dir menu\n\ + info emacs start at emacs node from top-level dir\n\ + info emacs buffers start at buffers node within emacs manual\n\ + info --show-options emacs start at node with emacs' command line options\n\ + info -f ./foo.info show file ./foo.info, not searching dir\n\ \n\ -Email bug reports to bug-texinfo@gnu.org."), program_name); +Email bug reports to bug-texinfo@gnu.org,\n\ +general questions and discussion to help-texinfo@gnu.org.\n\ +"), + program_name, +#ifdef __MSDOS__ +"\ + --speech-friendly be friendly to speech synthesizers.\n" +#else +"" +#endif + ); - exit (0); + xexit (0); +} + + +/* Initialize strings for gettext. Because gettext doesn't handle N_ or + _ within macro definitions, we put shared messages into variables and + use them that way. This also has the advantage that there's only one + copy of the strings. */ + +char *msg_cant_find_node; +char *msg_cant_file_node; +char *msg_cant_find_window; +char *msg_cant_find_point; +char *msg_cant_kill_last; +char *msg_no_menu_node; +char *msg_no_foot_node; +char *msg_no_xref_node; +char *msg_no_pointer; +char *msg_unknown_command; +char *msg_term_too_dumb; +char *msg_at_node_bottom; +char *msg_at_node_top; +char *msg_one_window; +char *msg_win_too_small; +char *msg_cant_make_help; + +static void +init_messages () +{ + msg_cant_find_node = _("Cannot find node `%s'."); + msg_cant_file_node = _("Cannot find node `(%s)%s'."); + msg_cant_find_window = _("Cannot find a window!"); + msg_cant_find_point = _("Point doesn't appear within this window's node!"); + msg_cant_kill_last = _("Cannot delete the last window."); + msg_no_menu_node = _("No menu in this node."); + msg_no_foot_node = _("No footnotes in this node."); + msg_no_xref_node = _("No cross references in this node."); + msg_no_pointer = _("No `%s' pointer for this node."); + msg_unknown_command = _("Unknown Info command `%c'; try `?' for help."); + msg_term_too_dumb = _("Terminal type `%s' is not smart enough to run Info."); + msg_at_node_bottom = _("You are already at the last page of this node."); + msg_at_node_top = _("You are already at the first page of this node."); + msg_one_window = _("Only one window."); + msg_win_too_small = _("Resulting window would be too small."); + msg_cant_make_help = _("Not enough room for a help window, please delete a window."); } diff --git a/contrib/texinfo/info/info.h b/contrib/texinfo/info/info.h index 092ef41..2f85d80 100644 --- a/contrib/texinfo/info/info.h +++ b/contrib/texinfo/info/info.h @@ -1,10 +1,7 @@ /* info.h -- Header file which includes all of the other headers. - $Id: info.h,v 1.7 1998/02/27 21:36:04 karl Exp $ + $Id: info.h,v 1.14 1999/09/25 16:10:04 karl Exp $ - This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 97, 98 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,7 +19,7 @@ Written by Brian Fox (bfox@ai.mit.edu). */ -#if !defined (INFO_H) +#ifndef INFO_H #define INFO_H /* We always want these, so why clutter up the compile command? */ @@ -119,6 +116,9 @@ extern int info_error_was_printed; /* Non-zero means ring terminal bell on errors. */ extern int info_error_rings_bell_p; +/* Non-zero means default keybindings are loosely modeled on vi(1). */ +extern int vi_keys_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. */ @@ -127,28 +127,23 @@ extern void info_error (); /* The version numbers of Info. */ extern int info_major_version, info_minor_version; -/* How to get the version string for this version of Info. Returns - something similar to "2.11". */ -extern char *version_string (); - /* Error message defines. */ -#define CANT_FIND_NODE _("Cannot find the node \"%s\".") -#define CANT_FILE_NODE _("Cannot find the node \"(%s)%s\".") -#define CANT_FIND_WIND _("Cannot find a window!") -#define CANT_FIND_POINT _("Point doesn't appear within this window's node!") -#define CANT_KILL_LAST _("Cannot delete the last window.") -#define NO_MENU_NODE _("No menu in this node.") -#define NO_FOOT_NODE _("No footnotes in this node.") -#define NO_XREF_NODE _("No cross references in this node.") -#define NO_POINTER _("No \"%s\" pointer for this node.") -#define UNKNOWN_COMMAND _("Unknown Info command `%c'. `?' for help.") -#define TERM_TOO_DUMB _("Terminal type \"%s\" is not smart enough to run Info.") -#define AT_NODE_BOTTOM _("You are already at the last page of this node.") -#define AT_NODE_TOP _("You are already at the first page of this node.") -#define ONE_WINDOW _("Only one window.") -#define WIN_TOO_SMALL _("Resulting window would be too small.") -#define CANT_MAKE_HELP \ -_("There isn't enough room to make a help window. Please delete a window.") +extern char *msg_cant_find_node; +extern char *msg_cant_file_node; +extern char *msg_cant_find_window; +extern char *msg_cant_find_point; +extern char *msg_cant_kill_last; +extern char *msg_no_menu_node; +extern char *msg_no_foot_node; +extern char *msg_no_xref_node; +extern char *msg_no_pointer; +extern char *msg_unknown_command; +extern char *msg_term_too_dumb; +extern char *msg_at_node_bottom; +extern char *msg_at_node_top; +extern char *msg_one_window; +extern char *msg_win_too_small; +extern char *msg_cant_make_help; /* Found in info-utils.c. */ diff --git a/contrib/texinfo/info/infodoc.c b/contrib/texinfo/info/infodoc.c index 4fc0419..2b70918 100644 --- a/contrib/texinfo/info/infodoc.c +++ b/contrib/texinfo/info/infodoc.c @@ -1,7 +1,7 @@ /* infodoc.c -- Functions which build documentation nodes. - $Id: infodoc.c,v 1.4 1997/07/25 21:08:40 karl Exp $ + $Id: infodoc.c,v 1.23 1999/09/25 16:10:04 karl Exp $ - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,14 +21,9 @@ #include "info.h" -/* Normally we do not define HELP_NODE_GETS_REGENERATED because the - contents of the help node currently can never change once an info - session has been started. You should consider defining this in - the case that you place information about dynamic variables in the - help text. When that happens, the contents of the help node will - change dependent on the value of those variables, and the user will - expect to see those changes. */ -/* #define HELP_NODE_GETS_REGENERATED 1 */ +/* HELP_NODE_GETS_REGENERATED is always defined now that keys may get + rebound, or other changes in the help text may occur. */ +#define HELP_NODE_GETS_REGENERATED 1 /* **************************************************************** */ /* */ @@ -47,40 +42,94 @@ static char *internal_info_help_node_contents = (char *)NULL; /* The static text which appears in the internal info help node. */ static char *info_internal_help_text[] = { - N_ ("Basic Commands in Info Windows"), - "******************************", - "", - " h Invoke the Info tutorial.", - " CTRL-x 0 Quit this help.", - " q Quit Info altogether.", - "", - "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.", - "", - "Other commands:", - "--------------------", - " 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.", + N_("Basic Commands in Info Windows\n"), + N_("******************************\n"), + "\n", + N_(" %-10s Quit this help.\n"), + N_(" %-10s Quit Info altogether.\n"), + N_(" %-10s Invoke the Info tutorial.\n"), + "\n", + N_("Moving within a node:\n"), + N_("---------------------\n"), + N_(" %-10s Scroll forward a page.\n"), + N_(" %-10s Scroll backward a page.\n"), + N_(" %-10s Go to the beginning of this node.\n"), + N_(" %-10s Go to the end of this node.\n"), + N_(" %-10s Scroll forward 1 line.\n"), + N_(" %-10s Scroll backward 1 line.\n"), + "\n", + N_("Selecting other nodes:\n"), + N_("----------------------\n"), + N_(" %-10s Move to the `next' node of this node.\n"), + N_(" %-10s Move to the `previous' node of this node.\n"), + N_(" %-10s Move `up' from this node.\n"), + N_(" %-10s Pick menu item specified by name.\n"), + N_(" Picking a menu item causes another node to be selected.\n"), + N_(" %-10s Follow a cross reference. Reads name of reference.\n"), + N_(" %-10s Move to the last node seen in this window.\n"), + N_(" %-10s Skip to next hypertext link within this node.\n"), + N_(" %-10s Follow the hypertext link under cursor.\n"), + N_(" %-10s Move to the `directory' node. Equivalent to `g (DIR)'.\n"), + N_(" %-10s Move to the Top node. Equivalent to `g Top'.\n"), + "\n", + N_("Other commands:\n"), + N_("---------------\n"), + N_(" %-10s Pick first ... ninth item in node's menu.\n"), + N_(" %-10s Pick last item in node's menu.\n"), + N_(" %-10s Search for a specified string in the index entries of this Info\n"), + N_(" file, and select the node referenced by the first entry found.\n"), + N_(" %-10s Move to node specified by name.\n"), + N_(" You may include a filename as well, as in (FILENAME)NODENAME.\n"), + N_(" %-10s Search forward through this Info file for a specified string,\n"), + N_(" and select the node in which the next occurrence is found.\n"), + N_(" %-10s Search backward in this Info file for a specified string,\n"), + N_(" and select the node in which the next occurrence is found.\n"), + NULL +}; + +static char *info_help_keys_text[][2] = { + { "", "" }, + { "", "" }, + { "", "" }, + { "CTRL-x 0", "CTRL-x 0" }, + { "q", "q" }, + { "h", "ESC h" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "SPC", "SPC" }, + { "DEL", "b" }, + { "b", "ESC b" }, + { "e", "ESC e" }, + { "ESC 1 SPC", "RET" }, + { "ESC 1 DEL", "y" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "n", "CTRL-x n" }, + { "p", "CTRL-x p" }, + { "u", "CTRL-x u" }, + { "m", "ESC m" }, + { "", "" }, + { "f", "ESC f" }, + { "l", "l" }, + { "TAB", "TAB" }, + { "RET", "CTRL-x RET" }, + { "d", "ESC d" }, + { "t", "ESC t" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "1-9", "ESC 1-9" }, + { "0", "ESC 0" }, + { "i", "CTRL-x i" }, + { "", "" }, + { "g", "CTRL-x g" }, + { "", "" }, + { "s", "/" }, + { "", "" }, + { "ESC - s", "?" }, + { "", "" }, NULL }; @@ -163,15 +212,21 @@ dump_map_to_message_buffer (prefix, map) } } -/* How to create internal_info_help_node. */ +/* How to create internal_info_help_node. HELP_IS_ONLY_WINDOW_P says + whether we're going to end up in a second (or more) window of our + own, or whether there's only one window and we're going to usurp it. + This determines how to quit the help window. Maybe we should just + make q do the right thing in both cases. */ + static void -create_internal_info_help_node () +create_internal_info_help_node (help_is_only_window_p) + int help_is_only_window_p; { register int i; - char *contents = (char *)NULL; NODE *node; + char *contents = NULL; -#if !defined (HELP_NODE_GETS_REGENERATED) +#ifndef HELP_NODE_GETS_REGENERATED if (internal_info_help_node_contents) contents = internal_info_help_node_contents; #endif /* !HELP_NODE_GETS_REGENERATED */ @@ -183,16 +238,30 @@ create_internal_info_help_node () initialize_message_buffer (); for (i = 0; info_internal_help_text[i]; i++) - printf_to_message_buffer ("%s\n", info_internal_help_text[i]); + { + /* Don't translate blank lines, gettext outputs the po file + header in that case. We want a blank line. */ + char *msg = *(info_internal_help_text[i]) + ? _(info_internal_help_text[i]) + : info_internal_help_text[i]; + char *key = info_help_keys_text[i][vi_keys_p]; + + /* If we have only one window (because the window size was too + small to split it), CTRL-x 0 doesn't work to `quit' help. */ + if (STREQ (key, "CTRL-x 0") && help_is_only_window_p) + key = "l"; + + printf_to_message_buffer (msg, key); + } 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 (_("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"); + 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"); + printf_to_message_buffer (_("Commands available in the echo area:\n\n")); dump_map_to_message_buffer ("", echo_area_keymap); #if defined (NAMED_FUNCTIONS) @@ -215,7 +284,11 @@ create_internal_info_help_node () printf_to_message_buffer ("M-x %s\n %s\n", function_doc_array[i].func_name, - replace_in_documentation (function_doc_array[i].doc)); + replace_in_documentation (strlen (function_doc_array[i].doc) + == 0 + ? function_doc_array[i].doc + : _(function_doc_array[i].doc))); + } } @@ -258,17 +331,22 @@ create_internal_info_help_node () } /* Return a window which is the window showing help in this Info. */ + +/* If the eligible window's height is >= this, split it to make the help + window. Otherwise display the help window in the current window. */ +#define HELP_SPLIT_SIZE 24 + static WINDOW * info_find_or_create_help_window () { - WINDOW *help_window, *eligible, *window; - - eligible = (WINDOW *)NULL; - help_window = get_internal_info_window (info_help_nodename); + int help_is_only_window_p; + WINDOW *eligible = NULL; + WINDOW *help_window = get_window_of_node (internal_info_help_node); /* If we couldn't find the help window, then make it. */ if (!help_window) { + WINDOW *window; int max = 0; for (window = windows; window; window = window->next) @@ -281,23 +359,29 @@ info_find_or_create_help_window () } if (!eligible) - return ((WINDOW *)NULL); + return NULL; } -#if !defined (HELP_NODE_GETS_REGENERATED) +#ifndef HELP_NODE_GETS_REGENERATED else - return (help_window); -#endif /* !HELP_NODE_GETS_REGENERATED */ - - /* Make sure that we have a node containing the help text. */ - create_internal_info_help_node (); + /* help window is static, just return it. */ + return help_window; +#endif /* not HELP_NODE_GETS_REGENERATED */ + + /* Make sure that we have a node containing the help text. The + argument is false if help will be the only window (so l must be used + to quit help), true if help will be one of several visible windows + (so CTRL-x 0 must be used to quit help). */ + help_is_only_window_p + = (help_window && !windows->next + || !help_window && eligible->height < HELP_SPLIT_SIZE); + create_internal_info_help_node (help_is_only_window_p); /* Either use the existing window to display the help node, or create a new window if there was no existing help window. */ if (!help_window) - { - /* Split the largest window into 2 windows, and show the help text + { /* Split the largest window into 2 windows, and show the help text in that window. */ - if (eligible->height > 30) + if (eligible->height >= HELP_SPLIT_SIZE) { active_window = eligible; help_window = window_make_window (internal_info_help_node); @@ -310,8 +394,7 @@ info_find_or_create_help_window () } } else - { - /* Case where help node always gets regenerated, and we have an + { /* Case where help node always gets regenerated, and we have an existing window in which to place the node. */ if (active_window != help_window) { @@ -321,7 +404,7 @@ info_find_or_create_help_window () window_set_node_of_window (active_window, internal_info_help_node); } remember_window_and_node (help_window, help_window->node); - return (help_window); + return help_window; } /* Create or move to the help window. */ @@ -337,7 +420,7 @@ DECLARE_INFO_COMMAND (info_get_help_window, _("Display help message")) } else { - info_error (CANT_MAKE_HELP); + info_error (msg_cant_make_help); } } @@ -381,7 +464,7 @@ DECLARE_INFO_COMMAND (info_get_info_help_node, _("Visit Info node `(info)Help'") if (info_recent_file_error) info_error (info_recent_file_error); else - info_error (CANT_FILE_NODE, "Info", nodename); + info_error (msg_cant_file_node, "Info", nodename); } else { @@ -418,7 +501,9 @@ function_documentation (function) if (function == function_doc_array[i].func) break; - return (replace_in_documentation (function_doc_array[i].doc)); + return replace_in_documentation ((strlen (function_doc_array[i].doc) == 0) + ? function_doc_array[i].doc + : _(function_doc_array[i].doc)); } #if defined (NAMED_FUNCTIONS) @@ -475,21 +560,21 @@ DECLARE_INFO_COMMAND (describe_key, _("Print documentation for KEY")) char *rep; Keymap map; - keyname[0] = '\0'; + keyname[0] = 0; map = window->keymap; - while (1) + for (;;) { 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 (Meta_p (keystroke)) { if (map[ESC].type != ISKMAP) { window_message_in_echo_area - (_("ESC %s is undefined."), pretty_keyname (UnMeta (keystroke))); + (_("ESC %s is undefined."), pretty_keyname (UnMeta (keystroke))); return; } @@ -627,7 +712,7 @@ replace_in_documentation (string) /* 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 + /* 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) @@ -687,7 +772,7 @@ where_is_internal (map, function) 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++) @@ -718,13 +803,13 @@ where_is_internal (map, function) } } - return ((char *)NULL); + return NULL; } extern char *read_function_name (); DECLARE_INFO_COMMAND (info_where_is, - "Show what to type to execute a given command") + _("Show what to type to execute a given command")) { char *command_name; diff --git a/contrib/texinfo/info/infomap.c b/contrib/texinfo/info/infomap.c index 7591283..932435e 100644 --- a/contrib/texinfo/info/infomap.c +++ b/contrib/texinfo/info/infomap.c @@ -1,7 +1,7 @@ /* infomap.c -- Keymaps for Info. - $Id: infomap.c,v 1.7 1997/07/31 20:37:32 karl Exp $ + $Id: infomap.c,v 1.20 1999/06/25 21:57:40 karl Exp $ - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -67,7 +67,7 @@ keymap_copy_keymap (map) return (keymap); } -/* Free the keymap and it's descendents. */ +/* Free the keymap and its descendants. */ void keymap_discard_keymap (map) Keymap (map); @@ -141,49 +141,54 @@ keymap_bind_keyseq (map, keyseq, keyentry) /* Initialize the standard info keymaps. */ -Keymap info_keymap = (Keymap)NULL; -Keymap echo_area_keymap = (Keymap)NULL; +Keymap info_keymap = NULL; +Keymap echo_area_keymap = NULL; -void -initialize_info_keymaps () +static void +initialize_emacs_like_keymaps () { - register int i; + 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 (); } + 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 (); + + /* Bind the echo area insert routines. Let's make all characters + insertable by default, regardless of which character set we might + be using. */ + for (i = 0; i < 256; i++) + echo_area_keymap[i].function = ea_insert; + + 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)[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; + info_keymap['-'].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; @@ -203,7 +208,12 @@ initialize_info_keymaps () map[SPC].function = ea_complete; map[TAB].function = ea_complete; map['?'].function = ea_possible_completions; +#ifdef __MSDOS__ + /* PC users will lynch me if I don't give them their usual DEL effect... */ + map[DEL].function = ea_delete; +#else map[DEL].function = ea_rubout; +#endif /* Bind the echo area ESC keymap. */ map = (Keymap)echo_area_keymap[ESC].function; @@ -272,6 +282,7 @@ initialize_info_keymaps () map[Control ('u')].function = info_universal_argument; map[Control ('v')].function = info_scroll_forward; map[','].function = info_next_index_match; + map['/'].function = info_search; for (i = '1'; i < '9' + 1; i++) map[i].function = info_menu_digit; @@ -288,15 +299,19 @@ initialize_info_keymaps () map['e'].function = info_end_of_node; map['f'].function = info_xref_item; map['g'].function = info_goto_node; + map['G'].function = info_menu_sequence; map['h'].function = info_get_info_help_node; map['i'].function = info_index_search; + map['I'].function = info_goto_invocation_node; map['l'].function = info_history_node; map['m'].function = info_menu_item; map['n'].function = info_next_node; + map['O'].function = info_goto_invocation_node; map['p'].function = info_prev_node; map['q'].function = info_quit; map['r'].function = info_xref_item; map['s'].function = info_search; + map['S'].function = info_search_case_sensitively; map['t'].function = info_top_node; map['u'].function = info_up_node; map[DEL].function = info_scroll_backward; @@ -316,6 +331,281 @@ initialize_info_keymaps () #if defined (NAMED_FUNCTIONS) map['x'].function = info_execute_command; #endif /* NAMED_FUNCTIONS */ + map[DEL].function = info_scroll_other_window_backward; + + /* 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['n'].function = info_search_next; + map['N'].function = info_search_previous; + map['o'].function = info_next_window; + map['t'].function = info_tile_windows; + map['w'].function = info_toggle_wrap; + + /* Arrow key bindings for Info windows keymap. */ + map = info_keymap; + keymap_bind_keyseq (map, term_kN, &map[Control ('v')]); /* pagedown */ + keymap_bind_keyseq (map, term_ku, &map[Control ('p')]); /* up */ + keymap_bind_keyseq (map, "\033OA", &map[Control ('p')]); + keymap_bind_keyseq (map, "\033[A", &map[Control ('p')]); + keymap_bind_keyseq (map, term_kd, &map[Control ('n')]); /* down */ + keymap_bind_keyseq (map, "\033OB", &map[Control ('n')]); + keymap_bind_keyseq (map, "\033[B", &map[Control ('n')]); + keymap_bind_keyseq (map, term_kr, &map[Control ('f')]); /* right */ + keymap_bind_keyseq (map, "\033OC", &map[Control ('f')]); + keymap_bind_keyseq (map, "\033[C", &map[Control ('f')]); + keymap_bind_keyseq (map, term_kl, &map[Control ('b')]); /* left */ + keymap_bind_keyseq (map, "\033OD", &map[Control ('b')]); + keymap_bind_keyseq (map, "\033[D", &map[Control ('b')]); + + map = (Keymap)info_keymap[ESC].function; + keymap_bind_keyseq (map, term_kl, &map['b']); /* left */ + keymap_bind_keyseq (map, "\033OA", &map['b']); + keymap_bind_keyseq (map, "\033[A", &map['b']); + keymap_bind_keyseq (map, term_kr, &map['f']); /* right */ + keymap_bind_keyseq (map, "\033OB", &map['f']); + keymap_bind_keyseq (map, "\033[B", &map['f']); + keymap_bind_keyseq (map, term_kN, &map[Control ('v')]); /* pagedown */ + keymap_bind_keyseq (map, term_kP, &map[DEL]); /* pageup */ + + /* The alternative to this definition of a `main map' key in the + `ESC map' section, is something like: + keymap_bind_keyseq (map, term_kP, &((KeyMap)map[ESC].function).map['v']); + */ + keymap_bind_keyseq (info_keymap/*sic*/, term_kP, &map['v']); /* pageup */ +} + +static void +initialize_vi_like_keymaps () +{ + register int i; + Keymap map; + + if (!info_keymap) + { + info_keymap = keymap_make_keymap (); + echo_area_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 (); + + /* Bind the echo area insert routines. */ + for (i = 0; i < 256; i++) + echo_area_keymap[i].function = ea_insert; + + 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++) + { + info_keymap[i].function = + ((Keymap) echo_area_keymap[ESC].function)[i].function = + info_add_digit_to_numeric_arg; + } + info_keymap['-'].function = + ((Keymap) echo_area_keymap[ESC].function)['-'].function = + info_add_digit_to_numeric_arg; + + /* Bind the echo area routines. */ + map = echo_area_keymap; + + 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 = ea_abort; + map[Control ('v')].function = ea_quoted_insert; + 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; +#ifdef __MSDOS__ + /* PC users will lynch me if I don't give them their usual DEL effect... */ + map[DEL].function = ea_delete; +#else + map[DEL].function = ea_rubout; +#endif + + /* Bind the echo area ESC keymap. */ + map = (Keymap)echo_area_keymap[ESC].function; + + map[Control ('g')].function = ea_abort; + map[Control ('h')].function = ea_backward_kill_word; + map[Control ('v')].function = ea_scroll_completions_window; + map['0'].function = ea_beg_of_line; + map['$'].function = ea_end_of_line; + map['b'].function = ea_backward_word; + map['d'].function = ea_kill_word; + map['f'].function = ea_forward_word; + map['h'].function = ea_forward; + map['l'].function = ea_backward; + map['w'].function = ea_forward_word; + map['x'].function = ea_delete; + map['X'].function = ea_kill_word; + map['y'].function = ea_yank_pop; + map['?'].function = ea_possible_completions; + map[TAB].function = ea_tab_insert; + map[DEL].function = ea_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; + + /* Arrow key bindings for echo area keymaps. It seems that some + terminals do not match their termcap entries, so it's best to just + define everything with both of the usual prefixes. */ + map = echo_area_keymap; + keymap_bind_keyseq (map, term_ku, &map[Control ('p')]); /* up */ + keymap_bind_keyseq (map, "\033OA", &map[Control ('p')]); + keymap_bind_keyseq (map, "\033[A", &map[Control ('p')]); + keymap_bind_keyseq (map, term_kd, &map[Control ('n')]); /* down */ + keymap_bind_keyseq (map, "\033OB", &map[Control ('n')]); + keymap_bind_keyseq (map, "\033[B", &map[Control ('n')]); + keymap_bind_keyseq (map, term_kr, &map[Control ('f')]); /* right */ + keymap_bind_keyseq (map, "\033OC", &map[Control ('f')]); + keymap_bind_keyseq (map, "\033[C", &map[Control ('f')]); + keymap_bind_keyseq (map, term_kl, &map[Control ('b')]); /* left */ + keymap_bind_keyseq (map, "\033OD", &map[Control ('b')]); + keymap_bind_keyseq (map, "\033[D", &map[Control ('b')]); + + map = (Keymap)echo_area_keymap[ESC].function; + keymap_bind_keyseq (map, term_kl, &map['b']); /* left */ + keymap_bind_keyseq (map, "\033OA", &map['b']); + keymap_bind_keyseq (map, "\033[A", &map['b']); + keymap_bind_keyseq (map, term_kr, &map['f']); /* right */ + keymap_bind_keyseq (map, "\033OB", &map['f']); + keymap_bind_keyseq (map, "\033[B", &map['f']); + + /* Bind commands for Info window keymaps. */ + map = info_keymap; + map[TAB].function = info_move_to_next_xref; + map[LFD].function = info_down_line; + map[RET].function = info_down_line; + map[SPC].function = info_scroll_forward; + map[Control ('a')].function = info_beginning_of_line; + map[Control ('b')].function = info_scroll_backward; + map[Control ('d')].function = info_scroll_half_screen_down; + map[Control ('e')].function = info_down_line; + map[Control ('f')].function = info_scroll_forward; + map[Control ('g')].function = info_abort_key; + map[Control ('k')].function = info_up_line; + map[Control ('l')].function = info_redraw_display; + map[Control ('n')].function = info_down_line; + map[Control ('p')].function = info_up_line; + map[Control ('r')].function = info_redraw_display; + map[Control ('s')].function = isearch_forward; + map[Control ('u')].function = info_scroll_half_screen_up; + map[Control ('v')].function = info_scroll_forward; + map[Control ('y')].function = info_up_line; + map[','].function = info_next_index_match; + map['/'].function = info_search; + + for (i = '1'; i < '9' + 1; i++) + ((Keymap) info_keymap[ESC].function)[i].function = info_menu_digit; + ((Keymap) info_keymap[ESC].function)['0'].function = info_last_menu_item; + + map['<'].function = info_first_node; + map['>'].function = info_last_node; + map['?'].function = info_search_backward; + map['['].function = info_global_prev_node; + map[']'].function = info_global_next_node; + map['\''].function = info_history_node; + + map['b'].function = info_scroll_backward; + map['d'].function = info_scroll_half_screen_down; + map['e'].function = info_down_line; + map['E'].function = info_view_file; + map['f'].function = info_scroll_forward; + map['F'].function = info_scroll_forward; + map['g'].function = info_first_node; + map['G'].function = info_last_node; + map['h'].function = info_get_help_window; + map['H'].function = info_get_help_window; + map['i'].function = info_index_search; + map['I'].function = info_goto_invocation_node; + map['j'].function = info_down_line; + map['k'].function = info_up_line; + map['l'].function = info_history_node; + map['m'].function = info_menu_item; + map['n'].function = info_search_next; + map['N'].function = info_search_previous; + map['O'].function = info_goto_invocation_node; + map['p'].function = info_prev_node; + map['q'].function = info_quit; + map['Q'].function = info_quit; + map['r'].function = info_redraw_display; + map['R'].function = info_redraw_display; + map['s'].function = info_search; + map['S'].function = info_search_case_sensitively; + map['t'].function = info_top_node; + map['u'].function = info_scroll_half_screen_up; + map['w'].function = info_scroll_backward_set_window; + map['y'].function = info_up_line; + map['z'].function = info_scroll_forward_set_window; + map['Z'].function = NULL; /* unbind, so it works to bind "ZZ" below */ + map[DEL].function = info_scroll_backward; + keymap_bind_keyseq (map, ":q", &map['q']); + keymap_bind_keyseq (map, ":Q", &map['q']); + keymap_bind_keyseq (map, "ZZ", &map['q']); + + /* 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[SPC].function = info_scroll_forward; + map[Control ('v')].function = info_scroll_other_window; + map['<'].function = info_beginning_of_node; + map['>'].function = info_end_of_node; + map['/'].function = info_search; + map['?'].function = info_search_backward; + 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_select_reference_this_line; + map['h'].function = info_get_info_help_node; + map['m'].function = info_menu_item; + map['n'].function = info_search; + map['N'].function = info_search_backward; + map['r'].function = isearch_backward; + map['s'].function = isearch_forward; + map['t'].function = info_top_node; + map['v'].function = info_scroll_backward; +#if defined (NAMED_FUNCTIONS) + map['x'].function = info_execute_command; +#endif /* NAMED_FUNCTIONS */ + map[DEL].function = info_scroll_other_window_backward; /* Bind members in the Control-X map for Info windows. */ map = (Keymap)info_keymap[Control ('x')].function; @@ -325,15 +615,27 @@ initialize_info_keymaps () map[Control ('f')].function = info_view_file; map[Control ('g')].function = info_abort_key; map[Control ('v')].function = info_view_file; + map[LFD].function = info_select_reference_this_line; + map[RET].function = info_select_reference_this_line; 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['g'].function = info_goto_node; + map['i'].function = info_index_search; + map['I'].function = info_goto_invocation_node; map['k'].function = info_kill_node; + map['n'].function = info_next_node; map['o'].function = info_next_window; + map['O'].function = info_goto_invocation_node; + map['p'].function = info_prev_node; + map['r'].function = info_xref_item; map['t'].function = info_tile_windows; + map['u'].function = info_up_node; map['w'].function = info_toggle_wrap; + map[','].function = info_next_index_match; + keymap_bind_keyseq (info_keymap, ":e", &map[Control ('v')]); /* Arrow key bindings for Info windows keymap. */ map = info_keymap; @@ -359,6 +661,7 @@ initialize_info_keymaps () keymap_bind_keyseq (map, "\033OB", &map['f']); keymap_bind_keyseq (map, "\033[B", &map['f']); keymap_bind_keyseq (map, term_kN, &map[Control ('v')]); /* pagedown */ + keymap_bind_keyseq (map, term_kP, &map[DEL]); /* pageup */ /* The alternative to this definition of a `main map' key in the `ESC map' section, is something like: @@ -366,3 +669,13 @@ initialize_info_keymaps () */ keymap_bind_keyseq (info_keymap/*sic*/, term_kP, &map['v']); /* pageup */ } + +void +initialize_info_keymaps () +{ + if (vi_keys_p) + initialize_vi_like_keymaps (); + else + initialize_emacs_like_keymaps (); +} + diff --git a/contrib/texinfo/info/m-x.c b/contrib/texinfo/info/m-x.c index 28b8e80..2fc5a60 100644 --- a/contrib/texinfo/info/m-x.c +++ b/contrib/texinfo/info/m-x.c @@ -1,7 +1,7 @@ -/* m-x.c -- Meta-X minibuffer reader. - $Id: m-x.c,v 1.5 1997/07/24 21:28:00 karl Exp $ +/* m-x.c -- Meta-x minibuffer reader. + $Id: m-x.c,v 1.8 1999/06/25 21:57:40 karl Exp $ - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98 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 @@ -149,7 +149,7 @@ DECLARE_INFO_COMMAND (info_execute_command, DECLARE_INFO_COMMAND (set_screen_height, _("Set the height of the displayed window")) { - int new_height; + int new_height, old_height = screenheight; if (info_explicit_arg || count != 1) new_height = count; @@ -185,6 +185,20 @@ DECLARE_INFO_COMMAND (set_screen_height, terminal_clear_screen (); display_clear_display (the_display); screenheight = new_height; - display_initialize_display (screenwidth, screenheight); - window_new_screen_size (screenwidth, screenheight); +#ifdef SET_SCREEN_SIZE_HELPER + SET_SCREEN_SIZE_HELPER; +#endif + if (screenheight == old_height) + { + /* Display dimensions didn't actually change, so + window_new_screen_size won't do anything, but we've + already cleared the display above. Undo the damage. */ + window_mark_chain (windows, W_UpdateWindow); + display_update_display (windows); + } + else + { + display_initialize_display (screenwidth, screenheight); + window_new_screen_size (screenwidth, screenheight); + } } diff --git a/contrib/texinfo/info/man.c b/contrib/texinfo/info/man.c index a669595..ee68cbb 100644 --- a/contrib/texinfo/info/man.c +++ b/contrib/texinfo/info/man.c @@ -1,7 +1,7 @@ /* man.c: How to read and format man files. - $Id: man.c,v 1.6 1997/07/31 23:49:59 karl Exp $ + $Id: man.c,v 1.13 1999/07/05 20:43:23 karl Exp $ - Copyright (C) 1995, 97 Free Software Foundation, Inc. + Copyright (C) 1995, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,6 +44,14 @@ # endif /* !hpux */ #endif /* FD_SET */ +#if STRIP_DOT_EXE +static char const * const exec_extensions[] = { + ".exe", ".com", ".bat", ".btm", ".sh", ".ksh", ".pl", ".sed", "", NULL +}; +#else +static char const * const exec_extensions[] = { "", NULL }; +#endif + static char *read_from_fd (); static void clean_manpage (); static NODE *manpage_node_of_file_buffer (); @@ -76,6 +84,7 @@ get_manpage_node (file_buffer, pagename) char header[1024]; long oldsize, newsize; int hlen, plen; + char *old_contents = file_buffer->contents; sprintf (header, "\n\n%c\n%s %s, %s %s, %s (dir)\n\n", INFO_COOKIE, @@ -89,13 +98,49 @@ get_manpage_node (file_buffer, pagename) file_buffer->contents = (char *)xrealloc (file_buffer->contents, 1 + newsize); memcpy (file_buffer->contents + oldsize, header, hlen); - oldsize += hlen; - memcpy (file_buffer->contents + oldsize, page, plen); + memcpy (file_buffer->contents + oldsize + hlen, page, plen); file_buffer->contents[newsize] = '\0'; file_buffer->filesize = newsize; file_buffer->finfo.st_size = newsize; build_tags_and_nodes (file_buffer); free (page); + /* We have just relocated file_buffer->contents from under + the feet of info_windows[] array. Therefore, all the + nodes on that list which are showing man pages have their + contents member pointing into the blue. Undo that harm. */ + if (old_contents && oldsize && old_contents != file_buffer->contents) + { + int iw; + INFO_WINDOW *info_win; + char *old_contents_end = old_contents + oldsize; + + for (iw = 0; (info_win = info_windows[iw]); iw++) + { + int in; + + for (in = 0; in < info_win->nodes_index; in++) + { + NODE *node = info_win->nodes[in]; + + /* It really only suffices to see that node->filename + is "*manpages*". But after several hours of + debugging this, would you blame me for being a bit + paranoid? */ + if (node && node->filename && node->contents && + strcmp (node->filename, + MANPAGE_FILE_BUFFER_NAME) == 0 && + node->contents >= old_contents && + node->contents + node->nodelen <= old_contents_end) + { + info_win->nodes[in] = + manpage_node_of_file_buffer (file_buffer, + node->nodename); + free (node->nodename); + free (node); + } + } + } + } } node = manpage_node_of_file_buffer (file_buffer, pagename); @@ -134,6 +179,8 @@ executable_file_in_path (filename, path) while ((temp_dirname = extract_colon_unit (path, &dirname_index))) { char *temp; + char *temp_end; + int i; /* Expand a leading tilde if one is present. */ if (*temp_dirname == '~') @@ -145,22 +192,30 @@ executable_file_in_path (filename, path) temp_dirname = expanded_dirname; } - temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename)); + temp = (char *)xmalloc (34 + strlen (temp_dirname) + strlen (filename)); strcpy (temp, temp_dirname); - if (temp[(strlen (temp)) - 1] != '/') + if (!IS_SLASH (temp[(strlen (temp)) - 1])) strcat (temp, "/"); strcat (temp, filename); + temp_end = temp + strlen (temp); free (temp_dirname); - statable = (stat (temp, &finfo) == 0); - - /* If we have found a regular executable file, then use it. */ - if ((statable) && (S_ISREG (finfo.st_mode)) && - (access (temp, X_OK) == 0)) - return (temp); - else - free (temp); + /* Look for FILENAME, possibly with any of the extensions + in EXEC_EXTENSIONS[]. */ + for (i = 0; exec_extensions[i]; i++) + { + if (exec_extensions[i][0]) + strcpy (temp_end, exec_extensions[i]); + statable = (stat (temp, &finfo) == 0); + + /* If we have found a regular executable file, then use it. */ + if ((statable) && (S_ISREG (finfo.st_mode)) && + (access (temp, X_OK) == 0)) + return (temp); + } + + free (temp); } return ((char *)NULL); } @@ -210,13 +265,14 @@ get_page_and_section (pagename) } } +#if PIPE_USE_FORK static void reap_children (sig) int sig; { - int status; - wait (&status); + wait (NULL); } +#endif static char * get_manpage_contents (pagename) @@ -225,7 +281,8 @@ get_manpage_contents (pagename) static char *formatter_args[4] = { (char *)NULL }; int pipes[2]; pid_t child; - char *formatted_page = (char *)NULL; + RETSIGTYPE (*sigsave) (); + char *formatted_page = NULL; int arg_index = 1; if (formatter_args[0] == (char *)NULL) @@ -245,12 +302,12 @@ get_manpage_contents (pagename) /* Open a pipe to this program, read the output, and save it away in FORMATTED_PAGE. The reader end of the pipe is pipes[0]; the writer end is pipes[1]. */ +#if PIPE_USE_FORK pipe (pipes); - signal (SIGCHLD, reap_children); + sigsave = signal (SIGCHLD, reap_children); child = fork (); - if (child == -1) return ((char *)NULL); @@ -261,14 +318,14 @@ get_manpage_contents (pagename) close (pipes[1]); formatted_page = read_from_fd (pipes[0]); close (pipes[0]); + signal (SIGCHLD, sigsave); } else - { - /* In the child, close the read end of the pipe, make the write end + { /* In the child, close the read end of the pipe, make the write end of the pipe be stdout, and execute the man page formatter. */ close (pipes[0]); - close (fileno (stderr)); - close (fileno (stdin)); /* Don't print errors. */ + freopen (NULL_DEVICE, "w", stderr); + freopen (NULL_DEVICE, "r", stdin); dup2 (pipes[1], fileno (stdout)); execv (formatter_args[0], formatter_args); @@ -276,8 +333,39 @@ get_manpage_contents (pagename) /* If we get here, we couldn't exec, so close out the pipe and exit. */ close (pipes[1]); - exit (0); + xexit (0); } +#else /* !PIPE_USE_FORK */ + /* Cannot fork/exec, but can popen/pclose. */ + { + FILE *fpipe; + char *cmdline = xmalloc (strlen (formatter_args[0]) + + strlen (manpage_pagename) + + (arg_index > 2 ? strlen (manpage_section) : 0) + + 3); + int save_stderr = dup (fileno (stderr)); + int fd_err = open (NULL_DEVICE, O_WRONLY, 0666); + + if (fd_err > 2) + dup2 (fd_err, fileno (stderr)); /* Don't print errors. */ + sprintf (cmdline, "%s %s %s", formatter_args[0], manpage_pagename, + arg_index > 2 ? manpage_section : ""); + fpipe = popen (cmdline, "r"); + free (cmdline); + if (fd_err > 2) + close (fd_err); + dup2 (save_stderr, fileno (stderr)); + if (fpipe == 0) + return ((char *)NULL); + formatted_page = read_from_fd (fileno (fpipe)); + if (pclose (fpipe) == -1) + { + if (formatted_page) + free (formatted_page); + return ((char *)NULL); + } + } +#endif /* !PIPE_USE_FORK */ /* If we have the page, then clean it up. */ if (formatted_page) @@ -342,10 +430,11 @@ manpage_node_of_file_buffer (file_buffer, pagename) { node = (NODE *)xmalloc (sizeof (NODE)); node->filename = file_buffer->filename; - node->nodename = tag->nodename; + node->nodename = xstrdup (tag->nodename); node->contents = file_buffer->contents + tag->nodestart; node->nodelen = tag->nodelen; node->flags = 0; + node->display_pos = 0; node->parent = (char *)NULL; node->flags = (N_HasTagsTable | N_IsManPage); node->contents += skip_node_separator (node->contents); diff --git a/contrib/texinfo/info/nodemenu.c b/contrib/texinfo/info/nodemenu.c index 2632657..b109057 100644 --- a/contrib/texinfo/info/nodemenu.c +++ b/contrib/texinfo/info/nodemenu.c @@ -1,7 +1,7 @@ -/* nodemenu.c -- Produce a menu of all visited nodes. - $Id: nodemenu.c,v 1.7 1997/07/24 21:30:30 karl Exp $ +/* nodemenu.c -- produce a menu of all visited nodes. + $Id: nodemenu.c,v 1.8 1998/06/28 19:54:27 karl Exp $ - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98 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 @@ -168,7 +168,9 @@ get_visited_nodes (filter_func) /* Delete duplicates. */ for (i = 0, newlen = 1; i < lines_index - 1; i++) { - if (strcmp (lines[i], lines[i + 1]) == 0) + /* Use FILENAME_CMP here, since the most important piece + of info in each line is the file name of the node. */ + if (FILENAME_CMP (lines[i], lines[i + 1]) == 0) { free (lines[i]); lines[i] = (char *)NULL; diff --git a/contrib/texinfo/info/nodes.c b/contrib/texinfo/info/nodes.c index f2737e7..0aaee52 100644 --- a/contrib/texinfo/info/nodes.c +++ b/contrib/texinfo/info/nodes.c @@ -1,9 +1,7 @@ -/* nodes.c -- How to get an Info file and node. */ +/* nodes.c -- how to get an Info file and node. + $Id: nodes.c,v 1.14 1999/08/15 10:18:09 karl Exp $ -/* This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993 Free Software Foundation, Inc. + Copyright (C) 1993, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,12 +30,6 @@ # include "man.h" #endif /* HANDLE_MAN_PAGES */ -/* **************************************************************** */ -/* */ -/* Functions Static to this File */ -/* */ -/* **************************************************************** */ - static void forget_info_file (), remember_info_file (); static void free_file_buffer_tags (), free_info_tag (); static void get_nodes_of_tags_table (), get_nodes_of_info_file (); @@ -50,8 +42,7 @@ static NODE *info_node_of_file_buffer_tags (); static long get_node_length (); /* Magic number that RMS used to decide how much a tags table pointer could - be off by. I feel that it should be much smaller, like on the order of - 4. */ + be off by. I feel that it should be much smaller, like 4. */ #define DEFAULT_INFO_FUDGE 1000 /* Passed to *_internal functions. INFO_GET_TAGS says to do what is @@ -59,46 +50,36 @@ static long get_node_length (); #define INFO_NO_TAGS 0 #define INFO_GET_TAGS 1 -/* **************************************************************** */ -/* */ -/* Global Variables */ -/* */ -/* **************************************************************** */ +/* Global variables. */ /* When non-zero, this is a string describing the recent file error. */ -char *info_recent_file_error = (char *)NULL; +char *info_recent_file_error = NULL; /* The list of already loaded nodes. */ -FILE_BUFFER **info_loaded_files = (FILE_BUFFER **)NULL; +FILE_BUFFER **info_loaded_files = NULL; /* The number of slots currently allocated to LOADED_FILES. */ int info_loaded_files_slots = 0; -/* **************************************************************** */ -/* */ -/* Public Functions for Node Manipulation */ -/* */ -/* **************************************************************** */ +/* Public functions for node manipulation. */ -/* Used to build "dir" menu from "localdir" files found in INFOPATH. */ +/* Used to build `dir' menu from `localdir' files found in INFOPATH. */ extern void maybe_build_dir_node (); /* Return a pointer to a NODE structure for the Info node (FILENAME)NODENAME. - FILENAME can be passed as NULL, in which case the filename of "dir" is used. - NODENAME can be passed as NULL, in which case the nodename of "Top" is used. - If the node cannot be found, return a NULL pointer. */ + If FILENAME is NULL, `dir' is used. + IF NODENAME is NULL, `Top' is used. + If the node cannot be found, return NULL. */ NODE * info_get_node (filename, nodename) char *filename, *nodename; { - FILE_BUFFER *file_buffer; NODE *node; + FILE_BUFFER *file_buffer = NULL; - file_buffer = (FILE_BUFFER *)NULL; - info_recent_file_error = (char *)NULL; - + info_recent_file_error = NULL; info_parse_node (nodename, DONT_SKIP_NEWLINES); - nodename = (char *)NULL; + nodename = NULL; if (info_parsed_filename) filename = info_parsed_filename; @@ -112,23 +93,23 @@ info_get_node (filename, nodename) /* If the file to be looked up is "dir", build the contents from all of the "dir"s and "localdir"s found in INFOPATH. */ - if (strcasecmp (filename, "dir") == 0) + if (is_dir_name (filename)) maybe_build_dir_node (filename); - /* Find the correct info file. */ + /* Find the correct info file, or give up. */ file_buffer = info_find_file (filename); - if (!file_buffer) { if (filesys_error_number) info_recent_file_error = filesys_error_string (filename, filesys_error_number); - return ((NODE *)NULL); + return NULL; } + /* Look for the node. */ node = info_get_node_of_file_buffer (nodename, file_buffer); - /* If the node looked for was "Top", try again looking for the node under - a slightly different name. */ + + /* If the node not found was "Top", try again with different case. */ if (!node && (nodename == NULL || strcasecmp (nodename, "Top") == 0)) { node = info_get_node_of_file_buffer ("Top", file_buffer); @@ -137,7 +118,8 @@ info_get_node (filename, nodename) if (!node) node = info_get_node_of_file_buffer ("TOP", file_buffer); } - return (node); + + return node; } /* Return a pointer to a NODE structure for the Info node NODENAME in @@ -149,12 +131,12 @@ info_get_node_of_file_buffer (nodename, file_buffer) char *nodename; FILE_BUFFER *file_buffer; { - NODE *node = (NODE *)NULL; + NODE *node = NULL; /* If we are unable to find the file, we have to give up. There isn't anything else we can do. */ if (!file_buffer) - return ((NODE *)NULL); + return NULL; /* If the file buffer was gc'ed, reload the contents now. */ if (!file_buffer->contents) @@ -171,11 +153,12 @@ info_get_node_of_file_buffer (nodename, file_buffer) { node = (NODE *)xmalloc (sizeof (NODE)); node->filename = file_buffer->fullpath; - node->parent = (char *)NULL; + node->parent = NULL; node->nodename = xstrdup ("*"); node->contents = file_buffer->contents; node->nodelen = file_buffer->filesize; node->flags = 0; + node->display_pos = 0; } #if defined (HANDLE_MAN_PAGES) /* If the file buffer is the magic one associated with manpages, call @@ -195,7 +178,7 @@ info_get_node_of_file_buffer (nodename, file_buffer) } /* Return the results of our node search. */ - return (node); + return node; } /* Locate the file named by FILENAME, and return the information structure @@ -207,7 +190,7 @@ FILE_BUFFER * info_find_file (filename) char *filename; { - return (info_find_file_internal (filename, INFO_GET_TAGS)); + return info_find_file_internal (filename, INFO_GET_TAGS); } /* Load the info file FILENAME, remembering information about it in a @@ -216,15 +199,11 @@ FILE_BUFFER * info_load_file (filename) char *filename; { - return (info_load_file_internal (filename, INFO_GET_TAGS)); + return info_load_file_internal (filename, INFO_GET_TAGS); } -/* **************************************************************** */ -/* */ -/* Private Functions Implementation */ -/* */ -/* **************************************************************** */ +/* Private functions implementation. */ /* The workhorse for info_find_file (). Non-zero 2nd argument says to try to build a tags table (or otherwise glean the nodes) for this @@ -236,30 +215,30 @@ info_find_file_internal (filename, get_tags) char *filename; int get_tags; { - register int i; - register FILE_BUFFER *file_buffer; + int i; + FILE_BUFFER *file_buffer; /* First try to find the file in our list of already loaded files. */ if (info_loaded_files) { for (i = 0; (file_buffer = info_loaded_files[i]); i++) - if ((strcmp (filename, file_buffer->filename) == 0) || - (strcmp (filename, file_buffer->fullpath) == 0) || - ((*filename != '/') && - strcmp (filename, - filename_non_directory (file_buffer->fullpath)) == 0)) + if ((FILENAME_CMP (filename, file_buffer->filename) == 0) || + (FILENAME_CMP (filename, file_buffer->fullpath) == 0) || + (!IS_ABSOLUTE (filename) && + FILENAME_CMP (filename, + filename_non_directory (file_buffer->fullpath)) == 0)) { struct stat new_info, *old_info; /* This file is loaded. If the filename that we want is specifically "dir", then simply return the file buffer. */ - if (strcasecmp (filename_non_directory (filename), "dir") == 0) - return (file_buffer); + if (is_dir_name (filename_non_directory (filename))) + return file_buffer; #if defined (HANDLE_MAN_PAGES) /* Do the same for the magic MANPAGE file. */ if (file_buffer->flags & N_IsManPage) - return (file_buffer); + return file_buffer; #endif /* HANDLE_MAN_PAGES */ /* The file appears to be already loaded, and it is not "dir". @@ -268,7 +247,7 @@ info_find_file_internal (filename, get_tags) if (stat (file_buffer->fullpath, &new_info) == -1) { filesys_error_number = errno; - return ((FILE_BUFFER *)NULL); + return NULL; } old_info = &file_buffer->finfo; @@ -288,10 +267,18 @@ info_find_file_internal (filename, get_tags) for this file, and there isn't one here, build the nodes for this file_buffer. In any case, return the file_buffer object. */ + if (!file_buffer->contents) + { + /* The file's contents have been gc'ed. Reload it. */ + info_reload_file_buffer_contents (file_buffer); + if (!file_buffer->contents) + return NULL; + } + if (get_tags && !file_buffer->tags) build_tags_and_nodes (file_buffer); - return (file_buffer); + return file_buffer; } } } @@ -310,7 +297,7 @@ info_find_file_internal (filename, get_tags) if (file_buffer) remember_info_file (file_buffer); - return (file_buffer); + return file_buffer; } /* The workhorse function for info_load_file (). Non-zero second argument @@ -325,8 +312,8 @@ info_load_file_internal (filename, get_tags) char *fullpath, *contents; long filesize; struct stat finfo; - int retcode; - FILE_BUFFER *file_buffer = (FILE_BUFFER *)NULL; + int retcode, compressed; + FILE_BUFFER *file_buffer = NULL; /* Get the full pathname of this file, as known by the info system. That is to say, search along INFOPATH and expand tildes, etc. */ @@ -338,18 +325,16 @@ info_load_file_internal (filename, get_tags) /* If the file referenced by the name returned from info_find_fullpath () doesn't exist, then try again with the last part of the filename appearing in lowercase. */ + /* This is probably not needed at all on those systems which define + FILENAME_CMP to be strcasecmp. But let's do it anyway, lest some + network redirector supports case sensitivity. */ if (retcode < 0) { char *lowered_name; char *basename; lowered_name = xstrdup (filename); - basename = (char *) strrchr (lowered_name, '/'); - - if (basename) - basename++; - else - basename = lowered_name; + basename = filename_non_directory (lowered_name); while (*basename) { @@ -369,14 +354,14 @@ info_load_file_internal (filename, get_tags) if (retcode < 0) { filesys_error_number = errno; - return ((FILE_BUFFER *)NULL); + return NULL; } /* Otherwise, try to load the file. */ - contents = filesys_read_info_file (fullpath, &filesize, &finfo); + contents = filesys_read_info_file (fullpath, &filesize, &finfo, &compressed); if (!contents) - return ((FILE_BUFFER *)NULL); + return NULL; /* The file was found, and can be read. Allocate FILE_BUFFER and fill in the various members. */ @@ -386,16 +371,16 @@ info_load_file_internal (filename, get_tags) file_buffer->finfo = finfo; file_buffer->filesize = filesize; file_buffer->contents = contents; - if (file_buffer->filesize != file_buffer->finfo.st_size) + if (compressed) file_buffer->flags |= N_IsCompressed; /* If requested, build the tags and nodes for this file buffer. */ if (get_tags) build_tags_and_nodes (file_buffer); - return (file_buffer); + return file_buffer; } - + /* Grovel FILE_BUFFER->contents finding tags and nodes, and filling in the various slots. This can also be used to rebuild a tag or node table. */ void @@ -527,6 +512,7 @@ get_nodes_of_info_file (file_buffer) int start, end; char *nodeline; TAG *entry; + int anchor = 0; /* Skip past the characters just found. */ binding.start = nodestart; @@ -537,6 +523,13 @@ get_nodes_of_info_file (file_buffer) /* Find "Node:" */ start = string_in_line (INFO_NODE_LABEL, nodeline); + /* No Node:. Maybe it's a Ref:. */ + if (start == -1) + { + start = string_in_line (INFO_REF_LABEL, nodeline); + if (start != -1) + anchor = 1; + } /* If not there, this is not the start of a node. */ if (start == -1) @@ -550,21 +543,24 @@ get_nodes_of_info_file (file_buffer) skip_node_characters (nodeline + start, DONT_SKIP_NEWLINES); /* Okay, we have isolated the node name, and we know where the - node starts. Remember this information in a NODE structure. */ - entry = (TAG *)xmalloc (sizeof (TAG)); - entry->nodename = (char *)xmalloc (1 + (end - start)); + node starts. Remember this information. */ + entry = xmalloc (sizeof (TAG)); + entry->nodename = xmalloc (1 + (end - start)); strncpy (entry->nodename, nodeline + start, end - start); - entry->nodename[end - start] = '\0'; + entry->nodename[end - start] = 0; entry->nodestart = nodestart; - { - SEARCH_BINDING node_body; + if (anchor) + entry->nodelen = 0; + else + { + SEARCH_BINDING node_body; - node_body.buffer = binding.buffer + binding.start; - node_body.start = 0; - node_body.end = binding.end - binding.start; - node_body.flags = S_FoldCase; - entry->nodelen = get_node_length (&node_body); - } + node_body.buffer = binding.buffer + binding.start; + node_body.start = 0; + node_body.end = binding.end - binding.start; + node_body.flags = S_FoldCase; + entry->nodelen = get_node_length (&node_body); + } entry->filename = file_buffer->fullpath; @@ -579,17 +575,16 @@ static long get_node_length (binding) SEARCH_BINDING *binding; { - register int i; + int i; char *body; - /* From the Info-RFC file: - [A node] ends with either a ^_, a ^L, or the end of file. */ + /* [A node] ends with either a ^_, a ^L, or end of file. */ for (i = binding->start, body = binding->buffer; i < binding->end; i++) { if (body[i] == INFO_FF || body[i] == INFO_COOKIE) break; } - return ((long) i - binding->start); + return i - binding->start; } /* Build and save the array of nodes in FILE_BUFFER by searching through the @@ -599,9 +594,10 @@ get_nodes_of_tags_table (file_buffer, buffer_binding) FILE_BUFFER *file_buffer; SEARCH_BINDING *buffer_binding; { - int offset, tags_index = 0; + int name_offset; SEARCH_BINDING *search; long position; + int tags_index = 0; search = copy_binding (buffer_binding); @@ -624,6 +620,8 @@ get_nodes_of_tags_table (file_buffer, buffer_binding) { TAG *entry; char *nodedef; + unsigned p; + int anchor = 0; /* Prepare to skip this line. */ search->start = position; @@ -634,36 +632,45 @@ get_nodes_of_tags_table (file_buffer, buffer_binding) continue; /* Find the label preceding the node name. */ - offset = + name_offset = string_in_line (INFO_NODE_LABEL, search->buffer + search->start); + /* If no node label, maybe it's an anchor. */ + if (name_offset == -1) + { + name_offset = string_in_line (INFO_REF_LABEL, + search->buffer + search->start); + if (name_offset != -1) + anchor = 1; + } + /* If not there, not a defining line, so we must be out of the - tags table. */ - if (offset == -1) + tags table. */ + if (name_offset == -1) break; - /* Point to the beginning of the node definition. */ - search->start += offset; + entry = xmalloc (sizeof (TAG)); + + /* Find the beginning of the node definition. */ + search->start += name_offset; nodedef = search->buffer + search->start; nodedef += skip_whitespace (nodedef); - /* Move past the node's name. */ - for (offset = 0; - (nodedef[offset]) && (nodedef[offset] != INFO_TAGSEP); - offset++); - - if (nodedef[offset] != INFO_TAGSEP) + /* Move past the node's name in this tag to the TAGSEP character. */ + for (p = 0; nodedef[p] && nodedef[p] != INFO_TAGSEP; p++) + ; + if (nodedef[p] != INFO_TAGSEP) continue; - entry = (TAG *)xmalloc (sizeof (TAG)); - entry->nodename = (char *)xmalloc (1 + offset); - strncpy (entry->nodename, nodedef, offset); - entry->nodename[offset] = '\0'; - offset++; - entry->nodestart = (long) atol (nodedef + offset); + entry->nodename = xmalloc (p + 1); + strncpy (entry->nodename, nodedef, p); + entry->nodename[p] = 0; + p++; + entry->nodestart = atol (nodedef + p); - /* We don't know the length of this node yet. */ - entry->nodelen = -1; + /* If a node, we don't know the length yet, but if it's an + anchor, the length is 0. */ + entry->nodelen = anchor ? 0 : -1; /* The filename of this node is currently known as the same as the name of this file. */ @@ -677,7 +684,7 @@ get_nodes_of_tags_table (file_buffer, buffer_binding) free (search); } -/* A structure used only in get_tags_of_indirect_tags_table () to hold onto +/* A structure used only in `get_tags_of_indirect_tags_table' to hold onto an intermediate value. */ typedef struct { char *filename; @@ -692,8 +699,8 @@ get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding) FILE_BUFFER *file_buffer; SEARCH_BINDING *indirect_binding, *tags_binding; { - register int i; - SUBFILE **subfiles = (SUBFILE **)NULL; + int i; + SUBFILE **subfiles = NULL; int subfiles_index = 0, subfiles_slots = 0; TAG *entry; @@ -723,7 +730,7 @@ get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding) subfile = (SUBFILE *)xmalloc (sizeof (SUBFILE)); subfile->filename = (char *)xmalloc (colon); strncpy (subfile->filename, line, colon - 1); - subfile->filename[colon - 1] = '\0'; + subfile->filename[colon - 1] = 0; subfile->first_byte = (long) atol (line + colon); add_pointer_to_array @@ -742,7 +749,7 @@ get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding) } else { - register int tags_index; + int tags_index; long header_length; SEARCH_BINDING binding; @@ -762,14 +769,21 @@ get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding) /* Build the file buffer's list of subfiles. */ { - char *containing_dir, *temp; + char *containing_dir = xstrdup (file_buffer->fullpath); + char *temp = filename_non_directory (containing_dir); int len_containing_dir; - containing_dir = xstrdup (file_buffer->fullpath); - temp = (char *) strrchr (containing_dir, '/'); - - if (temp) - *temp = '\0'; + if (temp > containing_dir) + { + if (HAVE_DRIVE (file_buffer->fullpath) && + temp == containing_dir + 2) + { + /* Avoid converting "d:foo" into "d:/foo" below. */ + *temp = '.'; + temp += 2; + } + temp[-1] = 0; + } len_containing_dir = strlen (containing_dir); @@ -789,7 +803,7 @@ get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding) file_buffer->subfiles[i] = fullpath; } - file_buffer->subfiles[i] = (char *)NULL; + file_buffer->subfiles[i] = NULL; free (containing_dir); } @@ -814,7 +828,7 @@ get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding) free (subfiles[i]); free (file_buffer->subfiles[i]); } - file_buffer->subfiles = (char **)NULL; + file_buffer->subfiles = NULL; free_file_buffer_tags (file_buffer); return; } @@ -825,9 +839,8 @@ get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding) preceding this one is the one containing the node. */ entry->filename = file_buffer->subfiles[i - 1]; - entry->nodestart -= subfiles[i -1]->first_byte; + entry->nodestart -= subfiles[i - 1]->first_byte; entry->nodestart += header_length; - entry->nodelen = -1; } /* We have successfully built the tags table. Remember that it @@ -845,18 +858,89 @@ get_tags_of_indirect_tags_table (file_buffer, indirect_binding, tags_binding) free (subfiles); } + +/* Return the node that contains TAG in FILE_BUFFER, else + (pathologically) NULL. Called from info_node_of_file_buffer_tags. */ +static NODE * +find_node_of_anchor (file_buffer, tag) + FILE_BUFFER *file_buffer; + TAG *tag; +{ + int anchor_pos, node_pos; + TAG *node_tag; + NODE *node; + + /* Look through the tag list for the anchor. */ + for (anchor_pos = 0; file_buffer->tags[anchor_pos]; anchor_pos++) + { + TAG *t = file_buffer->tags[anchor_pos]; + if (t->nodestart == tag->nodestart) + break; + } + + /* Should not happen, because we should always find the anchor. */ + if (!file_buffer->tags[anchor_pos]) + return NULL; + + /* We've found the anchor. Look backwards in the tag table for the + preceding node (we're assuming the tags are given in order), + skipping over any preceding anchors. */ + for (node_pos = anchor_pos - 1; + node_pos >= 0 && file_buffer->tags[node_pos]->nodelen == 0; + node_pos--) + ; + + /* An info file with an anchor before any nodes is pathological, but + it's possible, so don't crash. */ + if (node_pos < 0) + return NULL; + + /* We have the tag for the node that contained the anchor tag. */ + node_tag = file_buffer->tags[node_pos]; + + /* Look up the node name in the tag table to get the actual node. + This is a recursive call, but it can't recurse again, because we + call it with a real node. */ + node = info_node_of_file_buffer_tags (file_buffer, node_tag->nodename); + + /* Start displaying the node at the anchor position. */ + if (node) + { /* The nodestart for real nodes is three characters before the `F' + in the `File:' line (a newline, the CTRL-_, and another + newline). The nodestart for anchors is the actual position. + But we offset by only 2, rather than 3, because if an anchor is + at the beginning of a paragraph, it's nicer for it to end up on + the beginning of the first line of the paragraph rather than + the blank line before it. (makeinfo has no way of knowing that + a paragraph is going to start, so we can't fix it there.) */ + node->display_pos = file_buffer->tags[anchor_pos]->nodestart + - (node_tag->nodestart + 2); + + /* Otherwise an anchor at the end of a node ends up displaying at + the end of the last line of the node (way over on the right of + the screen), which looks wrong. */ + if (node->display_pos >= node->nodelen) + node->display_pos = node->nodelen - 1; + + /* Don't search in the node for the xref text, it's not there. */ + node->flags |= N_FromAnchor; + } + + return node; +} + + /* Return the node from FILE_BUFFER which matches NODENAME by searching - the tags table in FILE_BUFFER. If the node could not be found, return - a NULL pointer. */ + the tags table in FILE_BUFFER, or NULL. */ static NODE * info_node_of_file_buffer_tags (file_buffer, nodename) FILE_BUFFER *file_buffer; char *nodename; { - register int i; TAG *tag; + int i; - for (i = 0; (tag = file_buffer->tags[i]); i++) + for (i = 0; (tag = file_buffer->tags[i]); i++) if (strcmp (nodename, tag->nodename) == 0) { FILE_BUFFER *subfile; @@ -864,27 +948,26 @@ info_node_of_file_buffer_tags (file_buffer, nodename) subfile = info_find_file_internal (tag->filename, INFO_NO_TAGS); if (!subfile) - return ((NODE *)NULL); + return NULL; if (!subfile->contents) { info_reload_file_buffer_contents (subfile); if (!subfile->contents) - return ((NODE *)NULL); + return NULL; } /* If we were able to find this file and load it, then return the node within it. */ { - NODE *node; - - node = (NODE *)xmalloc (sizeof (NODE)); - node->filename = (subfile->fullpath); - node->nodename = tag->nodename; - node->contents = subfile->contents + tag->nodestart; - node->flags = 0; - node->parent = (char *)NULL; + NODE *node = xmalloc (sizeof (NODE)); + node->filename = subfile->fullpath; + node->parent = NULL; + node->nodename = tag->nodename; + node->contents = subfile->contents + tag->nodestart; + node->display_pos = 0; + node->flags = 0; if (file_buffer->flags & N_HasTagsTable) { @@ -923,14 +1006,14 @@ info_node_of_file_buffer_tags (file_buffer, nodename) max = subfile->filesize - tag->nodestart; /* NODE_SEP gets the address of the separator which defines - this node, or (char *)NULL if the node wasn't found. + this node, or NULL if the node wasn't found. NODE->contents is side-effected to point to right after the separator. */ node_sep = adjust_nodestart (node, min, max); - if (node_sep == (char *)NULL) + if (node_sep == NULL) { free (node); - return ((NODE *)NULL); + return NULL; } /* Readjust tag->nodestart. */ tag->nodestart = node_sep - subfile->contents; @@ -943,46 +1026,49 @@ info_node_of_file_buffer_tags (file_buffer, nodename) node_body.end = buff_end - node_body.buffer; node_body.flags = 0; tag->nodelen = get_node_length (&node_body); + node->nodelen = tag->nodelen; } + + else if (tag->nodelen == 0) /* anchor, return containing node */ + { + free (node); + node = find_node_of_anchor (file_buffer, tag); + } + else { /* Since we know the length of this node, we have already adjusted tag->nodestart to point to the exact start of it. Simply skip the node separator. */ node->contents += skip_node_separator (node->contents); + node->nodelen = tag->nodelen; } - node->nodelen = tag->nodelen; - return (node); + return node; } } /* There was a tag table for this file, and the node wasn't found. Return NULL, since this file doesn't contain the desired node. */ - return ((NODE *)NULL); + return NULL; } -/* **************************************************************** */ -/* */ -/* Managing file_buffers, nodes, and tags. */ -/* */ -/* **************************************************************** */ +/* Managing file_buffers, nodes, and tags. */ /* Create a new, empty file buffer. */ FILE_BUFFER * make_file_buffer () { - FILE_BUFFER *file_buffer; + FILE_BUFFER *file_buffer = xmalloc (sizeof (FILE_BUFFER)); - file_buffer = (FILE_BUFFER *)xmalloc (sizeof (FILE_BUFFER)); - file_buffer->filename = file_buffer->fullpath = (char *)NULL; - file_buffer->contents = (char *)NULL; - file_buffer->tags = (TAG **)NULL; - file_buffer->subfiles = (char **)NULL; + file_buffer->filename = file_buffer->fullpath = NULL; + file_buffer->contents = NULL; + file_buffer->tags = NULL; + file_buffer->subfiles = NULL; file_buffer->tags_slots = 0; file_buffer->flags = 0; - return (file_buffer); + return file_buffer; } /* Add FILE_BUFFER to our list of already loaded info files. */ @@ -1004,15 +1090,15 @@ static void forget_info_file (filename) char *filename; { - register int i; + int i; FILE_BUFFER *file_buffer; if (!info_loaded_files) return; - for (i = 0; (file_buffer = info_loaded_files[i]); i++) - if ((strcmp (filename, file_buffer->filename) == 0) || - (strcmp (filename, file_buffer->fullpath) == 0)) + for (i = 0; file_buffer = info_loaded_files[i]; i++) + if (FILENAME_CMP (filename, file_buffer->filename) == 0 + || FILENAME_CMP (filename, file_buffer->fullpath) == 0) { free (file_buffer->filename); free (file_buffer->fullpath); @@ -1020,13 +1106,17 @@ forget_info_file (filename) if (file_buffer->contents) free (file_buffer->contents); - /* Note that free_file_buffer_tags () also kills the subfiles - list, since the subfiles list is only of use in conjunction - with tags. */ + /* free_file_buffer_tags () also kills the subfiles list, since + the subfiles list is only of use in conjunction with tags. */ free_file_buffer_tags (file_buffer); - while ((info_loaded_files[i] = info_loaded_files[++i])) - ; + /* Move rest of list down. */ + while (info_loaded_files[i + 1]) + { + info_loaded_files[i] = info_loaded_files[i + 1]; + i++; + } + info_loaded_files[i] = 0; break; } @@ -1037,17 +1127,17 @@ static void free_file_buffer_tags (file_buffer) FILE_BUFFER *file_buffer; { - register int i; + int i; if (file_buffer->tags) { - register TAG *tag; + TAG *tag; for (i = 0; (tag = file_buffer->tags[i]); i++) free_info_tag (tag); free (file_buffer->tags); - file_buffer->tags = (TAG **)NULL; + file_buffer->tags = NULL; file_buffer->tags_slots = 0; } @@ -1057,7 +1147,7 @@ free_file_buffer_tags (file_buffer) free (file_buffer->subfiles[i]); free (file_buffer->subfiles); - file_buffer->subfiles = (char **)NULL; + file_buffer->subfiles = NULL; } } @@ -1084,6 +1174,7 @@ static void info_reload_file_buffer_contents (fb) FILE_BUFFER *fb; { + int is_compressed; #if defined (HANDLE_MAN_PAGES) /* If this is the magic manpage node, don't try to reload, just give up. */ @@ -1095,8 +1186,9 @@ info_reload_file_buffer_contents (fb) /* Let the filesystem do all the work for us. */ fb->contents = - filesys_read_info_file (fb->fullpath, &(fb->filesize), &(fb->finfo)); - if (fb->filesize != (long) (fb->finfo.st_size)) + filesys_read_info_file (fb->fullpath, &(fb->filesize), &(fb->finfo), + &is_compressed); + if (is_compressed) fb->flags |= N_IsCompressed; } @@ -1157,7 +1249,7 @@ adjust_nodestart (node, min, max) (strncmp (node->nodename, nodedef, offset) == 0)) { node->contents = nodestart; - return (node_body.buffer + position); + return node_body.buffer + position; } } } @@ -1173,7 +1265,7 @@ adjust_nodestart (node, min, max) /* If the node couldn't be found, we lose big. */ if (position == -1) - return ((char *)NULL); + return NULL; /* Otherwise, the node was found, but the tags table could need updating (if we used a tag to get here, that is). Set the flag in NODE->flags. */ @@ -1181,5 +1273,5 @@ adjust_nodestart (node, min, max) node->contents += skip_node_separator (node->contents); if (node->flags & N_HasTagsTable) node->flags |= N_UpdateTags; - return (node_body.buffer + position); + return node_body.buffer + position; } diff --git a/contrib/texinfo/info/nodes.h b/contrib/texinfo/info/nodes.h index a96c07c..7fd625d 100644 --- a/contrib/texinfo/info/nodes.h +++ b/contrib/texinfo/info/nodes.h @@ -1,10 +1,7 @@ /* nodes.h -- How we represent nodes internally. - $Id: nodes.h,v 1.5 1997/07/18 14:33:44 karl Exp $ + $Id: nodes.h,v 1.8 1998/07/10 20:28:43 karl Exp $ - This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98 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 @@ -22,16 +19,12 @@ Written by Brian Fox (bfox@ai.mit.edu). */ -#if !defined (NODES_H) +#ifndef NODES_H #define NODES_H #include "info.h" -/* **************************************************************** */ -/* */ -/* User Code Interface */ -/* */ -/* **************************************************************** */ +/* 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 @@ -47,6 +40,7 @@ typedef struct { char *nodename; /* The name of this node. */ char *contents; /* Characters appearing in this node. */ long nodelen; /* The length of the CONTENTS member. */ + unsigned long display_pos; /* Where to display at, if nonzero. */ int flags; /* See immediately below. */ } NODE; @@ -57,18 +51,14 @@ typedef struct { #define N_IsCompressed 0x08 /* The file is compressed on disk. */ #define N_IsInternal 0x10 /* This node was made by Info. */ #define N_CannotGC 0x20 /* File buffer cannot be gc'ed. */ -#define N_IsManPage 0x40 /* This node is a Un*x manpage. */ +#define N_IsManPage 0x40 /* This node is a manpage. */ +#define N_FromAnchor 0x80 /* Synthesized for an anchor reference. */ -/* **************************************************************** */ -/* */ -/* Internal Data Structures */ -/* */ -/* **************************************************************** */ - -/* Some defines describing details about Info file contents. */ +/* Internal data structures. */ -/* String Constants. */ +/* String constants. */ #define INFO_FILE_LABEL "File:" +#define INFO_REF_LABEL "Ref:" #define INFO_NODE_LABEL "Node:" #define INFO_PREV_LABEL "Prev:" #define INFO_ALTPREV_LABEL "Previous:" @@ -82,7 +72,7 @@ typedef struct { #define INDIRECT_TAGS_TABLE_LABEL "Indirect:\n" #define TAGS_TABLE_IS_INDIRECT_LABEL "(Indirect)" -/* Character Constants. */ +/* Character constants. */ #define INFO_COOKIE '\037' #define INFO_FF '\014' #define INFO_TAGSEP '\177' @@ -119,12 +109,8 @@ typedef struct { int tags_slots; /* Number of slots allocated for TAGS. */ int flags; /* Various flags. Mimics of N_* flags. */ } FILE_BUFFER; - -/* **************************************************************** */ -/* */ -/* Externally Visible Functions */ -/* */ -/* **************************************************************** */ + +/* Externally visible functions. */ /* Array of FILE_BUFFER * which represents the currently loaded info files. */ extern FILE_BUFFER **info_loaded_files; @@ -166,4 +152,4 @@ extern char *info_recent_file_error; /* Create a new, empty file buffer. */ extern FILE_BUFFER *make_file_buffer (); -#endif /* !NODES_H */ +#endif /* not NODES_H */ diff --git a/contrib/texinfo/info/search.c b/contrib/texinfo/info/search.c index 0e8e619..2866704 100644 --- a/contrib/texinfo/info/search.c +++ b/contrib/texinfo/info/search.c @@ -1,9 +1,7 @@ -/* search.c -- How to search large bodies of text. */ +/* search.c -- searching large bodies of text. + $Id: search.c,v 1.5 1999/03/05 19:56:59 karl Exp $ -/* This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98 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 @@ -198,7 +196,7 @@ search_backward (input_string, binding) { c = *(buff - i); - if (c != string[i] && (alternate && c != alternate[i])) + if (c != string[i] && (!alternate || c != alternate[i])) break; } @@ -292,7 +290,7 @@ skip_whitespace_and_newlines (string) { register int i; - for (i = 0; string && (whitespace (string[i]) || string[i] == '\n'); i++); + for (i = 0; string && whitespace_or_newline (string[i]); i++); return (i); } diff --git a/contrib/texinfo/info/search.h b/contrib/texinfo/info/search.h index 6425536..757ec5c 100644 --- a/contrib/texinfo/info/search.h +++ b/contrib/texinfo/info/search.h @@ -1,10 +1,7 @@ /* search.h -- Structure used to search large bodies of text, with bounds. - $Id: search.h,v 1.3 1997/07/15 18:43:49 karl Exp $ + $Id: search.h,v 1.4 1998/04/19 20:50:23 karl Exp $ - This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98 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 @@ -53,11 +50,6 @@ extern int looking_at (); after the string. */ extern int string_in_line (); -/* Some unixes don't have strcasecmp or strncasecmp. */ -#if !defined (HAVE_STRCASECMP) -extern int strcasecmp (), strncasecmp (); -#endif /* !HAVE_STRCASECMP */ - /* Function names that start with "skip" are passed a string, and return an offset from the start of that string. Function names that start with "find" are passed a SEARCH_BINDING, and return an absolute position diff --git a/contrib/texinfo/info/session.c b/contrib/texinfo/info/session.c index 63a6ecd..69b138d 100644 --- a/contrib/texinfo/info/session.c +++ b/contrib/texinfo/info/session.c @@ -1,7 +1,7 @@ -/* session.c -- The user windowing interface to Info. - $Id: session.c,v 1.13 1998/02/22 22:38:30 karl Exp $ +/* session.c -- user windowing interface to Info. + $Id: session.c,v 1.38 1999/09/25 16:10:04 karl Exp $ - Copyright (C) 1993, 96, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 96, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,6 +31,12 @@ # include "man.h" #endif +#ifdef M_XENIX +/* SCO 3.2v5.0.2 defines but does not correctly declare strncasecmp. + Since we use it as a symbol, have to get it right. --gildea, 1jul99. */ +extern int strncasecmp (const char *, const char *, size_t); +#endif + static void info_clear_pending_input (), info_set_pending_input (); static void info_handle_pointer (); @@ -94,7 +100,7 @@ begin_multiple_window_info_session (filename, nodenames) /* Find the largest window in WINDOWS, and make that be the active one. Then split it and add our window and node to the list of remembered windows and nodes. Then tile the windows. */ - register WINDOW *win, *largest = (WINDOW *)NULL; + WINDOW *win, *largest = NULL; int max_height = 0; for (win = windows; win; win = win->next) @@ -107,9 +113,9 @@ begin_multiple_window_info_session (filename, nodenames) if (!largest) { display_update_display (windows); - info_error (CANT_FIND_WIND); + info_error (msg_cant_find_window); info_session (); - exit (0); + xexit (0); } active_window = largest; @@ -122,9 +128,9 @@ begin_multiple_window_info_session (filename, nodenames) else { display_update_display (windows); - info_error (WIN_TOO_SMALL); + info_error (msg_win_too_small); info_session (); - exit (0); + xexit (0); } } } @@ -134,13 +140,14 @@ begin_multiple_window_info_session (filename, nodenames) /* Start an info session with INITIAL_NODE, and an error message in the echo area made from FORMAT and ARG. */ void -begin_info_session_with_error (initial_node, format, arg) +begin_info_session_with_error (initial_node, format, arg1, arg2) NODE *initial_node; char *format; - void *arg; + void *arg1; + void *arg2; { initialize_info_session (initial_node, 1); - info_error (format, arg, (void *)NULL); + info_error (format, arg1, arg2); info_session (); } @@ -159,9 +166,9 @@ display_startup_message_and_start () char *format; format = replace_in_documentation - (_("Welcome to Info version %s. \"\\[get-help-window]\" for help, \"\\[menu-item]\" for menu item.")); + (_("Welcome to Info version %s. Type \\[get-help-window] for help, \\[menu-item] for menu item.")); - window_message_in_echo_area (format, version_string ()); + window_message_in_echo_area (format, VERSION); info_session (); } @@ -267,8 +274,8 @@ initialize_info_session (node, clear_screen) if (!term_name) term_name = "dumb"; - info_error (TERM_TOO_DUMB, term_name); - exit (1); + info_error (msg_term_too_dumb, term_name); + xexit (1); } if (clear_screen) @@ -281,7 +288,7 @@ initialize_info_session (node, clear_screen) window_initialize_windows (screenwidth, screenheight); initialize_info_signal_handler (); display_initialize_display (screenwidth, screenheight); - info_set_node_of_window (active_window, node); + info_set_node_of_window (0, active_window, node); /* Tell the window system how to notify us when a window needs to be asynchronously deleted (e.g., user resizes window very small). */ @@ -291,7 +298,7 @@ initialize_info_session (node, clear_screen) standard input. */ if (!info_input_stream) { - setbuf(stdin, NULL); + setbuf (stdin, NULL); info_input_stream = stdin; } @@ -305,7 +312,8 @@ info_set_input_from_file (filename) { FILE *stream; - stream = fopen (filename, "r"); + /* Input may include binary characters. */ + stream = fopen (filename, FOPEN_RBIN); if (!stream) return; @@ -484,12 +492,17 @@ forget_window_and_nodes (window) /* Set WINDOW to show NODE. Remember the new window in our list of Info windows. If we are doing automatic footnote display, also try to display - the footnotes for this window. */ + the footnotes for this window. If REMEMBER is nonzero, first call + set_remembered_pagetop_and_point. */ void -info_set_node_of_window (window, node) +info_set_node_of_window (remember, window, node) + int remember; WINDOW *window; NODE *node; { + if (remember) + set_remembered_pagetop_and_point (window); + /* Put this node into the window. */ window_set_node_of_window (window, node); @@ -607,7 +620,7 @@ move_to_new_line (old, new, window) { if (old == -1) { - info_error (CANT_FIND_POINT); + info_error (msg_cant_find_point); } else { @@ -686,7 +699,7 @@ DECLARE_INFO_COMMAND (info_beginning_of_line, _("Move to the start of the line") for (; (point) && (buffer[point - 1] != '\n'); point--); - /* If at a line start alreay, do nothing. */ + /* If at a line start already, do nothing. */ if (point != window->point) { window->point = point; @@ -827,38 +840,6 @@ DECLARE_INFO_COMMAND (info_backward_word, _("Move backward a word")) info_show_point (window); } -/* Here is a list of time counter names which correspond to ordinal numbers. - It is used to print "once" instead of "1". */ -static char *counter_names[] = { - "not at all", "once", "twice", "three", "four", "five", "six", - (char *)NULL -}; - -/* Buffer used to return values from times_description (). */ -static char td_buffer[50]; - -/* Function returns a static string fully describing the number of times - present in COUNT. */ -static char * -times_description (count) - int count; -{ - register int i; - - td_buffer[0] = '\0'; - - for (i = 0; counter_names[i]; i++) - if (count == i) - break; - - if (counter_names[i]) - sprintf (td_buffer, "%s%s", counter_names[i], count > 2 ? _(" times") : ""); - else - sprintf (td_buffer, _("%d times"), count); - - return (td_buffer); -} - /* Variable controlling the behaviour of default scrolling when you are already at the bottom of a node. Possible values are defined in session.h. The meanings are: @@ -877,6 +858,14 @@ char *info_scroll_choices[] = { "Continuous", "Next Only", "Page Only", (char *)NULL }; +/* Default window sizes for scrolling commands. */ +int default_window_size = -1; /* meaning 1 window-full */ +int default_scroll_size = -1; /* meaning half screen size */ + +#define INFO_LABEL_FOUND() \ + (info_parsed_nodename || (info_parsed_filename \ + && !is_dir_name (info_parsed_filename))) + /* Move to 1st menu item, Next, Up/Next, or error in this window. */ static void forward_move_node_structure (window, behaviour) @@ -886,17 +875,17 @@ forward_move_node_structure (window, behaviour) switch (behaviour) { case IS_PageOnly: - info_error (AT_NODE_BOTTOM); + info_error (msg_at_node_bottom); break; case IS_NextOnly: info_next_label_of_node (window->node); if (!info_parsed_nodename && !info_parsed_filename) - info_error (_("No \"Next\" pointer for this node.")); + info_error (msg_no_pointer, _("Next")); else { - window_message_in_echo_area (_("Following \"Next\" node...")); - info_handle_pointer (_("Next"), window); + window_message_in_echo_area (_("Following Next node...")); + info_handle_pointer ("Next", window); } break; @@ -921,10 +910,10 @@ forward_move_node_structure (window, behaviour) /* Okay, this node does not contain a menu. If it contains a "Next:" pointer, use that. */ info_next_label_of_node (window->node); - if (info_label_was_found) + if (INFO_LABEL_FOUND ()) { - window_message_in_echo_area (_("Selecting \"Next\" node...")); - info_handle_pointer (_("Next"), window); + window_message_in_echo_area (_("Selecting Next node...")); + info_handle_pointer ("Next", window); return; } @@ -945,9 +934,9 @@ forward_move_node_structure (window, behaviour) while (!info_error_was_printed) { info_up_label_of_node (window->node); - if (info_label_was_found) + if (INFO_LABEL_FOUND ()) { - info_handle_pointer (_("Up"), window); + info_handle_pointer ("Up", window); if (info_error_was_printed) continue; @@ -956,7 +945,7 @@ forward_move_node_structure (window, behaviour) info_next_label_of_node (window->node); /* If no "Next" pointer, keep backing up. */ - if (!info_label_was_found) + if (!INFO_LABEL_FOUND ()) continue; /* If this node's first menu item is the same as this node's @@ -993,10 +982,10 @@ forward_move_node_structure (window, behaviour) /* This node has a "Next" pointer, and it is not the same as the first menu item found in this node. */ window_message_in_echo_area - ("Moving \"Up\" %s, then \"Next\".", - times_description (up_counter)); + (_("Moving Up %d time(s), then Next."), + up_counter); - info_handle_pointer (_("Next"), window); + info_handle_pointer ("Next", window); return; } else @@ -1017,7 +1006,7 @@ forward_move_node_structure (window, behaviour) window->point = info_win->points[old_current]; recalculate_line_starts (window); window->flags |= W_UpdateWindow; - info_error (_("No more nodes.")); + info_error (_("No more nodes within this document.")); } } } @@ -1035,32 +1024,34 @@ backward_move_node_structure (window, behaviour) switch (behaviour) { case IS_PageOnly: - info_error (AT_NODE_TOP); + info_error (msg_at_node_top); break; case IS_NextOnly: info_prev_label_of_node (window->node); if (!info_parsed_nodename && !info_parsed_filename) - info_error (_("No \"Prev\" for this node.")); + info_error (_("No `Prev' for this node.")); else { - window_message_in_echo_area (_("Moving \"Prev\" in this window.")); - info_handle_pointer (_("Prev"), window); + window_message_in_echo_area (_("Moving Prev in this window.")); + info_handle_pointer ("Prev", window); } break; case IS_Continuous: info_prev_label_of_node (window->node); - if (!info_parsed_nodename && !info_parsed_filename) + if (!info_parsed_nodename && (!info_parsed_filename + || is_dir_name (info_parsed_filename))) { info_up_label_of_node (window->node); - if (!info_parsed_nodename && !info_parsed_filename) - info_error (_("No \"Prev\" or \"Up\" for this node.")); + if (!info_parsed_nodename && (!info_parsed_filename + || is_dir_name (info_parsed_filename))) + info_error (_("No `Prev' or `Up' for this node within this document.")); else { - window_message_in_echo_area (_("Moving \"Up\" in this window.")); - info_handle_pointer (_("Up"), window); + window_message_in_echo_area (_("Moving Up in this window.")); + info_handle_pointer ("Up", window); } } else @@ -1097,8 +1088,8 @@ backward_move_node_structure (window, behaviour) /* Move to the previous node. If this node now contains a menu, and we have not inhibited movement to it, move to the node corresponding to the last menu item. */ - window_message_in_echo_area (_("Moving \"Prev\" in this window.")); - info_handle_pointer (_("Prev"), window); + window_message_in_echo_area (_("Moving Prev in this window.")); + info_handle_pointer ("Prev", window); if (!inhibit_menu_traversing) { @@ -1107,7 +1098,7 @@ backward_move_node_structure (window, behaviour) { info_free_references (menu); window_message_in_echo_area - (_("Moving to \"Prev\"'s last menu item.")); + (_("Moving to `Prev's last menu item.")); info_menu_digit (window, 1, '0'); } } @@ -1161,7 +1152,9 @@ DECLARE_INFO_COMMAND (info_scroll_forward, _("Scroll forward in this window")) lines to the top of this window, Or, if at bottom of window, and the user wishes to scroll through nodes get the "Next" node for this window. */ - if (!info_explicit_arg && count == 1) + if (default_window_size > 0) + desired_top = window->pagetop + default_window_size; + else if (!info_explicit_arg && count == 1) { desired_top = window->pagetop + (window->height - 2); @@ -1193,6 +1186,16 @@ DECLARE_INFO_COMMAND (info_scroll_forward, _("Scroll forward in this window")) } } +/* Like info_scroll_forward, but sets default_window_size as a side + effect. */ +DECLARE_INFO_COMMAND (info_scroll_forward_set_window, + _("Scroll forward in this window and set default window size")) +{ + if (info_explicit_arg) + default_window_size = count; + info_scroll_forward (window, count, key); +} + /* Show the previous screen of WINDOW's node. */ DECLARE_INFO_COMMAND (info_scroll_backward, _("Scroll backward in this window")) { @@ -1205,7 +1208,9 @@ DECLARE_INFO_COMMAND (info_scroll_backward, _("Scroll backward in this window")) /* Without an explicit numeric argument, scroll the top two lines to the bottom of this window, or move to the previous, or Up'th node. */ - if (!info_explicit_arg && count == 1) + if (default_window_size > 0) + desired_top = window->pagetop - default_window_size; + else if (!info_explicit_arg && count == 1) { desired_top = window->pagetop - (window->height - 2); @@ -1233,6 +1238,16 @@ DECLARE_INFO_COMMAND (info_scroll_backward, _("Scroll backward in this window")) } } +/* Like info_scroll_backward, but sets default_window_size as a side + effect. */ +DECLARE_INFO_COMMAND (info_scroll_backward_set_window, + _("Scroll backward in this window and set default window size")) +{ + if (info_explicit_arg) + default_window_size = count; + info_scroll_backward (window, count, key); +} + /* Move to the beginning of the node. */ DECLARE_INFO_COMMAND (info_beginning_of_node, _("Move to the start of this node")) { @@ -1246,6 +1261,90 @@ DECLARE_INFO_COMMAND (info_end_of_node, _("Move to the end of this node")) window->point = window->node->nodelen - 1; info_show_point (window); } + +/* Scroll the window forward by N lines. */ +DECLARE_INFO_COMMAND (info_down_line, _("Scroll down by lines")) +{ + if (count < 0) + info_up_line (window, -count, key); + else + { + int desired_top = window->pagetop + count; + + if (desired_top >= window->line_count) + desired_top = window->line_count - 2; + + if (window->pagetop <= desired_top) + set_window_pagetop (window, desired_top); + } +} + +/* Scroll the window backward by N lines. */ +DECLARE_INFO_COMMAND (info_up_line, _("Scroll up by lines")) +{ + if (count < 0) + info_down_line (window, -count, key); + else + { + int desired_top = window->pagetop - count; + + if (desired_top < 0) + desired_top = 0; + + set_window_pagetop (window, desired_top); + } +} + +/* Scroll the window forward by N lines and remember N as default for + subsequent commands. */ +DECLARE_INFO_COMMAND (info_scroll_half_screen_down, + _("Scroll down by half screen size")) +{ + if (count < 0) + info_scroll_half_screen_up (window -count, key); + else + { + int scroll_size = (the_screen->height + 1) / 2; + int desired_top; + + if (info_explicit_arg) + default_scroll_size = count; + if (default_scroll_size > 0) + scroll_size = default_scroll_size; + + desired_top = window->pagetop + scroll_size; + if (desired_top >= window->line_count) + desired_top = window->line_count - 2; + + if (window->pagetop <= desired_top) + set_window_pagetop (window, desired_top); + } +} + +/* Scroll the window backward by N lines and remember N as default for + subsequent commands. */ +DECLARE_INFO_COMMAND (info_scroll_half_screen_up, + _("Scroll up by half screen size")) +{ + if (count < 0) + info_scroll_half_screen_down (window -count, key); + else + { + int scroll_size = (the_screen->height + 1) / 2; + int desired_top; + + if (info_explicit_arg) + default_scroll_size = count; + if (default_scroll_size > 0) + scroll_size = default_scroll_size; + + desired_top = window->pagetop - scroll_size; + if (desired_top < 0) + desired_top = 0; + + set_window_pagetop (window, desired_top); + } +} /* **************************************************************** */ /* */ @@ -1265,7 +1364,7 @@ DECLARE_INFO_COMMAND (info_next_window, _("Select the next window")) /* If no other window, error now. */ if (!windows->next && !echo_area_is_active) { - info_error (ONE_WINDOW); + info_error (msg_one_window); return; } @@ -1305,7 +1404,7 @@ DECLARE_INFO_COMMAND (info_prev_window, _("Select the previous window")) if (!windows->next && !echo_area_is_active) { - info_error (ONE_WINDOW); + info_error (msg_one_window); return; } @@ -1361,7 +1460,7 @@ DECLARE_INFO_COMMAND (info_split_window, _("Split the current window")) if (!split) { - info_error (WIN_TOO_SMALL); + info_error (msg_win_too_small); } else { @@ -1429,7 +1528,7 @@ DECLARE_INFO_COMMAND (info_delete_window, _("Delete the current window")) { if (!windows->next) { - info_error (CANT_KILL_LAST); + info_error (msg_cant_kill_last); } else if (window->flags & W_WindowIsPerm) { @@ -1519,7 +1618,7 @@ DECLARE_INFO_COMMAND (info_scroll_other_window, _("Scroll the other window")) /* If only one window, give up. */ if (!windows->next) { - info_error (ONE_WINDOW); + info_error (msg_one_window); return; } @@ -1531,6 +1630,13 @@ DECLARE_INFO_COMMAND (info_scroll_other_window, _("Scroll the other window")) info_scroll_forward (other, count, key); } +/* Scroll the "other" window of WINDOW. */ +DECLARE_INFO_COMMAND (info_scroll_other_window_backward, + _("Scroll the other window backward")) +{ + info_scroll_other_window (window, -count, key); +} + /* Change the size of WINDOW by AMOUNT. */ DECLARE_INFO_COMMAND (info_grow_window, _("Grow (or shrink) this window")) { @@ -1561,6 +1667,28 @@ DECLARE_INFO_COMMAND (info_toggle_wrap, /* */ /* **************************************************************** */ +/* Return (FILENAME)NODENAME for NODE, or just NODENAME if NODE's + filename is not set. */ +char * +node_printed_rep (node) + NODE *node; +{ + char *rep; + + if (node->filename) + { + char *filename + = filename_non_directory (node->parent ? node->parent : node->filename); + rep = xmalloc (1 + strlen (filename) + 1 + strlen (node->nodename) + 1); + sprintf (rep, "(%s)%s", filename, node->nodename); + } + else + rep = node->nodename; + + return rep; +} + + /* Using WINDOW for various defaults, select the node referenced by ENTRY in it. If the node is selected, the window and node are remembered. */ void @@ -1613,7 +1741,7 @@ info_select_reference (window, entry) if (file_system_error) info_error (file_system_error); else - info_error (CANT_FIND_NODE, nodename); + info_error (msg_cant_find_node, nodename); } maybe_free (file_system_error); @@ -1621,10 +1749,7 @@ info_select_reference (window, entry) maybe_free (nodename); if (node) - { - set_remembered_pagetop_and_point (window); - info_set_node_of_window (window, node); - } + info_set_node_of_window (1, window, node); } /* Parse the node specification in LINE using WINDOW to default the filename. @@ -1689,15 +1814,14 @@ info_handle_pointer (label, window) info_win->pagetops[info_win->current] = window->pagetop; info_win->points[info_win->current] = window->point; } - set_remembered_pagetop_and_point (window); - info_set_node_of_window (window, node); + info_set_node_of_window (1, window, node); } else { if (info_recent_file_error) info_error (info_recent_file_error); else - info_error (CANT_FILE_NODE, filename, nodename); + info_error (msg_cant_file_node, filename, nodename); } free (filename); @@ -1705,32 +1829,32 @@ info_handle_pointer (label, window) } else { - info_error (NO_POINTER, label); + info_error (msg_no_pointer, label); } } /* Make WINDOW display the "Next:" node of the node currently being displayed. */ -DECLARE_INFO_COMMAND (info_next_node, _("Select the `Next' node")) +DECLARE_INFO_COMMAND (info_next_node, _("Select the Next node")) { info_next_label_of_node (window->node); - info_handle_pointer (_("Next"), window); + info_handle_pointer ("Next", window); } /* Make WINDOW display the "Prev:" node of the node currently being displayed. */ -DECLARE_INFO_COMMAND (info_prev_node, _("Select the `Prev' node")) +DECLARE_INFO_COMMAND (info_prev_node, _("Select the Prev node")) { info_prev_label_of_node (window->node); - info_handle_pointer (_("Prev"), window); + info_handle_pointer ("Prev", window); } /* Make WINDOW display the "Up:" node of the node currently being displayed. */ -DECLARE_INFO_COMMAND (info_up_node, _("Select the `Up' node")) +DECLARE_INFO_COMMAND (info_up_node, _("Select the Up node")) { info_up_label_of_node (window->node); - info_handle_pointer (_("Up"), window); + info_handle_pointer ("Up", window); } /* Make WINDOW display the last node of this info file. */ @@ -1742,17 +1866,28 @@ DECLARE_INFO_COMMAND (info_last_node, _("Select the last node in this file")) if (fb && fb->tags) { - for (i = 0; fb->tags[i]; i++); - node = info_get_node (fb->filename, fb->tags[i - 1]->nodename); + int last_node_tag_idx = -1; + + /* If no explicit argument, or argument of zero, default to the + last node. */ + if (count == 0 || (count == 1 && !info_explicit_arg)) + count = -1; + for (i = 0; count && fb->tags[i]; i++) + if (fb->tags[i]->nodelen != 0) /* don't count anchor tags */ + { + count--; + last_node_tag_idx = i; + } + if (count > 0) + i = last_node_tag_idx + 1; + if (i > 0) + node = info_get_node (fb->filename, fb->tags[i - 1]->nodename); } if (!node) info_error (_("This window has no additional nodes")); else - { - set_remembered_pagetop_and_point (window); - info_set_node_of_window (window, node); - } + info_set_node_of_window (1, window, node); } /* Make WINDOW display the first node of this info file. */ @@ -1761,16 +1896,31 @@ DECLARE_INFO_COMMAND (info_first_node, _("Select the first node in this file")) FILE_BUFFER *fb = file_buffer_of_window (window); NODE *node = (NODE *)NULL; + /* If no explicit argument, or argument of zero, default to the + first node. */ + if (count == 0) + count = 1; if (fb && fb->tags) - node = info_get_node (fb->filename, fb->tags[0]->nodename); + { + register int i; + int last_node_tag_idx = -1; + + for (i = 0; count && fb->tags[i]; i++) + if (fb->tags[i]->nodelen != 0) /* don't count anchor tags */ + { + count--; + last_node_tag_idx = i; + } + if (count > 0) + i = last_node_tag_idx + 1; + if (i > 0) + node = info_get_node (fb->filename, fb->tags[i - 1]->nodename); + } if (!node) info_error (_("This window has no additional nodes")); else - { - set_remembered_pagetop_and_point (window); - info_set_node_of_window (window, node); - } + info_set_node_of_window (1, window, node); } /* Select the last menu item in WINDOW->node. */ @@ -1790,7 +1940,7 @@ DECLARE_INFO_COMMAND (info_menu_digit, _("Select this menu item")) if (!menu) { - info_error (NO_MENU_NODE); + info_error (msg_no_menu_node); return; } @@ -1837,9 +1987,9 @@ info_menu_or_ref_item (window, count, key, builder, ask_p) if (!menu) { if (builder == info_menu_of_node) - info_error (NO_MENU_NODE); + info_error (msg_no_menu_node); else - info_error (NO_XREF_NODE); + info_error (msg_no_xref_node); return; } @@ -1996,12 +2146,11 @@ info_menu_or_ref_item (window, count, key, builder, ask_p) info_error (_("The reference disappeared! (%s)."), line); else { - NODE *orig; - - orig = window->node; + NODE *orig = window->node; info_select_reference (window, entry); - if ((builder == info_xrefs_of_node) && (window->node != orig)) - { + if (builder == info_xrefs_of_node && window->node != orig + && !(window->node->flags & N_FromAnchor)) + { /* Search for this reference in the node. */ long offset; long start; @@ -2066,7 +2215,7 @@ DECLARE_INFO_COMMAND (info_find_menu, _("Move to the start of this node's menu") position = search (INFO_MENU_LABEL, &binding); if (position == -1) - info_error (NO_MENU_NODE); + info_error (msg_no_menu_node); else { window->point = position; @@ -2085,7 +2234,7 @@ DECLARE_INFO_COMMAND (info_visit_menu, menu = info_menu_of_node (window->node); if (!menu) - info_error (NO_MENU_NODE); + info_error (msg_no_menu_node); for (i = 0; (!info_error_was_printed) && (entry = menu[i]); i++) { @@ -2095,7 +2244,7 @@ DECLARE_INFO_COMMAND (info_visit_menu, window_tile_windows (TILE_INTERNALS); if (!new) - info_error (WIN_TOO_SMALL); + info_error (msg_win_too_small); else { active_window = new; @@ -2144,33 +2293,27 @@ DECLARE_INFO_COMMAND (info_goto_node, _("Read a node name and select it")) { entry = (REFERENCE *)xmalloc (sizeof (REFERENCE)); entry->filename = entry->nodename = (char *)NULL; - entry->label = (char *) xmalloc - (4 + strlen (fb->filename) + strlen (fb->tags[i]->nodename)); - sprintf (entry->label, "(%s)%s", - fb->filename, fb->tags[i]->nodename); + if (this_is_the_current_fb) + entry->label = xstrdup (fb->tags[i]->nodename); + else + { + entry->label = (char *) xmalloc + (4 + strlen (fb->filename) + + strlen (fb->tags[i]->nodename)); + sprintf (entry->label, "(%s)%s", + fb->filename, fb->tags[i]->nodename); + } add_pointer_to_array (entry, items_index, items, items_slots, 100, REFERENCE *); - } - - if (this_is_the_current_fb) - { - for (i = 0; fb->tags[i]; i++) - { - entry = (REFERENCE *)xmalloc (sizeof (REFERENCE)); - entry->filename = entry->nodename = (char *)NULL; - entry->label = xstrdup (fb->tags[i]->nodename); - add_pointer_to_array (entry, items_index, items, - items_slots, 100, REFERENCE *); - } } } } - line = info_read_maybe_completing (window, _("Goto Node: "), items); + line = info_read_maybe_completing (window, _("Goto node: "), items); info_free_references (items); } #else /* !GOTO_COMPLETES */ - line = info_read_in_echo_area (window, _("Goto Node: ")); + line = info_read_in_echo_area (window, _("Goto node: ")); #endif /* !GOTO_COMPLETES */ /* If the user aborted, quit now. */ @@ -2189,7 +2332,413 @@ DECLARE_INFO_COMMAND (info_goto_node, _("Read a node name and select it")) if (!info_error_was_printed) window_clear_echo_area (); } + +/* Follow the menu list in MENUS (list of strings terminated by a NULL + entry) from INITIAL_NODE. If can't continue at any point (no menu or + no menu entry for the next item), return the node so far -- that + might be INITIAL_NODE itself. If error, *ERRSTR and *ERRARG[12] will + be set to the error message and argument for message, otherwise they + will be NULL. */ + +NODE * +info_follow_menus (initial_node, menus, errstr, errarg1, errarg2) + NODE *initial_node; + char **menus; + char **errstr, **errarg1, **errarg2; +{ + NODE *node = NULL; + *errstr = *errarg1 = *errarg2 = NULL; + + for (; *menus; menus++) + { + static char *first_arg = NULL; + REFERENCE **menu; + REFERENCE *entry; + char *arg = *menus; /* Remember the name of the menu entry we want. */ + + /* A leading space is certainly NOT part of a node name. Most + probably, they typed a space after the separating comma. The + strings in menus[] have their whitespace canonicalized, so + there's at most one space to ignore. */ + if (*arg == ' ') + arg++; + if (!first_arg) + first_arg = arg; + + /* Build and return a list of the menu items in this node. */ + menu = info_menu_of_node (initial_node); + + /* If no menu item in this node, stop here, but let the user + continue to use Info. Perhaps they wanted this node and didn't + realize it. */ + if (!menu) + { + if (arg == first_arg) + { + node = make_manpage_node (first_arg); + if (node) + goto maybe_got_node; + } + *errstr = _("No menu in node `%s'."); + *errarg1 = node_printed_rep (initial_node); + return initial_node; + } + + /* 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) + { + int i; + int best_guess = -1; + + for (i = 0; (entry = menu[i]); i++) + { + if (strcasecmp (entry->label, arg) == 0) + break; + else + if (strncasecmp (entry->label, arg, strlen (arg)) == 0) + best_guess = i; + } + + if (!entry && best_guess != -1) + entry = menu[best_guess]; + } + + /* If we still failed to find the reference, start Info with the current + node anyway. It is probably a misspelling. */ + if (!entry) + { + if (arg == first_arg) + { + node = make_manpage_node (first_arg); + if (node) + goto maybe_got_node; + } + + info_free_references (menu); + *errstr = _("No menu item `%s' in node `%s'."); + *errarg1 = arg; + *errarg2 = node_printed_rep (initial_node); + return initial_node; + } + + /* We have found the reference that the user specified. If no + filename in this reference, define it. */ + if (!entry->filename) + entry->filename = xstrdup (initial_node->parent ? initial_node->parent + : initial_node->filename); + + /* Try to find this node. */ + node = info_get_node (entry->filename, entry->nodename); + if (!node && arg == first_arg) + { + node = make_manpage_node (first_arg); + if (node) + goto maybe_got_node; + } + + /* Since we cannot find it, try using the label of the entry as a + file, i.e., "(LABEL)Top". */ + if (!node && entry->nodename + && strcmp (entry->label, entry->nodename) == 0) + node = info_get_node (entry->label, "Top"); + + maybe_got_node: + if (!node) + { + *errstr = _("Unable to find node referenced by `%s' in `%s'."); + *errarg1 = xstrdup (entry->label); + *errarg2 = node_printed_rep (initial_node); + info_free_references (menu); + return initial_node; + } + + info_free_references (menu); + + /* Success. Go round the loop again. */ + free (initial_node); + initial_node = node; + } + + return initial_node; +} + +/* Split STR into individual node names by writing null bytes in wherever + there are commas and constructing a list of the resulting pointers. + (We can do this since STR has had canonicalize_whitespace called on it.) + Return array terminated with NULL. */ + +static char ** +split_list_of_nodenames (str) + char *str; +{ + unsigned len = 2; + char **nodes = xmalloc (len * sizeof (char *)); + + nodes[len - 2] = str; + + while (*str++) + { + if (*str == ',') + { + *str++ = 0; /* get past the null byte */ + len++; + nodes = xrealloc (nodes, len * sizeof (char *)); + nodes[len - 2] = str; + } + } + + nodes[len - 1] = NULL; + + return nodes; +} + +/* Read a line of input which is a sequence of menus (starting from + dir), and follow them. */ +DECLARE_INFO_COMMAND (info_menu_sequence, + _("Read a list of menus starting from dir and follow them")) +{ + char *line = info_read_in_echo_area (window, _("Follow menus: ")); + + /* If the user aborted, quit now. */ + if (!line) + { + info_abort_key (window, 0, 0); + return; + } + + canonicalize_whitespace (line); + + if (*line) + { + char *errstr, *errarg1, *errarg2; + NODE *dir_node = info_get_node (NULL, NULL); + char **nodes = split_list_of_nodenames (line); + NODE *node; + + /* If DIR_NODE is NULL, they might be reading a file directly, + like in "info -d . -f ./foo". Try using "Top" instead. */ + if (!dir_node) + { + char *file_name = window->node->parent; + + if (!file_name) + file_name = window->node->filename; + dir_node = info_get_node (file_name, NULL); + } + + /* If we still cannot find the starting point, give up. + We cannot allow a NULL pointer inside info_follow_menus. */ + if (!dir_node) + info_error (msg_cant_find_node, "Top"); + else + node + = info_follow_menus (dir_node, nodes, &errstr, &errarg1, &errarg2); + + free (nodes); + if (!errstr) + info_set_node_of_window (1, window, node); + else + info_error (errstr, errarg1, errarg2); + } + + free (line); + if (!info_error_was_printed) + window_clear_echo_area (); +} + +/* Search the menu MENU for a (possibly mis-spelled) entry ARG. + Return the menu entry, or the best guess for what they meant by ARG, + or NULL if there's nothing in this menu seems to fit the bill. + If EXACT is non-zero, allow only exact matches. */ +static REFERENCE * +entry_in_menu (arg, menu, exact) + char *arg; + REFERENCE **menu; + int exact; +{ + REFERENCE *entry; + + /* First, try to find the specified menu item verbatim. */ + entry = info_get_labeled_reference (arg, menu); + + /* If the item wasn't found, search the list sloppily. Perhaps we + have "Option Summary", but ARG is "option". */ + if (!entry && !exact) + { + int i; + int best_guess = -1; + + for (i = 0; (entry = menu[i]); i++) + { + if (strcasecmp (entry->label, arg) == 0) + break; + else + if (strncasecmp (entry->label, arg, strlen (arg)) == 0) + best_guess = i; + } + + if (!entry && best_guess != -1) + entry = menu[best_guess]; + } + + return entry; +} + +/* Find the node that is the best candidate to list the PROGRAM's + invocation info and its command-line options, by looking for menu + items and chains of menu items with characteristic names. */ +void +info_intuit_options_node (window, initial_node, program) + WINDOW *window; + NODE *initial_node; + char *program; +{ + /* The list of node names typical for GNU manuals where the program + usage and specifically the command-line arguments are described. + This is pure heuristics. I gathered these node names by looking + at all the Info files I could put my hands on. If you are + looking for evidence to complain to the GNU project about + non-uniform style of documentation, here you have your case! */ + static const char *invocation_nodes[] = { + "%s invocation", + "Invoking %s", + "Preliminaries", /* m4 has Invoking under Preliminaries! */ + "Invocation", + "Command Arguments",/* Emacs */ + "Invoking `%s'", + "%s options", + "Options", + "Option ", /* e.g. "Option Summary" */ + "Invoking", + "All options", /* tar, paxutils */ + "Arguments", + "%s cmdline", /* ar */ + "%s", /* last resort */ + (const char *)0 + }; + NODE *node = NULL; + REFERENCE **menu; + const char **try_node; + + /* We keep looking deeper and deeper in the menu structure until + there are no more menus or no menu items from the above list. + Some manuals have the invocation node sitting 3 or 4 levels deep + in the menu hierarchy... */ + for (node = initial_node; node; initial_node = node) + { + REFERENCE *entry; + + /* Build and return a list of the menu items in this node. */ + menu = info_menu_of_node (initial_node); + + /* If no menu item in this node, stop here. Perhaps this node + is the one they need. */ + if (!menu) + break; + + /* Look for node names typical for usage nodes in this menu. */ + for (try_node = invocation_nodes; *try_node; try_node++) + { + char nodename[200]; + + sprintf (nodename, *try_node, program); + /* The last resort "%s" is dangerous, so we restrict it + to exact matches here. */ + entry = entry_in_menu (nodename, menu, + strcmp (*try_node, "%s") == 0); + if (entry) + break; + } + + if (!entry) + break; + + if (!entry->filename) + entry->filename = xstrdup (initial_node->parent ? initial_node->parent + : initial_node->filename); + /* Try to find this node. */ + node = info_get_node (entry->filename, entry->nodename); + info_free_references (menu); + if (!node) + break; + } + + /* We've got our best shot at the invocation node. Now select it. */ + if (initial_node) + info_set_node_of_window (1, window, initial_node); + if (!info_error_was_printed) + window_clear_echo_area (); +} + +/* Given a name of an Info file, find the name of the package it + describes by removing the leading directories and extensions. */ +char * +program_name_from_file_name (file_name) + char *file_name; +{ + int i; + char *program_name = xstrdup (filename_non_directory (file_name)); + + for (i = strlen (program_name) - 1; i > 0; i--) + if (program_name[i] == '.' + && (FILENAME_CMPN (program_name + i, ".info", 5) == 0 + || FILENAME_CMPN (program_name + i, ".inf", 4) == 0 +#ifdef __MSDOS__ + || FILENAME_CMPN (program_name + i, ".i", 2) == 0 +#endif + || isdigit (program_name[i + 1]))) /* a man page foo.1 */ + { + program_name[i] = 0; + break; + } + return program_name; +} + +DECLARE_INFO_COMMAND (info_goto_invocation_node, + _("Find the node describing program invocation")) +{ + char *invocation_prompt = _("Find Invocation node of [%s]: "); + char *program_name, *line; + char *default_program_name, *prompt, *file_name; + NODE *top_node; + + /* Intuit the name of the program they are likely to want. + We use the file name of the current Info file as a hint. */ + file_name = window->node->parent ? window->node->parent + : window->node->filename; + default_program_name = program_name_from_file_name (file_name); + + prompt = (char *)xmalloc (strlen (default_program_name) + + strlen (invocation_prompt)); + sprintf (prompt, invocation_prompt, default_program_name); + line = info_read_in_echo_area (window, prompt); + free (prompt); + if (!line) + { + info_abort_key (); + return; + } + if (*line) + program_name = line; + else + program_name = default_program_name; + + /* In interactive usage they'd probably expect us to begin looking + from the Top node. */ + top_node = info_get_node (file_name, NULL); + if (!top_node) + info_error (msg_cant_find_node, "Top"); + + info_intuit_options_node (window, top_node, program_name); + free (line); + free (default_program_name); +} + #if defined (HANDLE_MAN_PAGES) DECLARE_INFO_COMMAND (info_man, _("Read a manpage reference and select it")) { @@ -2227,7 +2776,7 @@ DECLARE_INFO_COMMAND (info_man, _("Read a manpage reference and select it")) /* Move to the "Top" node in this file. */ DECLARE_INFO_COMMAND (info_top_node, _("Select the node `Top' in this file")) { - info_parse_and_select (_("Top"), window); + info_parse_and_select ("Top", window); } /* Move to the node "(dir)Top". */ @@ -2288,7 +2837,7 @@ kill_node (window, nodename) int iw, i; INFO_WINDOW *info_win; NODE *temp; - + /* If there is no nodename to kill, quit now. */ if (!nodename) { @@ -2298,7 +2847,8 @@ kill_node (window, nodename) /* If there is a nodename, find it in our window list. */ for (iw = 0; (info_win = info_windows[iw]); iw++) - if (strcmp (nodename, info_win->nodes[info_win->current]->nodename) == 0) + if (strcmp (nodename, info_win->nodes[info_win->current]->nodename) == 0 + && info_win->window == window) break; if (!info_win) @@ -2321,7 +2871,7 @@ kill_node (window, nodename) /* INFO_WIN contains the node that the user wants to stop viewing. Delete this node from the list of nodes previously shown in this window. */ for (i = info_win->current; i < info_win->nodes_index; i++) - info_win->nodes[i] = info_win->nodes[i++]; + info_win->nodes[i] = info_win->nodes[i + 1]; /* There is one less node in this window's history list. */ info_win->nodes_index--; @@ -2359,7 +2909,7 @@ kill_node (window, nodename) /* Copy this node. */ { NODE *copy = xmalloc (sizeof (NODE)); - + temp = stealer->nodes[which]; point = stealer->points[which]; pagetop = stealer->pagetops[which]; @@ -2370,6 +2920,7 @@ kill_node (window, nodename) copy->contents = temp->contents; copy->nodelen = temp->nodelen; copy->flags = temp->flags; + copy->display_pos = temp->display_pos; temp = copy; } @@ -2382,6 +2933,7 @@ kill_node (window, nodename) else { temp = info_win->nodes[info_win->current]; + temp->display_pos = info_win->points[info_win->current]; window_set_node_of_window (info_win->window, temp); } @@ -2433,13 +2985,11 @@ DECLARE_INFO_COMMAND (info_view_file, _("Read the name of a file and select it") if (info_recent_file_error) info_error (info_recent_file_error); else - info_error (_("Cannot find \"%s\"."), line); + info_error (_("Cannot find `%s'."), line); } else - { - set_remembered_pagetop_and_point (active_window); - info_set_node_of_window (window, node); - } + info_set_node_of_window (1, window, node); + free (line); } @@ -2480,7 +3030,7 @@ dump_nodes_to_file (filename, nodenames, output_filename, dump_subnodes) if (!output_stream) { - info_error (_("Could not create output file \"%s\"."), output_filename); + info_error (_("Could not create output file `%s'."), output_filename); return; } @@ -2529,10 +3079,10 @@ dump_node_to_stream (filename, nodename, stream, dump_subnodes) else { if (filename && *nodename != '(') - info_error - (CANT_FILE_NODE, filename_non_directory (filename), nodename); + info_error (msg_cant_file_node, filename_non_directory (filename), + nodename); else - info_error (CANT_FIND_NODE, nodename); + info_error (msg_cant_find_node, nodename); } return; } @@ -2549,11 +3099,7 @@ dump_node_to_stream (filename, nodename, stream, dump_subnodes) #if defined (VERBOSE_NODE_DUMPING) /* Maybe we should print some information about the node being output. */ - if (node->filename) - info_error (_("Writing node \"(%s)%s\"..."), - filename_non_directory (node->filename), node->nodename); - else - info_error (_("Writing node \"%s\"..."), node->nodename); + info_error (_("Writing node %s..."), node_printed_rep (node)); #endif /* VERBOSE_NODE_DUMPING */ write_node_to_stream (node, stream); @@ -2605,7 +3151,7 @@ dump_node_to_file (node, filename, dump_subnodes) if (!output_stream) { - info_error (_("Could not create output file \"%s\"."), filename); + info_error (_("Could not create output file `%s'."), filename); return; } @@ -2643,29 +3189,44 @@ print_node (node) { FILE *printer_pipe; char *print_command = getenv ("INFO_PRINT_COMMAND"); + int piping = 0; if (!print_command || !*print_command) print_command = DEFAULT_INFO_PRINT_COMMAND; - printer_pipe = popen (print_command, "w"); + /* Note that on MS-DOS/MS-Windows, this MUST open the pipe in the + (default) text mode, since the printer drivers there need to see + DOS-style CRLF pairs at the end of each line. + + FIXME: if we are to support Mac-style text files, we might need + to convert the text here. */ + + /* INFO_PRINT_COMMAND which says ">file" means write to that file. + Presumably, the name of the file is the local printer device. */ + if (*print_command == '>') + printer_pipe = fopen (++print_command, "w"); + else + { + printer_pipe = popen (print_command, "w"); + piping = 1; + } if (!printer_pipe) { - info_error (_("Cannot open pipe to \"%s\"."), print_command); + info_error (_("Cannot open pipe to `%s'."), print_command); return; } #if defined (VERBOSE_NODE_DUMPING) /* Maybe we should print some information about the node being output. */ - if (node->filename) - info_error (_("Printing node \"(%s)%s\"..."), - filename_non_directory (node->filename), node->nodename); - else - info_error (_("Printing node \"%s\"..."), node->nodename); + info_error (_("Printing node %s..."), node_printed_rep (node)); #endif /* VERBOSE_NODE_DUMPING */ write_node_to_stream (node, printer_pipe); - pclose (printer_pipe); + if (piping) + pclose (printer_pipe); + else + fclose (printer_pipe); #if defined (VERBOSE_NODE_DUMPING) info_error (_("Done.")); @@ -2693,12 +3254,16 @@ write_node_to_stream (node, stream) int gc_compressed_files = 0; static void info_gc_file_buffers (); +static void info_search_1 (); static char *search_string = (char *)NULL; static int search_string_index = 0; static int search_string_size = 0; static int isearch_is_active = 0; +static int last_search_direction = 0; +static int last_search_case_sensitive = 0; + /* Return the file buffer which belongs to WINDOW's node. */ FILE_BUFFER * file_buffer_of_window (window) @@ -2724,12 +3289,12 @@ file_buffer_of_window (window) DIR says which direction to search in. If it is positive, search forward, else backwards. */ long -info_search_in_node (string, node, start, window, dir) +info_search_in_node (string, node, start, window, dir, case_sensitive) char *string; NODE *node; long start; WINDOW *window; - int dir; + int dir, case_sensitive; { SEARCH_BINDING binding; long offset; @@ -2737,7 +3302,9 @@ info_search_in_node (string, node, start, window, dir) binding.buffer = node->contents; binding.start = start; binding.end = node->nodelen; - binding.flags = S_FoldCase; + binding.flags = 0; + if (!case_sensitive) + binding.flags |= S_FoldCase; if (dir < 0) { @@ -2786,7 +3353,7 @@ info_target_search_node (node, string, start) while (i) { target[i] = '\0'; - offset = info_search_in_node (target, node, start, (WINDOW *)NULL, 1); + offset = info_search_in_node (target, node, start, (WINDOW *)NULL, 1, 0); if (offset != -1) break; @@ -2803,12 +3370,11 @@ info_target_search_node (node, string, start) associated with WINDOW's node, and search through each node in that file. If the search fails, return non-zero, else zero. Side-effect window leaving the node and point where the string was found current. */ -static char *last_searched_for_string = (char *)NULL; static int -info_search_internal (string, window, dir) +info_search_internal (string, window, dir, case_sensitive) char *string; WINDOW *window; - int dir; + int dir, case_sensitive; { register int i; FILE_BUFFER *file_buffer; @@ -2818,21 +3384,14 @@ info_search_internal (string, window, dir) file_buffer = file_buffer_of_window (window); initial_nodename = window->node->nodename; - if ((info_last_executed_command == info_search) && - (last_searched_for_string) && - (strcmp (last_searched_for_string, string) == 0)) - { - ret = info_search_in_node - (string, window->node, window->point + dir, window, dir); - } - else - { - ret = info_search_in_node - (string, window->node, window->point, window, dir); - } - - maybe_free (last_searched_for_string); - last_searched_for_string = xstrdup (string); + /* This used to begin from window->point, unless this was a repeated + search command. But invoking search with an argument loses with + that logic, since info_last_executed_command is then set to + info_add_digit_to_numeric_arg. I think there's no sense in + ``finding'' a string that is already under the cursor, anyway. */ + ret = info_search_in_node + (string, window->node, window->point + dir, window, dir, + case_sensitive); if (ret != -1) { @@ -2881,19 +3440,28 @@ info_search_internal (string, window, dir) /* Allow C-g to quit the search, failing it if pressed. */ return_if_control_g (-1); - current_tag += dir; + /* Find the next tag that isn't an anchor. */ + for (i = current_tag + dir; i != current_tag; i += dir) + { + if (i < 0) + i = number_of_tags - 1; + else if (i == number_of_tags) + i = 0; - if (current_tag < 0) - current_tag = number_of_tags - 1; - else if (current_tag == number_of_tags) - current_tag = 0; + tag = file_buffer->tags[i]; + if (tag->nodelen != 0) + break; + } - tag = file_buffer->tags[current_tag]; + /* If we got past out starting point, bail out. */ + if (i == current_tag) + return (-1); + current_tag = i; if (!echo_area_is_active && (last_subfile != tag->filename)) { window_message_in_echo_area - (_("Searching subfile \"%s\"..."), + (_("Searching subfile %s ..."), filename_non_directory (tag->filename)); last_subfile = tag->filename; @@ -2909,7 +3477,7 @@ info_search_internal (string, window, dir) if (info_recent_file_error) info_error (info_recent_file_error); else - info_error (CANT_FILE_NODE, + info_error (msg_cant_file_node, filename_non_directory (file_buffer->filename), tag->nodename); } @@ -2920,7 +3488,8 @@ info_search_internal (string, window, dir) start = tag->nodelen; ret = - info_search_in_node (string, node, start, window, dir); + info_search_in_node (string, node, start, window, dir, + case_sensitive); /* Did we find the string in this node? */ if (ret != -1) @@ -2943,16 +3512,52 @@ info_search_internal (string, window, dir) return (-1); } +DECLARE_INFO_COMMAND (info_search_case_sensitively, + _("Read a string and search for it case-sensitively")) +{ + last_search_direction = count > 0 ? 1 : -1; + last_search_case_sensitive = 1; + info_search_1 (window, count, key, 1, 1); +} + DECLARE_INFO_COMMAND (info_search, _("Read a string and search for it")) { + last_search_direction = count > 0 ? 1 : -1; + last_search_case_sensitive = 0; + info_search_1 (window, count, key, 0, 1); +} + +DECLARE_INFO_COMMAND (info_search_backward, + _("Read a string and search backward for it")) +{ + last_search_direction = count > 0 ? -1 : 1; + last_search_case_sensitive = 0; + info_search_1 (window, -count, key, 0, 1); +} + +static void +info_search_1 (window, count, key, case_sensitive, ask_for_string) + WINDOW *window; + int count; + unsigned char key; + int case_sensitive; + int ask_for_string; +{ char *line, *prompt; int result, old_pagetop; int direction; if (count < 0) - direction = -1; + { + direction = -1; + count = -count; + } else - direction = 1; + { + direction = 1; + if (count == 0) + count = 1; /* for backward compatibility */ + } /* Read a string from the user, defaulting the search to SEARCH_STRING. */ if (!search_string) @@ -2961,34 +3566,50 @@ DECLARE_INFO_COMMAND (info_search, _("Read a string and search for it")) search_string[0] = '\0'; } - prompt = (char *)xmalloc (50 + strlen (search_string)); + if (ask_for_string) + { + prompt = (char *)xmalloc (50 + strlen (search_string)); - sprintf (prompt, _("%s for string [%s]: "), - direction < 0 ? _("Search backward") : _("Search"), - search_string); + sprintf (prompt, _("%s%sfor string [%s]: "), + direction < 0 ? _("Search backward") : _("Search"), + case_sensitive ? _(" case-sensitively ") : _(" "), + search_string); - line = info_read_in_echo_area (window, prompt); - free (prompt); + line = info_read_in_echo_area (window, prompt); + free (prompt); - if (!line) - { - info_abort_key (); - return; - } + if (!line) + { + info_abort_key (); + return; + } - if (*line) - { - if (strlen (line) + 1 > search_string_size) - search_string = (char *) - xrealloc (search_string, (search_string_size += 50 + strlen (line))); + if (*line) + { + if (strlen (line) + 1 > search_string_size) + search_string = (char *) xrealloc + (search_string, (search_string_size += 50 + strlen (line))); - strcpy (search_string, line); - search_string_index = strlen (line); - free (line); + strcpy (search_string, line); + search_string_index = strlen (line); + free (line); + } } + /* If the search string includes upper-case letters, make the search + case-sensitive. */ + if (case_sensitive == 0) + for (line = search_string; *line; line++) + if (isupper (*line)) + { + case_sensitive = 1; + break; + } + old_pagetop = active_window->pagetop; - result = info_search_internal (search_string, active_window, direction); + for (result = 0; result == 0 && count--; ) + result = info_search_internal (search_string, + active_window, direction, case_sensitive); if (result != 0 && !info_error_was_printed) info_error (_("Search failed.")); @@ -3008,6 +3629,26 @@ DECLARE_INFO_COMMAND (info_search, _("Read a string and search for it")) info_gc_file_buffers (); } +DECLARE_INFO_COMMAND (info_search_next, + _("Repeat last search in the same direction")) +{ + if (!last_search_direction) + info_error (_("No previous search string")); + else + info_search_1 (window, last_search_direction * count, + key, last_search_case_sensitive, 0); +} + +DECLARE_INFO_COMMAND (info_search_previous, + _("Repeat last search in the reverse direction")) +{ + if (!last_search_direction) + info_error (_("No previous search string")); + else + info_search_1 (window, -last_search_direction * count, + key, last_search_case_sensitive, 0); +} + /* **************************************************************** */ /* */ /* Incremental Searching */ @@ -3162,6 +3803,8 @@ incremental_search (window, count, ignore) unsigned char key; int last_search_result, search_result, dir; SEARCH_STATE mystate, orig_state; + char *p; + int case_sensitive = 0; if (count < 0) dir = -1; @@ -3228,7 +3871,7 @@ incremental_search (window, count, ignore) if (quoted) goto insert_and_search; - if (!Meta_p (key) || (ISO_Latin_p && key < 160)) + if (!Meta_p (key) || key > 32) { func = window->keymap[key].function; @@ -3320,7 +3963,16 @@ incremental_search (window, count, ignore) last_isearch_accepted = xstrdup (isearch_string); } - if (key != isearch_terminate_search_key) + /* If the key is the isearch_terminate_search_key, but some buffered + input is pending, it is almost invariably because the ESC key is + actually the beginning of an escape sequence, like in case they + pressed an arrow key. So don't gobble the ESC key, push it back + into pending input. */ + /* FIXME: this seems like a kludge! We need a more reliable + mechanism to know when ESC is a separate key and when it is + part of an escape sequence. */ + if (key != isearch_terminate_search_key || + info_any_buffered_input_p ()) info_set_pending_input (key); if (func == info_abort_key) @@ -3343,17 +3995,29 @@ incremental_search (window, count, ignore) search_now: show_isearch_prompt (dir, isearch_string, search_result); + /* If the search string includes upper-case letters, make the + search case-sensitive. */ + for (p = isearch_string; *p; p++) + if (isupper (*p)) + { + case_sensitive = 1; + break; + } + + if (search_result == 0) { /* Check to see if the current search string is right here. If we are looking at it, then don't bother calling the search function. */ if (((dir < 0) && - (strncasecmp (window->node->contents + window->point, + ((case_sensitive ? strncmp : strncasecmp) + (window->node->contents + window->point, isearch_string, isearch_string_index) == 0)) || ((dir > 0) && ((window->point - isearch_string_index) >= 0) && - (strncasecmp (window->node->contents + + ((case_sensitive ? strncmp : strncasecmp) + (window->node->contents + (window->point - (isearch_string_index - 1)), isearch_string, isearch_string_index) == 0))) { @@ -3361,7 +4025,8 @@ incremental_search (window, count, ignore) window->point++; } else - search_result = info_search_internal (isearch_string, window, dir); + search_result = info_search_internal (isearch_string, + window, dir, case_sensitive); } /* If this search failed, and we didn't already have a failed search, @@ -3437,8 +4102,8 @@ info_gc_file_buffers () { for (i = 0; iw->nodes && iw->nodes[i]; i++) { - if ((strcmp (fb->fullpath, iw->nodes[i]->filename) == 0) || - (strcmp (fb->filename, iw->nodes[i]->filename) == 0)) + if ((FILENAME_CMP (fb->fullpath, iw->nodes[i]->filename) == 0) || + (FILENAME_CMP (fb->filename, iw->nodes[i]->filename) == 0)) { fb_referenced_p = 1; break; @@ -3483,7 +4148,7 @@ info_move_to_xref (window, count, key, dir) found is moved to. */ firstmenu = info_search_in_node - (INFO_MENU_ENTRY_LABEL, node, start, (WINDOW *)NULL, dir); + (INFO_MENU_ENTRY_LABEL, node, start, (WINDOW *)NULL, dir, 0); /* FIRSTMENU may point directly to the line defining the menu. Skip that and go directly to the first item. */ @@ -3494,11 +4159,11 @@ info_move_to_xref (window, count, key, dir) if (strncmp (text, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL)) == 0) firstmenu = info_search_in_node - (INFO_MENU_ENTRY_LABEL, node, firstmenu + dir, (WINDOW *)NULL, dir); + (INFO_MENU_ENTRY_LABEL, node, firstmenu + dir, (WINDOW *)NULL, dir, 0); } firstxref = - info_search_in_node (INFO_XREF_LABEL, node, start, (WINDOW *)NULL, dir); + info_search_in_node (INFO_XREF_LABEL, node, start, (WINDOW *)NULL, dir, 0); #if defined (HANDLE_MAN_PAGES) if ((firstxref == -1) && (node->flags & N_IsManPage)) @@ -3509,7 +4174,7 @@ info_move_to_xref (window, count, key, dir) if (firstmenu == -1 && firstxref == -1) { - info_error (_("No cross references in this node.")); + info_error (msg_no_xref_node); return; } @@ -3517,10 +4182,10 @@ info_move_to_xref (window, count, key, dir) Try hard to find the next available one. */ nextmenu = info_search_in_node - (INFO_MENU_ENTRY_LABEL, node, window->point + dir, (WINDOW *)NULL, dir); + (INFO_MENU_ENTRY_LABEL, node, window->point + dir, (WINDOW *)NULL, dir, 0); nextxref = info_search_in_node - (INFO_XREF_LABEL, node, window->point + dir, (WINDOW *)NULL, dir); + (INFO_XREF_LABEL, node, window->point + dir, (WINDOW *)NULL, dir, 0); #if defined (HANDLE_MAN_PAGES) if ((nextxref == -1) && (node->flags & N_IsManPage) && (firstxref != -1)) @@ -3534,7 +4199,7 @@ info_move_to_xref (window, count, key, dir) if (strncmp (text, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL)) == 0) nextmenu = info_search_in_node - (INFO_MENU_ENTRY_LABEL, node, nextmenu + dir, (WINDOW *)NULL, dir); + (INFO_MENU_ENTRY_LABEL, node, nextmenu + dir, (WINDOW *)NULL, dir, 0); } /* If there is both a next menu entry, and a next xref entry, choose the @@ -3633,7 +4298,7 @@ DECLARE_INFO_COMMAND (info_abort_key, _("Cancel current operation")) /* Move the cursor to the desired line of the window. */ DECLARE_INFO_COMMAND (info_move_to_window_line, - _("Move to the cursor to a specific line of the window")) + _("Move the cursor to a specific line of the window")) { int line; @@ -3728,10 +4393,7 @@ dispatch_error (keyseq) info_error (_("Unknown command (%s)."), rep); else { - char *temp; - - temp = (char *)xmalloc (1 + strlen (rep) + strlen (_("\"\" is invalid"))); - + char *temp = xmalloc (1 + strlen (rep) + strlen (_("\"\" is invalid"))); sprintf (temp, _("\"%s\" is invalid"), rep); terminal_ring_bell (); inform_in_echo_area (temp); @@ -4172,6 +4834,31 @@ info_gather_typeahead () if (chars_avail == -1) chars_avail = 0; } +# else /* !O_NDELAY */ +# ifdef __DJGPP__ + { + extern long pc_term_chars_avail (void); + + if (isatty (tty)) + chars_avail = pc_term_chars_avail (); + else + { + /* We could be more accurate by calling ltell, but we have no idea + whether tty is buffered by stdio functions, and if so, how many + characters are already waiting in the buffer. So we punt. */ + struct stat st; + + if (fstat (tty, &st) < 0) + chars_avail = 1; + else + chars_avail = st.st_size; + } + if (chars_avail > space_avail) + chars_avail = space_avail; + if (chars_avail) + chars_avail = read (tty, &input[0], chars_avail); + } +# endif/* __DJGPP__ */ # endif /* O_NDELAY */ #endif /* !FIONREAD */ @@ -4229,6 +4916,7 @@ info_get_input_char () { fclose (info_input_stream); info_input_stream = stdin; + tty = fileno (info_input_stream); display_inhibited = 0; display_update_display (windows); display_cursor_at_point (active_window); @@ -4240,7 +4928,7 @@ info_get_input_char () { terminal_unprep_terminal (); close_dribble_file (); - exit (0); + xexit (0); } } } diff --git a/contrib/texinfo/info/session.h b/contrib/texinfo/info/session.h index f1e5b23..07ffd5f 100644 --- a/contrib/texinfo/info/session.h +++ b/contrib/texinfo/info/session.h @@ -1,9 +1,7 @@ -/* session.h -- Functions found in session.c. */ +/* session.h -- Functions found in session.c. + $Id: session.h,v 1.9 1999/06/25 21:57:40 karl Exp $ -/* This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993 Free Software Foundation, Inc. + Copyright (C) 1993, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,7 +19,7 @@ Written by Brian Fox (bfox@ai.mit.edu). */ -#if !defined (SESSION_H) +#ifndef SESSION_H #define SESSION_H #include "info.h" @@ -76,6 +74,7 @@ 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 (); +extern char *program_name_from_file_name (); /* Do the physical deletion of WINDOW, and forget this window and associated nodes. */ @@ -110,6 +109,8 @@ extern void info_move_to_prev_xref (), info_move_to_next_xref (); extern void info_scroll_forward (), info_scroll_backward (); extern void info_redraw_display (), info_toggle_wrap (); extern void info_move_to_window_line (); +extern void info_up_line (), info_down_line (); +extern void info_scroll_half_screen_down (), info_scroll_half_screen_up (); /* Manipulating multiple windows. */ extern void info_split_window (), info_delete_window (); @@ -123,6 +124,8 @@ 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 (); +extern void info_menu_sequence (); +extern NODE *info_follow_menus (/* initial_node, menus, errstr, errarg */); /* Selecting cross references. */ extern void info_menu_digit (), info_menu_item (), info_xref_item (); @@ -136,6 +139,8 @@ extern void info_initialize_numeric_arg (), info_numeric_arg_digit_loop (); /* Searching commands. */ extern void info_search (), isearch_forward (), isearch_backward (); +extern void info_search_case_sensitively (), info_search_backward (); +extern void info_search_next (), info_search_previous (); /* Dumping and printing nodes. */ extern void info_print_node (); @@ -143,4 +148,4 @@ extern void info_print_node (); /* Miscellaneous commands. */ extern void info_abort_key (), info_quit (), info_do_lowercase_version (); -#endif /* SESSION_H */ +#endif /* not SESSION_H */ diff --git a/contrib/texinfo/info/signals.c b/contrib/texinfo/info/signals.c index b93a585..0e92578 100644 --- a/contrib/texinfo/info/signals.c +++ b/contrib/texinfo/info/signals.c @@ -1,9 +1,7 @@ -/* signals.c -- Install and maintain Info signal handlers. */ +/* signals.c -- install and maintain Info signal handlers. + $Id: signals.c,v 1.6 1998/12/06 22:00:04 karl Exp $ -/* This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. + Copyright (C) 1993, 94, 95, 98 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 @@ -30,6 +28,9 @@ /* */ /* **************************************************************** */ +/* Non-zero when our signal handler has been called to handle SIGWINCH. */ +static int in_sigwinch = 0; + #if !defined (HAVE_SIGPROCMASK) && defined (HAVE_SIGSETMASK) /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */ static void @@ -66,7 +67,7 @@ typedef RETSIGTYPE signal_handler (); static RETSIGTYPE info_signal_handler (); static signal_handler *old_TSTP, *old_TTOU, *old_TTIN; -static signal_handler *old_WINCH, *old_INT; +static signal_handler *old_WINCH, *old_INT, *old_USR1; void initialize_info_signal_handler () @@ -84,6 +85,11 @@ initialize_info_signal_handler () #if defined (SIGINT) old_INT = (signal_handler *) signal (SIGINT, info_signal_handler); #endif + +#if defined (SIGUSR1) + /* Used by DJGPP to simulate SIGTSTP on Ctrl-Z. */ + old_USR1 = (signal_handler *) signal (SIGUSR1, info_signal_handler); +#endif } static void @@ -97,6 +103,19 @@ redisplay_after_signal () fflush (stdout); } +static void +reset_info_window_sizes () +{ + terminal_goto_xy (0, 0); + fflush (stdout); + terminal_unprep_terminal (); + terminal_get_screen_size (); + terminal_prep_terminal (); + display_initialize_display (screenwidth, screenheight); + window_new_screen_size (screenwidth, screenheight, NULL); + redisplay_after_signal (); +} + static RETSIGTYPE info_signal_handler (sig) int sig; @@ -145,28 +164,43 @@ info_signal_handler (sig) } break; -#if defined (SIGWINCH) +#if defined (SIGWINCH) || defined (SIGUSR1) +#ifdef SIGWINCH case SIGWINCH: +#endif +#ifdef SIGUSR1 + case SIGUSR1: +#endif { - /* 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 = (signal_handler *) signal (sig, info_signal_handler); - redisplay_after_signal (); + if (!in_sigwinch) { + in_sigwinch++; + + /* Turn off terminal IO, tell our parent that the window has changed, + then reinitialize the terminal and rebuild our windows. */ +#ifdef SIGWINCH + if (sig == SIGWINCH) + old_signal_handler = &old_WINCH; +#endif +#ifdef SIGUSR1 + if (sig == SIGUSR1) + old_signal_handler = &old_USR1; +#endif + 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... */ + *old_signal_handler + = (signal_handler *) signal (sig, info_signal_handler); + terminal_prep_terminal (); + reset_info_window_sizes (); + in_sigwinch--; + } } break; -#endif /* SIGWINCH */ +#endif /* SIGWINCH || SIGUSR1 */ } } diff --git a/contrib/texinfo/info/termdep.h b/contrib/texinfo/info/termdep.h index fc0f992..5f4b41a 100644 --- a/contrib/texinfo/info/termdep.h +++ b/contrib/texinfo/info/termdep.h @@ -1,10 +1,7 @@ /* termdep.h -- System things that terminal.c depends on. - $Id: termdep.h,v 1.3 1997/07/05 21:17:14 karl Exp $ + $Id: termdep.h,v 1.4 1998/04/13 22:02:57 karl Exp $ - This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 96, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 96, 97, 98 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 @@ -33,6 +30,9 @@ #ifdef HAVE_TERMIOS_H # include <termios.h> +# ifdef GWINSZ_IN_SYS_IOCTL +# include <sys/ioctl.h> +# endif #else # if defined (HAVE_TERMIO_H) # include <termio.h> diff --git a/contrib/texinfo/info/terminal.c b/contrib/texinfo/info/terminal.c index f0e43be..9223d95 100644 --- a/contrib/texinfo/info/terminal.c +++ b/contrib/texinfo/info/terminal.c @@ -1,7 +1,7 @@ /* terminal.c -- How to handle the physical terminal for Info. - $Id: terminal.c,v 1.9 1998/02/22 00:05:15 karl Exp $ + $Id: terminal.c,v 1.19 1999/09/20 12:28:54 karl Exp $ - Copyright (C) 1988, 89, 90, 91, 92, 93, 96, 97, 98 + Copyright (C) 1988, 89, 90, 91, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include <sys/types.h> #include <signal.h> +#include <sys/ioctl.h> /* TIOCGWINSZ on LynxOS, at least */ /* The Unix termcap interface code. */ #ifdef HAVE_NCURSES_TERMCAP_H @@ -76,9 +77,10 @@ VFunction *terminal_scroll_terminal_hook = (VFunction *)NULL; /* **************************************************************** */ /* 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; + used to float within it. And the name of the terminal. */ +static char *term_buffer = NULL; +static char *term_string_buffer = NULL; +static char *term_name; /* Some strings to control terminal actions. These are output by tputs (). */ static char *term_goto, *term_clreol, *term_cr, *term_clrpag; @@ -146,12 +148,13 @@ terminal_begin_using_terminal () #endif send_to_terminal (term_begin_use); - /* Without this fflush and sleep, running info in a shelltool or - cmdtool (TERM=sun-cmd) with scrollbars loses -- the scrollbars are - not restored properly. - From: strube@physik3.gwdg.de (Hans Werner Strube). */ fflush (stdout); - sleep (1); + if (STREQ (term_name, "sun-cmd")) + /* Without this fflush and sleep, running info in a shelltool or + cmdtool (TERM=sun-cmd) with scrollbars loses -- the scrollbars are + not restored properly. + From: strube@physik3.gwdg.de (Hans Werner Strube). */ + sleep (1); #ifdef SIGWINCH signal (SIGWINCH, sigsave); @@ -177,7 +180,9 @@ terminal_end_using_terminal () send_to_terminal (term_end_use); fflush (stdout); - sleep (1); + if (STREQ (term_name, "sun-cmd")) + /* See comments at other sleep. */ + sleep (1); #ifdef SIGWINCH signal (SIGWINCH, sigsave); @@ -516,7 +521,7 @@ void terminal_initialize_terminal (terminal_name) char *terminal_name; { - char *term, *buffer; + char *buffer; terminal_is_dumb_p = 0; @@ -526,37 +531,46 @@ terminal_initialize_terminal (terminal_name) return; } - term = terminal_name ? terminal_name : getenv ("TERM"); + term_name = terminal_name ? terminal_name : getenv ("TERM"); + if (!term_name) + term_name = "dumb"; if (!term_string_buffer) - term_string_buffer = (char *)xmalloc (2048); + term_string_buffer = xmalloc (2048); if (!term_buffer) - term_buffer = (char *)xmalloc (2048); + term_buffer = xmalloc (2048); buffer = term_string_buffer; - term_clrpag = term_cr = term_clreol = (char *)NULL; + term_clrpag = term_cr = term_clreol = NULL; - if (!term) - term = "dumb"; - - if (tgetent (term_buffer, term) <= 0) + /* HP-UX 11.x returns 0 for OK --jeff.hull@state.co.us. */ + if (tgetent (term_buffer, term_name) < 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; - term_kP = term_kN = (char *)NULL; + term_up = term_dn = audible_bell = visible_bell = NULL; + term_ku = term_kd = term_kl = term_kr = NULL; + term_kP = term_kN = NULL; return; } BC = tgetstr ("pc", &buffer); PC = BC ? *BC : 0; -#if defined (TIOCGETP) +#if defined (HAVE_TERMIOS_H) + { + struct termios ti; + if (tcgetattr (fileno(stdout), &ti) != -1) + ospeed = cfgetospeed (&ti); + else + ospeed = B9600; + } +#else +# if defined (TIOCGETP) { struct sgttyb sg; @@ -565,16 +579,17 @@ terminal_initialize_terminal (terminal_name) else ospeed = B9600; } -#else +# else ospeed = B9600; -#endif /* !TIOCGETP */ +# endif /* !TIOCGETP */ +#endif 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. */ + /* Find out about this terminal's scrolling capability. */ term_AL = tgetstr ("AL", &buffer); term_DL = tgetstr ("DL", &buffer); term_al = tgetstr ("al", &buffer); @@ -633,23 +648,7 @@ terminal_initialize_terminal (terminal_name) terminal_is_dumb_p = 1; } -/* **************************************************************** */ -/* */ -/* 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 +/* How to read characters from the terminal. */ #if defined (HAVE_TERMIOS_H) struct termios original_termios, ttybuff; @@ -662,6 +661,25 @@ struct termio original_termio, ttybuff; int original_tty_flags = 0; int original_lmode; struct sgttyb ttybuff; + +# if defined(TIOCGETC) && defined(M_XENIX) +/* SCO 3.2v5.0.2 defines but does not support TIOCGETC. Gak. Maybe + better fix would be to use Posix termios in preference. --gildea, + 1jul99. */ +# undef TIOCGETC +# endif + +# 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 # endif /* !HAVE_TERMIO_H */ #endif /* !HAVE_TERMIOS_H */ @@ -835,3 +853,6 @@ terminal_unprep_terminal () terminal_end_using_terminal (); } +#ifdef __MSDOS__ +# include "pcterm.c" +#endif diff --git a/contrib/texinfo/info/tilde.c b/contrib/texinfo/info/tilde.c index 401f7e1..bba285a 100644 --- a/contrib/texinfo/info/tilde.c +++ b/contrib/texinfo/info/tilde.c @@ -1,10 +1,7 @@ -/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). - $Id: tilde.c,v 1.9 1998/02/22 23:03:21 karl Exp $ +/* tilde.c -- tilde expansion code (~/foo := $HOME/foo). + $Id: tilde.c,v 1.13 1999/03/03 22:42:21 karl Exp $ - This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1988, 89, 90, 91, 92, 93, 96, 98 + Copyright (C) 1988, 89, 90, 91, 92, 93, 96, 98, 99 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -23,27 +20,9 @@ Written by Brian Fox (bfox@ai.mit.edu). */ -/* Indent #pragma so that older Cpp's don't try to parse it. */ -#ifdef _AIX - #pragma alloca -#endif /* _AIX */ - /* Include config.h before doing alloca. */ #include "info.h" -#ifdef __GNUC__ -# undef alloca -# define alloca __builtin_alloca -#else -# ifdef HAVE_ALLOCA_H -# include <alloca.h> -# else -# ifndef _AIX -char *alloca (); -# endif -# endif -#endif - #if defined (TEST) || defined (STATIC_MALLOC) static void *xmalloc (), *xrealloc (); #endif /* TEST || STATIC_MALLOC */ @@ -123,7 +102,7 @@ tilde_find_suffix (string) for (i = 0; i < string_len; i++) { - if (string[i] == '/' || !string[i]) + if (IS_SLASH (string[i]) || !string[i]) break; for (j = 0; suffixes && suffixes[j]; j++) @@ -203,14 +182,12 @@ char * tilde_expand_word (filename) char *filename; { - char *dirname; - - dirname = filename ? xstrdup (filename) : (char *)NULL; + char *dirname = filename ? xstrdup (filename) : NULL; if (dirname && *dirname == '~') { char *temp_name; - if (!dirname[1] || dirname[1] == '/') + if (!dirname[1] || IS_SLASH (dirname[1])) { /* Prepend $HOME to the rest of the string. */ char *temp_home = getenv ("HOME"); @@ -226,30 +203,31 @@ tilde_expand_word (filename) temp_home = entry->pw_dir; } - temp_name = (char *) - alloca (1 + strlen (&dirname[1]) - + (temp_home ? strlen (temp_home) : 0)); - temp_name[0] = '\0'; + temp_name = xmalloc (1 + strlen (&dirname[1]) + + (temp_home ? strlen (temp_home) : 0)); if (temp_home) strcpy (temp_name, temp_home); + else + temp_name[0] = 0; strcat (temp_name, &dirname[1]); free (dirname); dirname = xstrdup (temp_name); + free (temp_name); } else { struct passwd *user_entry; - char *username = (char *)alloca (257); + char *username = xmalloc (257); int i, c; for (i = 1; (c = dirname[i]); i++) { - if (c == '/') + if (IS_SLASH (c)) break; else username[i - 1] = c; } - username[i - 1] = '\0'; + username[i - 1] = 0; if (!(user_entry = (struct passwd *) getpwnam (username))) { @@ -264,8 +242,8 @@ tilde_expand_word (filename) if (expansion) { - temp_name = (char *)alloca - (1 + strlen (expansion) + strlen (&dirname[i])); + temp_name = xmalloc (1 + strlen (expansion) + + strlen (&dirname[i])); strcpy (temp_name, expansion); strcat (temp_name, &dirname[i]); free (expansion); @@ -276,18 +254,22 @@ tilde_expand_word (filename) } else { - temp_name = (char *)alloca - (1 + strlen (user_entry->pw_dir) + strlen (&dirname[i])); + temp_name = xmalloc (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 = xstrdup (temp_name); + free (temp_name); } - endpwent (); + + endpwent (); + free (username); } } - return (dirname); + return dirname; } @@ -322,7 +304,7 @@ main (argc, argv) printf (" --> %s\n", result); free (result); } - exit (0); + xexit (0); } static void memory_error_and_abort (); diff --git a/contrib/texinfo/info/variables.c b/contrib/texinfo/info/variables.c index 248c8af..9412797 100644 --- a/contrib/texinfo/info/variables.c +++ b/contrib/texinfo/info/variables.c @@ -1,5 +1,5 @@ /* variables.c -- How to manipulate user visible variables in Info. - $Id: variables.c,v 1.5 1997/07/18 14:34:23 karl Exp $ + $Id: variables.c,v 1.7 1999/06/25 21:57:40 karl Exp $ This file is part of GNU Info, a program for reading online documentation stored in Info format. diff --git a/contrib/texinfo/info/window.c b/contrib/texinfo/info/window.c index dbe706e..1b6d062 100644 --- a/contrib/texinfo/info/window.c +++ b/contrib/texinfo/info/window.c @@ -1,10 +1,7 @@ -/* window.c -- Windows in Info. - $Id: window.c,v 1.5 1998/02/23 22:43:38 karl Exp $ +/* window.c -- windows in Info. + $Id: window.c,v 1.11 1999/06/25 21:57:40 karl Exp $ - This file is part of GNU Info, a program for reading online documentation - stored in Info format. - - Copyright (C) 1993, 97 Free Software Foundation, Inc. + Copyright (C) 1993, 97, 98 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 @@ -30,16 +27,16 @@ #include "infomap.h" /* The window which describes the screen. */ -WINDOW *the_screen = (WINDOW *)NULL; +WINDOW *the_screen = NULL; /* The window which describes the echo area. */ -WINDOW *the_echo_area = (WINDOW *)NULL; +WINDOW *the_echo_area = NULL; /* The list of windows in Info. */ -WINDOW *windows = (WINDOW *)NULL; +WINDOW *windows = NULL; /* Pointer to the active window in WINDOW_LIST. */ -WINDOW *active_window = (WINDOW *)NULL; +WINDOW *active_window = NULL; /* The size of the echo area in Info. It never changes, irregardless of the size of the screen. */ @@ -56,9 +53,9 @@ void window_initialize_windows (width, height) int width, height; { - the_screen = (WINDOW *)xmalloc (sizeof (WINDOW)); - the_echo_area = (WINDOW *)xmalloc (sizeof (WINDOW)); - windows = (WINDOW *)xmalloc (sizeof (WINDOW)); + the_screen = xmalloc (sizeof (WINDOW)); + the_echo_area = xmalloc (sizeof (WINDOW)); + windows = xmalloc (sizeof (WINDOW)); active_window = windows; zero_mem (the_screen, sizeof (WINDOW)); @@ -85,7 +82,7 @@ window_initialize_windows (width, height) area. */ the_echo_area->height = ECHO_AREA_HEIGHT; active_window->height = the_screen->height - 1 - the_echo_area->height; - window_new_screen_size (width, height, (VFunction *)NULL); + window_new_screen_size (width, height, NULL); /* The echo area uses a different keymap than normal info windows. */ the_echo_area->keymap = echo_area_keymap; @@ -102,7 +99,7 @@ window_initialize_windows (width, height) /* If non-null, a function to call with WINDOW as argument when the function window_new_screen_size () has deleted WINDOW. */ -VFunction *window_deletion_notifier = (VFunction *)NULL; +VFunction *window_deletion_notifier = NULL; void window_new_screen_size (width, height) @@ -139,7 +136,7 @@ window_new_screen_size (width, height) { windows->height = 0; maybe_free (windows->line_starts); - windows->line_starts = (char **)NULL; + windows->line_starts = NULL; windows->line_count = 0; break; } @@ -187,7 +184,7 @@ window_new_screen_size (width, height) { win->width = width; maybe_free (win->modeline); - win->modeline = (char *)xmalloc (1 + width); + win->modeline = xmalloc (1 + width); } win->height += delta_each; @@ -274,14 +271,14 @@ window_make_window (node) /* If there isn't enough room to make another window, return now. */ if ((active_window->height / 2) < WINDOW_MIN_SIZE) - return ((WINDOW *)NULL); + return (NULL); /* Make and initialize the new window. The fudging about with -1 and +1 is because the following window in the chain cannot start at window->height, since that is where the modeline for the previous window is displayed. The inverse adjustment is made in window_delete_window (). */ - window = (WINDOW *)xmalloc (sizeof (WINDOW)); + window = xmalloc (sizeof (WINDOW)); window->width = the_screen->width; window->height = (active_window->height / 2) - 1; #if defined (SPLIT_BEFORE_ACTIVE) @@ -292,8 +289,8 @@ window_make_window (node) #endif window->keymap = info_keymap; window->goal_column = -1; - window->modeline = (char *)xmalloc (1 + window->width); - window->line_starts = (char **)NULL; + window->modeline = xmalloc (1 + window->width); + window->line_starts = NULL; window->flags = W_UpdateWindow | W_WindowVisible; window_set_node_of_window (window, node); @@ -538,7 +535,7 @@ window_tile_windows (style) per_win_height = avail / numwins; leftover = avail - (per_win_height * numwins); - last_adjusted = (WINDOW *)NULL; + last_adjusted = NULL; for (win = windows; win; win = win->next) { if (do_internals || !win->node || @@ -610,10 +607,12 @@ window_set_node_of_window (window, node) window->point = 0; recalculate_line_starts (window); window->flags |= W_UpdateWindow; + /* The display_pos member is nonzero if we're displaying an anchor. */ + window->point = node ? node->display_pos : 0; window_adjust_pagetop (window); window_make_modeline (window); } - + /* Delete WINDOW from the list of known windows. If this window was the active window, make the next window in the chain be the active window. If the active window is the next or previous window, choose that window @@ -766,7 +765,7 @@ string_width (string, hpos) return (width); } -/* Quickly guess the approximate number of lines to that NODE would +/* Quickly guess the approximate number of lines that NODE would take to display. This really only counts carriage returns. */ int window_physical_lines (node) @@ -793,12 +792,12 @@ calculate_line_starts (window) WINDOW *window; { register int i, hpos; - char **line_starts = (char **)NULL; + char **line_starts = NULL; int line_starts_index = 0, line_starts_slots = 0; int bump_index; NODE *node; - window->line_starts = (char **)NULL; + window->line_starts = NULL; window->line_count = 0; node = window->node; @@ -1079,9 +1078,9 @@ window_make_modeline (window) /* Calculate the maximum size of the information to stick in MODELINE. */ { int modeline_len = 0; - char *parent = (char *)NULL, *filename = "*no file*"; + char *parent = NULL, *filename = "*no file*"; char *nodename = "*no node*"; - char *update_message = (char *)NULL; + char *update_message = NULL; NODE *node = window->node; if (node) @@ -1113,7 +1112,7 @@ window_make_modeline (window) modeline_len += 10 + strlen (_("-----Info: (), lines ----, ")); modeline_len += window->width; - modeline = (char *)xmalloc (1 + modeline_len); + modeline = xmalloc (1 + modeline_len); /* Special internal windows have no filename. */ if (!parent && !*filename) @@ -1194,14 +1193,10 @@ window_set_state (window, state) } -/* **************************************************************** */ -/* */ -/* Manipulating Home-Made Nodes */ -/* */ -/* **************************************************************** */ +/* Manipulating home-made nodes. */ /* A place to buffer echo area messages. */ -static NODE *echo_area_node = (NODE *)NULL; +static NODE *echo_area_node = NULL; /* Make the node of the_echo_area be an empty one. */ static void @@ -1213,7 +1208,7 @@ free_echo_area () free (echo_area_node); } - echo_area_node = (NODE *)NULL; + echo_area_node = NULL; window_set_node_of_window (the_echo_area, echo_area_node); } @@ -1245,7 +1240,7 @@ window_message_in_echo_area (format, arg1, arg2) and ARG2. The message appears immediately, but does not destroy any existing message. A future call to unmessage_in_echo_area () restores the old contents. */ -static NODE **old_echo_area_nodes = (NODE **)NULL; +static NODE **old_echo_area_nodes = NULL; static int old_echo_area_nodes_index = 0; static int old_echo_area_nodes_slots = 0; @@ -1260,7 +1255,7 @@ message_in_echo_area (format, arg1, arg2) old_echo_area_nodes, old_echo_area_nodes_slots, 4, NODE *); } - echo_area_node = (NODE *)NULL; + echo_area_node = NULL; window_message_in_echo_area (format, arg1, arg2); } @@ -1277,7 +1272,7 @@ unmessage_in_echo_area () } /* A place to build a message. */ -static char *message_buffer = (char *)NULL; +static char *message_buffer = NULL; static int message_buffer_index = 0; static int message_buffer_size = 0; @@ -1290,7 +1285,7 @@ message_buffer_resize (length) if (!message_buffer) { message_buffer_size = length + 1; - message_buffer = (char *)xmalloc (message_buffer_size); + message_buffer = xmalloc (message_buffer_size); message_buffer_index = 0; } @@ -1328,14 +1323,44 @@ build_message_buffer (format, arg1, arg2) else { char c; + char *fmt_start = format + i; + char *fmt; + int fmt_len, formatted_len; + + i++; + while (format[i] && strchr ("-. +0123456789", format[i])) + i++; + c = format[i]; + + if (c == '\0') + abort (); + + fmt_len = format + i - fmt_start + 1; + fmt = (char *) xmalloc (fmt_len + 1); + strncpy (fmt, fmt_start, fmt_len); + fmt[fmt_len] = '\0'; - c = format[++i]; + /* If we have "%-98s", maybe 98 calls for a longer string. */ + if (fmt_len > 2) + { + int j; + + for (j = 0; j < fmt_len; j++) + if (isdigit (fmt[j])) + break; + + formatted_len = atoi (fmt + j); + } + else + formatted_len = c == 's' ? 0 : 1; /* %s can produce empty string */ switch (c) { case '%': /* Insert a percent sign. */ - message_buffer_resize (len + 1); - message_buffer[message_buffer_index++] = '%'; + message_buffer_resize (len + formatted_len); + sprintf + (message_buffer + message_buffer_index, fmt, "%"); + message_buffer_index += formatted_len; break; case 's': /* Insert the current arg as a string. */ @@ -1346,9 +1371,11 @@ build_message_buffer (format, arg1, arg2) string = (char *)args[arg_index++]; string_len = strlen (string); + if (formatted_len > string_len) + string_len = formatted_len; message_buffer_resize (len + string_len); sprintf - (message_buffer + message_buffer_index, "%s", string); + (message_buffer + message_buffer_index, fmt, string); message_buffer_index += string_len; } break; @@ -1361,9 +1388,10 @@ build_message_buffer (format, arg1, arg2) long_val = (long)args[arg_index++]; integer = (int)long_val; - message_buffer_resize (len + 32); + message_buffer_resize (len + formatted_len > 32 + ? formatted_len : 32); sprintf - (message_buffer + message_buffer_index, "%d", integer); + (message_buffer + message_buffer_index, fmt, integer); message_buffer_index = strlen (message_buffer); } break; @@ -1376,14 +1404,17 @@ build_message_buffer (format, arg1, arg2) long_val = (long)args[arg_index++]; character = (int)long_val; - message_buffer_resize (len + 1); - message_buffer[message_buffer_index++] = character; + message_buffer_resize (len + formatted_len); + sprintf + (message_buffer + message_buffer_index, fmt, character); + message_buffer_index += formatted_len; } break; default: abort (); } + free (fmt); } } message_buffer[message_buffer_index] = '\0'; @@ -1411,15 +1442,16 @@ message_buffer_to_node () { NODE *node; - node = (NODE *)xmalloc (sizeof (NODE)); - node->filename = (char *)NULL; - node->parent = (char *)NULL; - node->nodename = (char *)NULL; + node = xmalloc (sizeof (NODE)); + node->filename = NULL; + node->parent = NULL; + node->nodename = NULL; node->flags = 0; + node->display_pos =0; /* Make sure that this buffer ends with a newline. */ node->nodelen = 1 + strlen (message_buffer); - node->contents = (char *)xmalloc (1 + node->nodelen); + node->contents = xmalloc (1 + node->nodelen); strcpy (node->contents, message_buffer); node->contents[node->nodelen - 1] = '\n'; node->contents[node->nodelen] = '\0'; |