xref: /openbsd-src/gnu/usr.bin/texinfo/info/info-utils.c (revision a1acfa9b69ad64eb720639240c8438f11107dc85)
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