diff options
author | Norbert Preining <norbert@preining.info> | 2022-11-09 03:02:50 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2022-11-09 03:02:50 +0000 |
commit | 5de83ec843cdc88e6adc42b1fe3f0ec48c52b7f3 (patch) | |
tree | b49f7c180396c8ef389c8fd519370b6d03f4e100 /macros/texinfo/texinfo/info/util.c | |
parent | 118cb5bbc5236bf86ca1088b9b3bae04c7b09beb (diff) |
CTAN sync 202211090302
Diffstat (limited to 'macros/texinfo/texinfo/info/util.c')
-rw-r--r-- | macros/texinfo/texinfo/info/util.c | 437 |
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 |