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