[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.60

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

CVSweb <webmaster@jp.NetBSD.org>