X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=string.c;h=e731bb496b4b0d0f2f5a7dac417cbbeab7b9f3f6;hp=39d16c3a343ade4db21c9e5d9465728613403c7c;hb=06d0c50525fc14e8127916481a74c14a2f7098af;hpb=bc15c3ff65eb00e04ebc303cfa9ee3d1a4675b35 diff --git a/string.c b/string.c index 39d16c3a..e731bb49 100644 --- a/string.c +++ b/string.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2014 Andre Noll + * Copyright (C) 2004 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -31,8 +31,8 @@ * A wrapper for realloc(3). It calls \p exit(\p EXIT_FAILURE) on errors, * i.e. there is no need to check the return value in the caller. * - * \return A pointer to the newly allocated memory, which is suitably aligned - * for any kind of variable and may be different from \a p. + * \return A pointer to newly allocated memory which is suitably aligned for + * any kind of variable and may be different from \a p. * * \sa realloc(3). */ @@ -380,14 +380,13 @@ int for_each_line(unsigned flags, char *buf, size_t size, char *next_cr; next_cr = memchr(start, '\n', buf + size - start); - next_null = memchr(start, '\0', buf + size - start); + next_null = memchr(start, '\0', next_cr? + next_cr - start : buf + size - start); if (!next_cr && !next_null) break; - if (next_cr && next_null) { - end = next_cr < next_null? next_cr : next_null; - } else if (next_null) { + if (next_null) end = next_null; - } else + else end = next_cr; num_lines++; if (!(flags & FELF_DISCARD_FIRST) || start != buf) { @@ -563,10 +562,18 @@ int para_atoi64(const char *str, int64_t *value) tmp = strtoll(str, &endptr, 10); if (errno == ERANGE && (tmp == LLONG_MAX || tmp == LLONG_MIN)) return -E_ATOI_OVERFLOW; - if (errno != 0 && tmp == 0) /* other error */ - return -E_STRTOLL; + /* + * If there were no digits at all, strtoll() stores the original value + * of str in *endptr. + */ if (endptr == str) return -E_ATOI_NO_DIGITS; + /* + * The implementation may also set errno and return 0 in case no + * conversion was performed. + */ + if (errno != 0 && tmp == 0) + return -E_ATOI_NO_DIGITS; if (*endptr != '\0') /* Further characters after number */ return -E_ATOI_JUNK_AT_END; *value = tmp; @@ -626,7 +633,7 @@ int get_loglevel_by_name(const char *txt) return LL_CRIT; if (loglevel_equal(txt, "emerg")) return LL_EMERG; - return -1; + return -E_BAD_LL; } static int get_next_word(const char *buf, const char *delim, char **word) @@ -948,36 +955,24 @@ static bool utf8_mode(void) return have_utf8; } -/* - * glibc's wcswidth returns -1 if the string contains a tab character, which - * makes the function next to useless. The two functions below are taken from - * mutt. - */ - -#define IsWPrint(wc) (iswprint(wc) || wc >= 0xa0) - -static int mutt_wcwidth(wchar_t wc, size_t pos) +static int xwcwidth(wchar_t wc, size_t pos) { int n; + /* special-case for tab */ if (wc == 0x09) /* tab */ return (pos | 7) + 1 - pos; n = wcwidth(wc); - if (IsWPrint(wc) && n > 0) - return n; - if (!(wc & ~0x7f)) - return 2; - if (!(wc & ~0xffff)) - return 6; - return 10; + /* wcswidth() returns -1 for non-printable characters */ + return n >= 0? n : 1; } -static size_t mutt_wcswidth(const wchar_t *s, size_t n) +static size_t xwcswidth(const wchar_t *s, size_t n) { size_t w = 0; while (n--) - w += mutt_wcwidth(*s++, w); + w += xwcwidth(*s++, w); return w; } @@ -1022,7 +1017,7 @@ int skip_cells(const char *s, size_t cells_to_skip, size_t *bytes_to_skip) if (mbret == (size_t)-1 || mbret == (size_t)-2) return -ERRNO_TO_PARA_ERROR(EILSEQ); bytes_parsed += mbret; - cells_skipped += mutt_wcwidth(wc, cells_skipped); + cells_skipped += xwcwidth(wc, cells_skipped); } *bytes_to_skip = bytes_parsed; return 1; @@ -1066,12 +1061,75 @@ __must_check int strwidth(const char *s, size_t *result) return -ERRNO_TO_PARA_ERROR(errno); if (num_wchars == 0) return 0; - dest = para_malloc(num_wchars * sizeof(*dest)); + dest = para_malloc((num_wchars + 1) * sizeof(*dest)); src = s; memset(&state, 0, sizeof(state)); num_wchars = mbsrtowcs(dest, &src, num_wchars, &state); assert(num_wchars > 0 && num_wchars != (size_t)-1); - *result = mutt_wcswidth(dest, num_wchars); + *result = xwcswidth(dest, num_wchars); free(dest); return 1; } + +/** + * Truncate and sanitize a (wide character) string. + * + * This replaces all non-printable characters by spaces and makes sure that the + * modified string does not exceed the given maximal width. + * + * \param src The source string in multi-byte form. + * \param max_width The maximal number of cells the result may occupy. + * \param result Sanitized multi-byte string, must be freed by caller. + * \param width The width of the sanitized string, always <= max_width. + * + * The function is wide-character aware but falls back to C strings for + * non-UTF-8 locales. + * + * \return Standard. On success, *result points to a sanitized copy of the + * given string. This copy was allocated with malloc() and should hence be + * freed when the caller is no longer interested in the result. + * + * The function fails if the given string contains an invalid multibyte + * sequence. In this case, *result is set to NULL, and *width to zero. + */ +__must_check int sanitize_str(const char *src, size_t max_width, + char **result, size_t *width) +{ + mbstate_t state; + static wchar_t *wcs; + size_t num_wchars, n; + + if (!utf8_mode()) { + *result = para_strdup(src); + /* replace non-printable characters by spaces */ + for (n = 0; n < max_width && src[n]; n++) { + if (!isprint((unsigned char)src[n])) + (*result)[n] = ' '; + } + (*result)[n] = '\0'; + *width = n; + return 0; + } + *result = NULL; + *width = 0; + memset(&state, 0, sizeof(state)); + num_wchars = mbsrtowcs(NULL, &src, 0, &state); + if (num_wchars == (size_t)-1) + return -ERRNO_TO_PARA_ERROR(errno); + wcs = para_malloc((num_wchars + 1) * sizeof(*wcs)); + memset(&state, 0, sizeof(state)); + num_wchars = mbsrtowcs(wcs, &src, num_wchars + 1, &state); + assert(num_wchars != (size_t)-1); + for (n = 0; n < num_wchars && *width < max_width; n++) { + if (!iswprint(wcs[n])) + wcs[n] = L' '; + *width += xwcwidth(wcs[n], *width); + } + wcs[n] = L'\0'; + n = wcstombs(NULL, wcs, 0) + 1; + *result = para_malloc(n); + num_wchars = wcstombs(*result, wcs, n); + assert(num_wchars != (size_t)-1); + free(wcs); + return 1; +}