vis.c revision 1.84 1 /* $NetBSD: vis.c,v 1.84 2023/08/13 15:19:13 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*-
33 * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55 * POSSIBILITY OF SUCH DAMAGE.
56 */
57
58 #include <sys/cdefs.h>
59 #if defined(LIBC_SCCS) && !defined(lint)
60 __RCSID("$NetBSD: vis.c,v 1.84 2023/08/13 15:19:13 riastradh Exp $");
61 #endif /* LIBC_SCCS and not lint */
62 #ifdef __FBSDID
63 __FBSDID("$FreeBSD$");
64 #define _DIAGASSERT(x) assert(x)
65 #endif
66
67 #include "namespace.h"
68
69 #include <sys/types.h>
70 #include <sys/param.h>
71
72 #include <assert.h>
73 #include <errno.h>
74 #include <stdlib.h>
75 #include <vis.h>
76 #include <wchar.h>
77 #include <wctype.h>
78
79 #ifdef __weak_alias
80 __weak_alias(strvisx,_strvisx)
81 #endif
82
83 #if !HAVE_VIS || !HAVE_SVIS
84 #include <ctype.h>
85 #include <limits.h>
86 #include <stdio.h>
87 #include <string.h>
88
89 /*
90 * The reason for going through the trouble to deal with character encodings
91 * in vis(3), is that we use this to safe encode output of commands. This
92 * safe encoding varies depending on the character set. For example if we
93 * display ps output in French, we don't want to display French characters
94 * as M-foo.
95 */
96
97 static wchar_t *do_svis(wchar_t *, wint_t, int, wint_t, const wchar_t *);
98
99 #undef BELL
100 #define BELL L'\a'
101
102 #if defined(LC_C_LOCALE)
103 #define iscgraph(c) isgraph_l(c, LC_C_LOCALE)
104 #else
105 /* Keep it simple for now, no locale stuff */
106 #define iscgraph(c) isgraph(c)
107 #ifdef notyet
108 #include <locale.h>
109 static int
110 iscgraph(int c) {
111 int rv;
112 char *ol;
113
114 ol = setlocale(LC_CTYPE, "C");
115 rv = isgraph(c);
116 if (ol)
117 setlocale(LC_CTYPE, ol);
118 return rv;
119 }
120 #endif
121 #endif
122
123 #define ISGRAPH(flags, c) \
124 (((flags) & VIS_NOLOCALE) ? iscgraph(c) : iswgraph(c))
125
126 #define iswoctal(c) (((u_char)(c)) >= L'0' && ((u_char)(c)) <= L'7')
127 #define iswwhite(c) (c == L' ' || c == L'\t' || c == L'\n')
128 #define iswsafe(c) (c == L'\b' || c == BELL || c == L'\r')
129 #define xtoa(c) L"0123456789abcdef"[c]
130 #define XTOA(c) L"0123456789ABCDEF"[c]
131
132 #define MAXEXTRAS 30
133
134 static const wchar_t char_shell[] = L"'`\";&<>()|{}]\\$!^~";
135 static const wchar_t char_glob[] = L"*?[#";
136
137 #if !HAVE_NBTOOL_CONFIG_H
138 #ifndef __NetBSD__
139 /*
140 * On NetBSD MB_LEN_MAX is currently 32 which does not fit on any integer
141 * integral type and it is probably wrong, since currently the maximum
142 * number of bytes and character needs is 6. Until this is fixed, the
143 * loops below are using sizeof(uint64_t) - 1 instead of MB_LEN_MAX, and
144 * the assertion is commented out.
145 */
146 #ifdef __FreeBSD__
147 /*
148 * On FreeBSD including <sys/systm.h> for CTASSERT only works in kernel
149 * mode.
150 */
151 #ifndef CTASSERT
152 #define CTASSERT(x) _CTASSERT(x, __LINE__)
153 #define _CTASSERT(x, y) __CTASSERT(x, y)
154 #define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1]
155 #endif
156 #endif /* __FreeBSD__ */
157 CTASSERT(MB_LEN_MAX <= sizeof(uint64_t));
158 #endif /* !__NetBSD__ */
159 #endif
160
161 /*
162 * This is do_hvis, for HTTP style (RFC 1808)
163 */
164 static wchar_t *
165 do_hvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
166 {
167 if (iswalnum(c)
168 /* safe */
169 || c == L'$' || c == L'-' || c == L'_' || c == L'.' || c == L'+'
170 /* extra */
171 || c == L'!' || c == L'*' || c == L'\'' || c == L'(' || c == L')'
172 || c == L',')
173 dst = do_svis(dst, c, flags, nextc, extra);
174 else {
175 *dst++ = L'%';
176 *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
177 *dst++ = xtoa((unsigned int)c & 0xf);
178 }
179
180 return dst;
181 }
182
183 /*
184 * This is do_mvis, for Quoted-Printable MIME (RFC 2045)
185 * NB: No handling of long lines or CRLF.
186 */
187 static wchar_t *
188 do_mvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
189 {
190 if ((c != L'\n') &&
191 /* Space at the end of the line */
192 ((iswspace(c) && (nextc == L'\r' || nextc == L'\n')) ||
193 /* Out of range */
194 (!iswspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||
195 /* Specific char to be escaped */
196 wcschr(L"#$@[\\]^`{|}~", c) != NULL)) {
197 *dst++ = L'=';
198 *dst++ = XTOA(((unsigned int)c >> 4) & 0xf);
199 *dst++ = XTOA((unsigned int)c & 0xf);
200 } else
201 dst = do_svis(dst, c, flags, nextc, extra);
202 return dst;
203 }
204
205 /*
206 * Output single byte of multibyte character.
207 */
208 static wchar_t *
209 do_mbyte(wchar_t *dst, wint_t c, int flags, wint_t nextc, int iswextra)
210 {
211 if (flags & VIS_CSTYLE) {
212 switch (c) {
213 case L'\n':
214 *dst++ = L'\\'; *dst++ = L'n';
215 return dst;
216 case L'\r':
217 *dst++ = L'\\'; *dst++ = L'r';
218 return dst;
219 case L'\b':
220 *dst++ = L'\\'; *dst++ = L'b';
221 return dst;
222 case BELL:
223 *dst++ = L'\\'; *dst++ = L'a';
224 return dst;
225 case L'\v':
226 *dst++ = L'\\'; *dst++ = L'v';
227 return dst;
228 case L'\t':
229 *dst++ = L'\\'; *dst++ = L't';
230 return dst;
231 case L'\f':
232 *dst++ = L'\\'; *dst++ = L'f';
233 return dst;
234 case L' ':
235 *dst++ = L'\\'; *dst++ = L's';
236 return dst;
237 case L'\0':
238 *dst++ = L'\\'; *dst++ = L'0';
239 if (iswoctal(nextc)) {
240 *dst++ = L'0';
241 *dst++ = L'0';
242 }
243 return dst;
244 /* We cannot encode these characters in VIS_CSTYLE
245 * because they special meaning */
246 case L'n':
247 case L'r':
248 case L'b':
249 case L'a':
250 case L'v':
251 case L't':
252 case L'f':
253 case L's':
254 case L'0':
255 case L'M':
256 case L'^':
257 case L'$': /* vis(1) -l */
258 break;
259 default:
260 if (ISGRAPH(flags, c) && !iswoctal(c)) {
261 *dst++ = L'\\';
262 *dst++ = c;
263 return dst;
264 }
265 }
266 }
267 if (iswextra || ((c & 0177) == L' ') || (flags & VIS_OCTAL)) {
268 *dst++ = L'\\';
269 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + L'0';
270 *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + L'0';
271 *dst++ = (c & 07) + L'0';
272 } else {
273 if ((flags & VIS_NOSLASH) == 0)
274 *dst++ = L'\\';
275
276 if (c & 0200) {
277 c &= 0177;
278 *dst++ = L'M';
279 }
280
281 if (iswcntrl(c)) {
282 *dst++ = L'^';
283 if (c == 0177)
284 *dst++ = L'?';
285 else
286 *dst++ = c + L'@';
287 } else {
288 *dst++ = L'-';
289 *dst++ = c;
290 }
291 }
292
293 return dst;
294 }
295
296 /*
297 * This is do_vis, the central code of vis.
298 * dst: Pointer to the destination buffer
299 * c: Character to encode
300 * flags: Flags word
301 * nextc: The character following 'c'
302 * extra: Pointer to the list of extra characters to be
303 * backslash-protected.
304 */
305 static wchar_t *
306 do_svis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
307 {
308 int iswextra, i, shft;
309 uint64_t bmsk, wmsk;
310
311 iswextra = wcschr(extra, c) != NULL;
312 if (!iswextra && (ISGRAPH(flags, c) || iswwhite(c) ||
313 ((flags & VIS_SAFE) && iswsafe(c)))) {
314 *dst++ = c;
315 return dst;
316 }
317
318 /* See comment in istrsenvisx() output loop, below. */
319 wmsk = 0;
320 for (i = sizeof(wmsk) - 1; i >= 0; i--) {
321 shft = i * NBBY;
322 bmsk = (uint64_t)0xffLL << shft;
323 wmsk |= bmsk;
324 if ((c & wmsk) || i == 0)
325 dst = do_mbyte(dst, (wint_t)(
326 (uint64_t)(c & bmsk) >> shft),
327 flags, nextc, iswextra);
328 }
329
330 return dst;
331 }
332
333 typedef wchar_t *(*visfun_t)(wchar_t *, wint_t, int, wint_t, const wchar_t *);
334
335 /*
336 * Return the appropriate encoding function depending on the flags given.
337 */
338 static visfun_t
339 getvisfun(int flags)
340 {
341 if (flags & VIS_HTTPSTYLE)
342 return do_hvis;
343 if (flags & VIS_MIMESTYLE)
344 return do_mvis;
345 return do_svis;
346 }
347
348 /*
349 * Expand list of extra characters to not visually encode.
350 */
351 static wchar_t *
352 makeextralist(int flags, const char *src)
353 {
354 wchar_t *dst, *d;
355 size_t len;
356 const wchar_t *s;
357 mbstate_t mbstate;
358
359 len = strlen(src);
360 if ((dst = calloc(len + MAXEXTRAS, sizeof(*dst))) == NULL)
361 return NULL;
362
363 memset(&mbstate, 0, sizeof(mbstate));
364 if ((flags & VIS_NOLOCALE)
365 || mbsrtowcs(dst, &src, len, &mbstate) == (size_t)-1) {
366 size_t i;
367 for (i = 0; i < len; i++)
368 dst[i] = (wchar_t)(u_char)src[i];
369 d = dst + len;
370 } else
371 d = dst + wcslen(dst);
372
373 if (flags & VIS_GLOB)
374 for (s = char_glob; *s; *d++ = *s++)
375 continue;
376
377 if (flags & VIS_SHELL)
378 for (s = char_shell; *s; *d++ = *s++)
379 continue;
380
381 if (flags & VIS_SP) *d++ = L' ';
382 if (flags & VIS_TAB) *d++ = L'\t';
383 if (flags & VIS_NL) *d++ = L'\n';
384 if (flags & VIS_DQ) *d++ = L'"';
385 if ((flags & VIS_NOSLASH) == 0) *d++ = L'\\';
386 *d = L'\0';
387
388 return dst;
389 }
390
391 /*
392 * istrsenvisx()
393 * The main internal function.
394 * All user-visible functions call this one.
395 */
396 static int
397 istrsenvisx(char **mbdstp, size_t *dlen, const char *mbsrc, size_t mblength,
398 int flags, const char *mbextra, int *cerr_ptr)
399 {
400 char mbbuf[MB_LEN_MAX];
401 wchar_t *dst, *src, *pdst, *psrc, *start, *extra;
402 size_t len, olen;
403 uint64_t bmsk, wmsk;
404 wint_t c;
405 visfun_t f;
406 int clen = 0, cerr, error = -1, i, shft;
407 char *mbdst, *mbwrite, *mdst;
408 size_t mbslength;
409 size_t maxolen;
410 mbstate_t mbstate;
411
412 _DIAGASSERT(mbdstp != NULL);
413 _DIAGASSERT(mbsrc != NULL || mblength == 0);
414 _DIAGASSERT(mbextra != NULL);
415
416 mbslength = mblength;
417 /*
418 * When inputing a single character, must also read in the
419 * next character for nextc, the look-ahead character.
420 */
421 if (mbslength == 1)
422 mbslength++;
423
424 /*
425 * Input (mbsrc) is a char string considered to be multibyte
426 * characters. The input loop will read this string pulling
427 * one character, possibly multiple bytes, from mbsrc and
428 * converting each to wchar_t in src.
429 *
430 * The vis conversion will be done using the wide char
431 * wchar_t string.
432 *
433 * This will then be converted back to a multibyte string to
434 * return to the caller.
435 */
436
437 /*
438 * Guarantee the arithmetic on input to calloc won't overflow.
439 */
440 if (mbslength > (SIZE_MAX - 1)/16) {
441 errno = ENOMEM;
442 return -1;
443 }
444
445 /* Allocate space for the wide char strings */
446 psrc = pdst = extra = NULL;
447 mdst = NULL;
448 if ((psrc = calloc(mbslength + 1, sizeof(*psrc))) == NULL)
449 return -1;
450 if ((pdst = calloc((16 * mbslength) + 1, sizeof(*pdst))) == NULL)
451 goto out;
452 if (*mbdstp == NULL) {
453 if ((mdst = calloc((16 * mbslength) + 1, sizeof(*mdst))) == NULL)
454 goto out;
455 *mbdstp = mdst;
456 }
457
458 mbdst = *mbdstp;
459 dst = pdst;
460 src = psrc;
461
462 if (flags & VIS_NOLOCALE) {
463 /* Do one byte at a time conversion */
464 cerr = 1;
465 } else {
466 /* Use caller's multibyte conversion error flag. */
467 cerr = cerr_ptr ? *cerr_ptr : 0;
468 }
469
470 /*
471 * Input loop.
472 * Handle up to mblength characters (not bytes). We do not
473 * stop at NULs because we may be processing a block of data
474 * that includes NULs.
475 */
476 memset(&mbstate, 0, sizeof(mbstate));
477 while (mbslength > 0) {
478 /* Convert one multibyte character to wchar_t. */
479 if (!cerr) {
480 clen = mbrtowc(src, mbsrc,
481 (mbslength < MB_LEN_MAX
482 ? mbslength
483 : MB_LEN_MAX),
484 &mbstate);
485 assert(clen < 0 || (size_t)clen <= mbslength);
486 assert(clen <= MB_LEN_MAX);
487 }
488 if (cerr || clen < 0) {
489 /* Conversion error, process as a byte instead. */
490 *src = (wint_t)(u_char)*mbsrc;
491 clen = 1;
492 cerr = 1;
493 }
494 if (clen == 0) {
495 /*
496 * NUL in input gives 0 return value. process
497 * as single NUL byte and keep going.
498 */
499 clen = 1;
500 }
501 /*
502 * Let n := MIN(mbslength, MB_LEN_MAX). We have:
503 *
504 * mbslength >= 1
505 * mbrtowc(..., n, &mbstate) <= n,
506 * by the contract of mbrtowc
507 *
508 * clen is either
509 * (a) mbrtowc(..., n, &mbstate), in which case
510 * clen <= n <= mbslength; or
511 * (b) 1, in which case clen = 1 <= mbslength.
512 */
513 assert(clen > 0);
514 assert((size_t)clen <= mbslength);
515 /* Advance buffer character pointer. */
516 src++;
517 /* Advance input pointer by number of bytes read. */
518 mbsrc += clen;
519 /* Decrement input byte count. */
520 mbslength -= clen;
521 }
522 len = src - psrc;
523 src = psrc;
524
525 /*
526 * In the single character input case, we will have actually
527 * processed two characters, c and nextc. Reset len back to
528 * just a single character.
529 */
530 if (mblength < len)
531 len = mblength;
532
533 /* Convert extra argument to list of characters for this mode. */
534 extra = makeextralist(flags, mbextra);
535 if (!extra) {
536 if (dlen && *dlen == 0) {
537 errno = ENOSPC;
538 goto out;
539 }
540 *mbdst = '\0'; /* can't create extra, return "" */
541 error = 0;
542 goto out;
543 }
544
545 /* Look up which processing function to call. */
546 f = getvisfun(flags);
547
548 /*
549 * Main processing loop.
550 * Call do_Xvis processing function one character at a time
551 * with next character available for look-ahead.
552 */
553 for (start = dst; len > 0; len--) {
554 c = *src++;
555 dst = (*f)(dst, c, flags, len >= 1 ? *src : L'\0', extra);
556 if (dst == NULL) {
557 errno = ENOSPC;
558 goto out;
559 }
560 }
561
562 /* Terminate the string in the buffer. */
563 *dst = L'\0';
564
565 /*
566 * Output loop.
567 * Convert wchar_t string back to multibyte output string.
568 * If we have hit a multi-byte conversion error on input,
569 * output byte-by-byte here. Else use wctomb().
570 */
571 len = wcslen(start);
572 if (dlen) {
573 maxolen = *dlen;
574 if (maxolen == 0) {
575 errno = ENOSPC;
576 goto out;
577 }
578 } else {
579 if (len > (SIZE_MAX - 1)/MB_LEN_MAX) {
580 errno = ENOSPC;
581 goto out;
582 }
583 maxolen = len*MB_LEN_MAX + 1;
584 }
585 olen = 0;
586 memset(&mbstate, 0, sizeof(mbstate));
587 for (dst = start; len > 0; len--) {
588 if (!cerr) {
589 /*
590 * If we have at least MB_CUR_MAX bytes in the buffer,
591 * we'll just do the conversion in-place into mbdst. We
592 * need to be a little more conservative when we get to
593 * the end of the buffer, as we may not have MB_CUR_MAX
594 * bytes but we may not need it.
595 */
596 if (maxolen - olen > MB_CUR_MAX)
597 mbwrite = mbdst;
598 else
599 mbwrite = mbbuf;
600 clen = wcrtomb(mbwrite, *dst, &mbstate);
601 if (clen > 0 && mbwrite != mbdst) {
602 /*
603 * Don't break past our output limit, noting
604 * that maxolen includes the nul terminator so
605 * we can't write past maxolen - 1 here.
606 */
607 if (olen + clen >= maxolen) {
608 errno = ENOSPC;
609 goto out;
610 }
611
612 memcpy(mbdst, mbwrite, clen);
613 }
614 }
615 if (cerr || clen < 0) {
616 /*
617 * Conversion error, process as a byte(s) instead.
618 * Examine each byte and higher-order bytes for
619 * data. E.g.,
620 * 0x000000000000a264 -> a2 64
621 * 0x000000001f00a264 -> 1f 00 a2 64
622 */
623 clen = 0;
624 wmsk = 0;
625 for (i = sizeof(wmsk) - 1; i >= 0; i--) {
626 shft = i * NBBY;
627 bmsk = (uint64_t)0xffLL << shft;
628 wmsk |= bmsk;
629 if ((*dst & wmsk) || i == 0) {
630 if (olen + clen + 1 >= maxolen) {
631 errno = ENOSPC;
632 goto out;
633 }
634
635 mbdst[clen++] = (char)(
636 (uint64_t)(*dst & bmsk) >>
637 shft);
638 }
639 }
640 cerr = 1;
641 }
642
643 /*
644 * We'll be dereferencing mbdst[clen] after this to write the
645 * nul terminator; the above paths should have checked for a
646 * possible overflow already.
647 */
648 assert(olen + clen < maxolen);
649
650 /* Advance output pointer by number of bytes written. */
651 mbdst += clen;
652 /* Advance buffer character pointer. */
653 dst++;
654 /* Incrment output character count. */
655 olen += clen;
656 }
657
658 /* Terminate the output string. */
659 assert(olen < maxolen);
660 *mbdst = '\0';
661
662 if (flags & VIS_NOLOCALE) {
663 /* Pass conversion error flag out. */
664 if (cerr_ptr)
665 *cerr_ptr = cerr;
666 }
667
668 free(extra);
669 free(pdst);
670 free(psrc);
671
672 return (int)olen;
673 out:
674 free(extra);
675 free(pdst);
676 free(psrc);
677 free(mdst);
678 return error;
679 }
680
681 static int
682 istrsenvisxl(char **mbdstp, size_t *dlen, const char *mbsrc,
683 int flags, const char *mbextra, int *cerr_ptr)
684 {
685 return istrsenvisx(mbdstp, dlen, mbsrc,
686 mbsrc != NULL ? strlen(mbsrc) : 0, flags, mbextra, cerr_ptr);
687 }
688
689 #endif
690
691 #if !HAVE_SVIS
692 /*
693 * The "svis" variants all take an "extra" arg that is a pointer
694 * to a NUL-terminated list of characters to be encoded, too.
695 * These functions are useful e. g. to encode strings in such a
696 * way so that they are not interpreted by a shell.
697 */
698
699 char *
700 svis(char *mbdst, int c, int flags, int nextc, const char *mbextra)
701 {
702 char cc[2];
703 int ret;
704
705 cc[0] = c;
706 cc[1] = nextc;
707
708 ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, mbextra, NULL);
709 if (ret < 0)
710 return NULL;
711 return mbdst + ret;
712 }
713
714 char *
715 snvis(char *mbdst, size_t dlen, int c, int flags, int nextc, const char *mbextra)
716 {
717 char cc[2];
718 int ret;
719
720 cc[0] = c;
721 cc[1] = nextc;
722
723 ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, mbextra, NULL);
724 if (ret < 0)
725 return NULL;
726 return mbdst + ret;
727 }
728
729 int
730 strsvis(char *mbdst, const char *mbsrc, int flags, const char *mbextra)
731 {
732 return istrsenvisxl(&mbdst, NULL, mbsrc, flags, mbextra, NULL);
733 }
734
735 int
736 strsnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags, const char *mbextra)
737 {
738 return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, mbextra, NULL);
739 }
740
741 int
742 strsvisx(char *mbdst, const char *mbsrc, size_t len, int flags, const char *mbextra)
743 {
744 return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, mbextra, NULL);
745 }
746
747 int
748 strsnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
749 const char *mbextra)
750 {
751 return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, NULL);
752 }
753
754 int
755 strsenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
756 const char *mbextra, int *cerr_ptr)
757 {
758 return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, mbextra, cerr_ptr);
759 }
760 #endif
761
762 #if !HAVE_VIS
763 /*
764 * vis - visually encode characters
765 */
766 char *
767 vis(char *mbdst, int c, int flags, int nextc)
768 {
769 char cc[2];
770 int ret;
771
772 cc[0] = c;
773 cc[1] = nextc;
774
775 ret = istrsenvisx(&mbdst, NULL, cc, 1, flags, "", NULL);
776 if (ret < 0)
777 return NULL;
778 return mbdst + ret;
779 }
780
781 char *
782 nvis(char *mbdst, size_t dlen, int c, int flags, int nextc)
783 {
784 char cc[2];
785 int ret;
786
787 cc[0] = c;
788 cc[1] = nextc;
789
790 ret = istrsenvisx(&mbdst, &dlen, cc, 1, flags, "", NULL);
791 if (ret < 0)
792 return NULL;
793 return mbdst + ret;
794 }
795
796 /*
797 * strvis - visually encode characters from src into dst
798 *
799 * Dst must be 4 times the size of src to account for possible
800 * expansion. The length of dst, not including the trailing NULL,
801 * is returned.
802 */
803
804 int
805 strvis(char *mbdst, const char *mbsrc, int flags)
806 {
807 return istrsenvisxl(&mbdst, NULL, mbsrc, flags, "", NULL);
808 }
809
810 int
811 strnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags)
812 {
813 return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, "", NULL);
814 }
815
816 int
817 stravis(char **mbdstp, const char *mbsrc, int flags)
818 {
819 *mbdstp = NULL;
820 return istrsenvisxl(mbdstp, NULL, mbsrc, flags, "", NULL);
821 }
822
823 /*
824 * strvisx - visually encode characters from src into dst
825 *
826 * Dst must be 4 times the size of src to account for possible
827 * expansion. The length of dst, not including the trailing NULL,
828 * is returned.
829 *
830 * Strvisx encodes exactly len characters from src into dst.
831 * This is useful for encoding a block of data.
832 */
833
834 int
835 strvisx(char *mbdst, const char *mbsrc, size_t len, int flags)
836 {
837 return istrsenvisx(&mbdst, NULL, mbsrc, len, flags, "", NULL);
838 }
839
840 int
841 strnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags)
842 {
843 return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", NULL);
844 }
845
846 int
847 strenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
848 int *cerr_ptr)
849 {
850 return istrsenvisx(&mbdst, &dlen, mbsrc, len, flags, "", cerr_ptr);
851 }
852 #endif
853