@@ -10,8 +10,10 @@ in the source distribution for its full text.
10
10
#include "XUtils.h"
11
11
12
12
#include <assert.h>
13
+ #include <ctype.h> // IWYU pragma: keep
13
14
#include <errno.h>
14
15
#include <fcntl.h>
16
+ #include <limits.h> // IWYU pragma: keep
15
17
#include <math.h>
16
18
#include <stdarg.h>
17
19
#include <stdint.h>
@@ -224,6 +226,187 @@ size_t String_safeStrncpy(char* restrict dest, const char* restrict src, size_t
224
226
return i ;
225
227
}
226
228
229
+ #ifdef HAVE_LIBNCURSESW
230
+ static void String_encodeWChar (WCharEncoderState * ps , wchar_t wc ) {
231
+ char tempBuf [MB_LEN_MAX ];
232
+
233
+ char * dest = ps -> buf ? (char * )ps -> buf + ps -> pos : tempBuf ;
234
+ size_t len = wcrtomb (dest , wc , & ps -> mbState );
235
+ assert (len != (size_t )-1 );
236
+ assert (len > 0 );
237
+
238
+ ps -> pos += len ;
239
+ }
240
+ #else
241
+ static void String_encodeWChar (WCharEncoderState * ps , int c ) {
242
+ char * buf = (char * )ps -> buf ;
243
+ if (buf ) {
244
+ buf [ps -> pos ] = (char )c ;
245
+ }
246
+ ps -> pos += 1 ;
247
+ }
248
+ #endif
249
+
250
+ void EncodePrintableString (WCharEncoderState * ps , const char * src , size_t maxLen , EncodeWChar encodeWChar ) {
251
+ assert (src || maxLen == 0 );
252
+
253
+ size_t pos = 0 ;
254
+ bool wasReplaced = false;
255
+
256
+ #ifdef HAVE_LIBNCURSESW
257
+ const wchar_t replacementChar = CRT_utf8 ? L'\xFFFD' : L'?' ;
258
+ wchar_t ch ;
259
+
260
+ mbstate_t decState ;
261
+ memset (& decState , 0 , sizeof (decState ));
262
+ mbstate_t newState ;
263
+ #else
264
+ const char replacementChar = '?' ;
265
+ char ch ;
266
+ #endif
267
+
268
+ do {
269
+ size_t len = 0 ;
270
+ bool shouldReplace = false;
271
+ ch = 0 ;
272
+
273
+ if (pos < maxLen ) {
274
+ // Read the next character from the byte sequence
275
+ #ifdef HAVE_LIBNCURSESW
276
+ memcpy (& newState , & decState , sizeof (newState ));
277
+ len = mbrtowc (& ch , & src [pos ], maxLen - pos , & newState );
278
+
279
+ switch (len ) {
280
+ case (size_t )-2 :
281
+ errno = EILSEQ ;
282
+ shouldReplace = true;
283
+ len = maxLen - pos ;
284
+ break ;
285
+
286
+ case (size_t )-1 :
287
+ shouldReplace = true;
288
+ len = 1 ;
289
+ break ;
290
+
291
+ case 0 :
292
+ assert (ch == 0 );
293
+ len = 1 ;
294
+ // Fallthrough
295
+
296
+ default :
297
+ memcpy (& decState , & newState , sizeof (decState ));
298
+ }
299
+ #else
300
+ len = 1 ;
301
+ ch = src [pos ];
302
+ #endif
303
+ }
304
+
305
+ pos += len ;
306
+
307
+ // Filter unprintable characters
308
+ if (!shouldReplace && ch != 0 ) {
309
+ #ifdef HAVE_LIBNCURSESW
310
+ shouldReplace = !iswprint (ch );
311
+ #else
312
+ shouldReplace = !isprint ((unsigned char )ch );
313
+ #endif
314
+ }
315
+
316
+ if (shouldReplace ) {
317
+ ch = replacementChar ;
318
+ if (wasReplaced ) {
319
+ continue ;
320
+ }
321
+ }
322
+ wasReplaced = shouldReplace ;
323
+
324
+ encodeWChar (ps , ch );
325
+ } while (ch != 0 );
326
+ }
327
+
328
+ char * String_makePrintable (const char * str , size_t maxLen ) {
329
+ WCharEncoderState encState ;
330
+
331
+ memset (& encState , 0 , sizeof (encState ));
332
+ EncodePrintableString (& encState , str , maxLen , String_encodeWChar );
333
+ size_t bufSize = encState .pos ;
334
+ assert (bufSize > 0 );
335
+
336
+ memset (& encState , 0 , sizeof (encState ));
337
+ char * buf = xMalloc (bufSize );
338
+ encState .buf = buf ;
339
+ EncodePrintableString (& encState , str , maxLen , String_encodeWChar );
340
+ assert (encState .pos == bufSize );
341
+
342
+ return buf ;
343
+ }
344
+
345
+ #ifndef HAVE_STRNLEN
346
+ static size_t strnlen (const char * str , size_t maxLen ) {
347
+ for (size_t len = 0 ; len < maxLen ; len ++ ) {
348
+ if (!str [len ]) {
349
+ return len ;
350
+ }
351
+ }
352
+ return maxLen ;
353
+ }
354
+ #endif
355
+
356
+ int String_mbswidth (const char * * str , size_t maxLen , int maxWidth ) {
357
+ assert (* str || maxLen == 0 );
358
+
359
+ if (maxWidth < 0 )
360
+ maxWidth = INT_MAX ;
361
+
362
+ const char * start = * str ;
363
+
364
+ #ifdef HAVE_LIBNCURSESW
365
+ mbstate_t state ;
366
+ memset (& state , 0 , sizeof (state ));
367
+
368
+ int totalWidth = 0 ;
369
+ for (size_t pos = 0 ; pos < maxLen ; ) {
370
+ wchar_t wc ;
371
+ size_t len = mbrtowc (& wc , & start [pos ], maxLen - pos , & state );
372
+ if (len == 0 || len == (size_t )-2 || len == (size_t )-1 ) {
373
+ assert (len != (size_t )-1 );
374
+ break ;
375
+ }
376
+
377
+ pos += len ;
378
+
379
+ assert (wc != L'\0' );
380
+ int w = wcwidth (wc );
381
+ if (w < 0 ) {
382
+ assert (w >= 0 );
383
+ break ;
384
+ }
385
+
386
+ if (w > maxWidth - totalWidth )
387
+ break ;
388
+
389
+ if (w > 0 || CRT_utf8 ) {
390
+ // (*str - start) will represent the length of the substring bounded
391
+ // by the width limit.
392
+
393
+ // In Unicode, combining characters are always placed after the base
394
+ // character. Some legacy 8-bit encodings instead place combining
395
+ // characters before the base character.
396
+ * str = & start [pos ];
397
+ }
398
+ totalWidth += w ;
399
+ }
400
+
401
+ return totalWidth ;
402
+ #else
403
+ maxLen = MINIMUM ((unsigned int )maxWidth , maxLen );
404
+ size_t len = strnlen (* str , maxLen );
405
+ * str = start + len ;
406
+ return (int )len ;
407
+ #endif
408
+ }
409
+
227
410
int xAsprintf (char * * strp , const char * fmt , ...) {
228
411
va_list vl ;
229
412
va_start (vl , fmt );
0 commit comments