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