From 5dd8d8ec4dff493448287564863b8d60b44654ff Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Tue, 30 Jan 2018 11:36:49 +0000 Subject: New upstream release --- src/pstring.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 src/pstring.c (limited to 'src/pstring.c') diff --git a/src/pstring.c b/src/pstring.c new file mode 100644 index 0000000..ef845f3 --- /dev/null +++ b/src/pstring.c @@ -0,0 +1,310 @@ +/*-------------------------------------------------------------------- + * Copyright © 2012-2016 James Hunt . + * + * 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 . + *-------------------------------------------------------------------- + */ + +#include "pstring.h" + +#include + +extern wchar_t wide_indent_char; + +wchar_t * +char_to_wchar (const char *str) +{ + const char *p; + wchar_t *wstr = NULL; + size_t len; + size_t bytes; + + assert (str); + + len = mbsrtowcs (NULL, &str, 0, NULL); + if (len <= 0) + return NULL; + + /* include space for terminator */ + bytes = (1 + len) * sizeof (wchar_t); + + wstr = malloc (bytes); + if (! wstr) + return NULL; + + p = str; + + if (mbsrtowcs (wstr, &p, len, NULL) != len) + goto error; + + /* ensure it's terminated */ + wstr[len] = L'\0'; + + return wstr; + +error: + free (wstr); + return NULL; +} + +char * +wchar_to_char (const wchar_t *wstr) +{ + char *str = NULL; + size_t len; + size_t bytes; + size_t ret; + + assert (wstr); + + len = wcslen (wstr); + + /* determine number of MBS (char) bytes requires to hold the + * wchar_t string. + */ + bytes = wcstombs (NULL, wstr, len); + if (! bytes) + return NULL; + + str = calloc (bytes + 1, sizeof (char)); + if (! str) + return NULL; + + /* actually perform the conversion */ + ret = wcstombs (str, wstr, bytes); + + if (! ret) + goto error; + + return str; + +error: + free (str); + return NULL; +} + +pstring * +pstring_new (void) +{ + pstring *pstr = NULL; + + pstr = calloc (1, sizeof (pstring)); + if (! pstr) + return NULL; + + pstr->len = 0; + pstr->size = 0; + pstr->buf = NULL; + + return pstr; +} + +pstring * +pstring_create (const wchar_t *str) +{ + pstring *pstr = NULL; + + assert (str); + + pstr = pstring_new (); + + if (! pstr) + return NULL; + + pstr->buf = wcsdup (str); + if (! pstr->buf) { + pstring_free (pstr); + return NULL; + } + + /* include the L'\0' terminator */ + pstr->len = 1 + wcslen (pstr->buf); + + pstr->size = pstr->len * sizeof (wchar_t); + + return pstr; +} + +void +pstring_free (pstring *str) +{ + assert (str); + + if (str->buf) + free (str->buf); + + free (str); +} + +pstring * +char_to_pstring (const char *str) +{ + pstring *pstr = NULL; + wchar_t *s; + + assert (str); + + s = char_to_wchar (str); + if (! s) + return NULL; + + pstr = pstring_create (s); + + free (s); + + return pstr; +} + +char * +pstring_to_char (const pstring *str) +{ + assert (str); + + return wchar_to_char (str->buf); +} + +/** + * pstring_chomp: + * + * Remove trailing extraneous newlines and indent_chars from @str. + **/ +void +pstring_chomp (pstring *str) +{ + size_t len; + int removable = 0; + wchar_t *p; + + assert (str); + + /* Unable to add '\n' in this scenario */ + if (str->len < 2) + return; + + for (p = str->buf+str->len-1; + *p == L'\n' || *p == wide_indent_char; + p--, removable++) + ; + + /* Chop string at the appropriate place after first adding a new + * newline. + */ + if (removable > 1) { + len = str->len - (removable-1); + str->buf[len-1] = L'\n'; + str->buf[len] = L'\0'; + str->len = len; + } +} + +/** + * pstring_compress: + * + * Remove lines composed entirely of whitespace from @str. + * + * This is required specifically for '--output=text' which in some + * scenarios generates lines comprising pure whitespace. This is + * unecessary and results from the fact that when an + * ELEMENT_TYPE_OBJECT_* is encountered, formatting is applied for the + * previously seen element, but sometimes such "objects" should be + * invisible. + **/ +void +pstring_compress (pstring **wstr, wchar_t remove_char) +{ + wchar_t *from; + wchar_t *to; + wchar_t *p; + wchar_t *start; + size_t count = 0; + size_t blanks = 0; + size_t new_len; + size_t bytes; + + assert (wstr); + + to = from = (*wstr)->buf; + assert (from); + + while (to && *to) { +again: + while (*to == L'\n' && *(to+1) == L'\n') { + /* skip over blank lines */ + to++; + blanks++; + } + + start = to; + + while (*to == remove_char) { + /* skip runs of contiguous characters */ + to++; + count++; + } + + if (to != start) { + /* Only start consuming NLs at the end of a + * contiguous run *iff* there was more than a + * single removed char. This is a heuristic to + * avoid removing valid entries for example env + * vars that are set to nul are shown as: + * + * 'var: ' + * + * Shudder. + */ + if (*to == L'\n' && to != start+1) { + while (*to == L'\n') { + /* consume the NL at the end of the contiguous run */ + to++; + } + + /* check to ensure that we haven't entered a new line + * containing another block of chars to remove. + */ + if (*to == remove_char) + goto again; + + blanks++; + + } else { + /* not a full line so backtrack */ + to = start; + count = 0; + } + } + + *from++ = *to++; + } + + /* terminate */ + *from = L'\0'; + + if (blanks || count) { + new_len = (*wstr)->len - (blanks + count); + + bytes = new_len * sizeof (wchar_t); + + p = realloc ((*wstr)->buf, bytes); + assert (p); + + (*wstr)->buf = p; + + (*wstr)->buf[new_len-1] = L'\0'; + + (*wstr)->len = new_len; + (*wstr)->size = bytes; + } +} + -- cgit v1.2.3