1*8ccca122SBrooks Davis /* $NetBSD: vis.c,v 1.45 2012/12/14 21:38:18 christos Exp $ */ 2*8ccca122SBrooks Davis 3*8ccca122SBrooks Davis /*- 4*8ccca122SBrooks Davis * Copyright (c) 1989, 1993 5*8ccca122SBrooks Davis * The Regents of the University of California. All rights reserved. 6*8ccca122SBrooks Davis * 7*8ccca122SBrooks Davis * Redistribution and use in source and binary forms, with or without 8*8ccca122SBrooks Davis * modification, are permitted provided that the following conditions 9*8ccca122SBrooks Davis * are met: 10*8ccca122SBrooks Davis * 1. Redistributions of source code must retain the above copyright 11*8ccca122SBrooks Davis * notice, this list of conditions and the following disclaimer. 12*8ccca122SBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright 13*8ccca122SBrooks Davis * notice, this list of conditions and the following disclaimer in the 14*8ccca122SBrooks Davis * documentation and/or other materials provided with the distribution. 15*8ccca122SBrooks Davis * 3. Neither the name of the University nor the names of its contributors 16*8ccca122SBrooks Davis * may be used to endorse or promote products derived from this software 17*8ccca122SBrooks Davis * without specific prior written permission. 18*8ccca122SBrooks Davis * 19*8ccca122SBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20*8ccca122SBrooks Davis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*8ccca122SBrooks Davis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*8ccca122SBrooks Davis * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23*8ccca122SBrooks Davis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24*8ccca122SBrooks Davis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25*8ccca122SBrooks Davis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26*8ccca122SBrooks Davis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27*8ccca122SBrooks Davis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28*8ccca122SBrooks Davis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29*8ccca122SBrooks Davis * SUCH DAMAGE. 30*8ccca122SBrooks Davis */ 31*8ccca122SBrooks Davis 32*8ccca122SBrooks Davis /*- 33*8ccca122SBrooks Davis * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc. 34*8ccca122SBrooks Davis * All rights reserved. 35*8ccca122SBrooks Davis * 36*8ccca122SBrooks Davis * Redistribution and use in source and binary forms, with or without 37*8ccca122SBrooks Davis * modification, are permitted provided that the following conditions 38*8ccca122SBrooks Davis * are met: 39*8ccca122SBrooks Davis * 1. Redistributions of source code must retain the above copyright 40*8ccca122SBrooks Davis * notice, this list of conditions and the following disclaimer. 41*8ccca122SBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright 42*8ccca122SBrooks Davis * notice, this list of conditions and the following disclaimer in the 43*8ccca122SBrooks Davis * documentation and/or other materials provided with the distribution. 44*8ccca122SBrooks Davis * 45*8ccca122SBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 46*8ccca122SBrooks Davis * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 47*8ccca122SBrooks Davis * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 48*8ccca122SBrooks Davis * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 49*8ccca122SBrooks Davis * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 50*8ccca122SBrooks Davis * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 51*8ccca122SBrooks Davis * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 52*8ccca122SBrooks Davis * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 53*8ccca122SBrooks Davis * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54*8ccca122SBrooks Davis * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 55*8ccca122SBrooks Davis * POSSIBILITY OF SUCH DAMAGE. 56*8ccca122SBrooks Davis */ 57*8ccca122SBrooks Davis 58*8ccca122SBrooks Davis #include <sys/cdefs.h> 59*8ccca122SBrooks Davis #if defined(LIBC_SCCS) && !defined(lint) 60*8ccca122SBrooks Davis __RCSID("$NetBSD: vis.c,v 1.45 2012/12/14 21:38:18 christos Exp $"); 61*8ccca122SBrooks Davis #endif /* LIBC_SCCS and not lint */ 62*8ccca122SBrooks Davis __FBSDID("$FreeBSD$"); 63*8ccca122SBrooks Davis 64*8ccca122SBrooks Davis #include "namespace.h" 65*8ccca122SBrooks Davis #include <sys/types.h> 66*8ccca122SBrooks Davis 67*8ccca122SBrooks Davis #include <assert.h> 68*8ccca122SBrooks Davis #include <vis.h> 69*8ccca122SBrooks Davis #include <errno.h> 70*8ccca122SBrooks Davis #include <stdlib.h> 71*8ccca122SBrooks Davis 72*8ccca122SBrooks Davis #define _DIAGASSERT(x) assert(x) 73*8ccca122SBrooks Davis 74*8ccca122SBrooks Davis #ifdef __weak_alias 75*8ccca122SBrooks Davis __weak_alias(strvisx,_strvisx) 76*8ccca122SBrooks Davis #endif 77*8ccca122SBrooks Davis 78*8ccca122SBrooks Davis #if !HAVE_VIS || !HAVE_SVIS 79*8ccca122SBrooks Davis #include <ctype.h> 80*8ccca122SBrooks Davis #include <limits.h> 81*8ccca122SBrooks Davis #include <stdio.h> 82*8ccca122SBrooks Davis #include <string.h> 83*8ccca122SBrooks Davis 84*8ccca122SBrooks Davis static char *do_svis(char *, size_t *, int, int, int, const char *); 85*8ccca122SBrooks Davis 86*8ccca122SBrooks Davis #undef BELL 87*8ccca122SBrooks Davis #define BELL '\a' 88*8ccca122SBrooks Davis 89*8ccca122SBrooks Davis #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') 90*8ccca122SBrooks Davis #define iswhite(c) (c == ' ' || c == '\t' || c == '\n') 91*8ccca122SBrooks Davis #define issafe(c) (c == '\b' || c == BELL || c == '\r') 92*8ccca122SBrooks Davis #define xtoa(c) "0123456789abcdef"[c] 93*8ccca122SBrooks Davis #define XTOA(c) "0123456789ABCDEF"[c] 94*8ccca122SBrooks Davis 95*8ccca122SBrooks Davis #define MAXEXTRAS 9 96*8ccca122SBrooks Davis 97*8ccca122SBrooks Davis #define MAKEEXTRALIST(flag, extra, orig_str) \ 98*8ccca122SBrooks Davis do { \ 99*8ccca122SBrooks Davis const char *orig = orig_str; \ 100*8ccca122SBrooks Davis const char *o = orig; \ 101*8ccca122SBrooks Davis char *e; \ 102*8ccca122SBrooks Davis while (*o++) \ 103*8ccca122SBrooks Davis continue; \ 104*8ccca122SBrooks Davis extra = malloc((size_t)((o - orig) + MAXEXTRAS)); \ 105*8ccca122SBrooks Davis if (!extra) break; \ 106*8ccca122SBrooks Davis for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ 107*8ccca122SBrooks Davis continue; \ 108*8ccca122SBrooks Davis e--; \ 109*8ccca122SBrooks Davis if (flag & VIS_GLOB) { \ 110*8ccca122SBrooks Davis *e++ = '*'; \ 111*8ccca122SBrooks Davis *e++ = '?'; \ 112*8ccca122SBrooks Davis *e++ = '['; \ 113*8ccca122SBrooks Davis *e++ = '#'; \ 114*8ccca122SBrooks Davis } \ 115*8ccca122SBrooks Davis if (flag & VIS_SP) *e++ = ' '; \ 116*8ccca122SBrooks Davis if (flag & VIS_TAB) *e++ = '\t'; \ 117*8ccca122SBrooks Davis if (flag & VIS_NL) *e++ = '\n'; \ 118*8ccca122SBrooks Davis if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ 119*8ccca122SBrooks Davis *e = '\0'; \ 120*8ccca122SBrooks Davis } while (/*CONSTCOND*/0) 121*8ccca122SBrooks Davis 122*8ccca122SBrooks Davis /* 123*8ccca122SBrooks Davis * This is do_hvis, for HTTP style (RFC 1808) 124*8ccca122SBrooks Davis */ 125*8ccca122SBrooks Davis static char * 126*8ccca122SBrooks Davis do_hvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) 127*8ccca122SBrooks Davis { 128*8ccca122SBrooks Davis 129*8ccca122SBrooks Davis if ((isascii(c) && isalnum(c)) 130*8ccca122SBrooks Davis /* safe */ 131*8ccca122SBrooks Davis || c == '$' || c == '-' || c == '_' || c == '.' || c == '+' 132*8ccca122SBrooks Davis /* extra */ 133*8ccca122SBrooks Davis || c == '!' || c == '*' || c == '\'' || c == '(' || c == ')' 134*8ccca122SBrooks Davis || c == ',') { 135*8ccca122SBrooks Davis dst = do_svis(dst, dlen, c, flag, nextc, extra); 136*8ccca122SBrooks Davis } else { 137*8ccca122SBrooks Davis if (dlen) { 138*8ccca122SBrooks Davis if (*dlen < 3) 139*8ccca122SBrooks Davis return NULL; 140*8ccca122SBrooks Davis *dlen -= 3; 141*8ccca122SBrooks Davis } 142*8ccca122SBrooks Davis *dst++ = '%'; 143*8ccca122SBrooks Davis *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); 144*8ccca122SBrooks Davis *dst++ = xtoa((unsigned int)c & 0xf); 145*8ccca122SBrooks Davis } 146*8ccca122SBrooks Davis 147*8ccca122SBrooks Davis return dst; 148*8ccca122SBrooks Davis } 149*8ccca122SBrooks Davis 150*8ccca122SBrooks Davis /* 151*8ccca122SBrooks Davis * This is do_mvis, for Quoted-Printable MIME (RFC 2045) 152*8ccca122SBrooks Davis * NB: No handling of long lines or CRLF. 153*8ccca122SBrooks Davis */ 154*8ccca122SBrooks Davis static char * 155*8ccca122SBrooks Davis do_mvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) 156*8ccca122SBrooks Davis { 157*8ccca122SBrooks Davis if ((c != '\n') && 158*8ccca122SBrooks Davis /* Space at the end of the line */ 159*8ccca122SBrooks Davis ((isspace(c) && (nextc == '\r' || nextc == '\n')) || 160*8ccca122SBrooks Davis /* Out of range */ 161*8ccca122SBrooks Davis (!isspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) || 162*8ccca122SBrooks Davis /* Specific char to be escaped */ 163*8ccca122SBrooks Davis strchr("#$@[\\]^`{|}~", c) != NULL)) { 164*8ccca122SBrooks Davis if (dlen) { 165*8ccca122SBrooks Davis if (*dlen < 3) 166*8ccca122SBrooks Davis return NULL; 167*8ccca122SBrooks Davis *dlen -= 3; 168*8ccca122SBrooks Davis } 169*8ccca122SBrooks Davis *dst++ = '='; 170*8ccca122SBrooks Davis *dst++ = XTOA(((unsigned int)c >> 4) & 0xf); 171*8ccca122SBrooks Davis *dst++ = XTOA((unsigned int)c & 0xf); 172*8ccca122SBrooks Davis } else { 173*8ccca122SBrooks Davis dst = do_svis(dst, dlen, c, flag, nextc, extra); 174*8ccca122SBrooks Davis } 175*8ccca122SBrooks Davis return dst; 176*8ccca122SBrooks Davis } 177*8ccca122SBrooks Davis 178*8ccca122SBrooks Davis /* 179*8ccca122SBrooks Davis * This is do_vis, the central code of vis. 180*8ccca122SBrooks Davis * dst: Pointer to the destination buffer 181*8ccca122SBrooks Davis * c: Character to encode 182*8ccca122SBrooks Davis * flag: Flag word 183*8ccca122SBrooks Davis * nextc: The character following 'c' 184*8ccca122SBrooks Davis * extra: Pointer to the list of extra characters to be 185*8ccca122SBrooks Davis * backslash-protected. 186*8ccca122SBrooks Davis */ 187*8ccca122SBrooks Davis static char * 188*8ccca122SBrooks Davis do_svis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) 189*8ccca122SBrooks Davis { 190*8ccca122SBrooks Davis int isextra; 191*8ccca122SBrooks Davis size_t odlen = dlen ? *dlen : 0; 192*8ccca122SBrooks Davis 193*8ccca122SBrooks Davis isextra = strchr(extra, c) != NULL; 194*8ccca122SBrooks Davis #define HAVE(x) \ 195*8ccca122SBrooks Davis do { \ 196*8ccca122SBrooks Davis if (dlen) { \ 197*8ccca122SBrooks Davis if (*dlen < (x)) \ 198*8ccca122SBrooks Davis goto out; \ 199*8ccca122SBrooks Davis *dlen -= (x); \ 200*8ccca122SBrooks Davis } \ 201*8ccca122SBrooks Davis } while (/*CONSTCOND*/0) 202*8ccca122SBrooks Davis if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || 203*8ccca122SBrooks Davis ((flag & VIS_SAFE) && issafe(c)))) { 204*8ccca122SBrooks Davis HAVE(1); 205*8ccca122SBrooks Davis *dst++ = c; 206*8ccca122SBrooks Davis return dst; 207*8ccca122SBrooks Davis } 208*8ccca122SBrooks Davis if (flag & VIS_CSTYLE) { 209*8ccca122SBrooks Davis HAVE(2); 210*8ccca122SBrooks Davis switch (c) { 211*8ccca122SBrooks Davis case '\n': 212*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = 'n'; 213*8ccca122SBrooks Davis return dst; 214*8ccca122SBrooks Davis case '\r': 215*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = 'r'; 216*8ccca122SBrooks Davis return dst; 217*8ccca122SBrooks Davis case '\b': 218*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = 'b'; 219*8ccca122SBrooks Davis return dst; 220*8ccca122SBrooks Davis case BELL: 221*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = 'a'; 222*8ccca122SBrooks Davis return dst; 223*8ccca122SBrooks Davis case '\v': 224*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = 'v'; 225*8ccca122SBrooks Davis return dst; 226*8ccca122SBrooks Davis case '\t': 227*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = 't'; 228*8ccca122SBrooks Davis return dst; 229*8ccca122SBrooks Davis case '\f': 230*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = 'f'; 231*8ccca122SBrooks Davis return dst; 232*8ccca122SBrooks Davis case ' ': 233*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = 's'; 234*8ccca122SBrooks Davis return dst; 235*8ccca122SBrooks Davis case '\0': 236*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = '0'; 237*8ccca122SBrooks Davis if (isoctal(nextc)) { 238*8ccca122SBrooks Davis HAVE(2); 239*8ccca122SBrooks Davis *dst++ = '0'; 240*8ccca122SBrooks Davis *dst++ = '0'; 241*8ccca122SBrooks Davis } 242*8ccca122SBrooks Davis return dst; 243*8ccca122SBrooks Davis default: 244*8ccca122SBrooks Davis if (isgraph(c)) { 245*8ccca122SBrooks Davis *dst++ = '\\'; *dst++ = c; 246*8ccca122SBrooks Davis return dst; 247*8ccca122SBrooks Davis } 248*8ccca122SBrooks Davis if (dlen) 249*8ccca122SBrooks Davis *dlen = odlen; 250*8ccca122SBrooks Davis } 251*8ccca122SBrooks Davis } 252*8ccca122SBrooks Davis if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { 253*8ccca122SBrooks Davis HAVE(4); 254*8ccca122SBrooks Davis *dst++ = '\\'; 255*8ccca122SBrooks Davis *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; 256*8ccca122SBrooks Davis *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; 257*8ccca122SBrooks Davis *dst++ = (c & 07) + '0'; 258*8ccca122SBrooks Davis } else { 259*8ccca122SBrooks Davis if ((flag & VIS_NOSLASH) == 0) { 260*8ccca122SBrooks Davis HAVE(1); 261*8ccca122SBrooks Davis *dst++ = '\\'; 262*8ccca122SBrooks Davis } 263*8ccca122SBrooks Davis 264*8ccca122SBrooks Davis if (c & 0200) { 265*8ccca122SBrooks Davis HAVE(1); 266*8ccca122SBrooks Davis c &= 0177; *dst++ = 'M'; 267*8ccca122SBrooks Davis } 268*8ccca122SBrooks Davis 269*8ccca122SBrooks Davis if (iscntrl(c)) { 270*8ccca122SBrooks Davis HAVE(2); 271*8ccca122SBrooks Davis *dst++ = '^'; 272*8ccca122SBrooks Davis if (c == 0177) 273*8ccca122SBrooks Davis *dst++ = '?'; 274*8ccca122SBrooks Davis else 275*8ccca122SBrooks Davis *dst++ = c + '@'; 276*8ccca122SBrooks Davis } else { 277*8ccca122SBrooks Davis HAVE(2); 278*8ccca122SBrooks Davis *dst++ = '-'; *dst++ = c; 279*8ccca122SBrooks Davis } 280*8ccca122SBrooks Davis } 281*8ccca122SBrooks Davis return dst; 282*8ccca122SBrooks Davis out: 283*8ccca122SBrooks Davis *dlen = odlen; 284*8ccca122SBrooks Davis return NULL; 285*8ccca122SBrooks Davis } 286*8ccca122SBrooks Davis 287*8ccca122SBrooks Davis typedef char *(*visfun_t)(char *, size_t *, int, int, int, const char *); 288*8ccca122SBrooks Davis 289*8ccca122SBrooks Davis /* 290*8ccca122SBrooks Davis * Return the appropriate encoding function depending on the flags given. 291*8ccca122SBrooks Davis */ 292*8ccca122SBrooks Davis static visfun_t 293*8ccca122SBrooks Davis getvisfun(int flag) 294*8ccca122SBrooks Davis { 295*8ccca122SBrooks Davis if (flag & VIS_HTTPSTYLE) 296*8ccca122SBrooks Davis return do_hvis; 297*8ccca122SBrooks Davis if (flag & VIS_MIMESTYLE) 298*8ccca122SBrooks Davis return do_mvis; 299*8ccca122SBrooks Davis return do_svis; 300*8ccca122SBrooks Davis } 301*8ccca122SBrooks Davis 302*8ccca122SBrooks Davis /* 303*8ccca122SBrooks Davis * isnvis - visually encode characters, also encoding the characters 304*8ccca122SBrooks Davis * pointed to by `extra' 305*8ccca122SBrooks Davis */ 306*8ccca122SBrooks Davis static char * 307*8ccca122SBrooks Davis isnvis(char *dst, size_t *dlen, int c, int flag, int nextc, const char *extra) 308*8ccca122SBrooks Davis { 309*8ccca122SBrooks Davis char *nextra = NULL; 310*8ccca122SBrooks Davis visfun_t f; 311*8ccca122SBrooks Davis 312*8ccca122SBrooks Davis _DIAGASSERT(dst != NULL); 313*8ccca122SBrooks Davis _DIAGASSERT(extra != NULL); 314*8ccca122SBrooks Davis MAKEEXTRALIST(flag, nextra, extra); 315*8ccca122SBrooks Davis if (!nextra) { 316*8ccca122SBrooks Davis if (dlen && *dlen == 0) { 317*8ccca122SBrooks Davis errno = ENOSPC; 318*8ccca122SBrooks Davis return NULL; 319*8ccca122SBrooks Davis } 320*8ccca122SBrooks Davis *dst = '\0'; /* can't create nextra, return "" */ 321*8ccca122SBrooks Davis return dst; 322*8ccca122SBrooks Davis } 323*8ccca122SBrooks Davis f = getvisfun(flag); 324*8ccca122SBrooks Davis dst = (*f)(dst, dlen, c, flag, nextc, nextra); 325*8ccca122SBrooks Davis free(nextra); 326*8ccca122SBrooks Davis if (dst == NULL || (dlen && *dlen == 0)) { 327*8ccca122SBrooks Davis errno = ENOSPC; 328*8ccca122SBrooks Davis return NULL; 329*8ccca122SBrooks Davis } 330*8ccca122SBrooks Davis *dst = '\0'; 331*8ccca122SBrooks Davis return dst; 332*8ccca122SBrooks Davis } 333*8ccca122SBrooks Davis 334*8ccca122SBrooks Davis char * 335*8ccca122SBrooks Davis svis(char *dst, int c, int flag, int nextc, const char *extra) 336*8ccca122SBrooks Davis { 337*8ccca122SBrooks Davis return isnvis(dst, NULL, c, flag, nextc, extra); 338*8ccca122SBrooks Davis } 339*8ccca122SBrooks Davis 340*8ccca122SBrooks Davis char * 341*8ccca122SBrooks Davis snvis(char *dst, size_t dlen, int c, int flag, int nextc, const char *extra) 342*8ccca122SBrooks Davis { 343*8ccca122SBrooks Davis return isnvis(dst, &dlen, c, flag, nextc, extra); 344*8ccca122SBrooks Davis } 345*8ccca122SBrooks Davis 346*8ccca122SBrooks Davis 347*8ccca122SBrooks Davis /* 348*8ccca122SBrooks Davis * strsvis, strsvisx - visually encode characters from src into dst 349*8ccca122SBrooks Davis * 350*8ccca122SBrooks Davis * Extra is a pointer to a \0-terminated list of characters to 351*8ccca122SBrooks Davis * be encoded, too. These functions are useful e. g. to 352*8ccca122SBrooks Davis * encode strings in such a way so that they are not interpreted 353*8ccca122SBrooks Davis * by a shell. 354*8ccca122SBrooks Davis * 355*8ccca122SBrooks Davis * Dst must be 4 times the size of src to account for possible 356*8ccca122SBrooks Davis * expansion. The length of dst, not including the trailing NULL, 357*8ccca122SBrooks Davis * is returned. 358*8ccca122SBrooks Davis * 359*8ccca122SBrooks Davis * Strsvisx encodes exactly len bytes from src into dst. 360*8ccca122SBrooks Davis * This is useful for encoding a block of data. 361*8ccca122SBrooks Davis */ 362*8ccca122SBrooks Davis static int 363*8ccca122SBrooks Davis istrsnvis(char *dst, size_t *dlen, const char *csrc, int flag, const char *extra) 364*8ccca122SBrooks Davis { 365*8ccca122SBrooks Davis int c; 366*8ccca122SBrooks Davis char *start; 367*8ccca122SBrooks Davis char *nextra = NULL; 368*8ccca122SBrooks Davis const unsigned char *src = (const unsigned char *)csrc; 369*8ccca122SBrooks Davis visfun_t f; 370*8ccca122SBrooks Davis 371*8ccca122SBrooks Davis _DIAGASSERT(dst != NULL); 372*8ccca122SBrooks Davis _DIAGASSERT(src != NULL); 373*8ccca122SBrooks Davis _DIAGASSERT(extra != NULL); 374*8ccca122SBrooks Davis MAKEEXTRALIST(flag, nextra, extra); 375*8ccca122SBrooks Davis if (!nextra) { 376*8ccca122SBrooks Davis *dst = '\0'; /* can't create nextra, return "" */ 377*8ccca122SBrooks Davis return 0; 378*8ccca122SBrooks Davis } 379*8ccca122SBrooks Davis f = getvisfun(flag); 380*8ccca122SBrooks Davis for (start = dst; (c = *src++) != '\0'; /* empty */) { 381*8ccca122SBrooks Davis dst = (*f)(dst, dlen, c, flag, *src, nextra); 382*8ccca122SBrooks Davis if (dst == NULL) { 383*8ccca122SBrooks Davis errno = ENOSPC; 384*8ccca122SBrooks Davis return -1; 385*8ccca122SBrooks Davis } 386*8ccca122SBrooks Davis } 387*8ccca122SBrooks Davis free(nextra); 388*8ccca122SBrooks Davis if (dlen && *dlen == 0) { 389*8ccca122SBrooks Davis errno = ENOSPC; 390*8ccca122SBrooks Davis return -1; 391*8ccca122SBrooks Davis } 392*8ccca122SBrooks Davis *dst = '\0'; 393*8ccca122SBrooks Davis return (int)(dst - start); 394*8ccca122SBrooks Davis } 395*8ccca122SBrooks Davis 396*8ccca122SBrooks Davis int 397*8ccca122SBrooks Davis strsvis(char *dst, const char *csrc, int flag, const char *extra) 398*8ccca122SBrooks Davis { 399*8ccca122SBrooks Davis return istrsnvis(dst, NULL, csrc, flag, extra); 400*8ccca122SBrooks Davis } 401*8ccca122SBrooks Davis 402*8ccca122SBrooks Davis int 403*8ccca122SBrooks Davis strsnvis(char *dst, size_t dlen, const char *csrc, int flag, const char *extra) 404*8ccca122SBrooks Davis { 405*8ccca122SBrooks Davis return istrsnvis(dst, &dlen, csrc, flag, extra); 406*8ccca122SBrooks Davis } 407*8ccca122SBrooks Davis 408*8ccca122SBrooks Davis static int 409*8ccca122SBrooks Davis istrsnvisx(char *dst, size_t *dlen, const char *csrc, size_t len, int flag, 410*8ccca122SBrooks Davis const char *extra) 411*8ccca122SBrooks Davis { 412*8ccca122SBrooks Davis unsigned char c; 413*8ccca122SBrooks Davis char *start; 414*8ccca122SBrooks Davis char *nextra = NULL; 415*8ccca122SBrooks Davis const unsigned char *src = (const unsigned char *)csrc; 416*8ccca122SBrooks Davis visfun_t f; 417*8ccca122SBrooks Davis 418*8ccca122SBrooks Davis _DIAGASSERT(dst != NULL); 419*8ccca122SBrooks Davis _DIAGASSERT(src != NULL); 420*8ccca122SBrooks Davis _DIAGASSERT(extra != NULL); 421*8ccca122SBrooks Davis MAKEEXTRALIST(flag, nextra, extra); 422*8ccca122SBrooks Davis if (! nextra) { 423*8ccca122SBrooks Davis if (dlen && *dlen == 0) { 424*8ccca122SBrooks Davis errno = ENOSPC; 425*8ccca122SBrooks Davis return -1; 426*8ccca122SBrooks Davis } 427*8ccca122SBrooks Davis *dst = '\0'; /* can't create nextra, return "" */ 428*8ccca122SBrooks Davis return 0; 429*8ccca122SBrooks Davis } 430*8ccca122SBrooks Davis 431*8ccca122SBrooks Davis f = getvisfun(flag); 432*8ccca122SBrooks Davis for (start = dst; len > 0; len--) { 433*8ccca122SBrooks Davis c = *src++; 434*8ccca122SBrooks Davis dst = (*f)(dst, dlen, c, flag, len > 1 ? *src : '\0', nextra); 435*8ccca122SBrooks Davis if (dst == NULL) { 436*8ccca122SBrooks Davis errno = ENOSPC; 437*8ccca122SBrooks Davis return -1; 438*8ccca122SBrooks Davis } 439*8ccca122SBrooks Davis } 440*8ccca122SBrooks Davis free(nextra); 441*8ccca122SBrooks Davis if (dlen && *dlen == 0) { 442*8ccca122SBrooks Davis errno = ENOSPC; 443*8ccca122SBrooks Davis return -1; 444*8ccca122SBrooks Davis } 445*8ccca122SBrooks Davis *dst = '\0'; 446*8ccca122SBrooks Davis return (int)(dst - start); 447*8ccca122SBrooks Davis } 448*8ccca122SBrooks Davis 449*8ccca122SBrooks Davis int 450*8ccca122SBrooks Davis strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra) 451*8ccca122SBrooks Davis { 452*8ccca122SBrooks Davis return istrsnvisx(dst, NULL, csrc, len, flag, extra); 453*8ccca122SBrooks Davis } 454*8ccca122SBrooks Davis 455*8ccca122SBrooks Davis int 456*8ccca122SBrooks Davis strsnvisx(char *dst, size_t dlen, const char *csrc, size_t len, int flag, 457*8ccca122SBrooks Davis const char *extra) 458*8ccca122SBrooks Davis { 459*8ccca122SBrooks Davis return istrsnvisx(dst, &dlen, csrc, len, flag, extra); 460*8ccca122SBrooks Davis } 461*8ccca122SBrooks Davis #endif 462*8ccca122SBrooks Davis 463*8ccca122SBrooks Davis #if !HAVE_VIS 464*8ccca122SBrooks Davis /* 465*8ccca122SBrooks Davis * vis - visually encode characters 466*8ccca122SBrooks Davis */ 467*8ccca122SBrooks Davis static char * 468*8ccca122SBrooks Davis invis(char *dst, size_t *dlen, int c, int flag, int nextc) 469*8ccca122SBrooks Davis { 470*8ccca122SBrooks Davis char *extra = NULL; 471*8ccca122SBrooks Davis unsigned char uc = (unsigned char)c; 472*8ccca122SBrooks Davis visfun_t f; 473*8ccca122SBrooks Davis 474*8ccca122SBrooks Davis _DIAGASSERT(dst != NULL); 475*8ccca122SBrooks Davis 476*8ccca122SBrooks Davis MAKEEXTRALIST(flag, extra, ""); 477*8ccca122SBrooks Davis if (! extra) { 478*8ccca122SBrooks Davis if (dlen && *dlen == 0) { 479*8ccca122SBrooks Davis errno = ENOSPC; 480*8ccca122SBrooks Davis return NULL; 481*8ccca122SBrooks Davis } 482*8ccca122SBrooks Davis *dst = '\0'; /* can't create extra, return "" */ 483*8ccca122SBrooks Davis return dst; 484*8ccca122SBrooks Davis } 485*8ccca122SBrooks Davis f = getvisfun(flag); 486*8ccca122SBrooks Davis dst = (*f)(dst, dlen, uc, flag, nextc, extra); 487*8ccca122SBrooks Davis free(extra); 488*8ccca122SBrooks Davis if (dst == NULL || (dlen && *dlen == 0)) { 489*8ccca122SBrooks Davis errno = ENOSPC; 490*8ccca122SBrooks Davis return NULL; 491*8ccca122SBrooks Davis } 492*8ccca122SBrooks Davis *dst = '\0'; 493*8ccca122SBrooks Davis return dst; 494*8ccca122SBrooks Davis } 495*8ccca122SBrooks Davis 496*8ccca122SBrooks Davis char * 497*8ccca122SBrooks Davis vis(char *dst, int c, int flag, int nextc) 498*8ccca122SBrooks Davis { 499*8ccca122SBrooks Davis return invis(dst, NULL, c, flag, nextc); 500*8ccca122SBrooks Davis } 501*8ccca122SBrooks Davis 502*8ccca122SBrooks Davis char * 503*8ccca122SBrooks Davis nvis(char *dst, size_t dlen, int c, int flag, int nextc) 504*8ccca122SBrooks Davis { 505*8ccca122SBrooks Davis return invis(dst, &dlen, c, flag, nextc); 506*8ccca122SBrooks Davis } 507*8ccca122SBrooks Davis 508*8ccca122SBrooks Davis 509*8ccca122SBrooks Davis /* 510*8ccca122SBrooks Davis * strvis, strvisx - visually encode characters from src into dst 511*8ccca122SBrooks Davis * 512*8ccca122SBrooks Davis * Dst must be 4 times the size of src to account for possible 513*8ccca122SBrooks Davis * expansion. The length of dst, not including the trailing NULL, 514*8ccca122SBrooks Davis * is returned. 515*8ccca122SBrooks Davis * 516*8ccca122SBrooks Davis * Strvisx encodes exactly len bytes from src into dst. 517*8ccca122SBrooks Davis * This is useful for encoding a block of data. 518*8ccca122SBrooks Davis */ 519*8ccca122SBrooks Davis static int 520*8ccca122SBrooks Davis istrnvis(char *dst, size_t *dlen, const char *src, int flag) 521*8ccca122SBrooks Davis { 522*8ccca122SBrooks Davis char *extra = NULL; 523*8ccca122SBrooks Davis int rv; 524*8ccca122SBrooks Davis 525*8ccca122SBrooks Davis MAKEEXTRALIST(flag, extra, ""); 526*8ccca122SBrooks Davis if (!extra) { 527*8ccca122SBrooks Davis if (dlen && *dlen == 0) { 528*8ccca122SBrooks Davis errno = ENOSPC; 529*8ccca122SBrooks Davis return -1; 530*8ccca122SBrooks Davis } 531*8ccca122SBrooks Davis *dst = '\0'; /* can't create extra, return "" */ 532*8ccca122SBrooks Davis return 0; 533*8ccca122SBrooks Davis } 534*8ccca122SBrooks Davis rv = istrsnvis(dst, dlen, src, flag, extra); 535*8ccca122SBrooks Davis free(extra); 536*8ccca122SBrooks Davis return rv; 537*8ccca122SBrooks Davis } 538*8ccca122SBrooks Davis 539*8ccca122SBrooks Davis int 540*8ccca122SBrooks Davis strvis(char *dst, const char *src, int flag) 541*8ccca122SBrooks Davis { 542*8ccca122SBrooks Davis return istrnvis(dst, NULL, src, flag); 543*8ccca122SBrooks Davis } 544*8ccca122SBrooks Davis 545*8ccca122SBrooks Davis int 546*8ccca122SBrooks Davis strnvis(char *dst, size_t dlen, const char *src, int flag) 547*8ccca122SBrooks Davis { 548*8ccca122SBrooks Davis return istrnvis(dst, &dlen, src, flag); 549*8ccca122SBrooks Davis } 550*8ccca122SBrooks Davis 551*8ccca122SBrooks Davis static int 552*8ccca122SBrooks Davis istrnvisx(char *dst, size_t *dlen, const char *src, size_t len, int flag) 553*8ccca122SBrooks Davis { 554*8ccca122SBrooks Davis char *extra = NULL; 555*8ccca122SBrooks Davis int rv; 556*8ccca122SBrooks Davis 557*8ccca122SBrooks Davis MAKEEXTRALIST(flag, extra, ""); 558*8ccca122SBrooks Davis if (!extra) { 559*8ccca122SBrooks Davis if (dlen && *dlen == 0) { 560*8ccca122SBrooks Davis errno = ENOSPC; 561*8ccca122SBrooks Davis return -1; 562*8ccca122SBrooks Davis } 563*8ccca122SBrooks Davis *dst = '\0'; /* can't create extra, return "" */ 564*8ccca122SBrooks Davis return 0; 565*8ccca122SBrooks Davis } 566*8ccca122SBrooks Davis rv = istrsnvisx(dst, dlen, src, len, flag, extra); 567*8ccca122SBrooks Davis free(extra); 568*8ccca122SBrooks Davis return rv; 569*8ccca122SBrooks Davis } 570*8ccca122SBrooks Davis 571*8ccca122SBrooks Davis int 572*8ccca122SBrooks Davis strvisx(char *dst, const char *src, size_t len, int flag) 573*8ccca122SBrooks Davis { 574*8ccca122SBrooks Davis return istrnvisx(dst, NULL, src, len, flag); 575*8ccca122SBrooks Davis } 576*8ccca122SBrooks Davis 577*8ccca122SBrooks Davis int 578*8ccca122SBrooks Davis strnvisx(char *dst, size_t dlen, const char *src, size_t len, int flag) 579*8ccca122SBrooks Davis { 580*8ccca122SBrooks Davis return istrnvisx(dst, &dlen, src, len, flag); 581*8ccca122SBrooks Davis } 582*8ccca122SBrooks Davis 583*8ccca122SBrooks Davis #endif 584