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 block Executed 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 block Executed by:
| 1688 | ||||||||||||||||||
276 | - | |||||||||||||||||||
277 | return buf; executed 1688 times by 1 test: return buf; Executed by:
| 1688 | ||||||||||||||||||
278 | } | - | ||||||||||||||||||
Source code | Switch to Preprocessed file |