summaryrefslogtreecommitdiff
path: root/info/info-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'info/info-utils.c')
-rw-r--r--info/info-utils.c291
1 files changed, 250 insertions, 41 deletions
diff --git a/info/info-utils.c b/info/info-utils.c
index 7236452..37659d0 100644
--- a/info/info-utils.c
+++ b/info/info-utils.c
@@ -1,8 +1,8 @@
/* info-utils.c -- miscellanous.
- $Id: info-utils.c,v 1.12 2008/06/11 09:55:42 gray Exp $
+ $Id: info-utils.c 5379 2013-09-19 09:00:48Z eliz $
- Copyright (C) 1993, 1998, 2003, 2004, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright 1993, 1998, 2003, 2004, 2007, 2008, 2009, 2011, 2012,
+ 2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
- Originally written by Brian Fox (bfox@ai.mit.edu). */
+ Originally written by Brian Fox. */
#include "info.h"
#include "info-utils.h"
@@ -25,6 +25,10 @@
# include "man.h"
#endif /* HANDLE_MAN_PAGES */
+#ifdef __hpux
+#define va_copy(ap1,ap2) memcpy((&ap1),(&ap2),sizeof(va_list))
+#endif
+
/* When non-zero, various display and input functions handle ISO Latin
character sets correctly. */
int ISO_Latin_p = 1;
@@ -41,6 +45,9 @@ char *info_parsed_nodename = NULL;
calling info_parse_xxx (). */
int info_parsed_line_number = 0;
+static void save_string (char *string, char **string_p, int *string_size_p);
+static void saven_string (char *string, int len, char **string_p,
+ int *string_size_p);
/* Functions to remember a filename or nodename for later return. */
static void save_filename (char *filename);
static void saven_filename (char *filename, int len);
@@ -53,11 +60,16 @@ static REFERENCE **info_references_internal (char *label,
/* Parse the filename and nodename out of STRING. If STRING doesn't
contain a filename (i.e., it is NOT (FILENAME)NODENAME) then set
- INFO_PARSED_FILENAME to NULL. If second argument NEWLINES_OKAY is
- non-zero, it says to allow the nodename specification to cross a
- newline boundary (i.e., only `,', `.', or `TAB' can end the spec). */
+ INFO_PARSED_FILENAME to NULL. The second argument is one of
+ the PARSE_NODE_* constants. It specifies how to parse the node name:
+
+ PARSE_NODE_DFLT Node name stops at LF, `,', `.', or `TAB'
+ PARSE_NODE_SKIP_NEWLINES Node name stops at `,', `.', or `TAB'
+ PARSE_NODE_VERBATIM Don't parse nodename
+*/
+
void
-info_parse_node (char *string, int newlines_okay)
+info_parse_node (char *string, int flag)
{
register int i = 0;
@@ -74,14 +86,34 @@ info_parse_node (char *string, int newlines_okay)
/* Check for (FILENAME)NODENAME. */
if (*string == '(')
{
+ int bcnt;
+ int bfirst;
+
i = 0;
/* Advance past the opening paren. */
string++;
- /* Find the closing paren. */
- while (string[i] && string[i] != ')')
- i++;
+ /* Find the closing paren. Handle nested parens correctly. */
+ for (bcnt = 0, bfirst = -1; string[i]; i++)
+ {
+ if (string[i] == ')')
+ {
+ if (bcnt == 0)
+ {
+ bfirst = -1;
+ break;
+ }
+ else if (!bfirst)
+ bfirst = i;
+ bcnt--;
+ }
+ else if (string[i] == '(')
+ bcnt++;
+ }
+ if (bfirst >= 0)
+ i = bfirst;
+
/* Remember parsed filename. */
saven_filename (string, i);
@@ -93,7 +125,7 @@ info_parse_node (char *string, int newlines_okay)
}
/* Parse out nodename. */
- i = skip_node_characters (string, newlines_okay);
+ i = skip_node_characters (string, flag);
saven_nodename (string, i);
canonicalize_whitespace (info_parsed_nodename);
if (info_parsed_nodename && !*info_parsed_nodename)
@@ -157,7 +189,7 @@ info_parse_label (char *label, NODE *node)
nodeline += i;
nodeline += skip_whitespace (nodeline);
- info_parse_node (nodeline, DONT_SKIP_NEWLINES);
+ info_parse_node (nodeline, PARSE_NODE_DFLT);
}
/* **************************************************************** */
@@ -181,9 +213,8 @@ info_menu_of_node (NODE *node)
tmp_search.flags = S_FoldCase;
/* Find the start of the menu. */
- position = search_forward (INFO_MENU_LABEL, &tmp_search);
-
- if (position == -1)
+ if (search_forward (INFO_MENU_LABEL, &tmp_search, &position)
+ != search_success)
return NULL;
/* We have the start of the menu now. Glean menu items from the rest
@@ -241,7 +272,7 @@ info_references_internal (char *label, SEARCH_BINDING *binding)
{
SEARCH_BINDING tmp_search;
REFERENCE **refs = NULL;
- int refs_index = 0, refs_slots = 0;
+ size_t refs_index = 0, refs_slots = 0;
int searching_for_menu_items = 0;
long position;
@@ -252,7 +283,7 @@ info_references_internal (char *label, SEARCH_BINDING *binding)
searching_for_menu_items = (mbscasecmp (label, INFO_MENU_ENTRY_LABEL) == 0);
- while ((position = search_forward (label, &tmp_search)) != -1)
+ while (search_forward (label, &tmp_search, &position) == search_success)
{
int offset, start;
char *refdef;
@@ -310,9 +341,9 @@ info_references_internal (char *label, SEARCH_BINDING *binding)
refdef += skip_whitespace_and_newlines (refdef);
if (searching_for_menu_items)
- info_parse_node (refdef, DONT_SKIP_NEWLINES);
+ info_parse_node (refdef, PARSE_NODE_DFLT);
else
- info_parse_node (refdef, SKIP_NEWLINES);
+ info_parse_node (refdef, PARSE_NODE_SKIP_NEWLINES);
if (info_parsed_filename)
entry->filename = xstrdup (info_parsed_filename);
@@ -323,8 +354,7 @@ info_references_internal (char *label, SEARCH_BINDING *binding)
entry->line_number = info_parsed_line_number;
}
- add_pointer_to_array
- (entry, refs_index, refs, refs_slots, 50, REFERENCE *);
+ add_pointer_to_array (entry, refs_index, refs, refs_slots, 50);
}
return refs;
}
@@ -404,6 +434,18 @@ info_copy_reference (REFERENCE *src)
+void
+info_reference_free (REFERENCE *ref)
+{
+ if (ref)
+ {
+ free (ref->label);
+ free (ref->filename);
+ free (ref->nodename);
+ free (ref);
+ }
+}
+
/* Free the data associated with REFERENCES. */
void
info_free_references (REFERENCE **references)
@@ -414,13 +456,7 @@ info_free_references (REFERENCE **references)
if (references)
{
for (i = 0; references && (entry = references[i]); i++)
- {
- maybe_free (entry->label);
- maybe_free (entry->filename);
- maybe_free (entry->nodename);
-
- free (entry);
- }
+ info_reference_free (entry);
free (references);
}
@@ -485,10 +521,11 @@ static size_t the_rep_size;
/* Return a pointer to a string which is the printed representation
of CHARACTER if it were printed at HPOS. */
char *
-printed_representation (const unsigned char *cp, size_t len, size_t hpos,
+printed_representation (const char *character, size_t len, size_t hpos,
/* Return: */
size_t *plen)
{
+ const unsigned char *cp = (const unsigned char *) character;
register int i = 0;
int printable_limit = ISO_Latin_p ? 255 : 127;
#define REPSPACE(s) \
@@ -574,10 +611,6 @@ static int parsed_filename_size = 0;
/* Amount of space allocated to INFO_PARSED_NODENAME via xmalloc (). */
static int parsed_nodename_size = 0;
-static void save_string (char *string, char **string_p, int *string_size_p);
-static void saven_string (char *string, int len, char **string_p,
- int *string_size_p);
-
/* Remember FILENAME in PARSED_FILENAME. An empty FILENAME is translated
to a NULL pointer in PARSED_FILENAME. */
static void
@@ -624,14 +657,19 @@ save_string (char *string, char **string_p, int *string_size_p)
*string_p = NULL;
*string_size_p = 0;
}
- else
+ else if (string_size_p)
{
if (strlen (string) >= (unsigned int) *string_size_p)
- *string_p = xrealloc
- (*string_p, (*string_size_p = 1 + strlen (string)));
+ *string_p = xrealloc (*string_p,
+ (*string_size_p = 1 + strlen (string)));
strcpy (*string_p, string);
}
+ else
+ {
+ free (*string_p);
+ *string_p = xstrdup (string);
+ }
}
/* Just like save_string (), but you also pass the length of STRING. */
@@ -646,11 +684,18 @@ saven_string (char *string, int len, char **string_p, int *string_size_p)
*string_p = NULL;
*string_size_p = 0;
}
- else
+ else
{
- if (len >= *string_size_p)
- *string_p = xrealloc (*string_p, (*string_size_p = 1 + len));
-
+ if (string_size_p)
+ {
+ if (len >= *string_size_p)
+ *string_p = xrealloc (*string_p, (*string_size_p = 1 + len));
+ }
+ else
+ {
+ free (*string_p);
+ *string_p = xmalloc (1 + len);
+ }
strncpy (*string_p, string, len);
(*string_p)[len] = '\0';
}
@@ -727,3 +772,167 @@ get_window_of_node (NODE *node)
return win;
}
+
+/* Flexible Text Buffer */
+
+void
+text_buffer_init (struct text_buffer *buf)
+{
+ memset (buf, 0, sizeof *buf);
+}
+
+void
+text_buffer_free (struct text_buffer *buf)
+{
+ free (buf->base);
+}
+
+size_t
+text_buffer_vprintf (struct text_buffer *buf, const char *format, va_list ap)
+{
+ ssize_t n;
+ va_list ap_copy;
+
+ if (!buf->base)
+ {
+ if (buf->size == 0)
+ buf->size = MIN_TEXT_BUF_ALLOC; /* Initial allocation */
+
+ buf->base = xmalloc (buf->size);
+ }
+
+ for (;;)
+ {
+ va_copy (ap_copy, ap);
+ n = vsnprintf (buf->base + buf->off, buf->size - buf->off,
+ format, ap_copy);
+ va_end (ap_copy);
+ if (n < 0 || buf->off + n >= buf->size ||
+ !memchr (buf->base + buf->off, '\0', buf->size - buf->off + 1))
+ {
+ size_t newlen = buf->size * 2;
+ if (newlen < buf->size)
+ xalloc_die ();
+ buf->size = newlen;
+ buf->base = xrealloc (buf->base, buf->size);
+ }
+ else
+ {
+ buf->off += n;
+ break;
+ }
+ }
+ return n;
+}
+
+void
+text_buffer_alloc (struct text_buffer *buf, size_t len)
+{
+ if (buf->off + len > buf->size)
+ {
+ buf->size = buf->off + len;
+ if (buf->size < MIN_TEXT_BUF_ALLOC)
+ buf->size = MIN_TEXT_BUF_ALLOC;
+ buf->base = xrealloc (buf->base, buf->size);
+ }
+}
+
+size_t
+text_buffer_add_string (struct text_buffer *buf, const char *str, size_t len)
+{
+ text_buffer_alloc (buf, len);
+ memcpy (buf->base + buf->off, str, len);
+ buf->off += len;
+ return len;
+}
+
+size_t
+text_buffer_fill (struct text_buffer *buf, int c, size_t len)
+{
+ char *p;
+ int i;
+
+ text_buffer_alloc (buf, len);
+
+ for (i = 0, p = buf->base + buf->off; i < len; i++)
+ *p++ = c;
+ buf->off += len;
+
+ return len;
+}
+
+void
+text_buffer_add_char (struct text_buffer *buf, int c)
+{
+ char ch = c;
+ text_buffer_add_string (buf, &ch, 1);
+}
+
+size_t
+text_buffer_printf (struct text_buffer *buf, const char *format, ...)
+{
+ va_list ap;
+ size_t n;
+
+ va_start (ap, format);
+ n = text_buffer_vprintf (buf, format, ap);
+ va_end (ap);
+ return n;
+}
+
+#if defined(__MSDOS__) || defined(__MINGW32__)
+/* Cannot use FILENAME_CMP here, since that does not consider forward-
+ and back-slash characters equal. */
+static int
+fncmp (const char *fn1, const char *fn2)
+{
+ const char *s1 = fn1, *s2 = fn2;
+
+ while (tolower (*s1) == tolower (*s2)
+ || (IS_SLASH (*s1) && IS_SLASH (*s2)))
+ {
+ if (*s1 == 0)
+ return 0;
+ s1++;
+ s2++;
+ }
+
+ return tolower (*s1) - tolower (*s2);
+}
+#else
+# define fncmp(s,t) strcmp(s,t)
+#endif
+
+struct info_namelist_entry
+{
+ struct info_namelist_entry *next;
+ char name[1];
+};
+
+int
+info_namelist_add (struct info_namelist_entry **ptop, const char *name)
+{
+ struct info_namelist_entry *p;
+
+ for (p = *ptop; p; p = p->next)
+ if (fncmp (p->name, name) == 0)
+ return 1;
+
+ p = xmalloc (sizeof (*p) + strlen (name));
+ strcpy (p->name, name);
+ p->next = *ptop;
+ *ptop = p;
+ return 0;
+}
+
+void
+info_namelist_free (struct info_namelist_entry *top)
+{
+ while (top)
+ {
+ struct info_namelist_entry *next = top->next;
+ free (top);
+ top = next;
+ }
+}
+