[BACK]Return to vis.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / gen

Annotation of src/lib/libc/gen/vis.c, Revision 1.70

1.70    ! christos    1: /*     $NetBSD: vis.c,v 1.69 2015/05/23 14:21:11 christos Exp $        */
1.6       cgd         2:
1.1       cgd         3: /*-
1.6       cgd         4:  * Copyright (c) 1989, 1993
1.16      wennmach    5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         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.
1.29      lukem      15:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        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:
1.26      agc        32: /*-
1.31      lukem      33:  * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
1.30      lukem      34:  * All rights reserved.
1.26      agc        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:  *
1.30      lukem      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.
1.26      agc        56:  */
                     57:
1.7       christos   58: #include <sys/cdefs.h>
1.21      tv         59: #if defined(LIBC_SCCS) && !defined(lint)
1.70    ! christos   60: __RCSID("$NetBSD: vis.c,v 1.69 2015/05/23 14:21:11 christos Exp $");
1.21      tv         61: #endif /* LIBC_SCCS and not lint */
1.46      christos   62: #ifdef __FBSDID
                     63: __FBSDID("$FreeBSD$");
                     64: #define        _DIAGASSERT(x)  assert(x)
                     65: #endif
1.1       cgd        66:
1.8       jtc        67: #include "namespace.h"
1.1       cgd        68: #include <sys/types.h>
1.59      christos   69: #include <sys/param.h>
1.12      lukem      70:
                     71: #include <assert.h>
1.1       cgd        72: #include <vis.h>
1.44      christos   73: #include <errno.h>
1.22      christos   74: #include <stdlib.h>
1.46      christos   75: #include <wchar.h>
                     76: #include <wctype.h>
1.8       jtc        77:
                     78: #ifdef __weak_alias
1.18      mycroft    79: __weak_alias(strvisx,_strvisx)
1.20      tv         80: #endif
                     81:
1.24      pooka      82: #if !HAVE_VIS || !HAVE_SVIS
1.20      tv         83: #include <ctype.h>
                     84: #include <limits.h>
                     85: #include <stdio.h>
                     86: #include <string.h>
1.1       cgd        87:
1.47      christos   88: /*
                     89:  * The reason for going through the trouble to deal with character encodings
                     90:  * in vis(3), is that we use this to safe encode output of commands. This
                     91:  * safe encoding varies depending on the character set. For example if we
                     92:  * display ps output in French, we don't want to display French characters
                     93:  * as M-foo.
                     94:  */
                     95:
1.48      pooka      96: static wchar_t *do_svis(wchar_t *, wint_t, int, wint_t, const wchar_t *);
1.37      dsl        97:
1.15      wennmach   98: #undef BELL
1.46      christos   99: #define BELL L'\a'
1.68      christos  100:
1.70    ! christos  101: #if defined(LC_C_LOCALE)
        !           102: #define iscgraph(c)      isgraph_l(c, LC_C_LOCALE)
1.68      christos  103: #else
1.69      christos  104: /* Keep it simple for now, no locale stuff */
                    105: #define iscgraph(c)    isgraph(c)
                    106: #ifdef notyet
                    107: #include <locale.h>
1.68      christos  108: static int
                    109: iscgraph(int c) {
                    110:        int rv;
                    111:        char *ol;
                    112:
                    113:        ol = setlocale(LC_CTYPE, "C");
                    114:        rv = isgraph(c);
                    115:        if (ol)
                    116:                setlocale(LC_CTYPE, ol);
                    117:        return rv;
                    118: }
                    119: #endif
1.69      christos  120: #endif
1.68      christos  121:
                    122: #define ISGRAPH(flags, c) \
                    123:     (((flags) & VIS_NOLOCALE) ? iscgraph(c) : iswgraph(c))
1.15      wennmach  124:
1.46      christos  125: #define iswoctal(c)    (((u_char)(c)) >= L'0' && ((u_char)(c)) <= L'7')
                    126: #define iswwhite(c)    (c == L' ' || c == L'\t' || c == L'\n')
                    127: #define iswsafe(c)     (c == L'\b' || c == BELL || c == L'\r')
                    128: #define xtoa(c)                L"0123456789abcdef"[c]
                    129: #define XTOA(c)                L"0123456789ABCDEF"[c]
1.16      wennmach  130:
1.63      christos  131: #define MAXEXTRAS      30
                    132:
                    133: static const wchar_t char_shell[] = L"'`\";&<>()|{}]\\$!^~";
                    134: static const wchar_t char_glob[] = L"*?[#";
1.15      wennmach  135:
1.60      joerg     136: #if !HAVE_NBTOOL_CONFIG_H
1.59      christos  137: #ifndef __NetBSD__
1.57      christos  138: /*
                    139:  * On NetBSD MB_LEN_MAX is currently 32 which does not fit on any integer
                    140:  * integral type and it is probably wrong, since currently the maximum
                    141:  * number of bytes and character needs is 6. Until this is fixed, the
                    142:  * loops below are using sizeof(uint64_t) - 1 instead of MB_LEN_MAX, and
                    143:  * the assertion is commented out.
                    144:  */
1.59      christos  145: #ifdef __FreeBSD__
                    146: /*
                    147:  * On FreeBSD including <sys/systm.h> for CTASSERT only works in kernel
                    148:  * mode.
                    149:  */
                    150: #ifndef CTASSERT
                    151: #define CTASSERT(x)             _CTASSERT(x, __LINE__)
                    152: #define _CTASSERT(x, y)         __CTASSERT(x, y)
                    153: #define __CTASSERT(x, y)        typedef char __assert ## y[(x) ? 1 : -1]
1.57      christos  154: #endif
1.59      christos  155: #endif /* __FreeBSD__ */
                    156: CTASSERT(MB_LEN_MAX <= sizeof(uint64_t));
                    157: #endif /* !__NetBSD__ */
1.60      joerg     158: #endif
1.57      christos  159:
1.22      christos  160: /*
1.37      dsl       161:  * This is do_hvis, for HTTP style (RFC 1808)
1.22      christos  162:  */
1.46      christos  163: static wchar_t *
1.54      christos  164: do_hvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
1.37      dsl       165: {
1.46      christos  166:        if (iswalnum(c)
1.41      plunky    167:            /* safe */
1.46      christos  168:            || c == L'$' || c == L'-' || c == L'_' || c == L'.' || c == L'+'
1.41      plunky    169:            /* extra */
1.46      christos  170:            || c == L'!' || c == L'*' || c == L'\'' || c == L'(' || c == L')'
                    171:            || c == L',')
1.54      christos  172:                dst = do_svis(dst, c, flags, nextc, extra);
1.46      christos  173:        else {
                    174:                *dst++ = L'%';
1.37      dsl       175:                *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
                    176:                *dst++ = xtoa((unsigned int)c & 0xf);
                    177:        }
1.41      plunky    178:
1.37      dsl       179:        return dst;
                    180: }
1.27      enami     181:
1.15      wennmach  182: /*
1.39      christos  183:  * This is do_mvis, for Quoted-Printable MIME (RFC 2045)
                    184:  * NB: No handling of long lines or CRLF.
                    185:  */
1.46      christos  186: static wchar_t *
1.54      christos  187: do_mvis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
1.39      christos  188: {
1.46      christos  189:        if ((c != L'\n') &&
1.39      christos  190:            /* Space at the end of the line */
1.46      christos  191:            ((iswspace(c) && (nextc == L'\r' || nextc == L'\n')) ||
1.39      christos  192:            /* Out of range */
1.46      christos  193:            (!iswspace(c) && (c < 33 || (c > 60 && c < 62) || c > 126)) ||
1.55      christos  194:            /* Specific char to be escaped */
1.46      christos  195:            wcschr(L"#$@[\\]^`{|}~", c) != NULL)) {
                    196:                *dst++ = L'=';
1.39      christos  197:                *dst++ = XTOA(((unsigned int)c >> 4) & 0xf);
                    198:                *dst++ = XTOA((unsigned int)c & 0xf);
1.46      christos  199:        } else
1.54      christos  200:                dst = do_svis(dst, c, flags, nextc, extra);
1.39      christos  201:        return dst;
                    202: }
                    203:
                    204: /*
1.54      christos  205:  * Output single byte of multibyte character.
1.15      wennmach  206:  */
1.46      christos  207: static wchar_t *
1.54      christos  208: do_mbyte(wchar_t *dst, wint_t c, int flags, wint_t nextc, int iswextra)
1.37      dsl       209: {
1.54      christos  210:        if (flags & VIS_CSTYLE) {
1.37      dsl       211:                switch (c) {
1.46      christos  212:                case L'\n':
                    213:                        *dst++ = L'\\'; *dst++ = L'n';
1.37      dsl       214:                        return dst;
1.46      christos  215:                case L'\r':
                    216:                        *dst++ = L'\\'; *dst++ = L'r';
1.37      dsl       217:                        return dst;
1.46      christos  218:                case L'\b':
                    219:                        *dst++ = L'\\'; *dst++ = L'b';
1.37      dsl       220:                        return dst;
                    221:                case BELL:
1.46      christos  222:                        *dst++ = L'\\'; *dst++ = L'a';
1.37      dsl       223:                        return dst;
1.46      christos  224:                case L'\v':
                    225:                        *dst++ = L'\\'; *dst++ = L'v';
1.37      dsl       226:                        return dst;
1.46      christos  227:                case L'\t':
                    228:                        *dst++ = L'\\'; *dst++ = L't';
1.37      dsl       229:                        return dst;
1.46      christos  230:                case L'\f':
                    231:                        *dst++ = L'\\'; *dst++ = L'f';
1.37      dsl       232:                        return dst;
1.46      christos  233:                case L' ':
                    234:                        *dst++ = L'\\'; *dst++ = L's';
1.37      dsl       235:                        return dst;
1.46      christos  236:                case L'\0':
                    237:                        *dst++ = L'\\'; *dst++ = L'0';
                    238:                        if (iswoctal(nextc)) {
                    239:                                *dst++ = L'0';
                    240:                                *dst++ = L'0';
1.37      dsl       241:                        }
                    242:                        return dst;
1.65      roy       243:                /* We cannot encode these characters in VIS_CSTYLE
                    244:                 * because they special meaning */
                    245:                case L'n':
                    246:                case L'r':
                    247:                case L'b':
                    248:                case L'a':
                    249:                case L'v':
                    250:                case L't':
                    251:                case L'f':
                    252:                case L's':
                    253:                case L'0':
                    254:                case L'M':
                    255:                case L'^':
1.66      roy       256:                case L'$': /* vis(1) -l */
1.65      roy       257:                        break;
1.37      dsl       258:                default:
1.68      christos  259:                        if (ISGRAPH(flags, c) && !iswoctal(c)) {
1.46      christos  260:                                *dst++ = L'\\';
                    261:                                *dst++ = c;
1.37      dsl       262:                                return dst;
                    263:                        }
                    264:                }
                    265:        }
1.54      christos  266:        if (iswextra || ((c & 0177) == L' ') || (flags & VIS_OCTAL)) {
1.46      christos  267:                *dst++ = L'\\';
                    268:                *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + L'0';
                    269:                *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + L'0';
                    270:                *dst++ =                             (c       & 07) + L'0';
1.37      dsl       271:        } else {
1.54      christos  272:                if ((flags & VIS_NOSLASH) == 0)
1.46      christos  273:                        *dst++ = L'\\';
1.55      christos  274:
1.37      dsl       275:                if (c & 0200) {
1.46      christos  276:                        c &= 0177;
                    277:                        *dst++ = L'M';
1.37      dsl       278:                }
1.55      christos  279:
1.46      christos  280:                if (iswcntrl(c)) {
                    281:                        *dst++ = L'^';
1.37      dsl       282:                        if (c == 0177)
1.46      christos  283:                                *dst++ = L'?';
1.37      dsl       284:                        else
1.46      christos  285:                                *dst++ = c + L'@';
1.37      dsl       286:                } else {
1.46      christos  287:                        *dst++ = L'-';
                    288:                        *dst++ = c;
1.37      dsl       289:                }
                    290:        }
1.54      christos  291:
                    292:        return dst;
                    293: }
                    294:
                    295: /*
                    296:  * This is do_vis, the central code of vis.
                    297:  * dst:              Pointer to the destination buffer
                    298:  * c:        Character to encode
1.59      christos  299:  * flags:     Flags word
1.54      christos  300:  * nextc:     The character following 'c'
                    301:  * extra:     Pointer to the list of extra characters to be
                    302:  *           backslash-protected.
                    303:  */
                    304: static wchar_t *
                    305: do_svis(wchar_t *dst, wint_t c, int flags, wint_t nextc, const wchar_t *extra)
                    306: {
                    307:        int iswextra, i, shft;
1.57      christos  308:        uint64_t bmsk, wmsk;
1.54      christos  309:
                    310:        iswextra = wcschr(extra, c) != NULL;
1.68      christos  311:        if (!iswextra && (ISGRAPH(flags, c) || iswwhite(c) ||
1.54      christos  312:            ((flags & VIS_SAFE) && iswsafe(c)))) {
                    313:                *dst++ = c;
                    314:                return dst;
                    315:        }
                    316:
                    317:        /* See comment in istrsenvisx() output loop, below. */
                    318:        wmsk = 0;
1.59      christos  319:        for (i = sizeof(wmsk) - 1; i >= 0; i--) {
1.54      christos  320:                shft = i * NBBY;
1.59      christos  321:                bmsk = (uint64_t)0xffLL << shft;
1.54      christos  322:                wmsk |= bmsk;
                    323:                if ((c & wmsk) || i == 0)
                    324:                        dst = do_mbyte(dst, (wint_t)(
1.59      christos  325:                            (uint64_t)(c & bmsk) >> shft),
1.54      christos  326:                            flags, nextc, iswextra);
                    327:        }
                    328:
1.37      dsl       329:        return dst;
                    330: }
1.15      wennmach  331:
1.46      christos  332: typedef wchar_t *(*visfun_t)(wchar_t *, wint_t, int, wint_t, const wchar_t *);
1.39      christos  333:
                    334: /*
                    335:  * Return the appropriate encoding function depending on the flags given.
                    336:  */
                    337: static visfun_t
1.54      christos  338: getvisfun(int flags)
1.39      christos  339: {
1.54      christos  340:        if (flags & VIS_HTTPSTYLE)
1.39      christos  341:                return do_hvis;
1.54      christos  342:        if (flags & VIS_MIMESTYLE)
1.39      christos  343:                return do_mvis;
                    344:        return do_svis;
                    345: }
1.15      wennmach  346:
                    347: /*
1.54      christos  348:  * Expand list of extra characters to not visually encode.
                    349:  */
                    350: static wchar_t *
                    351: makeextralist(int flags, const char *src)
                    352: {
                    353:        wchar_t *dst, *d;
                    354:        size_t len;
1.64      christos  355:        const wchar_t *s;
1.54      christos  356:
                    357:        len = strlen(src);
                    358:        if ((dst = calloc(len + MAXEXTRAS, sizeof(*dst))) == NULL)
                    359:                return NULL;
                    360:
1.67      christos  361:        if ((flags & VIS_NOLOCALE) || mbstowcs(dst, src, len) == (size_t)-1) {
1.58      tron      362:                size_t i;
                    363:                for (i = 0; i < len; i++)
1.63      christos  364:                        dst[i] = (wchar_t)(u_char)src[i];
1.54      christos  365:                d = dst + len;
                    366:        } else
                    367:                d = dst + wcslen(dst);
                    368:
1.63      christos  369:        if (flags & VIS_GLOB)
1.64      christos  370:                for (s = char_glob; *s; *d++ = *s++)
1.63      christos  371:                        continue;
                    372:
                    373:        if (flags & VIS_SHELL)
1.64      christos  374:                for (s = char_shell; *s; *d++ = *s++)
1.63      christos  375:                        continue;
1.54      christos  376:
1.55      christos  377:        if (flags & VIS_SP) *d++ = L' ';
                    378:        if (flags & VIS_TAB) *d++ = L'\t';
1.54      christos  379:        if (flags & VIS_NL) *d++ = L'\n';
                    380:        if ((flags & VIS_NOSLASH) == 0) *d++ = L'\\';
                    381:        *d = L'\0';
                    382:
                    383:        return dst;
                    384: }
                    385:
                    386: /*
                    387:  * istrsenvisx()
1.46      christos  388:  *     The main internal function.
                    389:  *     All user-visible functions call this one.
1.15      wennmach  390:  */
1.46      christos  391: static int
1.54      christos  392: istrsenvisx(char *mbdst, size_t *dlen, const char *mbsrc, size_t mblength,
                    393:     int flags, const char *mbextra, int *cerr_ptr)
1.15      wennmach  394: {
1.54      christos  395:        wchar_t *dst, *src, *pdst, *psrc, *start, *extra;
1.50      christos  396:        size_t len, olen;
1.57      christos  397:        uint64_t bmsk, wmsk;
                    398:        wint_t c;
1.39      christos  399:        visfun_t f;
1.67      christos  400:        int clen = 0, cerr, error = -1, i, shft;
1.54      christos  401:        ssize_t mbslength, maxolen;
1.46      christos  402:
                    403:        _DIAGASSERT(mbdst != NULL);
1.61      christos  404:        _DIAGASSERT(mbsrc != NULL || mblength == 0);
1.46      christos  405:        _DIAGASSERT(mbextra != NULL);
                    406:
1.53      christos  407:        /*
                    408:         * Input (mbsrc) is a char string considered to be multibyte
                    409:         * characters.  The input loop will read this string pulling
                    410:         * one character, possibly multiple bytes, from mbsrc and
                    411:         * converting each to wchar_t in src.
                    412:         *
                    413:         * The vis conversion will be done using the wide char
                    414:         * wchar_t string.
                    415:         *
                    416:         * This will then be converted back to a multibyte string to
                    417:         * return to the caller.
                    418:         */
                    419:
                    420:        /* Allocate space for the wide char strings */
1.54      christos  421:        psrc = pdst = extra = NULL;
1.46      christos  422:        if ((psrc = calloc(mblength + 1, sizeof(*psrc))) == NULL)
                    423:                return -1;
                    424:        if ((pdst = calloc((4 * mblength) + 1, sizeof(*pdst))) == NULL)
                    425:                goto out;
                    426:        dst = pdst;
                    427:        src = psrc;
                    428:
1.67      christos  429:        if (flags & VIS_NOLOCALE) {
                    430:                /* Do one byte at a time conversion */
                    431:                cerr = 1;
                    432:        } else {
                    433:                /* Use caller's multibyte conversion error flag. */
                    434:                cerr = cerr_ptr ? *cerr_ptr : 0;
                    435:        }
1.54      christos  436:
1.53      christos  437:        /*
                    438:         * Input loop.
                    439:         * Handle up to mblength characters (not bytes).  We do not
                    440:         * stop at NULs because we may be processing a block of data
1.54      christos  441:         * that includes NULs.
1.53      christos  442:         */
1.50      christos  443:        mbslength = (ssize_t)mblength;
1.53      christos  444:        /*
                    445:         * When inputing a single character, must also read in the
                    446:         * next character for nextc, the look-ahead character.
                    447:         */
                    448:        if (mbslength == 1)
                    449:                mbslength++;
                    450:        while (mbslength > 0) {
                    451:                /* Convert one multibyte character to wchar_t. */
1.54      christos  452:                if (!cerr)
                    453:                        clen = mbtowc(src, mbsrc, MB_LEN_MAX);
                    454:                if (cerr || clen < 0) {
1.53      christos  455:                        /* Conversion error, process as a byte instead. */
1.54      christos  456:                        *src = (wint_t)(u_char)*mbsrc;
1.50      christos  457:                        clen = 1;
1.54      christos  458:                        cerr = 1;
1.51      christos  459:                }
1.50      christos  460:                if (clen == 0)
1.53      christos  461:                        /*
                    462:                         * NUL in input gives 0 return value. process
1.54      christos  463:                         * as single NUL byte and keep going.
1.53      christos  464:                         */
1.50      christos  465:                        clen = 1;
1.54      christos  466:                /* Advance buffer character pointer. */
1.50      christos  467:                src++;
1.53      christos  468:                /* Advance input pointer by number of bytes read. */
1.50      christos  469:                mbsrc += clen;
1.54      christos  470:                /* Decrement input byte count. */
1.50      christos  471:                mbslength -= clen;
1.46      christos  472:        }
1.55      christos  473:        len = src - psrc;
1.50      christos  474:        src = psrc;
1.53      christos  475:        /*
                    476:         * In the single character input case, we will have actually
                    477:         * processed two characters, c and nextc.  Reset len back to
                    478:         * just a single character.
                    479:         */
                    480:        if (mblength < len)
                    481:                len = mblength;
1.46      christos  482:
1.53      christos  483:        /* Convert extra argument to list of characters for this mode. */
1.54      christos  484:        extra = makeextralist(flags, mbextra);
                    485:        if (!extra) {
1.44      christos  486:                if (dlen && *dlen == 0) {
                    487:                        errno = ENOSPC;
1.46      christos  488:                        goto out;
1.44      christos  489:                }
1.54      christos  490:                *mbdst = '\0';          /* can't create extra, return "" */
1.46      christos  491:                error = 0;
                    492:                goto out;
1.31      lukem     493:        }
1.46      christos  494:
1.53      christos  495:        /* Look up which processing function to call. */
1.54      christos  496:        f = getvisfun(flags);
1.46      christos  497:
1.53      christos  498:        /*
                    499:         * Main processing loop.
                    500:         * Call do_Xvis processing function one character at a time
                    501:         * with next character available for look-ahead.
                    502:         */
1.46      christos  503:        for (start = dst; len > 0; len--) {
                    504:                c = *src++;
1.54      christos  505:                dst = (*f)(dst, c, flags, len >= 1 ? *src : L'\0', extra);
1.46      christos  506:                if (dst == NULL) {
                    507:                        errno = ENOSPC;
                    508:                        goto out;
                    509:                }
                    510:        }
                    511:
1.54      christos  512:        /* Terminate the string in the buffer. */
                    513:        *dst = L'\0';
                    514:
                    515:        /*
                    516:         * Output loop.
                    517:         * Convert wchar_t string back to multibyte output string.
                    518:         * If we have hit a multi-byte conversion error on input,
                    519:         * output byte-by-byte here.  Else use wctomb().
                    520:         */
                    521:        len = wcslen(start);
                    522:        maxolen = dlen ? *dlen : (wcslen(start) * MB_LEN_MAX + 1);
                    523:        olen = 0;
                    524:        for (dst = start; len > 0; len--) {
                    525:                if (!cerr)
                    526:                        clen = wctomb(mbdst, *dst);
                    527:                if (cerr || clen < 0) {
                    528:                        /*
                    529:                         * Conversion error, process as a byte(s) instead.
                    530:                         * Examine each byte and higher-order bytes for
1.55      christos  531:                         * data.  E.g.,
1.59      christos  532:                         *      0x000000000000a264 -> a2 64
                    533:                         *      0x000000001f00a264 -> 1f 00 a2 64
1.54      christos  534:                         */
                    535:                        clen = 0;
                    536:                        wmsk = 0;
1.59      christos  537:                        for (i = sizeof(wmsk) - 1; i >= 0; i--) {
1.54      christos  538:                                shft = i * NBBY;
1.59      christos  539:                                bmsk = (uint64_t)0xffLL << shft;
1.54      christos  540:                                wmsk |= bmsk;
                    541:                                if ((*dst & wmsk) || i == 0)
1.59      christos  542:                                        mbdst[clen++] = (char)(
                    543:                                            (uint64_t)(*dst & bmsk) >>
                    544:                                            shft);
1.54      christos  545:                        }
                    546:                        cerr = 1;
                    547:                }
                    548:                /* If this character would exceed our output limit, stop. */
                    549:                if (olen + clen > (size_t)maxolen)
                    550:                        break;
                    551:                /* Advance output pointer by number of bytes written. */
                    552:                mbdst += clen;
                    553:                /* Advance buffer character pointer. */
                    554:                dst++;
                    555:                /* Incrment output character count. */
                    556:                olen += clen;
                    557:        }
                    558:
1.53      christos  559:        /* Terminate the output string. */
1.54      christos  560:        *mbdst = '\0';
1.46      christos  561:
1.67      christos  562:        if (flags & VIS_NOLOCALE) {
                    563:                /* Pass conversion error flag out. */
                    564:                if (cerr_ptr)
                    565:                        *cerr_ptr = cerr;
                    566:        }
1.46      christos  567:
                    568:        free(extra);
                    569:        free(pdst);
                    570:        free(psrc);
                    571:
                    572:        return (int)olen;
                    573: out:
                    574:        free(extra);
                    575:        free(pdst);
                    576:        free(psrc);
                    577:        return error;
1.15      wennmach  578: }
1.62      christos  579:
                    580: static int
                    581: istrsenvisxl(char *mbdst, size_t *dlen, const char *mbsrc,
                    582:     int flags, const char *mbextra, int *cerr_ptr)
                    583: {
                    584:        return istrsenvisx(mbdst, dlen, mbsrc,
                    585:            mbsrc != NULL ? strlen(mbsrc) : 0, flags, mbextra, cerr_ptr);
                    586: }
                    587:
1.46      christos  588: #endif
                    589:
                    590: #if !HAVE_SVIS
                    591: /*
                    592:  *     The "svis" variants all take an "extra" arg that is a pointer
                    593:  *     to a NUL-terminated list of characters to be encoded, too.
                    594:  *     These functions are useful e. g. to encode strings in such a
                    595:  *     way so that they are not interpreted by a shell.
                    596:  */
1.15      wennmach  597:
1.44      christos  598: char *
1.54      christos  599: svis(char *mbdst, int c, int flags, int nextc, const char *mbextra)
1.44      christos  600: {
1.46      christos  601:        char cc[2];
                    602:        int ret;
                    603:
                    604:        cc[0] = c;
                    605:        cc[1] = nextc;
                    606:
1.54      christos  607:        ret = istrsenvisx(mbdst, NULL, cc, 1, flags, mbextra, NULL);
1.46      christos  608:        if (ret < 0)
                    609:                return NULL;
                    610:        return mbdst + ret;
1.44      christos  611: }
                    612:
                    613: char *
1.54      christos  614: snvis(char *mbdst, size_t dlen, int c, int flags, int nextc, const char *mbextra)
1.44      christos  615: {
1.46      christos  616:        char cc[2];
                    617:        int ret;
1.44      christos  618:
1.46      christos  619:        cc[0] = c;
                    620:        cc[1] = nextc;
1.15      wennmach  621:
1.54      christos  622:        ret = istrsenvisx(mbdst, &dlen, cc, 1, flags, mbextra, NULL);
1.46      christos  623:        if (ret < 0)
                    624:                return NULL;
                    625:        return mbdst + ret;
1.15      wennmach  626: }
                    627:
1.44      christos  628: int
1.54      christos  629: strsvis(char *mbdst, const char *mbsrc, int flags, const char *mbextra)
1.44      christos  630: {
1.62      christos  631:        return istrsenvisxl(mbdst, NULL, mbsrc, flags, mbextra, NULL);
1.44      christos  632: }
1.15      wennmach  633:
                    634: int
1.54      christos  635: strsnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags, const char *mbextra)
1.44      christos  636: {
1.62      christos  637:        return istrsenvisxl(mbdst, &dlen, mbsrc, flags, mbextra, NULL);
1.15      wennmach  638: }
1.44      christos  639:
                    640: int
1.54      christos  641: strsvisx(char *mbdst, const char *mbsrc, size_t len, int flags, const char *mbextra)
1.44      christos  642: {
1.54      christos  643:        return istrsenvisx(mbdst, NULL, mbsrc, len, flags, mbextra, NULL);
1.44      christos  644: }
                    645:
                    646: int
1.54      christos  647: strsnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
1.46      christos  648:     const char *mbextra)
1.44      christos  649: {
1.54      christos  650:        return istrsenvisx(mbdst, &dlen, mbsrc, len, flags, mbextra, NULL);
                    651: }
                    652:
                    653: int
                    654: strsenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
                    655:     const char *mbextra, int *cerr_ptr)
                    656: {
                    657:        return istrsenvisx(mbdst, &dlen, mbsrc, len, flags, mbextra, cerr_ptr);
1.44      christos  658: }
1.24      pooka     659: #endif
1.15      wennmach  660:
1.24      pooka     661: #if !HAVE_VIS
1.1       cgd       662: /*
                    663:  * vis - visually encode characters
                    664:  */
1.46      christos  665: char *
1.54      christos  666: vis(char *mbdst, int c, int flags, int nextc)
1.15      wennmach  667: {
1.46      christos  668:        char cc[2];
                    669:        int ret;
1.15      wennmach  670:
1.46      christos  671:        cc[0] = c;
                    672:        cc[1] = nextc;
1.15      wennmach  673:
1.54      christos  674:        ret = istrsenvisx(mbdst, NULL, cc, 1, flags, "", NULL);
1.46      christos  675:        if (ret < 0)
1.44      christos  676:                return NULL;
1.46      christos  677:        return mbdst + ret;
1.1       cgd       678: }
                    679:
1.44      christos  680: char *
1.54      christos  681: nvis(char *mbdst, size_t dlen, int c, int flags, int nextc)
1.44      christos  682: {
1.46      christos  683:        char cc[2];
                    684:        int ret;
                    685:
                    686:        cc[0] = c;
                    687:        cc[1] = nextc;
1.44      christos  688:
1.54      christos  689:        ret = istrsenvisx(mbdst, &dlen, cc, 1, flags, "", NULL);
1.46      christos  690:        if (ret < 0)
                    691:                return NULL;
                    692:        return mbdst + ret;
1.44      christos  693: }
                    694:
1.1       cgd       695: /*
1.46      christos  696:  * strvis - visually encode characters from src into dst
1.27      enami     697:  *
1.16      wennmach  698:  *     Dst must be 4 times the size of src to account for possible
                    699:  *     expansion.  The length of dst, not including the trailing NULL,
1.27      enami     700:  *     is returned.
1.1       cgd       701:  */
                    702:
1.44      christos  703: int
1.54      christos  704: strvis(char *mbdst, const char *mbsrc, int flags)
1.44      christos  705: {
1.62      christos  706:        return istrsenvisxl(mbdst, NULL, mbsrc, flags, "", NULL);
1.44      christos  707: }
1.15      wennmach  708:
1.1       cgd       709: int
1.54      christos  710: strnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags)
1.44      christos  711: {
1.62      christos  712:        return istrsenvisxl(mbdst, &dlen, mbsrc, flags, "", NULL);
1.44      christos  713: }
                    714:
1.46      christos  715: /*
                    716:  * strvisx - visually encode characters from src into dst
                    717:  *
                    718:  *     Dst must be 4 times the size of src to account for possible
                    719:  *     expansion.  The length of dst, not including the trailing NULL,
                    720:  *     is returned.
                    721:  *
                    722:  *     Strvisx encodes exactly len characters from src into dst.
                    723:  *     This is useful for encoding a block of data.
                    724:  */
1.44      christos  725:
                    726: int
1.54      christos  727: strvisx(char *mbdst, const char *mbsrc, size_t len, int flags)
                    728: {
                    729:        return istrsenvisx(mbdst, NULL, mbsrc, len, flags, "", NULL);
                    730: }
                    731:
                    732: int
                    733: strnvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags)
1.44      christos  734: {
1.54      christos  735:        return istrsenvisx(mbdst, &dlen, mbsrc, len, flags, "", NULL);
1.44      christos  736: }
                    737:
                    738: int
1.54      christos  739: strenvisx(char *mbdst, size_t dlen, const char *mbsrc, size_t len, int flags,
                    740:     int *cerr_ptr)
1.44      christos  741: {
1.54      christos  742:        return istrsenvisx(mbdst, &dlen, mbsrc, len, flags, "", cerr_ptr);
1.44      christos  743: }
1.20      tv        744: #endif

CVSweb <webmaster@jp.NetBSD.org>