OpenCoverage

mbsalign.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/coreutils/src/gl/lib/mbsalign.c
Source codeSwitch to Preprocessed file
LineSourceCount
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-
39static bool-
40wc_ensure_printable (wchar_t *wchars)-
41{-
42 bool replaced = false;-
43 wchar_t *wc = wchars;-
44 while (*wc)
*wcDescription
TRUEnever evaluated
FALSEnever evaluated
0
45 {-
46 if (!iswprint ((wint_t) *wc))
!iswprint ((wint_t) *wc)Description
TRUEnever evaluated
FALSEnever evaluated
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-
59static size_t-
60wc_truncate (wchar_t *wc, size_t width)-
61{-
62 size_t cells = 0;-
63 int next_cells = 0;-
64-
65 while (*wc)
*wcDescription
TRUEnever evaluated
FALSEnever evaluated
0
66 {-
67 next_cells = wcwidth (*wc);-
68 if (next_cells == -1) /* non printable */
next_cells == -1Description
TRUEnever evaluated
FALSEnever evaluated
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)
cells + next_cells > widthDescription
TRUEnever evaluated
FALSEnever evaluated
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-
87static char*-
88mbs_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))
n_spaces--Description
TRUEevaluated 119527 times by 4 tests
Evaluated by:
  • df
  • ls
  • numfmt
  • vdir
FALSEevaluated 10062 times by 4 tests
Evaluated by:
  • df
  • ls
  • numfmt
  • vdir
(dest < dest_end)Description
TRUEevaluated 119527 times by 4 tests
Evaluated by:
  • df
  • ls
  • numfmt
  • vdir
FALSEnever evaluated
0-119527
93 *dest++ = ' ';
executed 119527 times by 4 tests: *dest++ = ' ';
Executed by:
  • df
  • ls
  • numfmt
  • vdir
119527
94 *dest = '\0';-
95 return dest;
executed 10062 times by 4 tests: return dest;
Executed by:
  • df
  • ls
  • numfmt
  • vdir
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-
111size_t-
112mbsalign (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)
!(flags & MBA_UNIBYTE_ONLY)Description
TRUEevaluated 5000 times by 3 tests
Evaluated by:
  • df
  • ls
  • vdir
FALSEevaluated 31 times by 1 test
Evaluated by:
  • numfmt
(__ctype_get_m...ur_max ()) > 1Description
TRUEnever evaluated
FALSEevaluated 5000 times by 3 tests
Evaluated by:
  • df
  • ls
  • vdir
0-5000
130 {-
131 size_t src_chars = mbstowcs (NULL, src, 0);-
132 if (src_chars == SIZE_MAX)
src_chars == (...73709551615UL)Description
TRUEnever evaluated
FALSEnever evaluated
0
133 {-
134 if (flags & MBA_UNIBYTE_FALLBACK)
flags & MBA_UNIBYTE_FALLBACKDescription
TRUEnever evaluated
FALSEnever evaluated
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)
str_wc == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
142 {-
143 if (flags & MBA_UNIBYTE_FALLBACK)
flags & MBA_UNIBYTE_FALLBACKDescription
TRUEnever evaluated
FALSEnever evaluated
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)
mbstowcs (str_...rc_chars) != 0Description
TRUEnever evaluated
FALSEnever evaluated
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)))
wc_enabledDescription
TRUEnever evaluated
FALSEevaluated 5031 times by 4 tests
Evaluated by:
  • df
  • ls
  • numfmt
  • vdir
conversionDescription
TRUEnever evaluated
FALSEnever evaluated
(n_cols > *width)Description
TRUEnever evaluated
FALSEnever evaluated
0-5031
160 {-
161 if (conversion)
conversionDescription
TRUEnever evaluated
FALSEnever evaluated
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)
newstr == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
169 {-
170 if (flags & MBA_UNIBYTE_FALLBACK)
flags & MBA_UNIBYTE_FALLBACKDescription
TRUEnever evaluated
FALSEnever evaluated
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-
180mbsalign_unibyte:
code before this statement executed 5031 times by 4 tests: mbsalign_unibyte:
Executed by:
  • df
  • ls
  • numfmt
  • vdir
5031
181-
182 if (n_cols > *width) /* Unibyte truncation required. */
n_cols > *widthDescription
TRUEnever evaluated
FALSEevaluated 5031 times by 4 tests
Evaluated by:
  • df
  • ls
  • numfmt
  • vdir
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. */
*width > n_colsDescription
TRUEevaluated 3045 times by 4 tests
Evaluated by:
  • df
  • ls
  • numfmt
  • vdir
FALSEevaluated 1986 times by 3 tests
Evaluated by:
  • df
  • ls
  • vdir
1986-3045
189 n_spaces = *width - n_cols;
executed 3045 times by 4 tests: n_spaces = *width - n_cols;
Executed by:
  • df
  • ls
  • numfmt
  • vdir
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:
  • df
  • ls
  • numfmt
  • vdir
3927
200 start_spaces = 0;-
201 end_spaces = n_spaces;-
202 break;
executed 3927 times by 4 tests: break;
Executed by:
  • df
  • ls
  • numfmt
  • vdir
3927
203 case MBS_ALIGN_RIGHT:
executed 1104 times by 2 tests: case MBS_ALIGN_RIGHT:
Executed by:
  • df
  • numfmt
1104
204 start_spaces = n_spaces;-
205 end_spaces = 0;-
206 break;
executed 1104 times by 2 tests: break;
Executed by:
  • df
  • numfmt
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)
flags & MBA_NO_LEFT_PADDescription
TRUEnever evaluated
FALSEevaluated 5031 times by 4 tests
Evaluated by:
  • df
  • ls
  • numfmt
  • vdir
0-5031
215 start_spaces = 0;
never executed: start_spaces = 0;
0
216 if (flags & MBA_NO_RIGHT_PAD)
flags & MBA_NO_RIGHT_PADDescription
TRUEevaluated 311 times by 1 test
Evaluated by:
  • df
FALSEevaluated 4720 times by 4 tests
Evaluated by:
  • df
  • ls
  • numfmt
  • vdir
311-4720
217 end_spaces = 0;
executed 311 times by 1 test: end_spaces = 0;
Executed by:
  • df
311
218-
219 /* Write as much NUL terminated output to DEST as possible. */-
220 if (dest_size != 0)
dest_size != 0Description
TRUEevaluated 5031 times by 4 tests
Evaluated by:
  • df
  • ls
  • numfmt
  • vdir
FALSEnever evaluated
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:
  • df
  • ls
  • numfmt
  • vdir
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-
235mbsalign_cleanup:
code before this statement executed 5031 times by 4 tests: mbsalign_cleanup:
Executed by:
  • df
  • ls
  • numfmt
  • vdir
5031
236-
237 free (str_wc);-
238 free (newstr);-
239-
240 return ret;
executed 5031 times by 4 tests: return ret;
Executed by:
  • df
  • ls
  • numfmt
  • vdir
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-
247char *-
248ambsalign (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)
req >= sizeDescription
TRUEevaluated 1688 times by 1 test
Evaluated by:
  • df
FALSEevaluated 1688 times by 1 test
Evaluated by:
  • df
1688
256 {-
257 char *nbuf;-
258 size = req + 1; /* Space for NUL. */-
259 nbuf = realloc (buf, size);-
260 if (nbuf == NULL)
nbuf == ((void *)0)Description
TRUEnever evaluated
FALSEevaluated 1688 times by 1 test
Evaluated by:
  • df
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)
req == (184467...73709551615UL)Description
TRUEnever evaluated
FALSEevaluated 1688 times by 1 test
Evaluated by:
  • df
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:
  • df
1688
276-
277 return buf;
executed 1688 times by 1 test: return buf;
Executed by:
  • df
1688
278}-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.1.2