summaryrefslogtreecommitdiff
path: root/macros/texinfo/texinfo/info/util.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-11-09 03:02:50 +0000
committerNorbert Preining <norbert@preining.info>2022-11-09 03:02:50 +0000
commit5de83ec843cdc88e6adc42b1fe3f0ec48c52b7f3 (patch)
treeb49f7c180396c8ef389c8fd519370b6d03f4e100 /macros/texinfo/texinfo/info/util.c
parent118cb5bbc5236bf86ca1088b9b3bae04c7b09beb (diff)
CTAN sync 202211090302
Diffstat (limited to 'macros/texinfo/texinfo/info/util.c')
-rw-r--r--macros/texinfo/texinfo/info/util.c437
1 files changed, 437 insertions, 0 deletions
diff --git a/macros/texinfo/texinfo/info/util.c b/macros/texinfo/texinfo/info/util.c
new file mode 100644
index 0000000000..d07262d19b
--- /dev/null
+++ b/macros/texinfo/texinfo/info/util.c
@@ -0,0 +1,437 @@
+/* util.c -- various utility functions
+
+ Copyright 1993-2022 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "info.h"
+#include "session.h"
+#include "util.h"
+#include "tag.h"
+
+/* wrapper for asprintf */
+static int
+xvasprintf (char **ptr, const char *template, va_list ap)
+{
+ int ret;
+ ret = vasprintf (ptr, template, ap);
+ if (ret < 0)
+ abort (); /* out of memory */
+ return ret;
+}
+
+int
+xasprintf (char **ptr, const char *template, ...)
+{
+ va_list v;
+ va_start (v, template);
+ return xvasprintf (ptr, template, v);
+}
+
+/* Return the file buffer which belongs to WINDOW's node. */
+FILE_BUFFER *
+file_buffer_of_window (WINDOW *window)
+{
+ /* If this window has no node, then it has no file buffer. */
+ if (!window->node)
+ return NULL;
+
+ if (window->node->fullpath)
+ return info_find_file (window->node->fullpath);
+
+ return NULL;
+}
+
+/* Return "(FILENAME)NODENAME" for NODE, or just "NODENAME" if NODE's
+ filename is not set. Return value should not be freed. */
+char *
+node_printed_rep (NODE *node)
+{
+ static char *rep;
+
+ if (node->fullpath)
+ {
+ char *filename = filename_non_directory (node->fullpath);
+ rep = xrealloc (rep, 1 + strlen (filename) + 1 + strlen (node->nodename) + 1);
+ sprintf (rep, "(%s)%s", filename, node->nodename);
+ return rep;
+ }
+ else
+ return node->nodename;
+}
+
+
+/* Return a pointer to the part of PATHNAME that simply defines the file. */
+char *
+filename_non_directory (char *pathname)
+{
+ register char *filename = pathname + strlen (pathname);
+
+ if (HAVE_DRIVE (pathname))
+ pathname += 2;
+
+ while (filename > pathname && !IS_SLASH (filename[-1]))
+ filename--;
+
+ return filename;
+}
+
+/* Return non-zero if NODE is one especially created by Info. */
+int
+internal_info_node_p (NODE *node)
+{
+ return (node != NULL) && (node->flags & N_IsInternal);
+}
+
+/* Make NODE appear to be one especially created by Info. */
+void
+name_internal_node (NODE *node, char *name)
+{
+ if (!node)
+ return;
+
+ node->fullpath = "";
+ node->subfile = 0;
+ node->nodename = name;
+ node->flags |= N_IsInternal;
+}
+
+/* Return the window displaying NAME, the name of an internally created
+ Info window. */
+WINDOW *
+get_internal_info_window (char *name)
+{
+ WINDOW *win;
+
+ for (win = windows; win; win = win->next)
+ if (internal_info_node_p (win->node) &&
+ (strcmp (win->node->nodename, name) == 0))
+ break;
+
+ return win;
+}
+
+
+/* If ITER points to an ANSI escape sequence, process it, set PLEN to its
+ length in bytes, and return 1.
+ Otherwise, return 0.
+ */
+int
+ansi_escape (mbi_iterator_t iter, size_t *plen)
+{
+ if (raw_escapes_p && *mbi_cur_ptr (iter) == '\033' && mbi_avail (iter))
+ {
+ mbi_advance (iter);
+ if (*mbi_cur_ptr (iter) == '[' && mbi_avail (iter))
+ {
+ ITER_SETBYTES (iter, 1);
+ mbi_advance (iter);
+ if (isdigit (*mbi_cur_ptr (iter)) && mbi_avail (iter))
+ {
+ ITER_SETBYTES (iter, 1);
+ mbi_advance (iter);
+ if (*mbi_cur_ptr (iter) == 'm')
+ {
+ *plen = 4;
+ return 1;
+ }
+ else if (isdigit (*mbi_cur_ptr (iter)) && mbi_avail (iter))
+ {
+ ITER_SETBYTES (iter, 1);
+ mbi_advance (iter);
+ if (*mbi_cur_ptr (iter) == 'm')
+ {
+ *plen = 5;
+ return 1;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static struct text_buffer printed_rep = { 0 };
+
+/* Return pointer to string that is the printed representation of character
+ (or other logical unit) at ITER if it were printed at screen column
+ PL_CHARS. Use ITER_SETBYTES (util.h) on ITER if we need to advance
+ past a unit that the multibyte iteractor doesn't know about (like an ANSI
+ escape sequence). If ITER points at an end-of-line character, set *DELIM to
+ this character. *PCHARS gets the number of screen columns taken up by
+ outputting the return value, and *PBYTES the number of bytes in returned
+ string. Return value is not null-terminated. Return value must not be
+ freed by caller. */
+char *
+printed_representation (mbi_iterator_t *iter, int *delim, size_t pl_chars,
+ size_t *pchars, size_t *pbytes)
+{
+ struct text_buffer *rep = &printed_rep;
+
+ char *cur_ptr = (char *) mbi_cur_ptr (*iter);
+ size_t cur_len = mb_len (mbi_cur (*iter));
+
+ text_buffer_reset (&printed_rep);
+
+ if (mb_isprint (mbi_cur (*iter)))
+ {
+ /* cur.wc gives a wchar_t object. See mbiter.h in the
+ gnulib/lib directory. */
+ *pchars = wcwidth ((*iter).cur.wc);
+ *pbytes = cur_len;
+ return cur_ptr;
+ }
+ else if (cur_len == 1)
+ {
+ if (*cur_ptr == '\n' || *cur_ptr == '\r')
+ {
+ /* If this is a CRLF line ending, ignore this character. */
+ if (*cur_ptr == '\r' && cur_ptr[1] == '\n')
+ {
+ *pchars = 0;
+ *pbytes = 0;
+ return cur_ptr;
+ }
+
+ *pchars = 1;
+ *pbytes = cur_len;
+ *delim = *cur_ptr;
+ text_buffer_add_char (rep, ' ');
+ return cur_ptr;
+ }
+ else if (ansi_escape (*iter, &cur_len))
+ {
+ *pchars = 0;
+ *pbytes = cur_len;
+ ITER_SETBYTES (*iter, cur_len);
+
+ return cur_ptr;
+ }
+ else if (*cur_ptr == '\t')
+ {
+ int i = 0;
+
+ *pchars = ((pl_chars + 8) & 0xf8) - pl_chars;
+ *pbytes = *pchars;
+
+ /* We must output spaces instead of the tab because a tab may
+ not clear characters already on the screen. */
+ for (i = 0; i < *pbytes; i++)
+ text_buffer_add_char (rep, ' ');
+ return text_buffer_base (rep);
+ }
+ }
+
+ /* Show CTRL-x as "^X". */
+ if (iscntrl (*cur_ptr) && *(unsigned char *)cur_ptr < 127)
+ {
+ *pchars = 2;
+ *pbytes = 2;
+ text_buffer_add_char (rep, '^');
+ text_buffer_add_char (rep, *cur_ptr | 0x40);
+ return text_buffer_base (rep);
+ }
+ else if (*cur_ptr == DEL)
+ {
+ *pchars = 0;
+ *pbytes = 0;
+ return text_buffer_base (rep);
+ }
+ else
+ {
+ /* Original byte was not recognized as anything. Display its octal
+ value. This could happen in the C locale for bytes above 128,
+ or for bytes 128-159 in an ISO-8859-1 locale. Don't output the bytes
+ as they are, because they could have special meaning to the
+ terminal. */
+ *pchars = 4;
+ *pbytes = 4;
+ text_buffer_printf (rep, "\\%o", *(unsigned char *)cur_ptr);
+ return text_buffer_base (rep);
+ }
+}
+
+/* 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;
+}
+
+/* Make sure there are LEN free bytes at end of BUF. */
+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);
+ }
+}
+
+/* Return number of bytes that can be written to text buffer without
+ reallocating the text buffer. */
+size_t
+text_buffer_space_left (struct text_buffer *buf)
+{
+ /* buf->size is the offset of the first byte after the allocated space.
+ buf->off is the offset of the first byte to be written to. */
+ return buf->size - buf->off;
+}
+
+#if HAVE_ICONV
+
+/* Run iconv using text buffer as output buffer. */
+size_t
+text_buffer_iconv (struct text_buffer *buf, iconv_t iconv_state,
+ ICONV_CONST char **inbuf, size_t *inbytesleft)
+{
+ size_t out_bytes_left;
+ char *outptr;
+ size_t iconv_ret;
+
+ outptr = text_buffer_base (buf) + text_buffer_off (buf);
+ out_bytes_left = text_buffer_space_left (buf);
+
+ while (1)
+ {
+ iconv_ret = iconv (iconv_state, inbuf, inbytesleft,
+ &outptr, &out_bytes_left);
+ if (iconv_ret != (size_t) -1)
+ break; /* success */
+
+ /* If we ran out of space, allocate more and try again. */
+ if (errno == E2BIG)
+ text_buffer_alloc (buf, 4);
+ else
+ break; /* let calling code deal with it */
+ }
+ text_buffer_off (buf) = outptr - text_buffer_base (buf);
+ return iconv_ret;
+}
+
+#endif /* HAVE_ICONV */
+
+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. */
+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);
+}
+
+#endif