Home | History | Annotate | Line # | Download | only in info
      1  1.1  christos /*	$NetBSD: info-utils.c,v 1.1.1.1 2016/01/14 00:11:29 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* info-utils.c -- miscellanous.
      4  1.1  christos    Id: info-utils.c,v 1.4 2004/04/11 17:56:45 karl Exp
      5  1.1  christos 
      6  1.1  christos    Copyright (C) 1993, 1998, 2003, 2004 Free Software Foundation, Inc.
      7  1.1  christos 
      8  1.1  christos    This program is free software; you can redistribute it and/or modify
      9  1.1  christos    it under the terms of the GNU General Public License as published by
     10  1.1  christos    the Free Software Foundation; either version 2, or (at your option)
     11  1.1  christos    any later version.
     12  1.1  christos 
     13  1.1  christos    This program is distributed in the hope that it will be useful,
     14  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  1.1  christos    GNU General Public License for more details.
     17  1.1  christos 
     18  1.1  christos    You should have received a copy of the GNU General Public License
     19  1.1  christos    along with this program; if not, write to the Free Software
     20  1.1  christos    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     21  1.1  christos 
     22  1.1  christos    Originally written by Brian Fox (bfox (at) ai.mit.edu). */
     23  1.1  christos 
     24  1.1  christos #include "info.h"
     25  1.1  christos #include "info-utils.h"
     26  1.1  christos #if defined (HANDLE_MAN_PAGES)
     27  1.1  christos #  include "man.h"
     28  1.1  christos #endif /* HANDLE_MAN_PAGES */
     29  1.1  christos 
     30  1.1  christos /* When non-zero, various display and input functions handle ISO Latin
     31  1.1  christos    character sets correctly. */
     32  1.1  christos int ISO_Latin_p = 1;
     33  1.1  christos 
     34  1.1  christos /* Variable which holds the most recent filename parsed as a result of
     35  1.1  christos    calling info_parse_xxx (). */
     36  1.1  christos char *info_parsed_filename = (char *)NULL;
     37  1.1  christos 
     38  1.1  christos /* Variable which holds the most recent nodename parsed as a result of
     39  1.1  christos    calling info_parse_xxx (). */
     40  1.1  christos char *info_parsed_nodename = (char *)NULL;
     41  1.1  christos 
     42  1.1  christos /* Variable which holds the most recent line number parsed as a result of
     43  1.1  christos    calling info_parse_xxx (). */
     44  1.1  christos int info_parsed_line_number = 0;
     45  1.1  christos 
     46  1.1  christos /* Functions to remember a filename or nodename for later return. */
     47  1.1  christos static void save_filename (char *filename);
     48  1.1  christos static void saven_filename (char *filename, int len);
     49  1.1  christos static void save_nodename (char *nodename);
     50  1.1  christos static void saven_nodename (char *nodename, int len);
     51  1.1  christos 
     52  1.1  christos /* How to get a reference (either menu or cross). */
     53  1.1  christos static REFERENCE **info_references_internal (char *label,
     54  1.1  christos     SEARCH_BINDING *binding);
     55  1.1  christos 
     56  1.1  christos /* Parse the filename and nodename out of STRING.  If STRING doesn't
     57  1.1  christos    contain a filename (i.e., it is NOT (FILENAME)NODENAME) then set
     58  1.1  christos    INFO_PARSED_FILENAME to NULL.  If second argument NEWLINES_OKAY is
     59  1.1  christos    non-zero, it says to allow the nodename specification to cross a
     60  1.1  christos    newline boundary (i.e., only `,', `.', or `TAB' can end the spec). */
     61  1.1  christos void
     62  1.1  christos info_parse_node (char *string, int newlines_okay)
     63  1.1  christos {
     64  1.1  christos   register int i = 0;
     65  1.1  christos 
     66  1.1  christos   /* Default the answer. */
     67  1.1  christos   save_filename ((char *)NULL);
     68  1.1  christos   save_nodename ((char *)NULL);
     69  1.1  christos 
     70  1.1  christos   /* Special case of nothing passed.  Return nothing. */
     71  1.1  christos   if (!string || !*string)
     72  1.1  christos     return;
     73  1.1  christos 
     74  1.1  christos   string += skip_whitespace (string);
     75  1.1  christos 
     76  1.1  christos   /* Check for (FILENAME)NODENAME. */
     77  1.1  christos   if (*string == '(')
     78  1.1  christos     {
     79  1.1  christos       i = 0;
     80  1.1  christos       /* Advance past the opening paren. */
     81  1.1  christos       string++;
     82  1.1  christos 
     83  1.1  christos       /* Find the closing paren. */
     84  1.1  christos       while (string[i] && string[i] != ')')
     85  1.1  christos         i++;
     86  1.1  christos 
     87  1.1  christos       /* Remember parsed filename. */
     88  1.1  christos       saven_filename (string, i);
     89  1.1  christos 
     90  1.1  christos       /* Point directly at the nodename. */
     91  1.1  christos       string += i;
     92  1.1  christos 
     93  1.1  christos       if (*string)
     94  1.1  christos         string++;
     95  1.1  christos     }
     96  1.1  christos 
     97  1.1  christos   /* Parse out nodename. */
     98  1.1  christos   i = skip_node_characters (string, newlines_okay);
     99  1.1  christos   saven_nodename (string, i);
    100  1.1  christos   canonicalize_whitespace (info_parsed_nodename);
    101  1.1  christos   if (info_parsed_nodename && !*info_parsed_nodename)
    102  1.1  christos     {
    103  1.1  christos       free (info_parsed_nodename);
    104  1.1  christos       info_parsed_nodename = (char *)NULL;
    105  1.1  christos     }
    106  1.1  christos 
    107  1.1  christos   /* Parse ``(line ...)'' part of menus, if any.  */
    108  1.1  christos   {
    109  1.1  christos     char *rest = string + i;
    110  1.1  christos 
    111  1.1  christos     /* Advance only if it's not already at end of string.  */
    112  1.1  christos     if (*rest)
    113  1.1  christos       rest++;
    114  1.1  christos 
    115  1.1  christos     /* Skip any whitespace first, and then a newline in case the item
    116  1.1  christos        was so long to contain the ``(line ...)'' string in the same
    117  1.1  christos        physical line.  */
    118  1.1  christos     while (whitespace(*rest))
    119  1.1  christos       rest++;
    120  1.1  christos     if (*rest == '\n')
    121  1.1  christos       {
    122  1.1  christos         rest++;
    123  1.1  christos         while (whitespace(*rest))
    124  1.1  christos           rest++;
    125  1.1  christos       }
    126  1.1  christos 
    127  1.1  christos     /* Are we looking at an opening parenthesis?  That can only mean
    128  1.1  christos        we have a winner. :)  */
    129  1.1  christos     if (strncmp (rest, "(line ", strlen ("(line ")) == 0)
    130  1.1  christos       {
    131  1.1  christos         rest += strlen ("(line ");
    132  1.1  christos         info_parsed_line_number = strtol (rest, NULL, 0);
    133  1.1  christos       }
    134  1.1  christos     else
    135  1.1  christos       info_parsed_line_number = 0;
    136  1.1  christos   }
    137  1.1  christos }
    138  1.1  christos 
    139  1.1  christos /* Return the node addressed by LABEL in NODE (usually one of "Prev:",
    140  1.1  christos    "Next:", "Up:", "File:", or "Node:".  After a call to this function,
    141  1.1  christos    the global INFO_PARSED_NODENAME and INFO_PARSED_FILENAME contain
    142  1.1  christos    the information. */
    143  1.1  christos void
    144  1.1  christos info_parse_label (char *label, NODE *node)
    145  1.1  christos {
    146  1.1  christos   register int i;
    147  1.1  christos   char *nodeline;
    148  1.1  christos 
    149  1.1  christos   /* Default answer to failure. */
    150  1.1  christos   save_nodename ((char *)NULL);
    151  1.1  christos   save_filename ((char *)NULL);
    152  1.1  christos 
    153  1.1  christos   /* Find the label in the first line of this node. */
    154  1.1  christos   nodeline = node->contents;
    155  1.1  christos   i = string_in_line (label, nodeline);
    156  1.1  christos 
    157  1.1  christos   if (i == -1)
    158  1.1  christos     return;
    159  1.1  christos 
    160  1.1  christos   nodeline += i;
    161  1.1  christos   nodeline += skip_whitespace (nodeline);
    162  1.1  christos   info_parse_node (nodeline, DONT_SKIP_NEWLINES);
    163  1.1  christos }
    164  1.1  christos 
    165  1.1  christos /* **************************************************************** */
    167  1.1  christos /*                                                                  */
    168  1.1  christos /*                  Finding and Building Menus                      */
    169  1.1  christos /*                                                                  */
    170  1.1  christos /* **************************************************************** */
    171  1.1  christos 
    172  1.1  christos /* Return a NULL terminated array of REFERENCE * which represents the menu
    173  1.1  christos    found in NODE.  If there is no menu in NODE, just return a NULL pointer. */
    174  1.1  christos REFERENCE **
    175  1.1  christos info_menu_of_node (NODE *node)
    176  1.1  christos {
    177  1.1  christos   long position;
    178  1.1  christos   SEARCH_BINDING tmp_search;
    179  1.1  christos   REFERENCE **menu = (REFERENCE **)NULL;
    180  1.1  christos 
    181  1.1  christos   tmp_search.buffer = node->contents;
    182  1.1  christos   tmp_search.start = 0;
    183  1.1  christos   tmp_search.end = node->nodelen;
    184  1.1  christos   tmp_search.flags = S_FoldCase;
    185  1.1  christos 
    186  1.1  christos   /* Find the start of the menu. */
    187  1.1  christos   position = search_forward (INFO_MENU_LABEL, &tmp_search);
    188  1.1  christos 
    189  1.1  christos   if (position == -1)
    190  1.1  christos     return ((REFERENCE **) NULL);
    191  1.1  christos 
    192  1.1  christos   /* We have the start of the menu now.  Glean menu items from the rest
    193  1.1  christos      of the node. */
    194  1.1  christos   tmp_search.start = position + strlen (INFO_MENU_LABEL);
    195  1.1  christos   tmp_search.start += skip_line (tmp_search.buffer + tmp_search.start);
    196  1.1  christos   tmp_search.start--;
    197  1.1  christos   menu = info_menu_items (&tmp_search);
    198  1.1  christos   return (menu);
    199  1.1  christos }
    200  1.1  christos 
    201  1.1  christos /* Return a NULL terminated array of REFERENCE * which represents the cross
    202  1.1  christos    refrences found in NODE.  If there are no cross references in NODE, just
    203  1.1  christos    return a NULL pointer. */
    204  1.1  christos REFERENCE **
    205  1.1  christos info_xrefs_of_node (NODE *node)
    206  1.1  christos {
    207  1.1  christos   SEARCH_BINDING tmp_search;
    208  1.1  christos 
    209  1.1  christos #if defined (HANDLE_MAN_PAGES)
    210  1.1  christos   if (node->flags & N_IsManPage)
    211  1.1  christos     return (xrefs_of_manpage (node));
    212  1.1  christos #endif
    213  1.1  christos 
    214  1.1  christos   tmp_search.buffer = node->contents;
    215  1.1  christos   tmp_search.start = 0;
    216  1.1  christos   tmp_search.end = node->nodelen;
    217  1.1  christos   tmp_search.flags = S_FoldCase;
    218  1.1  christos 
    219  1.1  christos   return (info_xrefs (&tmp_search));
    220  1.1  christos }
    221  1.1  christos 
    222  1.1  christos /* Glean menu entries from BINDING->buffer + BINDING->start until we
    223  1.1  christos    have looked at the entire contents of BINDING.  Return an array
    224  1.1  christos    of REFERENCE * that represents each menu item in this range. */
    225  1.1  christos REFERENCE **
    226  1.1  christos info_menu_items (SEARCH_BINDING *binding)
    227  1.1  christos {
    228  1.1  christos   return (info_references_internal (INFO_MENU_ENTRY_LABEL, binding));
    229  1.1  christos }
    230  1.1  christos 
    231  1.1  christos /* Glean cross references from BINDING->buffer + BINDING->start until
    232  1.1  christos    BINDING->end.  Return an array of REFERENCE * that represents each
    233  1.1  christos    cross reference in this range. */
    234  1.1  christos REFERENCE **
    235  1.1  christos info_xrefs (SEARCH_BINDING *binding)
    236  1.1  christos {
    237  1.1  christos   return (info_references_internal (INFO_XREF_LABEL, binding));
    238  1.1  christos }
    239  1.1  christos 
    240  1.1  christos /* Glean cross references or menu items from BINDING.  Return an array
    241  1.1  christos    of REFERENCE * that represents the items found. */
    242  1.1  christos static REFERENCE **
    243  1.1  christos info_references_internal (char *label, SEARCH_BINDING *binding)
    244  1.1  christos {
    245  1.1  christos   SEARCH_BINDING tmp_search;
    246  1.1  christos   REFERENCE **refs = (REFERENCE **)NULL;
    247  1.1  christos   int refs_index = 0, refs_slots = 0;
    248  1.1  christos   int searching_for_menu_items = 0;
    249  1.1  christos   long position;
    250  1.1  christos 
    251  1.1  christos   tmp_search.buffer = binding->buffer;
    252  1.1  christos   tmp_search.start = binding->start;
    253  1.1  christos   tmp_search.end = binding->end;
    254  1.1  christos   tmp_search.flags = S_FoldCase | S_SkipDest;
    255  1.1  christos 
    256  1.1  christos   searching_for_menu_items = (strcasecmp (label, INFO_MENU_ENTRY_LABEL) == 0);
    257  1.1  christos 
    258  1.1  christos   while ((position = search_forward (label, &tmp_search)) != -1)
    259  1.1  christos     {
    260  1.1  christos       int offset, start;
    261  1.1  christos       char *refdef;
    262  1.1  christos       REFERENCE *entry;
    263  1.1  christos 
    264  1.1  christos       tmp_search.start = position;
    265  1.1  christos       tmp_search.start += skip_whitespace (tmp_search.buffer + tmp_search.start);
    266  1.1  christos       start = tmp_search.start - binding->start;
    267  1.1  christos       refdef = tmp_search.buffer + tmp_search.start;
    268  1.1  christos       offset = string_in_line (":", refdef);
    269  1.1  christos 
    270  1.1  christos       /* When searching for menu items, if no colon, there is no
    271  1.1  christos          menu item on this line. */
    272  1.1  christos       if (offset == -1)
    273  1.1  christos         {
    274  1.1  christos           if (searching_for_menu_items)
    275  1.1  christos             continue;
    276  1.1  christos           else
    277  1.1  christos             {
    278  1.1  christos               int temp;
    279  1.1  christos 
    280  1.1  christos               temp = skip_line (refdef);
    281  1.1  christos               offset = string_in_line (":", refdef + temp);
    282  1.1  christos               if (offset == -1)
    283  1.1  christos                 continue;       /* Give up? */
    284  1.1  christos               else
    285  1.1  christos                 offset += temp;
    286  1.1  christos             }
    287  1.1  christos         }
    288  1.1  christos 
    289  1.1  christos       entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
    290  1.1  christos       entry->filename = (char *)NULL;
    291  1.1  christos       entry->nodename = (char *)NULL;
    292  1.1  christos       entry->label = (char *)xmalloc (offset);
    293  1.1  christos       strncpy (entry->label, refdef, offset - 1);
    294  1.1  christos       entry->label[offset - 1] = '\0';
    295  1.1  christos       canonicalize_whitespace (entry->label);
    296  1.1  christos 
    297  1.1  christos       refdef += offset;
    298  1.1  christos       entry->start = start;
    299  1.1  christos       entry->end = refdef - binding->buffer;
    300  1.1  christos 
    301  1.1  christos       /* If this reference entry continues with another ':' then the
    302  1.1  christos          nodename is the same as the label. */
    303  1.1  christos       if (*refdef == ':')
    304  1.1  christos         {
    305  1.1  christos           entry->nodename = xstrdup (entry->label);
    306  1.1  christos         }
    307  1.1  christos       else
    308  1.1  christos         {
    309  1.1  christos           /* This entry continues with a specific nodename.  Parse the
    310  1.1  christos              nodename from the specification. */
    311  1.1  christos 
    312  1.1  christos           refdef += skip_whitespace_and_newlines (refdef);
    313  1.1  christos 
    314  1.1  christos           if (searching_for_menu_items)
    315  1.1  christos             info_parse_node (refdef, DONT_SKIP_NEWLINES);
    316  1.1  christos           else
    317  1.1  christos             info_parse_node (refdef, SKIP_NEWLINES);
    318  1.1  christos 
    319  1.1  christos           if (info_parsed_filename)
    320  1.1  christos             entry->filename = xstrdup (info_parsed_filename);
    321  1.1  christos 
    322  1.1  christos           if (info_parsed_nodename)
    323  1.1  christos             entry->nodename = xstrdup (info_parsed_nodename);
    324  1.1  christos 
    325  1.1  christos           entry->line_number = info_parsed_line_number;
    326  1.1  christos         }
    327  1.1  christos 
    328  1.1  christos       add_pointer_to_array
    329  1.1  christos         (entry, refs_index, refs, refs_slots, 50, REFERENCE *);
    330  1.1  christos     }
    331  1.1  christos   return (refs);
    332  1.1  christos }
    333  1.1  christos 
    334  1.1  christos /* Get the entry associated with LABEL in REFERENCES.  Return a pointer
    335  1.1  christos    to the ENTRY if found, or NULL. */
    336  1.1  christos REFERENCE *
    337  1.1  christos info_get_labeled_reference (char *label, REFERENCE **references)
    338  1.1  christos {
    339  1.1  christos   register int i;
    340  1.1  christos   REFERENCE *entry;
    341  1.1  christos 
    342  1.1  christos   for (i = 0; references && (entry = references[i]); i++)
    343  1.1  christos     {
    344  1.1  christos       if (strcmp (label, entry->label) == 0)
    345  1.1  christos         return (entry);
    346  1.1  christos     }
    347  1.1  christos   return ((REFERENCE *)NULL);
    348  1.1  christos }
    349  1.1  christos 
    350  1.1  christos /* A utility function for concatenating REFERENCE **.  Returns a new
    351  1.1  christos    REFERENCE ** which is the concatenation of REF1 and REF2.  The REF1
    352  1.1  christos    and REF2 arrays are freed, but their contents are not. */
    353  1.1  christos REFERENCE **
    354  1.1  christos info_concatenate_references (REFERENCE **ref1, REFERENCE **ref2)
    355  1.1  christos {
    356  1.1  christos   register int i, j;
    357  1.1  christos   REFERENCE **result;
    358  1.1  christos   int size;
    359  1.1  christos 
    360  1.1  christos   /* With one argument passed as NULL, simply return the other arg. */
    361  1.1  christos   if (!ref1)
    362  1.1  christos     return (ref2);
    363  1.1  christos   else if (!ref2)
    364  1.1  christos     return (ref1);
    365  1.1  christos 
    366  1.1  christos   /* Get the total size of the slots that we will need. */
    367  1.1  christos   for (i = 0; ref1[i]; i++);
    368  1.1  christos   size = i;
    369  1.1  christos   for (i = 0; ref2[i]; i++);
    370  1.1  christos   size += i;
    371  1.1  christos 
    372  1.1  christos   result = (REFERENCE **)xmalloc ((1 + size) * sizeof (REFERENCE *));
    373  1.1  christos 
    374  1.1  christos   /* Copy the contents over. */
    375  1.1  christos   for (i = 0; ref1[i]; i++)
    376  1.1  christos     result[i] = ref1[i];
    377  1.1  christos 
    378  1.1  christos   j = i;
    379  1.1  christos   for (i = 0; ref2[i]; i++)
    380  1.1  christos     result[j++] = ref2[i];
    381  1.1  christos 
    382  1.1  christos   result[j] = (REFERENCE *)NULL;
    383  1.1  christos   free (ref1);
    384  1.1  christos   free (ref2);
    385  1.1  christos   return (result);
    386  1.1  christos }
    387  1.1  christos 
    388  1.1  christos 
    389  1.1  christos 
    390  1.1  christos /* Copy a reference structure.  Since we tend to free everything at
    392  1.1  christos    every opportunity, we don't share any points, but copy everything into
    393  1.1  christos    new memory.  */
    394  1.1  christos REFERENCE *
    395  1.1  christos info_copy_reference (REFERENCE *src)
    396  1.1  christos {
    397  1.1  christos   REFERENCE *dest = xmalloc (sizeof (REFERENCE));
    398  1.1  christos   dest->label = src->label ? xstrdup (src->label) : NULL;
    399  1.1  christos   dest->filename = src->filename ? xstrdup (src->filename) : NULL;
    400  1.1  christos   dest->nodename = src->nodename ? xstrdup (src->nodename) : NULL;
    401  1.1  christos   dest->start = src->start;
    402  1.1  christos   dest->end = src->end;
    403  1.1  christos 
    404  1.1  christos   return dest;
    405  1.1  christos }
    406  1.1  christos 
    407  1.1  christos 
    408  1.1  christos 
    409  1.1  christos /* Free the data associated with REFERENCES. */
    411  1.1  christos void
    412  1.1  christos info_free_references (REFERENCE **references)
    413  1.1  christos {
    414  1.1  christos   register int i;
    415  1.1  christos   REFERENCE *entry;
    416  1.1  christos 
    417  1.1  christos   if (references)
    418  1.1  christos     {
    419  1.1  christos       for (i = 0; references && (entry = references[i]); i++)
    420  1.1  christos         {
    421  1.1  christos           maybe_free (entry->label);
    422  1.1  christos           maybe_free (entry->filename);
    423  1.1  christos           maybe_free (entry->nodename);
    424  1.1  christos 
    425  1.1  christos           free (entry);
    426  1.1  christos         }
    427  1.1  christos 
    428  1.1  christos       free (references);
    429  1.1  christos     }
    430  1.1  christos }
    431  1.1  christos 
    432  1.1  christos /* Search for sequences of whitespace or newlines in STRING, replacing
    433  1.1  christos    all such sequences with just a single space.  Remove whitespace from
    434  1.1  christos    start and end of string. */
    435  1.1  christos void
    436  1.1  christos canonicalize_whitespace (char *string)
    437  1.1  christos {
    438  1.1  christos   register int i, j;
    439  1.1  christos   int len, whitespace_found, whitespace_loc = 0;
    440  1.1  christos   char *temp;
    441  1.1  christos 
    442  1.1  christos   if (!string)
    443  1.1  christos     return;
    444  1.1  christos 
    445  1.1  christos   len = strlen (string);
    446  1.1  christos   temp = (char *)xmalloc (1 + len);
    447  1.1  christos 
    448  1.1  christos   /* Search for sequences of whitespace or newlines.  Replace all such
    449  1.1  christos      sequences in the string with just a single space. */
    450  1.1  christos 
    451  1.1  christos   whitespace_found = 0;
    452  1.1  christos   for (i = 0, j = 0; string[i]; i++)
    453  1.1  christos     {
    454  1.1  christos       if (whitespace_or_newline (string[i]))
    455  1.1  christos         {
    456  1.1  christos           whitespace_found++;
    457  1.1  christos           whitespace_loc = i;
    458  1.1  christos           continue;
    459  1.1  christos         }
    460  1.1  christos       else
    461  1.1  christos         {
    462  1.1  christos           if (whitespace_found && whitespace_loc)
    463  1.1  christos             {
    464  1.1  christos               whitespace_found = 0;
    465  1.1  christos 
    466  1.1  christos               /* Suppress whitespace at start of string. */
    467  1.1  christos               if (j)
    468  1.1  christos                 temp[j++] = ' ';
    469  1.1  christos             }
    470  1.1  christos 
    471  1.1  christos           temp[j++] = string[i];
    472  1.1  christos         }
    473  1.1  christos     }
    474  1.1  christos 
    475  1.1  christos   /* Kill trailing whitespace. */
    476  1.1  christos   if (j && whitespace (temp[j - 1]))
    477  1.1  christos     j--;
    478  1.1  christos 
    479  1.1  christos   temp[j] = '\0';
    480  1.1  christos   strcpy (string, temp);
    481  1.1  christos   free (temp);
    482  1.1  christos }
    483  1.1  christos 
    484  1.1  christos /* String representation of a char returned by printed_representation (). */
    485  1.1  christos static char the_rep[10];
    486  1.1  christos 
    487  1.1  christos /* Return a pointer to a string which is the printed representation
    488  1.1  christos    of CHARACTER if it were printed at HPOS. */
    489  1.1  christos char *
    490  1.1  christos printed_representation (unsigned char character, int hpos)
    491  1.1  christos {
    492  1.1  christos   register int i = 0;
    493  1.1  christos   int printable_limit = ISO_Latin_p ? 255 : 127;
    494  1.1  christos 
    495  1.1  christos   if (raw_escapes_p && character == '\033')
    496  1.1  christos     the_rep[i++] = character;
    497  1.1  christos   /* Show CTRL-x as ^X.  */
    498  1.1  christos   else if (iscntrl (character) && character < 127)
    499  1.1  christos     {
    500  1.1  christos       switch (character)
    501  1.1  christos         {
    502  1.1  christos         case '\r':
    503  1.1  christos         case '\n':
    504  1.1  christos           the_rep[i++] = character;
    505  1.1  christos           break;
    506  1.1  christos 
    507  1.1  christos         case '\t':
    508  1.1  christos           {
    509  1.1  christos             int tw;
    510  1.1  christos 
    511  1.1  christos             tw = ((hpos + 8) & 0xf8) - hpos;
    512  1.1  christos             while (i < tw)
    513  1.1  christos               the_rep[i++] = ' ';
    514  1.1  christos           }
    515  1.1  christos           break;
    516  1.1  christos 
    517  1.1  christos         default:
    518  1.1  christos           the_rep[i++] = '^';
    519  1.1  christos           the_rep[i++] = (character | 0x40);
    520  1.1  christos         }
    521  1.1  christos     }
    522  1.1  christos   /* Show META-x as 0370.  */
    523  1.1  christos   else if (character > printable_limit)
    524  1.1  christos     {
    525  1.1  christos       sprintf (the_rep + i, "\\%0o", character);
    526  1.1  christos       i = strlen (the_rep);
    527  1.1  christos     }
    528  1.1  christos   else if (character == DEL)
    529  1.1  christos     {
    530  1.1  christos       the_rep[i++] = '^';
    531  1.1  christos       the_rep[i++] = '?';
    532  1.1  christos     }
    533  1.1  christos   else
    534  1.1  christos     the_rep[i++] = character;
    535  1.1  christos 
    536  1.1  christos   the_rep[i] = 0;
    537  1.1  christos 
    538  1.1  christos   return the_rep;
    539  1.1  christos }
    540  1.1  christos 
    541  1.1  christos 
    542  1.1  christos /* **************************************************************** */
    544  1.1  christos /*                                                                  */
    545  1.1  christos /*                  Functions Static To This File                   */
    546  1.1  christos /*                                                                  */
    547  1.1  christos /* **************************************************************** */
    548  1.1  christos 
    549  1.1  christos /* Amount of space allocated to INFO_PARSED_FILENAME via xmalloc (). */
    550  1.1  christos static int parsed_filename_size = 0;
    551  1.1  christos 
    552  1.1  christos /* Amount of space allocated to INFO_PARSED_NODENAME via xmalloc (). */
    553  1.1  christos static int parsed_nodename_size = 0;
    554  1.1  christos 
    555  1.1  christos static void save_string (char *string, char **string_p, int *string_size_p);
    556  1.1  christos static void saven_string (char *string, int len, char **string_p,
    557  1.1  christos     int *string_size_p);
    558  1.1  christos 
    559  1.1  christos /* Remember FILENAME in PARSED_FILENAME.  An empty FILENAME is translated
    560  1.1  christos    to a NULL pointer in PARSED_FILENAME. */
    561  1.1  christos static void
    562  1.1  christos save_filename (char *filename)
    563  1.1  christos {
    564  1.1  christos   save_string (filename, &info_parsed_filename, &parsed_filename_size);
    565  1.1  christos }
    566  1.1  christos 
    567  1.1  christos /* Just like save_filename (), but you pass the length of the string. */
    568  1.1  christos static void
    569  1.1  christos saven_filename (char *filename, int len)
    570  1.1  christos {
    571  1.1  christos   saven_string (filename, len,
    572  1.1  christos                 &info_parsed_filename, &parsed_filename_size);
    573  1.1  christos }
    574  1.1  christos 
    575  1.1  christos /* Remember NODENAME in PARSED_NODENAME.  An empty NODENAME is translated
    576  1.1  christos    to a NULL pointer in PARSED_NODENAME. */
    577  1.1  christos static void
    578  1.1  christos save_nodename (char *nodename)
    579  1.1  christos {
    580  1.1  christos   save_string (nodename, &info_parsed_nodename, &parsed_nodename_size);
    581  1.1  christos }
    582  1.1  christos 
    583  1.1  christos /* Just like save_nodename (), but you pass the length of the string. */
    584  1.1  christos static void
    585  1.1  christos saven_nodename (char *nodename, int len)
    586  1.1  christos {
    587  1.1  christos   saven_string (nodename, len,
    588  1.1  christos                 &info_parsed_nodename, &parsed_nodename_size);
    589  1.1  christos }
    590  1.1  christos 
    591  1.1  christos /* Remember STRING in STRING_P.  STRING_P should currently have STRING_SIZE_P
    592  1.1  christos    bytes allocated to it.  An empty STRING is translated to a NULL pointer
    593  1.1  christos    in STRING_P. */
    594  1.1  christos static void
    595  1.1  christos save_string (char *string, char **string_p, int *string_size_p)
    596  1.1  christos {
    597  1.1  christos   if (!string || !*string)
    598  1.1  christos     {
    599  1.1  christos       if (*string_p)
    600  1.1  christos         free (*string_p);
    601  1.1  christos 
    602  1.1  christos       *string_p = (char *)NULL;
    603  1.1  christos       *string_size_p = 0;
    604  1.1  christos     }
    605  1.1  christos   else
    606  1.1  christos     {
    607  1.1  christos       if (strlen (string) >= (unsigned int) *string_size_p)
    608  1.1  christos         *string_p = (char *)xrealloc
    609  1.1  christos           (*string_p, (*string_size_p = 1 + strlen (string)));
    610  1.1  christos 
    611  1.1  christos       strcpy (*string_p, string);
    612  1.1  christos     }
    613  1.1  christos }
    614  1.1  christos 
    615  1.1  christos /* Just like save_string (), but you also pass the length of STRING. */
    616  1.1  christos static void
    617  1.1  christos saven_string (char *string, int len, char **string_p, int *string_size_p)
    618  1.1  christos {
    619  1.1  christos   if (!string)
    620  1.1  christos     {
    621  1.1  christos       if (*string_p)
    622  1.1  christos         free (*string_p);
    623  1.1  christos 
    624  1.1  christos       *string_p = (char *)NULL;
    625  1.1  christos       *string_size_p = 0;
    626  1.1  christos     }
    627  1.1  christos   else
    628  1.1  christos     {
    629  1.1  christos       if (len >= *string_size_p)
    630  1.1  christos         *string_p = (char *)xrealloc (*string_p, (*string_size_p = 1 + len));
    631  1.1  christos 
    632  1.1  christos       strncpy (*string_p, string, len);
    633  1.1  christos       (*string_p)[len] = '\0';
    634  1.1  christos     }
    635  1.1  christos }
    636  1.1  christos 
    637  1.1  christos /* Return a pointer to the part of PATHNAME that simply defines the file. */
    638  1.1  christos char *
    639  1.1  christos filename_non_directory (char *pathname)
    640  1.1  christos {
    641  1.1  christos   register char *filename = pathname + strlen (pathname);
    642  1.1  christos 
    643  1.1  christos   if (HAVE_DRIVE (pathname))
    644  1.1  christos     pathname += 2;
    645  1.1  christos 
    646  1.1  christos   while (filename > pathname && !IS_SLASH (filename[-1]))
    647  1.1  christos     filename--;
    648  1.1  christos 
    649  1.1  christos   return (filename);
    650  1.1  christos }
    651  1.1  christos 
    652  1.1  christos /* Return non-zero if NODE is one especially created by Info. */
    653  1.1  christos int
    654  1.1  christos internal_info_node_p (NODE *node)
    655  1.1  christos {
    656  1.1  christos #if defined (NEVER)
    657  1.1  christos   if (node &&
    658  1.1  christos       (node->filename && !*node->filename) &&
    659  1.1  christos       !node->parent && node->nodename)
    660  1.1  christos     return (1);
    661  1.1  christos   else
    662  1.1  christos     return (0);
    663  1.1  christos #else
    664  1.1  christos   return ((node != (NODE *)NULL) && ((node->flags & N_IsInternal) != 0));
    665  1.1  christos #endif /* !NEVER */
    666  1.1  christos }
    667  1.1  christos 
    668  1.1  christos /* Make NODE appear to be one especially created by Info. */
    669  1.1  christos void
    670  1.1  christos name_internal_node (NODE *node, char *name)
    671  1.1  christos {
    672  1.1  christos   if (!node)
    673  1.1  christos     return;
    674  1.1  christos 
    675  1.1  christos   node->filename = "";
    676  1.1  christos   node->parent = (char *)NULL;
    677  1.1  christos   node->nodename = name;
    678  1.1  christos   node->flags |= N_IsInternal;
    679  1.1  christos }
    680  1.1  christos 
    681  1.1  christos /* Return the window displaying NAME, the name of an internally created
    682  1.1  christos    Info window. */
    683  1.1  christos WINDOW *
    684  1.1  christos get_internal_info_window (char *name)
    685  1.1  christos {
    686  1.1  christos   WINDOW *win;
    687  1.1  christos 
    688  1.1  christos   for (win = windows; win; win = win->next)
    689  1.1  christos     if (internal_info_node_p (win->node) &&
    690  1.1  christos         (strcmp (win->node->nodename, name) == 0))
    691  1.1  christos       break;
    692  1.1  christos 
    693  1.1  christos   return (win);
    694  1.1  christos }
    695  1.1  christos 
    696  1.1  christos /* Return a window displaying the node NODE. */
    697  1.1  christos WINDOW *
    698  1.1  christos get_window_of_node (NODE *node)
    699  1.1  christos {
    700  1.1  christos   WINDOW *win = (WINDOW *)NULL;
    701  1.1  christos 
    702  1.1  christos   for (win = windows; win; win = win->next)
    703  1.1  christos     if (win->node == node)
    704                      break;
    705                
    706                  return (win);
    707                }
    708