| Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/coreutils/src/gl/lib/mbsalign.c |
| Source code | Switch to Preprocessed file |
| Line | Source | Count | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | /* Align/Truncate a string in a given screen width | - | ||||||||||||||||||
| 2 | Copyright (C) 2009-2018 Free Software Foundation, Inc. | - | ||||||||||||||||||
| 3 | - | |||||||||||||||||||
| 4 | This program is free software: you can redistribute it and/or modify | - | ||||||||||||||||||
| 5 | it under the terms of the GNU General Public License as published by | - | ||||||||||||||||||
| 6 | the Free Software Foundation, either version 3 of the License, or | - | ||||||||||||||||||
| 7 | (at your option) any later version. | - | ||||||||||||||||||
| 8 | - | |||||||||||||||||||
| 9 | This program is distributed in the hope that it will be useful, | - | ||||||||||||||||||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | ||||||||||||||||||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | ||||||||||||||||||
| 12 | GNU General Public License for more details. | - | ||||||||||||||||||
| 13 | - | |||||||||||||||||||
| 14 | You should have received a copy of the GNU General Public License | - | ||||||||||||||||||
| 15 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ | - | ||||||||||||||||||
| 16 | - | |||||||||||||||||||
| 17 | /* Written by Pádraig Brady. */ | - | ||||||||||||||||||
| 18 | - | |||||||||||||||||||
| 19 | #include <config.h> | - | ||||||||||||||||||
| 20 | #include "mbsalign.h" | - | ||||||||||||||||||
| 21 | - | |||||||||||||||||||
| 22 | #include <stdlib.h> | - | ||||||||||||||||||
| 23 | #include <string.h> | - | ||||||||||||||||||
| 24 | #include <stdio.h> | - | ||||||||||||||||||
| 25 | #include <stdint.h> | - | ||||||||||||||||||
| 26 | #include <stdbool.h> | - | ||||||||||||||||||
| 27 | #include <limits.h> | - | ||||||||||||||||||
| 28 | #include <wchar.h> | - | ||||||||||||||||||
| 29 | #include <wctype.h> | - | ||||||||||||||||||
| 30 | - | |||||||||||||||||||
| 31 | #ifndef MIN | - | ||||||||||||||||||
| 32 | # define MIN(a, b) ((a) < (b) ? (a) : (b)) | - | ||||||||||||||||||
| 33 | #endif | - | ||||||||||||||||||
| 34 | - | |||||||||||||||||||
| 35 | /* Replace non printable chars. | - | ||||||||||||||||||
| 36 | Note \t and \n etc. are non printable. | - | ||||||||||||||||||
| 37 | Return 1 if replacement made, 0 otherwise. */ | - | ||||||||||||||||||
| 38 | - | |||||||||||||||||||
| 39 | static bool | - | ||||||||||||||||||
| 40 | wc_ensure_printable (wchar_t *wchars) | - | ||||||||||||||||||
| 41 | { | - | ||||||||||||||||||
| 42 | bool replaced = false; | - | ||||||||||||||||||
| 43 | wchar_t *wc = wchars; | - | ||||||||||||||||||
| 44 | while (*wc)
| 0 | ||||||||||||||||||
| 45 | { | - | ||||||||||||||||||
| 46 | if (!iswprint ((wint_t) *wc))
| 0 | ||||||||||||||||||
| 47 | { | - | ||||||||||||||||||
| 48 | *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */ | - | ||||||||||||||||||
| 49 | replaced = true; | - | ||||||||||||||||||
| 50 | } never executed: end of block | 0 | ||||||||||||||||||
| 51 | wc++; | - | ||||||||||||||||||
| 52 | } never executed: end of block | 0 | ||||||||||||||||||
| 53 | return replaced; never executed: return replaced; | 0 | ||||||||||||||||||
| 54 | } | - | ||||||||||||||||||
| 55 | - | |||||||||||||||||||
| 56 | /* Truncate wchar string to width cells. | - | ||||||||||||||||||
| 57 | * Returns number of cells used. */ | - | ||||||||||||||||||
| 58 | - | |||||||||||||||||||
| 59 | static size_t | - | ||||||||||||||||||
| 60 | wc_truncate (wchar_t *wc, size_t width) | - | ||||||||||||||||||
| 61 | { | - | ||||||||||||||||||
| 62 | size_t cells = 0; | - | ||||||||||||||||||
| 63 | int next_cells = 0; | - | ||||||||||||||||||
| 64 | - | |||||||||||||||||||
| 65 | while (*wc)
| 0 | ||||||||||||||||||
| 66 | { | - | ||||||||||||||||||
| 67 | next_cells = wcwidth (*wc); | - | ||||||||||||||||||
| 68 | if (next_cells == -1) /* non printable */
| 0 | ||||||||||||||||||
| 69 | { | - | ||||||||||||||||||
| 70 | *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */ | - | ||||||||||||||||||
| 71 | next_cells = 1; | - | ||||||||||||||||||
| 72 | } never executed: end of block | 0 | ||||||||||||||||||
| 73 | if (cells + next_cells > width)
| 0 | ||||||||||||||||||
| 74 | break; never executed: break; | 0 | ||||||||||||||||||
| 75 | cells += next_cells; | - | ||||||||||||||||||
| 76 | wc++; | - | ||||||||||||||||||
| 77 | } never executed: end of block | 0 | ||||||||||||||||||
| 78 | *wc = L'\0'; | - | ||||||||||||||||||
| 79 | return cells; never executed: return cells; | 0 | ||||||||||||||||||
| 80 | } | - | ||||||||||||||||||
| 81 | - | |||||||||||||||||||
| 82 | /* Write N_SPACES space characters to DEST while ensuring | - | ||||||||||||||||||
| 83 | nothing is written beyond DEST_END. A terminating NUL | - | ||||||||||||||||||
| 84 | is always added to DEST. | - | ||||||||||||||||||
| 85 | A pointer to the terminating NUL is returned. */ | - | ||||||||||||||||||
| 86 | - | |||||||||||||||||||
| 87 | static char* | - | ||||||||||||||||||
| 88 | mbs_align_pad (char *dest, const char* dest_end, size_t n_spaces) | - | ||||||||||||||||||
| 89 | { | - | ||||||||||||||||||
| 90 | /* FIXME: Should we pad with "figure space" (\u2007) | - | ||||||||||||||||||
| 91 | if non ascii data present? */ | - | ||||||||||||||||||
| 92 | while (n_spaces-- && (dest < dest_end))
| 0-119527 | ||||||||||||||||||
| 93 | *dest++ = ' '; executed 119527 times by 4 tests: *dest++ = ' ';Executed by:
| 119527 | ||||||||||||||||||
| 94 | *dest = '\0'; | - | ||||||||||||||||||
| 95 | return dest; executed 10062 times by 4 tests: return dest;Executed by:
| 10062 | ||||||||||||||||||
| 96 | } | - | ||||||||||||||||||
| 97 | - | |||||||||||||||||||
| 98 | /* Align a string, SRC, in a field of *WIDTH columns, handling multi-byte | - | ||||||||||||||||||
| 99 | characters; write the result into the DEST_SIZE-byte buffer, DEST. | - | ||||||||||||||||||
| 100 | ALIGNMENT specifies whether to left- or right-justify or to center. | - | ||||||||||||||||||
| 101 | If SRC requires more than *WIDTH columns, truncate it to fit. | - | ||||||||||||||||||
| 102 | When centering, the number of trailing spaces may be one less than the | - | ||||||||||||||||||
| 103 | number of leading spaces. | - | ||||||||||||||||||
| 104 | Return the length in bytes required for the final result, not counting | - | ||||||||||||||||||
| 105 | the trailing NUL. A return value of DEST_SIZE or larger means there | - | ||||||||||||||||||
| 106 | wasn't enough space. DEST will be NUL terminated in any case. | - | ||||||||||||||||||
| 107 | Return SIZE_MAX upon error (invalid multi-byte sequence in SRC, | - | ||||||||||||||||||
| 108 | or malloc failure), unless MBA_UNIBYTE_FALLBACK is specified. | - | ||||||||||||||||||
| 109 | Update *WIDTH to indicate how many columns were used before padding. */ | - | ||||||||||||||||||
| 110 | - | |||||||||||||||||||
| 111 | size_t | - | ||||||||||||||||||
| 112 | mbsalign (const char *src, char *dest, size_t dest_size, | - | ||||||||||||||||||
| 113 | size_t *width, mbs_align_t align, int flags) | - | ||||||||||||||||||
| 114 | { | - | ||||||||||||||||||
| 115 | size_t ret = SIZE_MAX; | - | ||||||||||||||||||
| 116 | size_t src_size = strlen (src) + 1; | - | ||||||||||||||||||
| 117 | char *newstr = NULL; | - | ||||||||||||||||||
| 118 | wchar_t *str_wc = NULL; | - | ||||||||||||||||||
| 119 | const char *str_to_print = src; | - | ||||||||||||||||||
| 120 | size_t n_cols = src_size - 1; | - | ||||||||||||||||||
| 121 | size_t n_used_bytes = n_cols; /* Not including NUL */ | - | ||||||||||||||||||
| 122 | size_t n_spaces = 0; | - | ||||||||||||||||||
| 123 | bool conversion = false; | - | ||||||||||||||||||
| 124 | bool wc_enabled = false; | - | ||||||||||||||||||
| 125 | - | |||||||||||||||||||
| 126 | /* In multi-byte locales convert to wide characters | - | ||||||||||||||||||
| 127 | to allow easy truncation. Also determine number | - | ||||||||||||||||||
| 128 | of screen columns used. */ | - | ||||||||||||||||||
| 129 | if (!(flags & MBA_UNIBYTE_ONLY) && MB_CUR_MAX > 1)
| 0-5000 | ||||||||||||||||||
| 130 | { | - | ||||||||||||||||||
| 131 | size_t src_chars = mbstowcs (NULL, src, 0); | - | ||||||||||||||||||
| 132 | if (src_chars == SIZE_MAX)
| 0 | ||||||||||||||||||
| 133 | { | - | ||||||||||||||||||
| 134 | if (flags & MBA_UNIBYTE_FALLBACK)
| 0 | ||||||||||||||||||
| 135 | goto mbsalign_unibyte; never executed: goto mbsalign_unibyte; | 0 | ||||||||||||||||||
| 136 | else | - | ||||||||||||||||||
| 137 | goto mbsalign_cleanup; never executed: goto mbsalign_cleanup; | 0 | ||||||||||||||||||
| 138 | } | - | ||||||||||||||||||
| 139 | src_chars += 1; /* make space for NUL */ | - | ||||||||||||||||||
| 140 | str_wc = malloc (src_chars * sizeof (wchar_t)); | - | ||||||||||||||||||
| 141 | if (str_wc == NULL)
| 0 | ||||||||||||||||||
| 142 | { | - | ||||||||||||||||||
| 143 | if (flags & MBA_UNIBYTE_FALLBACK)
| 0 | ||||||||||||||||||
| 144 | goto mbsalign_unibyte; never executed: goto mbsalign_unibyte; | 0 | ||||||||||||||||||
| 145 | else | - | ||||||||||||||||||
| 146 | goto mbsalign_cleanup; never executed: goto mbsalign_cleanup; | 0 | ||||||||||||||||||
| 147 | } | - | ||||||||||||||||||
| 148 | if (mbstowcs (str_wc, src, src_chars) != 0)
| 0 | ||||||||||||||||||
| 149 | { | - | ||||||||||||||||||
| 150 | str_wc[src_chars - 1] = L'\0'; | - | ||||||||||||||||||
| 151 | wc_enabled = true; | - | ||||||||||||||||||
| 152 | conversion = wc_ensure_printable (str_wc); | - | ||||||||||||||||||
| 153 | n_cols = wcswidth (str_wc, src_chars); | - | ||||||||||||||||||
| 154 | } never executed: end of block | 0 | ||||||||||||||||||
| 155 | } never executed: end of block | 0 | ||||||||||||||||||
| 156 | - | |||||||||||||||||||
| 157 | /* If we transformed or need to truncate the source string | - | ||||||||||||||||||
| 158 | then create a modified copy of it. */ | - | ||||||||||||||||||
| 159 | if (wc_enabled && (conversion || (n_cols > *width)))
| 0-5031 | ||||||||||||||||||
| 160 | { | - | ||||||||||||||||||
| 161 | if (conversion)
| 0 | ||||||||||||||||||
| 162 | { | - | ||||||||||||||||||
| 163 | /* May have increased the size by converting | - | ||||||||||||||||||
| 164 | \t to \uFFFD for example. */ | - | ||||||||||||||||||
| 165 | src_size = wcstombs (NULL, str_wc, 0) + 1; | - | ||||||||||||||||||
| 166 | } never executed: end of block | 0 | ||||||||||||||||||
| 167 | newstr = malloc (src_size); | - | ||||||||||||||||||
| 168 | if (newstr == NULL)
| 0 | ||||||||||||||||||
| 169 | { | - | ||||||||||||||||||
| 170 | if (flags & MBA_UNIBYTE_FALLBACK)
| 0 | ||||||||||||||||||
| 171 | goto mbsalign_unibyte; never executed: goto mbsalign_unibyte; | 0 | ||||||||||||||||||
| 172 | else | - | ||||||||||||||||||
| 173 | goto mbsalign_cleanup; never executed: goto mbsalign_cleanup; | 0 | ||||||||||||||||||
| 174 | } | - | ||||||||||||||||||
| 175 | str_to_print = newstr; | - | ||||||||||||||||||
| 176 | n_cols = wc_truncate (str_wc, *width); | - | ||||||||||||||||||
| 177 | n_used_bytes = wcstombs (newstr, str_wc, src_size); | - | ||||||||||||||||||
| 178 | } never executed: end of block | 0 | ||||||||||||||||||
| 179 | - | |||||||||||||||||||
| 180 | mbsalign_unibyte: code before this statement executed 5031 times by 4 tests: mbsalign_unibyte:Executed by:
| 5031 | ||||||||||||||||||
| 181 | - | |||||||||||||||||||
| 182 | if (n_cols > *width) /* Unibyte truncation required. */
| 0-5031 | ||||||||||||||||||
| 183 | { | - | ||||||||||||||||||
| 184 | n_cols = *width; | - | ||||||||||||||||||
| 185 | n_used_bytes = n_cols; | - | ||||||||||||||||||
| 186 | } never executed: end of block | 0 | ||||||||||||||||||
| 187 | - | |||||||||||||||||||
| 188 | if (*width > n_cols) /* Padding required. */
| 1986-3045 | ||||||||||||||||||
| 189 | n_spaces = *width - n_cols; executed 3045 times by 4 tests: n_spaces = *width - n_cols;Executed by:
| 3045 | ||||||||||||||||||
| 190 | - | |||||||||||||||||||
| 191 | /* indicate to caller how many cells needed (not including padding). */ | - | ||||||||||||||||||
| 192 | *width = n_cols; | - | ||||||||||||||||||
| 193 | - | |||||||||||||||||||
| 194 | { | - | ||||||||||||||||||
| 195 | size_t start_spaces, end_spaces; | - | ||||||||||||||||||
| 196 | - | |||||||||||||||||||
| 197 | switch (align) | - | ||||||||||||||||||
| 198 | { | - | ||||||||||||||||||
| 199 | case MBS_ALIGN_LEFT: executed 3927 times by 4 tests: case MBS_ALIGN_LEFT:Executed by:
| 3927 | ||||||||||||||||||
| 200 | start_spaces = 0; | - | ||||||||||||||||||
| 201 | end_spaces = n_spaces; | - | ||||||||||||||||||
| 202 | break; executed 3927 times by 4 tests: break;Executed by:
| 3927 | ||||||||||||||||||
| 203 | case MBS_ALIGN_RIGHT: executed 1104 times by 2 tests: case MBS_ALIGN_RIGHT:Executed by:
| 1104 | ||||||||||||||||||
| 204 | start_spaces = n_spaces; | - | ||||||||||||||||||
| 205 | end_spaces = 0; | - | ||||||||||||||||||
| 206 | break; executed 1104 times by 2 tests: break;Executed by:
| 1104 | ||||||||||||||||||
| 207 | case MBS_ALIGN_CENTER: never executed: case MBS_ALIGN_CENTER: | 0 | ||||||||||||||||||
| 208 | default: never executed: default: | 0 | ||||||||||||||||||
| 209 | start_spaces = n_spaces / 2 + n_spaces % 2; | - | ||||||||||||||||||
| 210 | end_spaces = n_spaces / 2; | - | ||||||||||||||||||
| 211 | break; never executed: break; | 0 | ||||||||||||||||||
| 212 | } | - | ||||||||||||||||||
| 213 | - | |||||||||||||||||||
| 214 | if (flags & MBA_NO_LEFT_PAD)
| 0-5031 | ||||||||||||||||||
| 215 | start_spaces = 0; never executed: start_spaces = 0; | 0 | ||||||||||||||||||
| 216 | if (flags & MBA_NO_RIGHT_PAD)
| 311-4720 | ||||||||||||||||||
| 217 | end_spaces = 0; executed 311 times by 1 test: end_spaces = 0;Executed by:
| 311 | ||||||||||||||||||
| 218 | - | |||||||||||||||||||
| 219 | /* Write as much NUL terminated output to DEST as possible. */ | - | ||||||||||||||||||
| 220 | if (dest_size != 0)
| 0-5031 | ||||||||||||||||||
| 221 | { | - | ||||||||||||||||||
| 222 | size_t space_left; | - | ||||||||||||||||||
| 223 | char *dest_end = dest + dest_size - 1; | - | ||||||||||||||||||
| 224 | - | |||||||||||||||||||
| 225 | dest = mbs_align_pad (dest, dest_end, start_spaces); | - | ||||||||||||||||||
| 226 | space_left = dest_end - dest; | - | ||||||||||||||||||
| 227 | dest = mempcpy (dest, str_to_print, MIN (n_used_bytes, space_left)); | - | ||||||||||||||||||
| 228 | mbs_align_pad (dest, dest_end, end_spaces); | - | ||||||||||||||||||
| 229 | } executed 5031 times by 4 tests: end of blockExecuted by:
| 5031 | ||||||||||||||||||
| 230 | - | |||||||||||||||||||
| 231 | /* indicate to caller how many bytes needed (not including NUL). */ | - | ||||||||||||||||||
| 232 | ret = n_used_bytes + ((start_spaces + end_spaces) * 1); | - | ||||||||||||||||||
| 233 | } | - | ||||||||||||||||||
| 234 | - | |||||||||||||||||||
| 235 | mbsalign_cleanup: code before this statement executed 5031 times by 4 tests: mbsalign_cleanup:Executed by:
| 5031 | ||||||||||||||||||
| 236 | - | |||||||||||||||||||
| 237 | free (str_wc); | - | ||||||||||||||||||
| 238 | free (newstr); | - | ||||||||||||||||||
| 239 | - | |||||||||||||||||||
| 240 | return ret; executed 5031 times by 4 tests: return ret;Executed by:
| 5031 | ||||||||||||||||||
| 241 | } | - | ||||||||||||||||||
| 242 | - | |||||||||||||||||||
| 243 | /* A wrapper around mbsalign() to dynamically allocate the | - | ||||||||||||||||||
| 244 | minimum amount of memory to store the result. | - | ||||||||||||||||||
| 245 | Return NULL on failure. */ | - | ||||||||||||||||||
| 246 | - | |||||||||||||||||||
| 247 | char * | - | ||||||||||||||||||
| 248 | ambsalign (const char *src, size_t *width, mbs_align_t align, int flags) | - | ||||||||||||||||||
| 249 | { | - | ||||||||||||||||||
| 250 | size_t orig_width = *width; | - | ||||||||||||||||||
| 251 | size_t size = *width; /* Start with enough for unibyte mode. */ | - | ||||||||||||||||||
| 252 | size_t req = size; | - | ||||||||||||||||||
| 253 | char *buf = NULL; | - | ||||||||||||||||||
| 254 | - | |||||||||||||||||||
| 255 | while (req >= size)
| 1688 | ||||||||||||||||||
| 256 | { | - | ||||||||||||||||||
| 257 | char *nbuf; | - | ||||||||||||||||||
| 258 | size = req + 1; /* Space for NUL. */ | - | ||||||||||||||||||
| 259 | nbuf = realloc (buf, size); | - | ||||||||||||||||||
| 260 | if (nbuf == NULL)
| 0-1688 | ||||||||||||||||||
| 261 | { | - | ||||||||||||||||||
| 262 | free (buf); | - | ||||||||||||||||||
| 263 | buf = NULL; | - | ||||||||||||||||||
| 264 | break; never executed: break; | 0 | ||||||||||||||||||
| 265 | } | - | ||||||||||||||||||
| 266 | buf = nbuf; | - | ||||||||||||||||||
| 267 | *width = orig_width; | - | ||||||||||||||||||
| 268 | req = mbsalign (src, buf, size, width, align, flags); | - | ||||||||||||||||||
| 269 | if (req == SIZE_MAX)
| 0-1688 | ||||||||||||||||||
| 270 | { | - | ||||||||||||||||||
| 271 | free (buf); | - | ||||||||||||||||||
| 272 | buf = NULL; | - | ||||||||||||||||||
| 273 | break; never executed: break; | 0 | ||||||||||||||||||
| 274 | } | - | ||||||||||||||||||
| 275 | } executed 1688 times by 1 test: end of blockExecuted by:
| 1688 | ||||||||||||||||||
| 276 | - | |||||||||||||||||||
| 277 | return buf; executed 1688 times by 1 test: return buf;Executed by:
| 1688 | ||||||||||||||||||
| 278 | } | - | ||||||||||||||||||
| Source code | Switch to Preprocessed file |