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