[BACK]Return to process.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / sed

Annotation of src/usr.bin/sed/process.c, Revision 1.40

1.40    ! christos    1: /*     $NetBSD$        */
1.18      tls         2:
1.1       alm         3: /*-
1.40    ! christos    4:  * Copyright (c) 1992 Diomidis Spinellis.
1.19      mrg         5:  * Copyright (c) 1992, 1993, 1994
1.8       cgd         6:  *     The Regents of the University of California.  All rights reserved.
1.1       alm         7:  *
                      8:  * This code is derived from software contributed to Berkeley by
                      9:  * Diomidis Spinellis of Imperial College, University of London.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
1.33      agc        19:  * 3. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  */
                     35:
1.37      gdamore    36: #if HAVE_NBTOOL_CONFIG_H
                     37: #include "nbtool_config.h"
                     38: #endif
                     39:
1.20      lukem      40: #include <sys/cdefs.h>
1.40    ! christos   41: __RCSID("$NetBSD$");
        !            42: #ifdef __FBSDID
        !            43: __FBSDID("$FreeBSD: head/usr.bin/sed/process.c 192732 2009-05-25 06:45:33Z brian $");
        !            44: #endif
        !            45:
1.1       alm        46: #ifndef lint
1.40    ! christos   47: static const char sccsid[] = "@(#)process.c    8.6 (Berkeley) 4/20/94";
1.19      mrg        48: #endif
1.1       alm        49:
                     50: #include <sys/types.h>
                     51: #include <sys/stat.h>
                     52: #include <sys/ioctl.h>
                     53: #include <sys/uio.h>
                     54:
                     55: #include <ctype.h>
1.40    ! christos   56: #include <err.h>
1.1       alm        57: #include <errno.h>
                     58: #include <fcntl.h>
                     59: #include <limits.h>
                     60: #include <regex.h>
                     61: #include <stdio.h>
                     62: #include <stdlib.h>
                     63: #include <string.h>
                     64: #include <unistd.h>
1.40    ! christos   65: #include <wchar.h>
        !            66: #include <wctype.h>
1.1       alm        67:
                     68: #include "defs.h"
                     69: #include "extern.h"
                     70:
1.40    ! christos   71: static SPACE HS, PS, SS, YS;
1.1       alm        72: #define        pd              PS.deleted
                     73: #define        ps              PS.space
                     74: #define        psl             PS.len
                     75: #define        hs              HS.space
                     76: #define        hsl             HS.len
                     77:
1.40    ! christos   78: static __inline int     applies(struct s_command *);
        !            79: static void             do_tr(struct s_tr *);
1.32      wiz        80: static void             flush_appends(void);
1.40    ! christos   81: static void             lputs(char *, size_t);
        !            82: static __inline int     regexec_e(regex_t *, const char *, int, int, size_t);
1.32      wiz        83: static void             regsub(SPACE *, char *, char *);
                     84: static int              substitute(struct s_command *);
1.1       alm        85:
                     86: struct s_appends *appends;     /* Array of pointers to strings to append. */
1.40    ! christos   87: static size_t appendx;         /* Index into appends array. */
        !            88: size_t appendnum;                      /* Size of appends array. */
1.1       alm        89:
                     90: static int lastaddr;           /* Set by applies if last address of a range. */
                     91: static int sdone;              /* If any substitutes since last line input. */
                     92:                                /* Iov structure for 'w' commands. */
                     93: static regex_t *defpreg;
                     94: size_t maxnsub;
                     95: regmatch_t *match;
                     96:
1.40    ! christos   97: #define OUT() do {fwrite(ps, 1, psl, outfile); fputc('\n', outfile);} while (0)
1.8       cgd        98:
1.1       alm        99: void
1.32      wiz       100: process(void)
1.1       alm       101: {
                    102:        struct s_command *cp;
                    103:        SPACE tspace;
1.40    ! christos  104:        size_t oldpsl = 0;
1.15      mycroft   105:        char *p;
1.1       alm       106:
1.40    ! christos  107:        p = NULL;
        !           108:
1.1       alm       109:        for (linenum = 0; mf_fgets(&PS, REPLACE);) {
                    110:                pd = 0;
1.16      mycroft   111: top:
1.1       alm       112:                cp = prog;
                    113: redirect:
                    114:                while (cp != NULL) {
                    115:                        if (!applies(cp)) {
                    116:                                cp = cp->next;
                    117:                                continue;
                    118:                        }
                    119:                        switch (cp->code) {
                    120:                        case '{':
                    121:                                cp = cp->u.c;
                    122:                                goto redirect;
                    123:                        case 'a':
1.40    ! christos  124:                                if (appendx >= appendnum)
1.1       alm       125:                                        appends = xrealloc(appends,
                    126:                                            sizeof(struct s_appends) *
1.40    ! christos  127:                                            (appendnum *= 2));
1.1       alm       128:                                appends[appendx].type = AP_STRING;
                    129:                                appends[appendx].s = cp->t;
1.8       cgd       130:                                appends[appendx].len = strlen(cp->t);
1.1       alm       131:                                appendx++;
                    132:                                break;
                    133:                        case 'b':
                    134:                                cp = cp->u.c;
                    135:                                goto redirect;
                    136:                        case 'c':
                    137:                                pd = 1;
                    138:                                psl = 0;
1.40    ! christos  139:                                if (cp->a2 == NULL || lastaddr || lastline())
        !           140:                                        (void)fprintf(outfile, "%s", cp->t);
1.39      uwe       141:                                goto new;
1.1       alm       142:                        case 'd':
                    143:                                pd = 1;
                    144:                                goto new;
                    145:                        case 'D':
                    146:                                if (pd)
                    147:                                        goto new;
1.40    ! christos  148:                                if (psl == 0 ||
        !           149:                                    (p = memchr(ps, '\n', psl - 1)) == NULL) {
1.1       alm       150:                                        pd = 1;
1.16      mycroft   151:                                        goto new;
1.28      atatat    152:                                } else {
1.40    ! christos  153:                                        psl -= (size_t)((p + 1) - ps);
1.1       alm       154:                                        memmove(ps, p + 1, psl);
1.28      atatat    155:                                        goto top;
1.1       alm       156:                                }
                    157:                        case 'g':
                    158:                                cspace(&PS, hs, hsl, REPLACE);
                    159:                                break;
                    160:                        case 'G':
1.25      kim       161:                                if (hs == NULL)
1.40    ! christos  162:                                        cspace(&PS, "\n", 1, REPLACE);
        !           163:                                cspace(&PS, hs, hsl, APPEND);
1.1       alm       164:                                break;
                    165:                        case 'h':
                    166:                                cspace(&HS, ps, psl, REPLACE);
                    167:                                break;
                    168:                        case 'H':
1.40    ! christos  169:                                cspace(&HS, "\n", 1, APPEND);
        !           170:                                cspace(&HS, ps, psl, APPEND);
1.1       alm       171:                                break;
                    172:                        case 'i':
1.40    ! christos  173:                                (void)fprintf(outfile, "%s", cp->t);
1.1       alm       174:                                break;
                    175:                        case 'l':
1.40    ! christos  176:                                lputs(ps, psl);
1.1       alm       177:                                break;
                    178:                        case 'n':
                    179:                                if (!nflag && !pd)
1.40    ! christos  180:                                        OUT();
1.1       alm       181:                                flush_appends();
1.14      mycroft   182:                                if (!mf_fgets(&PS, REPLACE))
1.1       alm       183:                                        exit(0);
                    184:                                pd = 0;
                    185:                                break;
                    186:                        case 'N':
                    187:                                flush_appends();
1.40    ! christos  188:                                cspace(&PS, "\n", 1, APPEND);
        !           189:                                if (!mf_fgets(&PS, APPEND))
1.1       alm       190:                                        exit(0);
                    191:                                break;
                    192:                        case 'p':
                    193:                                if (pd)
                    194:                                        break;
1.40    ! christos  195:                                OUT();
1.1       alm       196:                                break;
                    197:                        case 'P':
                    198:                                if (pd)
                    199:                                        break;
1.15      mycroft   200:                                if ((p = memchr(ps, '\n', psl - 1)) != NULL) {
                    201:                                        oldpsl = psl;
1.40    ! christos  202:                                        psl = (size_t)(p - ps);
1.1       alm       203:                                }
1.40    ! christos  204:                                OUT();
1.1       alm       205:                                if (p != NULL)
1.15      mycroft   206:                                        psl = oldpsl;
1.1       alm       207:                                break;
                    208:                        case 'q':
                    209:                                if (!nflag && !pd)
1.40    ! christos  210:                                        OUT();
1.1       alm       211:                                flush_appends();
                    212:                                exit(0);
                    213:                        case 'r':
1.40    ! christos  214:                                if (appendx >= appendnum)
1.1       alm       215:                                        appends = xrealloc(appends,
                    216:                                            sizeof(struct s_appends) *
1.40    ! christos  217:                                            (appendnum *= 2));
1.1       alm       218:                                appends[appendx].type = AP_FILE;
                    219:                                appends[appendx].s = cp->t;
1.8       cgd       220:                                appends[appendx].len = strlen(cp->t);
1.1       alm       221:                                appendx++;
                    222:                                break;
                    223:                        case 's':
                    224:                                sdone |= substitute(cp);
                    225:                                break;
                    226:                        case 't':
                    227:                                if (sdone) {
                    228:                                        sdone = 0;
                    229:                                        cp = cp->u.c;
                    230:                                        goto redirect;
                    231:                                }
                    232:                                break;
                    233:                        case 'w':
                    234:                                if (pd)
                    235:                                        break;
                    236:                                if (cp->u.fd == -1 && (cp->u.fd = open(cp->t,
                    237:                                    O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
                    238:                                    DEFFILEMODE)) == -1)
1.40    ! christos  239:                                        err(1, "%s", cp->t);
        !           240:                                if (write(cp->u.fd, ps, psl) != (ssize_t)psl ||
        !           241:                                    write(cp->u.fd, "\n", 1) != 1)
        !           242:                                        err(1, "%s", cp->t);
1.1       alm       243:                                break;
                    244:                        case 'x':
1.40    ! christos  245:                                /*
        !           246:                                 * If the hold space is null, make it empty
        !           247:                                 * but not null.  Otherwise the pattern space
        !           248:                                 * will become null after the swap, which is
        !           249:                                 * an abnormal condition.
        !           250:                                 */
1.8       cgd       251:                                if (hs == NULL)
1.40    ! christos  252:                                        cspace(&HS, "", 0, REPLACE);
1.1       alm       253:                                tspace = PS;
                    254:                                PS = HS;
                    255:                                HS = tspace;
                    256:                                break;
                    257:                        case 'y':
1.40    ! christos  258:                                if (pd || psl == 0)
1.1       alm       259:                                        break;
1.40    ! christos  260:                                do_tr(cp->u.y);
1.1       alm       261:                                break;
                    262:                        case ':':
                    263:                        case '}':
                    264:                                break;
                    265:                        case '=':
1.40    ! christos  266:                                (void)fprintf(outfile, "%lu\n", linenum);
1.1       alm       267:                        }
                    268:                        cp = cp->next;
                    269:                } /* for all cp */
                    270:
                    271: new:           if (!nflag && !pd)
1.40    ! christos  272:                        OUT();
1.1       alm       273:                flush_appends();
                    274:        } /* for all lines */
                    275: }
                    276:
                    277: /*
                    278:  * TRUE if the address passed matches the current program state
                    279:  * (lastline, linenumber, ps).
                    280:  */
1.40    ! christos  281: #define        MATCH(a)                                                        \
        !           282:        ((a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, psl) :      \
        !           283:            (a)->type == AT_LINE ? linenum == (a)->u.l : lastline())
1.1       alm       284:
                    285: /*
1.40    ! christos  286:  * Return TRUE if the command applies to the current line.  Sets the start
        !           287:  * line for process ranges.  Interprets the non-select (``!'') flag.
1.1       alm       288:  */
1.40    ! christos  289: static __inline int
1.32      wiz       290: applies(struct s_command *cp)
1.1       alm       291: {
                    292:        int r;
                    293:
                    294:        lastaddr = 0;
                    295:        if (cp->a1 == NULL && cp->a2 == NULL)
                    296:                r = 1;
1.40    ! christos  297:        else if (cp->a2)
        !           298:                if (cp->startline > 0) {
1.1       alm       299:                        if (MATCH(cp->a2)) {
1.40    ! christos  300:                                cp->startline = 0;
1.1       alm       301:                                lastaddr = 1;
1.40    ! christos  302:                                r = 1;
        !           303:                        } else if (linenum - cp->startline <= cp->a2->u.l)
        !           304:                                r = 1;
        !           305:                        else if ((cp->a2->type == AT_LINE &&
        !           306:                                   linenum > cp->a2->u.l) ||
        !           307:                                   (cp->a2->type == AT_RELLINE &&
        !           308:                                   linenum - cp->startline > cp->a2->u.l)) {
        !           309:                                /*
        !           310:                                 * We missed the 2nd address due to a branch,
        !           311:                                 * so just close the range and return false.
        !           312:                                 */
        !           313:                                cp->startline = 0;
        !           314:                                r = 0;
        !           315:                        } else
        !           316:                                r = 1;
1.36      christos  317:                } else if (cp->a1 && MATCH(cp->a1)) {
1.1       alm       318:                        /*
                    319:                         * If the second address is a number less than or
                    320:                         * equal to the line number first selected, only
                    321:                         * one line shall be selected.
                    322:                         *      -- POSIX 1003.2
1.40    ! christos  323:                         * Likewise if the relative second line address is zero.
1.1       alm       324:                         */
1.40    ! christos  325:                        if ((cp->a2->type == AT_LINE &&
        !           326:                            linenum >= cp->a2->u.l) ||
        !           327:                            (cp->a2->type == AT_RELLINE && cp->a2->u.l == 0))
1.1       alm       328:                                lastaddr = 1;
1.40    ! christos  329:                        else {
        !           330:                                cp->startline = linenum;
        !           331:                        }
1.1       alm       332:                        r = 1;
                    333:                } else
                    334:                        r = 0;
1.40    ! christos  335:        else
1.1       alm       336:                r = MATCH(cp->a1);
                    337:        return (cp->nonsel ? ! r : r);
                    338: }
                    339:
                    340: /*
1.40    ! christos  341:  * Reset the sed processor to its initial state.
        !           342:  */
        !           343: void
        !           344: resetstate(void)
        !           345: {
        !           346:        struct s_command *cp;
        !           347:
        !           348:        /*
        !           349:         * Reset all in-range markers.
        !           350:         */
        !           351:        for (cp = prog; cp; cp = cp->code == '{' ? cp->u.c : cp->next)
        !           352:                if (cp->a2)
        !           353:                        cp->startline = 0;
        !           354:
        !           355:        /*
        !           356:         * Clear out the hold space.
        !           357:         */
        !           358:        cspace(&HS, "", 0, REPLACE);
        !           359: }
        !           360:
        !           361: /*
1.1       alm       362:  * substitute --
                    363:  *     Do substitutions in the pattern space.  Currently, we build a
                    364:  *     copy of the new pattern space in the substitute space structure
                    365:  *     and then swap them.
                    366:  */
                    367: static int
1.32      wiz       368: substitute(struct s_command *cp)
1.1       alm       369: {
                    370:        SPACE tspace;
                    371:        regex_t *re;
1.40    ! christos  372:        regoff_t re_off, slen;
1.19      mrg       373:        int lastempty, n;
1.1       alm       374:        char *s;
                    375:
                    376:        s = ps;
                    377:        re = cp->u.s->re;
                    378:        if (re == NULL) {
1.40    ! christos  379:                if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) {
1.1       alm       380:                        linenum = cp->u.s->linenum;
1.40    ! christos  381:                        errx(1, "%lu: %s: \\%u not defined in the RE",
        !           382:                                        linenum, fname, cp->u.s->maxbref);
1.1       alm       383:                }
                    384:        }
1.8       cgd       385:        if (!regexec_e(re, s, 0, 0, psl))
1.1       alm       386:                return (0);
                    387:
                    388:        SS.len = 0;                             /* Clean substitute space. */
1.40    ! christos  389:        slen = (regoff_t)psl;
1.1       alm       390:        n = cp->u.s->n;
1.12      cgd       391:        lastempty = 1;
                    392:
1.1       alm       393:        switch (n) {
                    394:        case 0:                                 /* Global */
                    395:                do {
1.12      cgd       396:                        if (lastempty || match[0].rm_so != match[0].rm_eo) {
                    397:                                /* Locate start of replaced string. */
                    398:                                re_off = match[0].rm_so;
                    399:                                /* Copy leading retained string. */
1.40    ! christos  400:                                cspace(&SS, s, (size_t)re_off, APPEND);
1.12      cgd       401:                                /* Add in regular expression. */
                    402:                                regsub(&SS, s, cp->u.s->new);
                    403:                        }
                    404:
1.1       alm       405:                        /* Move past this match. */
1.12      cgd       406:                        if (match[0].rm_so != match[0].rm_eo) {
                    407:                                s += match[0].rm_eo;
                    408:                                slen -= match[0].rm_eo;
                    409:                                lastempty = 0;
                    410:                        } else {
1.40    ! christos  411:                                if (match[0].rm_so < slen)
        !           412:                                        cspace(&SS, s + match[0].rm_so, 1,
        !           413:                                            APPEND);
1.12      cgd       414:                                s += match[0].rm_so + 1;
                    415:                                slen -= match[0].rm_so + 1;
                    416:                                lastempty = 1;
                    417:                        }
1.40    ! christos  418:                } while (slen >= 0 && regexec_e(re, s, REG_NOTBOL, 0, (size_t)slen));
1.1       alm       419:                /* Copy trailing retained string. */
1.12      cgd       420:                if (slen > 0)
1.40    ! christos  421:                        cspace(&SS, s, (size_t)slen, APPEND);
1.1       alm       422:                break;
                    423:        default:                                /* Nth occurrence */
                    424:                while (--n) {
1.40    ! christos  425:                        if (match[0].rm_eo == match[0].rm_so)
        !           426:                                match[0].rm_eo = match[0].rm_so + 1;
1.1       alm       427:                        s += match[0].rm_eo;
1.8       cgd       428:                        slen -= match[0].rm_eo;
1.40    ! christos  429:                        if (slen < 0)
        !           430:                                return (0);
        !           431:                        if (!regexec_e(re, s, REG_NOTBOL, 0, (size_t)slen))
1.1       alm       432:                                return (0);
                    433:                }
                    434:                /* FALLTHROUGH */
                    435:        case 1:                                 /* 1st occurrence */
                    436:                /* Locate start of replaced string. */
                    437:                re_off = match[0].rm_so + (s - ps);
                    438:                /* Copy leading retained string. */
1.40    ! christos  439:                cspace(&SS, ps, (size_t)re_off, APPEND);
1.1       alm       440:                /* Add in regular expression. */
                    441:                regsub(&SS, s, cp->u.s->new);
                    442:                /* Copy trailing retained string. */
                    443:                s += match[0].rm_eo;
1.8       cgd       444:                slen -= match[0].rm_eo;
1.40    ! christos  445:                cspace(&SS, s, (size_t)slen, APPEND);
1.1       alm       446:                break;
                    447:        }
                    448:
                    449:        /*
                    450:         * Swap the substitute space and the pattern space, and make sure
                    451:         * that any leftover pointers into stdio memory get lost.
                    452:         */
                    453:        tspace = PS;
                    454:        PS = SS;
                    455:        SS = tspace;
                    456:        SS.space = SS.back;
                    457:
                    458:        /* Handle the 'p' flag. */
                    459:        if (cp->u.s->p)
1.40    ! christos  460:                OUT();
1.1       alm       461:
                    462:        /* Handle the 'w' flag. */
                    463:        if (cp->u.s->wfile && !pd) {
                    464:                if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile,
                    465:                    O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1)
1.40    ! christos  466:                        err(1, "%s", cp->u.s->wfile);
        !           467:                if (write(cp->u.s->wfd, ps, psl) != (ssize_t)psl ||
        !           468:                    write(cp->u.s->wfd, "\n", 1) != 1)
        !           469:                        err(1, "%s", cp->u.s->wfile);
1.1       alm       470:        }
                    471:        return (1);
                    472: }
                    473:
                    474: /*
1.40    ! christos  475:  * do_tr --
        !           476:  *     Perform translation ('y' command) in the pattern space.
        !           477:  */
        !           478: static void
        !           479: do_tr(struct s_tr *y)
        !           480: {
        !           481:        SPACE tmp;
        !           482:        char c, *p;
        !           483:        size_t clen, left;
        !           484:        size_t i;
        !           485:
        !           486:        if (MB_CUR_MAX == 1) {
        !           487:                /*
        !           488:                 * Single-byte encoding: perform in-place translation
        !           489:                 * of the pattern space.
        !           490:                 */
        !           491:                for (p = ps; p < &ps[psl]; p++)
        !           492:                        *p = (char)y->bytetab[(u_char)*p];
        !           493:        } else {
        !           494:                /*
        !           495:                 * Multi-byte encoding: perform translation into the
        !           496:                 * translation space, then swap the translation and
        !           497:                 * pattern spaces.
        !           498:                 */
        !           499:                /* Clean translation space. */
        !           500:                YS.len = 0;
        !           501:                for (p = ps, left = psl; left > 0; p += clen, left -= clen) {
        !           502:                        if ((c = (char)y->bytetab[(u_char)*p]) != '\0') {
        !           503:                                cspace(&YS, &c, 1, APPEND);
        !           504:                                clen = 1;
        !           505:                                continue;
        !           506:                        }
        !           507:                        for (i = 0; i < y->nmultis; i++)
        !           508:                                if (left >= y->multis[i].fromlen &&
        !           509:                                    memcmp(p, y->multis[i].from,
        !           510:                                    y->multis[i].fromlen) == 0)
        !           511:                                        break;
        !           512:                        if (i < y->nmultis) {
        !           513:                                cspace(&YS, y->multis[i].to,
        !           514:                                    y->multis[i].tolen, APPEND);
        !           515:                                clen = y->multis[i].fromlen;
        !           516:                        } else {
        !           517:                                cspace(&YS, p, 1, APPEND);
        !           518:                                clen = 1;
        !           519:                        }
        !           520:                }
        !           521:                /* Swap the translation space and the pattern space. */
        !           522:                tmp = PS;
        !           523:                PS = YS;
        !           524:                YS = tmp;
        !           525:                YS.space = YS.back;
        !           526:        }
        !           527: }
        !           528:
        !           529: /*
1.1       alm       530:  * Flush append requests.  Always called before reading a line,
                    531:  * therefore it also resets the substitution done (sdone) flag.
                    532:  */
                    533: static void
1.32      wiz       534: flush_appends(void)
1.1       alm       535: {
                    536:        FILE *f;
1.40    ! christos  537:        size_t count, i;
1.1       alm       538:        char buf[8 * 1024];
                    539:
1.40    ! christos  540:        for (i = 0; i < appendx; i++)
1.1       alm       541:                switch (appends[i].type) {
                    542:                case AP_STRING:
1.40    ! christos  543:                        fwrite(appends[i].s, sizeof(char), appends[i].len,
        !           544:                            outfile);
1.1       alm       545:                        break;
                    546:                case AP_FILE:
                    547:                        /*
                    548:                         * Read files probably shouldn't be cached.  Since
                    549:                         * it's not an error to read a non-existent file,
                    550:                         * it's possible that another program is interacting
1.40    ! christos  551:                         * with the sed script through the filesystem.  It
1.1       alm       552:                         * would be truly bizarre, but possible.  It's probably
                    553:                         * not that big a performance win, anyhow.
                    554:                         */
                    555:                        if ((f = fopen(appends[i].s, "r")) == NULL)
                    556:                                break;
1.40    ! christos  557:                        while ((count = fread(buf, sizeof(char), sizeof(buf), f)))
        !           558:                                (void)fwrite(buf, sizeof(char), count, outfile);
1.1       alm       559:                        (void)fclose(f);
                    560:                        break;
                    561:                }
1.40    ! christos  562:        if (ferror(outfile))
        !           563:                errx(1, "%s: %s", outfname, strerror(errno ? errno : EIO));
        !           564:        appendx = 0;
        !           565:        sdone = 0;
1.1       alm       566: }
                    567:
                    568: static void
1.40    ! christos  569: lputs(char *s, size_t len)
1.1       alm       570: {
1.40    ! christos  571:        static const char escapes[] = "\\\a\b\f\r\t\v";
        !           572:        int c;
        !           573:        size_t col, width;
        !           574:        const char *p;
        !           575: #ifdef TIOCGWINSZ
1.1       alm       576:        struct winsize win;
1.37      gdamore   577: #endif
1.40    ! christos  578:        static size_t termwidth = (size_t)-1;
        !           579:        size_t clen, i;
        !           580:        wchar_t wc;
        !           581:        mbstate_t mbs;
        !           582:
        !           583:        if (outfile != stdout)
        !           584:                termwidth = 60;
        !           585:        if (termwidth == (size_t)-1) {
        !           586:                if ((p = getenv("COLUMNS")) && *p != '\0')
        !           587:                        termwidth = (size_t)atoi(p);
        !           588: #ifdef TIOCGWINSZ
1.1       alm       589:                else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
                    590:                    win.ws_col > 0)
                    591:                        termwidth = win.ws_col;
1.37      gdamore   592: #endif
1.1       alm       593:                else
                    594:                        termwidth = 60;
1.23      ross      595:        }
1.40    ! christos  596:        if (termwidth == 0)
        !           597:                termwidth = 1;
        !           598:
        !           599:        memset(&mbs, 0, sizeof(mbs));
        !           600:        col = 0;
        !           601:        while (len != 0) {
        !           602:                clen = mbrtowc(&wc, s, len, &mbs);
        !           603:                if (clen == 0)
        !           604:                        clen = 1;
        !           605:                if (clen == (size_t)-1 || clen == (size_t)-2) {
        !           606:                        wc = (unsigned char)*s;
        !           607:                        clen = 1;
        !           608:                        memset(&mbs, 0, sizeof(mbs));
1.1       alm       609:                }
1.40    ! christos  610:                if (wc == '\n') {
        !           611:                        if (col + 1 >= termwidth)
        !           612:                                fprintf(outfile, "\\\n");
        !           613:                        fputc('$', outfile);
        !           614:                        fputc('\n', outfile);
        !           615:                        col = 0;
        !           616:                } else if (iswprint(wc)) {
        !           617:                        width = (size_t)wcwidth(wc);
        !           618:                        if (col + width >= termwidth) {
        !           619:                                fprintf(outfile, "\\\n");
        !           620:                                col = 0;
        !           621:                        }
        !           622:                        fwrite(s, 1, clen, outfile);
        !           623:                        col += width;
        !           624:                } else if (wc != L'\0' && (c = wctob(wc)) != EOF &&
        !           625:                    (p = strchr(escapes, c)) != NULL) {
        !           626:                        if (col + 2 >= termwidth) {
        !           627:                                fprintf(outfile, "\\\n");
        !           628:                                col = 0;
        !           629:                        }
        !           630:                        fprintf(outfile, "\\%c", "\\abfrtv"[p - escapes]);
        !           631:                        col += 2;
1.1       alm       632:                } else {
1.40    ! christos  633:                        if (col + 4 * clen >= termwidth) {
        !           634:                                fprintf(outfile, "\\\n");
        !           635:                                col = 0;
1.1       alm       636:                        }
1.40    ! christos  637:                        for (i = 0; i < clen; i++)
        !           638:                                fprintf(outfile, "\\%03o",
        !           639:                                    (int)(unsigned char)s[i]);
        !           640:                        col += 4 * clen;
1.1       alm       641:                }
1.40    ! christos  642:                s += clen;
        !           643:                len -= clen;
1.1       alm       644:        }
1.40    ! christos  645:        if (col + 1 >= termwidth)
        !           646:                fprintf(outfile, "\\\n");
        !           647:        (void)fputc('$', outfile);
        !           648:        (void)fputc('\n', outfile);
        !           649:        if (ferror(outfile))
        !           650:                errx(1, "%s: %s", outfname, strerror(errno ? errno : EIO));
1.1       alm       651: }
                    652:
1.40    ! christos  653: static __inline int
        !           654: regexec_e(regex_t *preg, const char *string, int eflags, int nomatch,
        !           655:        size_t slen)
1.1       alm       656: {
                    657:        int eval;
1.40    ! christos  658:
1.1       alm       659:        if (preg == NULL) {
                    660:                if (defpreg == NULL)
1.40    ! christos  661:                        errx(1, "first RE may not be empty");
1.1       alm       662:        } else
                    663:                defpreg = preg;
                    664:
1.40    ! christos  665:        /* Set anchors */
1.8       cgd       666:        match[0].rm_so = 0;
1.40    ! christos  667:        match[0].rm_eo = (regoff_t)slen;
        !           668:
1.1       alm       669:        eval = regexec(defpreg, string,
1.8       cgd       670:            nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND);
1.1       alm       671:        switch(eval) {
                    672:        case 0:
                    673:                return (1);
                    674:        case REG_NOMATCH:
                    675:                return (0);
                    676:        }
1.40    ! christos  677:        errx(1, "RE error: %s", strregerror(eval, defpreg));
1.1       alm       678:        /* NOTREACHED */
                    679: }
                    680:
                    681: /*
                    682:  * regsub - perform substitutions after a regexp match
                    683:  * Based on a routine by Henry Spencer
                    684:  */
                    685: static void
1.32      wiz       686: regsub(SPACE *sp, char *string, char *src)
1.1       alm       687: {
1.40    ! christos  688:        size_t len;
        !           689:        int no;
1.20      lukem     690:        char c, *dst;
1.1       alm       691:
                    692: #define        NEEDSP(reqlen)                                                  \
1.40    ! christos  693:        /* XXX What is the +1 for? */                                   \
1.34      itojun    694:        if (sp->len + (reqlen) + 1 >= sp->blen) {                       \
1.40    ! christos  695:                sp->blen += (reqlen) + 1024;                            \
        !           696:                sp->space = sp->back = xrealloc(sp->back, sp->blen);    \
1.1       alm       697:                dst = sp->space + sp->len;                              \
                    698:        }
                    699:
                    700:        dst = sp->space + sp->len;
                    701:        while ((c = *src++) != '\0') {
                    702:                if (c == '&')
                    703:                        no = 0;
1.24      christos  704:                else if (c == '\\' && isdigit((unsigned char)*src))
1.1       alm       705:                        no = *src++ - '0';
                    706:                else
                    707:                        no = -1;
                    708:                if (no < 0) {           /* Ordinary character. */
1.40    ! christos  709:                        if (c == '\\' && (*src == '\\' || *src == '&'))
        !           710:                                c = *src++;
1.1       alm       711:                        NEEDSP(1);
1.40    ! christos  712:                        *dst++ = c;
1.1       alm       713:                        ++sp->len;
1.40    ! christos  714:                } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) {
        !           715:                        len = (size_t)(match[no].rm_eo - match[no].rm_so);
1.1       alm       716:                        NEEDSP(len);
                    717:                        memmove(dst, string + match[no].rm_so, len);
                    718:                        dst += len;
                    719:                        sp->len += len;
                    720:                }
                    721:        }
                    722:        NEEDSP(1);
                    723:        *dst = '\0';
                    724: }
                    725:
                    726: /*
1.40    ! christos  727:  * cspace --
        !           728:  *     Concatenate space: append the source space to the destination space,
        !           729:  *     allocating new space as necessary.
1.1       alm       730:  */
                    731: void
1.38      lukem     732: cspace(SPACE *sp, const char *p, size_t len, enum e_spflag spflag)
1.1       alm       733: {
                    734:        size_t tlen;
                    735:
1.8       cgd       736:        /* Make sure SPACE has enough memory and ramp up quickly. */
                    737:        tlen = sp->len + len + 1;
1.1       alm       738:        if (tlen > sp->blen) {
1.40    ! christos  739:                sp->blen = tlen + 1024;
        !           740:                sp->space = sp->back = xrealloc(sp->back, sp->blen);
1.1       alm       741:        }
                    742:
1.8       cgd       743:        if (spflag == REPLACE)
1.1       alm       744:                sp->len = 0;
                    745:
                    746:        memmove(sp->space + sp->len, p, len);
1.8       cgd       747:
1.1       alm       748:        sp->space[sp->len += len] = '\0';
                    749: }
                    750:
                    751: /*
                    752:  * Close all cached opened files and report any errors
                    753:  */
                    754: void
1.32      wiz       755: cfclose(struct s_command *cp, struct s_command *end)
1.1       alm       756: {
                    757:
                    758:        for (; cp != end; cp = cp->next)
                    759:                switch(cp->code) {
                    760:                case 's':
                    761:                        if (cp->u.s->wfd != -1 && close(cp->u.s->wfd))
1.40    ! christos  762:                                err(1, "%s", cp->u.s->wfile);
1.1       alm       763:                        cp->u.s->wfd = -1;
                    764:                        break;
                    765:                case 'w':
                    766:                        if (cp->u.fd != -1 && close(cp->u.fd))
1.40    ! christos  767:                                err(1, "%s", cp->t);
1.1       alm       768:                        cp->u.fd = -1;
                    769:                        break;
                    770:                case '{':
                    771:                        cfclose(cp->u.c, cp->next);
                    772:                        break;
                    773:                }
                    774: }

CVSweb <webmaster@jp.NetBSD.org>