156160Sru/* info-utils.c -- miscellanous.
2146515Sru   $Id: info-utils.c,v 1.4 2004/04/11 17:56:45 karl Exp $
321495Sjmacd
4146515Sru   Copyright (C) 1993, 1998, 2003, 2004 Free Software Foundation, Inc.
521495Sjmacd
621495Sjmacd   This program is free software; you can redistribute it and/or modify
721495Sjmacd   it under the terms of the GNU General Public License as published by
821495Sjmacd   the Free Software Foundation; either version 2, or (at your option)
921495Sjmacd   any later version.
1021495Sjmacd
1121495Sjmacd   This program is distributed in the hope that it will be useful,
1221495Sjmacd   but WITHOUT ANY WARRANTY; without even the implied warranty of
1321495Sjmacd   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1421495Sjmacd   GNU General Public License for more details.
1521495Sjmacd
1621495Sjmacd   You should have received a copy of the GNU General Public License
1721495Sjmacd   along with this program; if not, write to the Free Software
1821495Sjmacd   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1921495Sjmacd
20146515Sru   Originally written by Brian Fox (bfox@ai.mit.edu). */
2121495Sjmacd
2242660Smarkm#include "info.h"
2321495Sjmacd#include "info-utils.h"
2421495Sjmacd#if defined (HANDLE_MAN_PAGES)
2521495Sjmacd#  include "man.h"
2621495Sjmacd#endif /* HANDLE_MAN_PAGES */
2721495Sjmacd
2821495Sjmacd/* When non-zero, various display and input functions handle ISO Latin
2921495Sjmacd   character sets correctly. */
3056160Sruint ISO_Latin_p = 1;
3121495Sjmacd
3221495Sjmacd/* Variable which holds the most recent filename parsed as a result of
3321495Sjmacd   calling info_parse_xxx (). */
3421495Sjmacdchar *info_parsed_filename = (char *)NULL;
3521495Sjmacd
3621495Sjmacd/* Variable which holds the most recent nodename parsed as a result of
3721495Sjmacd   calling info_parse_xxx (). */
3821495Sjmacdchar *info_parsed_nodename = (char *)NULL;
3921495Sjmacd
40146515Sru/* Variable which holds the most recent line number parsed as a result of
41146515Sru   calling info_parse_xxx (). */
42146515Sruint info_parsed_line_number = 0;
43146515Sru
4421495Sjmacd/* Functions to remember a filename or nodename for later return. */
45146515Srustatic void save_filename (char *filename);
46146515Srustatic void saven_filename (char *filename, int len);
47146515Srustatic void save_nodename (char *nodename);
48146515Srustatic void saven_nodename (char *nodename, int len);
4921495Sjmacd
5021495Sjmacd/* How to get a reference (either menu or cross). */
51146515Srustatic REFERENCE **info_references_internal (char *label,
52146515Sru    SEARCH_BINDING *binding);
5321495Sjmacd
5421495Sjmacd/* Parse the filename and nodename out of STRING.  If STRING doesn't
5521495Sjmacd   contain a filename (i.e., it is NOT (FILENAME)NODENAME) then set
5621495Sjmacd   INFO_PARSED_FILENAME to NULL.  If second argument NEWLINES_OKAY is
5721495Sjmacd   non-zero, it says to allow the nodename specification to cross a
5821495Sjmacd   newline boundary (i.e., only `,', `.', or `TAB' can end the spec). */
5921495Sjmacdvoid
60146515Sruinfo_parse_node (char *string, int newlines_okay)
6121495Sjmacd{
6221495Sjmacd  register int i = 0;
6321495Sjmacd
6421495Sjmacd  /* Default the answer. */
6521495Sjmacd  save_filename ((char *)NULL);
6621495Sjmacd  save_nodename ((char *)NULL);
6721495Sjmacd
6821495Sjmacd  /* Special case of nothing passed.  Return nothing. */
6921495Sjmacd  if (!string || !*string)
7021495Sjmacd    return;
7121495Sjmacd
7221495Sjmacd  string += skip_whitespace (string);
7321495Sjmacd
7421495Sjmacd  /* Check for (FILENAME)NODENAME. */
7521495Sjmacd  if (*string == '(')
7621495Sjmacd    {
7721495Sjmacd      i = 0;
7821495Sjmacd      /* Advance past the opening paren. */
7921495Sjmacd      string++;
8021495Sjmacd
8121495Sjmacd      /* Find the closing paren. */
8221495Sjmacd      while (string[i] && string[i] != ')')
8342660Smarkm        i++;
8421495Sjmacd
8521495Sjmacd      /* Remember parsed filename. */
8621495Sjmacd      saven_filename (string, i);
8721495Sjmacd
8821495Sjmacd      /* Point directly at the nodename. */
8921495Sjmacd      string += i;
9021495Sjmacd
9121495Sjmacd      if (*string)
9242660Smarkm        string++;
9321495Sjmacd    }
9421495Sjmacd
9521495Sjmacd  /* Parse out nodename. */
9621495Sjmacd  i = skip_node_characters (string, newlines_okay);
9721495Sjmacd  saven_nodename (string, i);
9821495Sjmacd  canonicalize_whitespace (info_parsed_nodename);
9921495Sjmacd  if (info_parsed_nodename && !*info_parsed_nodename)
10021495Sjmacd    {
10121495Sjmacd      free (info_parsed_nodename);
10221495Sjmacd      info_parsed_nodename = (char *)NULL;
10321495Sjmacd    }
104146515Sru
105146515Sru  /* Parse ``(line ...)'' part of menus, if any.  */
106146515Sru  {
107146515Sru    char *rest = string + i;
108146515Sru
109146515Sru    /* Advance only if it's not already at end of string.  */
110146515Sru    if (*rest)
111146515Sru      rest++;
112146515Sru
113146515Sru    /* Skip any whitespace first, and then a newline in case the item
114146515Sru       was so long to contain the ``(line ...)'' string in the same
115146515Sru       physical line.  */
116146515Sru    while (whitespace(*rest))
117146515Sru      rest++;
118146515Sru    if (*rest == '\n')
119146515Sru      {
120146515Sru        rest++;
121146515Sru        while (whitespace(*rest))
122146515Sru          rest++;
123146515Sru      }
124146515Sru
125146515Sru    /* Are we looking at an opening parenthesis?  That can only mean
126146515Sru       we have a winner. :)  */
127146515Sru    if (strncmp (rest, "(line ", strlen ("(line ")) == 0)
128146515Sru      {
129146515Sru        rest += strlen ("(line ");
130146515Sru        info_parsed_line_number = strtol (rest, NULL, 0);
131146515Sru      }
132146515Sru    else
133146515Sru      info_parsed_line_number = 0;
134146515Sru  }
13521495Sjmacd}
13621495Sjmacd
13721495Sjmacd/* Return the node addressed by LABEL in NODE (usually one of "Prev:",
13821495Sjmacd   "Next:", "Up:", "File:", or "Node:".  After a call to this function,
13921495Sjmacd   the global INFO_PARSED_NODENAME and INFO_PARSED_FILENAME contain
14021495Sjmacd   the information. */
14121495Sjmacdvoid
142146515Sruinfo_parse_label (char *label, NODE *node)
14321495Sjmacd{
14421495Sjmacd  register int i;
14521495Sjmacd  char *nodeline;
14621495Sjmacd
14721495Sjmacd  /* Default answer to failure. */
14821495Sjmacd  save_nodename ((char *)NULL);
14921495Sjmacd  save_filename ((char *)NULL);
15021495Sjmacd
15121495Sjmacd  /* Find the label in the first line of this node. */
15221495Sjmacd  nodeline = node->contents;
15321495Sjmacd  i = string_in_line (label, nodeline);
15421495Sjmacd
15521495Sjmacd  if (i == -1)
15621495Sjmacd    return;
15721495Sjmacd
15821495Sjmacd  nodeline += i;
15921495Sjmacd  nodeline += skip_whitespace (nodeline);
16021495Sjmacd  info_parse_node (nodeline, DONT_SKIP_NEWLINES);
16121495Sjmacd}
16221495Sjmacd
16321495Sjmacd/* **************************************************************** */
16442660Smarkm/*                                                                  */
16542660Smarkm/*                  Finding and Building Menus                      */
16642660Smarkm/*                                                                  */
16721495Sjmacd/* **************************************************************** */
16821495Sjmacd
16921495Sjmacd/* Return a NULL terminated array of REFERENCE * which represents the menu
17021495Sjmacd   found in NODE.  If there is no menu in NODE, just return a NULL pointer. */
17121495SjmacdREFERENCE **
172146515Sruinfo_menu_of_node (NODE *node)
17321495Sjmacd{
17421495Sjmacd  long position;
175146515Sru  SEARCH_BINDING tmp_search;
17621495Sjmacd  REFERENCE **menu = (REFERENCE **)NULL;
17721495Sjmacd
178146515Sru  tmp_search.buffer = node->contents;
179146515Sru  tmp_search.start = 0;
180146515Sru  tmp_search.end = node->nodelen;
181146515Sru  tmp_search.flags = S_FoldCase;
18221495Sjmacd
18321495Sjmacd  /* Find the start of the menu. */
184146515Sru  position = search_forward (INFO_MENU_LABEL, &tmp_search);
18521495Sjmacd
18621495Sjmacd  if (position == -1)
18721495Sjmacd    return ((REFERENCE **) NULL);
18821495Sjmacd
18921495Sjmacd  /* We have the start of the menu now.  Glean menu items from the rest
19021495Sjmacd     of the node. */
191146515Sru  tmp_search.start = position + strlen (INFO_MENU_LABEL);
192146515Sru  tmp_search.start += skip_line (tmp_search.buffer + tmp_search.start);
193146515Sru  tmp_search.start--;
194146515Sru  menu = info_menu_items (&tmp_search);
19521495Sjmacd  return (menu);
19621495Sjmacd}
19721495Sjmacd
19821495Sjmacd/* Return a NULL terminated array of REFERENCE * which represents the cross
19921495Sjmacd   refrences found in NODE.  If there are no cross references in NODE, just
20021495Sjmacd   return a NULL pointer. */
20121495SjmacdREFERENCE **
202146515Sruinfo_xrefs_of_node (NODE *node)
20321495Sjmacd{
204146515Sru  SEARCH_BINDING tmp_search;
20521495Sjmacd
20621495Sjmacd#if defined (HANDLE_MAN_PAGES)
20721495Sjmacd  if (node->flags & N_IsManPage)
20821495Sjmacd    return (xrefs_of_manpage (node));
20921495Sjmacd#endif
21021495Sjmacd
211146515Sru  tmp_search.buffer = node->contents;
212146515Sru  tmp_search.start = 0;
213146515Sru  tmp_search.end = node->nodelen;
214146515Sru  tmp_search.flags = S_FoldCase;
21521495Sjmacd
216146515Sru  return (info_xrefs (&tmp_search));
21721495Sjmacd}
21821495Sjmacd
21921495Sjmacd/* Glean menu entries from BINDING->buffer + BINDING->start until we
22021495Sjmacd   have looked at the entire contents of BINDING.  Return an array
22121495Sjmacd   of REFERENCE * that represents each menu item in this range. */
22221495SjmacdREFERENCE **
223146515Sruinfo_menu_items (SEARCH_BINDING *binding)
22421495Sjmacd{
22521495Sjmacd  return (info_references_internal (INFO_MENU_ENTRY_LABEL, binding));
22621495Sjmacd}
22721495Sjmacd
22821495Sjmacd/* Glean cross references from BINDING->buffer + BINDING->start until
22921495Sjmacd   BINDING->end.  Return an array of REFERENCE * that represents each
23021495Sjmacd   cross reference in this range. */
23121495SjmacdREFERENCE **
232146515Sruinfo_xrefs (SEARCH_BINDING *binding)
23321495Sjmacd{
23421495Sjmacd  return (info_references_internal (INFO_XREF_LABEL, binding));
23521495Sjmacd}
23621495Sjmacd
23721495Sjmacd/* Glean cross references or menu items from BINDING.  Return an array
23821495Sjmacd   of REFERENCE * that represents the items found. */
23921495Sjmacdstatic REFERENCE **
240146515Sruinfo_references_internal (char *label, SEARCH_BINDING *binding)
24121495Sjmacd{
242146515Sru  SEARCH_BINDING tmp_search;
24321495Sjmacd  REFERENCE **refs = (REFERENCE **)NULL;
24421495Sjmacd  int refs_index = 0, refs_slots = 0;
24521495Sjmacd  int searching_for_menu_items = 0;
24621495Sjmacd  long position;
24721495Sjmacd
248146515Sru  tmp_search.buffer = binding->buffer;
249146515Sru  tmp_search.start = binding->start;
250146515Sru  tmp_search.end = binding->end;
251146515Sru  tmp_search.flags = S_FoldCase | S_SkipDest;
25221495Sjmacd
25321495Sjmacd  searching_for_menu_items = (strcasecmp (label, INFO_MENU_ENTRY_LABEL) == 0);
25421495Sjmacd
255146515Sru  while ((position = search_forward (label, &tmp_search)) != -1)
25621495Sjmacd    {
25721495Sjmacd      int offset, start;
25821495Sjmacd      char *refdef;
25921495Sjmacd      REFERENCE *entry;
26021495Sjmacd
261146515Sru      tmp_search.start = position;
262146515Sru      tmp_search.start += skip_whitespace (tmp_search.buffer + tmp_search.start);
263146515Sru      start = tmp_search.start - binding->start;
264146515Sru      refdef = tmp_search.buffer + tmp_search.start;
26521495Sjmacd      offset = string_in_line (":", refdef);
26621495Sjmacd
26721495Sjmacd      /* When searching for menu items, if no colon, there is no
26842660Smarkm         menu item on this line. */
26921495Sjmacd      if (offset == -1)
27042660Smarkm        {
27142660Smarkm          if (searching_for_menu_items)
27242660Smarkm            continue;
27342660Smarkm          else
27442660Smarkm            {
27542660Smarkm              int temp;
27621495Sjmacd
27742660Smarkm              temp = skip_line (refdef);
27842660Smarkm              offset = string_in_line (":", refdef + temp);
27942660Smarkm              if (offset == -1)
28042660Smarkm                continue;       /* Give up? */
28142660Smarkm              else
28242660Smarkm                offset += temp;
28342660Smarkm            }
28442660Smarkm        }
28521495Sjmacd
28621495Sjmacd      entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
28721495Sjmacd      entry->filename = (char *)NULL;
28821495Sjmacd      entry->nodename = (char *)NULL;
28921495Sjmacd      entry->label = (char *)xmalloc (offset);
29021495Sjmacd      strncpy (entry->label, refdef, offset - 1);
29121495Sjmacd      entry->label[offset - 1] = '\0';
29221495Sjmacd      canonicalize_whitespace (entry->label);
29321495Sjmacd
29421495Sjmacd      refdef += offset;
29521495Sjmacd      entry->start = start;
29621495Sjmacd      entry->end = refdef - binding->buffer;
29721495Sjmacd
29821495Sjmacd      /* If this reference entry continues with another ':' then the
29942660Smarkm         nodename is the same as the label. */
30021495Sjmacd      if (*refdef == ':')
30142660Smarkm        {
30242660Smarkm          entry->nodename = xstrdup (entry->label);
30342660Smarkm        }
30421495Sjmacd      else
30542660Smarkm        {
30642660Smarkm          /* This entry continues with a specific nodename.  Parse the
30742660Smarkm             nodename from the specification. */
30821495Sjmacd
30942660Smarkm          refdef += skip_whitespace_and_newlines (refdef);
31021495Sjmacd
31142660Smarkm          if (searching_for_menu_items)
31242660Smarkm            info_parse_node (refdef, DONT_SKIP_NEWLINES);
31342660Smarkm          else
31442660Smarkm            info_parse_node (refdef, SKIP_NEWLINES);
31521495Sjmacd
31642660Smarkm          if (info_parsed_filename)
31742660Smarkm            entry->filename = xstrdup (info_parsed_filename);
31821495Sjmacd
31942660Smarkm          if (info_parsed_nodename)
32042660Smarkm            entry->nodename = xstrdup (info_parsed_nodename);
321146515Sru
322146515Sru          entry->line_number = info_parsed_line_number;
32342660Smarkm        }
32421495Sjmacd
32521495Sjmacd      add_pointer_to_array
32642660Smarkm        (entry, refs_index, refs, refs_slots, 50, REFERENCE *);
32721495Sjmacd    }
32821495Sjmacd  return (refs);
32921495Sjmacd}
33021495Sjmacd
33156160Sru/* Get the entry associated with LABEL in REFERENCES.  Return a pointer
33256160Sru   to the ENTRY if found, or NULL. */
33321495SjmacdREFERENCE *
334146515Sruinfo_get_labeled_reference (char *label, REFERENCE **references)
33521495Sjmacd{
33621495Sjmacd  register int i;
33721495Sjmacd  REFERENCE *entry;
33821495Sjmacd
33921495Sjmacd  for (i = 0; references && (entry = references[i]); i++)
34021495Sjmacd    {
34121495Sjmacd      if (strcmp (label, entry->label) == 0)
34242660Smarkm        return (entry);
34321495Sjmacd    }
34421495Sjmacd  return ((REFERENCE *)NULL);
34521495Sjmacd}
34621495Sjmacd
34721495Sjmacd/* A utility function for concatenating REFERENCE **.  Returns a new
34821495Sjmacd   REFERENCE ** which is the concatenation of REF1 and REF2.  The REF1
34921495Sjmacd   and REF2 arrays are freed, but their contents are not. */
35021495SjmacdREFERENCE **
351146515Sruinfo_concatenate_references (REFERENCE **ref1, REFERENCE **ref2)
35221495Sjmacd{
35321495Sjmacd  register int i, j;
35421495Sjmacd  REFERENCE **result;
35521495Sjmacd  int size;
35621495Sjmacd
35721495Sjmacd  /* With one argument passed as NULL, simply return the other arg. */
35821495Sjmacd  if (!ref1)
35921495Sjmacd    return (ref2);
36021495Sjmacd  else if (!ref2)
36121495Sjmacd    return (ref1);
36221495Sjmacd
36321495Sjmacd  /* Get the total size of the slots that we will need. */
36421495Sjmacd  for (i = 0; ref1[i]; i++);
36521495Sjmacd  size = i;
36621495Sjmacd  for (i = 0; ref2[i]; i++);
36721495Sjmacd  size += i;
36821495Sjmacd
36921495Sjmacd  result = (REFERENCE **)xmalloc ((1 + size) * sizeof (REFERENCE *));
37021495Sjmacd
37121495Sjmacd  /* Copy the contents over. */
37221495Sjmacd  for (i = 0; ref1[i]; i++)
37321495Sjmacd    result[i] = ref1[i];
37421495Sjmacd
37521495Sjmacd  j = i;
37621495Sjmacd  for (i = 0; ref2[i]; i++)
37721495Sjmacd    result[j++] = ref2[i];
37821495Sjmacd
37921495Sjmacd  result[j] = (REFERENCE *)NULL;
38021495Sjmacd  free (ref1);
38121495Sjmacd  free (ref2);
38221495Sjmacd  return (result);
38321495Sjmacd}
38421495Sjmacd
385116525Sru
386116525Sru
387116525Sru/* Copy a reference structure.  Since we tend to free everything at
388116525Sru   every opportunity, we don't share any points, but copy everything into
389116525Sru   new memory.  */
390116525SruREFERENCE *
391146515Sruinfo_copy_reference (REFERENCE *src)
392116525Sru{
393116525Sru  REFERENCE *dest = xmalloc (sizeof (REFERENCE));
394116525Sru  dest->label = src->label ? xstrdup (src->label) : NULL;
395116525Sru  dest->filename = src->filename ? xstrdup (src->filename) : NULL;
396116525Sru  dest->nodename = src->nodename ? xstrdup (src->nodename) : NULL;
397116525Sru  dest->start = src->start;
398116525Sru  dest->end = src->end;
399116525Sru
400116525Sru  return dest;
401116525Sru}
402116525Sru
403116525Sru
404116525Sru
40521495Sjmacd/* Free the data associated with REFERENCES. */
40621495Sjmacdvoid
407146515Sruinfo_free_references (REFERENCE **references)
40821495Sjmacd{
40921495Sjmacd  register int i;
41021495Sjmacd  REFERENCE *entry;
41121495Sjmacd
41221495Sjmacd  if (references)
41321495Sjmacd    {
41421495Sjmacd      for (i = 0; references && (entry = references[i]); i++)
41542660Smarkm        {
41642660Smarkm          maybe_free (entry->label);
41742660Smarkm          maybe_free (entry->filename);
41842660Smarkm          maybe_free (entry->nodename);
41921495Sjmacd
42042660Smarkm          free (entry);
42142660Smarkm        }
42221495Sjmacd
42321495Sjmacd      free (references);
42421495Sjmacd    }
42521495Sjmacd}
42621495Sjmacd
42721495Sjmacd/* Search for sequences of whitespace or newlines in STRING, replacing
42821495Sjmacd   all such sequences with just a single space.  Remove whitespace from
42921495Sjmacd   start and end of string. */
43021495Sjmacdvoid
431146515Srucanonicalize_whitespace (char *string)
43221495Sjmacd{
43321495Sjmacd  register int i, j;
434146515Sru  int len, whitespace_found, whitespace_loc = 0;
43521495Sjmacd  char *temp;
43621495Sjmacd
43721495Sjmacd  if (!string)
43821495Sjmacd    return;
43921495Sjmacd
44021495Sjmacd  len = strlen (string);
44121495Sjmacd  temp = (char *)xmalloc (1 + len);
44221495Sjmacd
44321495Sjmacd  /* Search for sequences of whitespace or newlines.  Replace all such
44421495Sjmacd     sequences in the string with just a single space. */
44521495Sjmacd
44621495Sjmacd  whitespace_found = 0;
44721495Sjmacd  for (i = 0, j = 0; string[i]; i++)
44821495Sjmacd    {
44921495Sjmacd      if (whitespace_or_newline (string[i]))
45042660Smarkm        {
45142660Smarkm          whitespace_found++;
45242660Smarkm          whitespace_loc = i;
45342660Smarkm          continue;
45442660Smarkm        }
45521495Sjmacd      else
45642660Smarkm        {
45742660Smarkm          if (whitespace_found && whitespace_loc)
45842660Smarkm            {
45942660Smarkm              whitespace_found = 0;
46021495Sjmacd
46142660Smarkm              /* Suppress whitespace at start of string. */
46242660Smarkm              if (j)
46342660Smarkm                temp[j++] = ' ';
46442660Smarkm            }
46521495Sjmacd
46642660Smarkm          temp[j++] = string[i];
46742660Smarkm        }
46821495Sjmacd    }
46921495Sjmacd
47021495Sjmacd  /* Kill trailing whitespace. */
47121495Sjmacd  if (j && whitespace (temp[j - 1]))
47221495Sjmacd    j--;
47321495Sjmacd
47421495Sjmacd  temp[j] = '\0';
47521495Sjmacd  strcpy (string, temp);
47621495Sjmacd  free (temp);
47721495Sjmacd}
47821495Sjmacd
47921495Sjmacd/* String representation of a char returned by printed_representation (). */
48021495Sjmacdstatic char the_rep[10];
48121495Sjmacd
48221495Sjmacd/* Return a pointer to a string which is the printed representation
48321495Sjmacd   of CHARACTER if it were printed at HPOS. */
48421495Sjmacdchar *
485146515Sruprinted_representation (unsigned char character, int hpos)
48621495Sjmacd{
48721495Sjmacd  register int i = 0;
48856160Sru  int printable_limit = ISO_Latin_p ? 255 : 127;
489100513Sru
490100513Sru  if (raw_escapes_p && character == '\033')
491100513Sru    the_rep[i++] = character;
49256160Sru  /* Show CTRL-x as ^X.  */
493100513Sru  else if (iscntrl (character) && character < 127)
49421495Sjmacd    {
49521495Sjmacd      switch (character)
49642660Smarkm        {
49742660Smarkm        case '\r':
49842660Smarkm        case '\n':
49942660Smarkm          the_rep[i++] = character;
50042660Smarkm          break;
50121495Sjmacd
50242660Smarkm        case '\t':
50342660Smarkm          {
50442660Smarkm            int tw;
50521495Sjmacd
50642660Smarkm            tw = ((hpos + 8) & 0xf8) - hpos;
50742660Smarkm            while (i < tw)
50842660Smarkm              the_rep[i++] = ' ';
50942660Smarkm          }
51042660Smarkm          break;
51121495Sjmacd
51242660Smarkm        default:
51342660Smarkm          the_rep[i++] = '^';
51442660Smarkm          the_rep[i++] = (character | 0x40);
51542660Smarkm        }
51621495Sjmacd    }
51756160Sru  /* Show META-x as 0370.  */
51821495Sjmacd  else if (character > printable_limit)
51921495Sjmacd    {
52021495Sjmacd      sprintf (the_rep + i, "\\%0o", character);
52121495Sjmacd      i = strlen (the_rep);
52221495Sjmacd    }
52356160Sru  else if (character == DEL)
52456160Sru    {
52556160Sru      the_rep[i++] = '^';
52656160Sru      the_rep[i++] = '?';
52756160Sru    }
52821495Sjmacd  else
52921495Sjmacd    the_rep[i++] = character;
53021495Sjmacd
53156160Sru  the_rep[i] = 0;
53221495Sjmacd
53356160Sru  return the_rep;
53421495Sjmacd}
53521495Sjmacd
53621495Sjmacd
53721495Sjmacd/* **************************************************************** */
53842660Smarkm/*                                                                  */
53942660Smarkm/*                  Functions Static To This File                   */
54042660Smarkm/*                                                                  */
54121495Sjmacd/* **************************************************************** */
54221495Sjmacd
54321495Sjmacd/* Amount of space allocated to INFO_PARSED_FILENAME via xmalloc (). */
54421495Sjmacdstatic int parsed_filename_size = 0;
54521495Sjmacd
54621495Sjmacd/* Amount of space allocated to INFO_PARSED_NODENAME via xmalloc (). */
54721495Sjmacdstatic int parsed_nodename_size = 0;
54821495Sjmacd
549146515Srustatic void save_string (char *string, char **string_p, int *string_size_p);
550146515Srustatic void saven_string (char *string, int len, char **string_p,
551146515Sru    int *string_size_p);
55221495Sjmacd
55321495Sjmacd/* Remember FILENAME in PARSED_FILENAME.  An empty FILENAME is translated
55421495Sjmacd   to a NULL pointer in PARSED_FILENAME. */
55521495Sjmacdstatic void
556146515Srusave_filename (char *filename)
55721495Sjmacd{
55821495Sjmacd  save_string (filename, &info_parsed_filename, &parsed_filename_size);
55921495Sjmacd}
56021495Sjmacd
56121495Sjmacd/* Just like save_filename (), but you pass the length of the string. */
56221495Sjmacdstatic void
563146515Srusaven_filename (char *filename, int len)
56421495Sjmacd{
56521495Sjmacd  saven_string (filename, len,
56642660Smarkm                &info_parsed_filename, &parsed_filename_size);
56721495Sjmacd}
56821495Sjmacd
56921495Sjmacd/* Remember NODENAME in PARSED_NODENAME.  An empty NODENAME is translated
57021495Sjmacd   to a NULL pointer in PARSED_NODENAME. */
57121495Sjmacdstatic void
572146515Srusave_nodename (char *nodename)
57321495Sjmacd{
57421495Sjmacd  save_string (nodename, &info_parsed_nodename, &parsed_nodename_size);
57521495Sjmacd}
57621495Sjmacd
57721495Sjmacd/* Just like save_nodename (), but you pass the length of the string. */
57821495Sjmacdstatic void
579146515Srusaven_nodename (char *nodename, int len)
58021495Sjmacd{
58121495Sjmacd  saven_string (nodename, len,
58242660Smarkm                &info_parsed_nodename, &parsed_nodename_size);
58321495Sjmacd}
58421495Sjmacd
58521495Sjmacd/* Remember STRING in STRING_P.  STRING_P should currently have STRING_SIZE_P
58621495Sjmacd   bytes allocated to it.  An empty STRING is translated to a NULL pointer
58721495Sjmacd   in STRING_P. */
58821495Sjmacdstatic void
589146515Srusave_string (char *string, char **string_p, int *string_size_p)
59021495Sjmacd{
59121495Sjmacd  if (!string || !*string)
59221495Sjmacd    {
59321495Sjmacd      if (*string_p)
59442660Smarkm        free (*string_p);
59521495Sjmacd
59621495Sjmacd      *string_p = (char *)NULL;
59721495Sjmacd      *string_size_p = 0;
59821495Sjmacd    }
59921495Sjmacd  else
60021495Sjmacd    {
601146515Sru      if (strlen (string) >= (unsigned int) *string_size_p)
60242660Smarkm        *string_p = (char *)xrealloc
60342660Smarkm          (*string_p, (*string_size_p = 1 + strlen (string)));
60421495Sjmacd
60521495Sjmacd      strcpy (*string_p, string);
60621495Sjmacd    }
60721495Sjmacd}
60821495Sjmacd
60921495Sjmacd/* Just like save_string (), but you also pass the length of STRING. */
61021495Sjmacdstatic void
611146515Srusaven_string (char *string, int len, char **string_p, int *string_size_p)
61221495Sjmacd{
61321495Sjmacd  if (!string)
61421495Sjmacd    {
61521495Sjmacd      if (*string_p)
61642660Smarkm        free (*string_p);
61721495Sjmacd
61821495Sjmacd      *string_p = (char *)NULL;
61921495Sjmacd      *string_size_p = 0;
62021495Sjmacd    }
62121495Sjmacd  else
62221495Sjmacd    {
62321495Sjmacd      if (len >= *string_size_p)
62442660Smarkm        *string_p = (char *)xrealloc (*string_p, (*string_size_p = 1 + len));
62521495Sjmacd
62621495Sjmacd      strncpy (*string_p, string, len);
62721495Sjmacd      (*string_p)[len] = '\0';
62821495Sjmacd    }
62921495Sjmacd}
63021495Sjmacd
63121495Sjmacd/* Return a pointer to the part of PATHNAME that simply defines the file. */
63221495Sjmacdchar *
633146515Srufilename_non_directory (char *pathname)
63421495Sjmacd{
63556160Sru  register char *filename = pathname + strlen (pathname);
63621495Sjmacd
63756160Sru  if (HAVE_DRIVE (pathname))
63856160Sru    pathname += 2;
63921495Sjmacd
64056160Sru  while (filename > pathname && !IS_SLASH (filename[-1]))
64156160Sru    filename--;
64221495Sjmacd
64321495Sjmacd  return (filename);
64421495Sjmacd}
64521495Sjmacd
64621495Sjmacd/* Return non-zero if NODE is one especially created by Info. */
64721495Sjmacdint
648146515Sruinternal_info_node_p (NODE *node)
64921495Sjmacd{
65021495Sjmacd#if defined (NEVER)
65121495Sjmacd  if (node &&
65221495Sjmacd      (node->filename && !*node->filename) &&
65321495Sjmacd      !node->parent && node->nodename)
65421495Sjmacd    return (1);
65521495Sjmacd  else
65621495Sjmacd    return (0);
65721495Sjmacd#else
65821495Sjmacd  return ((node != (NODE *)NULL) && ((node->flags & N_IsInternal) != 0));
65921495Sjmacd#endif /* !NEVER */
66021495Sjmacd}
66121495Sjmacd
66221495Sjmacd/* Make NODE appear to be one especially created by Info. */
66321495Sjmacdvoid
664146515Sruname_internal_node (NODE *node, char *name)
66521495Sjmacd{
66621495Sjmacd  if (!node)
66721495Sjmacd    return;
66821495Sjmacd
66921495Sjmacd  node->filename = "";
67021495Sjmacd  node->parent = (char *)NULL;
67121495Sjmacd  node->nodename = name;
67221495Sjmacd  node->flags |= N_IsInternal;
67321495Sjmacd}
67421495Sjmacd
67521495Sjmacd/* Return the window displaying NAME, the name of an internally created
67621495Sjmacd   Info window. */
67721495SjmacdWINDOW *
678146515Sruget_internal_info_window (char *name)
67921495Sjmacd{
68021495Sjmacd  WINDOW *win;
68121495Sjmacd
68221495Sjmacd  for (win = windows; win; win = win->next)
68321495Sjmacd    if (internal_info_node_p (win->node) &&
68442660Smarkm        (strcmp (win->node->nodename, name) == 0))
68521495Sjmacd      break;
68621495Sjmacd
68721495Sjmacd  return (win);
68821495Sjmacd}
68956160Sru
69056160Sru/* Return a window displaying the node NODE. */
69156160SruWINDOW *
692146515Sruget_window_of_node (NODE *node)
69356160Sru{
69456160Sru  WINDOW *win = (WINDOW *)NULL;
69556160Sru
69656160Sru  for (win = windows; win; win = win->next)
69756160Sru    if (win->node == node)
69856160Sru      break;
69956160Sru
70056160Sru  return (win);
70156160Sru}
702