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

Annotation of src/usr.bin/patch/inp.c, Revision 1.15

1.15    ! itojun      1: /*     $NetBSD: inp.c,v 1.14 2003/07/08 01:55:35 kristerw Exp $        */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1988, Larry Wall
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following condition
        !             8:  * is met:
        !             9:  *  1. Redistributions of source code must retain the above copyright
        !            10:  *     notice, this condition and the following disclaimer.
        !            11:  *
        !            12:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            13:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            14:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            15:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            16:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            17:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            18:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            19:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            20:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            21:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            22:  * SUCH DAMAGE.
        !            23:  */
        !            24:
1.4       christos   25: #include <sys/cdefs.h>
1.2       mycroft    26: #ifndef lint
1.15    ! itojun     27: __RCSID("$NetBSD: inp.c,v 1.14 2003/07/08 01:55:35 kristerw Exp $");
1.2       mycroft    28: #endif /* not lint */
1.1       cgd        29:
                     30: #include "EXTERN.h"
1.7       kristerw   31: #include "backupfile.h"
1.1       cgd        32: #include "common.h"
                     33: #include "util.h"
                     34: #include "pch.h"
                     35: #include "INTERN.h"
                     36: #include "inp.h"
                     37:
1.4       christos   38: #include <stdlib.h>
                     39: #include <unistd.h>
                     40: #include <fcntl.h>
                     41:
1.13      kristerw   42: static void plan_a(char *);
1.10      kristerw   43: static bool rev_in_string(char *);
                     44:
1.9       kristerw   45: /* Input-file-with-indexable-lines abstract type. */
1.1       cgd        46:
1.11      kristerw   47: static size_t i_size;                  /* Size of the input file */
1.9       kristerw   48: static char *i_womp;                   /* Plan a buffer for entire file */
                     49: static char **i_ptr;                   /* Pointers to lines in i_womp */
1.1       cgd        50:
1.9       kristerw   51: /*
1.13      kristerw   52:  * New patch -- prepare to edit another file.
1.9       kristerw   53:  */
1.1       cgd        54: void
1.7       kristerw   55: re_input(void)
1.1       cgd        56: {
1.13      kristerw   57:        i_size = 0;
1.7       kristerw   58:
1.13      kristerw   59:        if (i_ptr != NULL)
                     60:                free(i_ptr);
                     61:        if (i_womp != NULL)
                     62:                free(i_womp);
                     63:        i_womp = NULL;
                     64:        i_ptr = NULL;
1.1       cgd        65: }
                     66:
1.9       kristerw   67: /*
1.13      kristerw   68:  * Construct the line index, somehow or other.
1.9       kristerw   69:  */
1.1       cgd        70: void
1.7       kristerw   71: scan_input(char *filename)
1.1       cgd        72: {
1.13      kristerw   73:        plan_a(filename);
                     74:        if (verbose)
                     75:                say("Patching file %s using Plan A...\n", filename);
1.1       cgd        76: }
                     77:
1.9       kristerw   78: /*
                     79:  * Try keeping everything in memory.
                     80:  */
1.13      kristerw   81: static void
1.7       kristerw   82: plan_a(char *filename)
1.1       cgd        83: {
1.9       kristerw   84:        int ifd, statfailed;
                     85:        char *s;
                     86:        LINENUM iline;
                     87:        char lbuf[MAXLINELEN];
                     88:
1.1       cgd        89:        statfailed = stat(filename, &filestat);
1.9       kristerw   90:        if (statfailed && ok_to_create_file) {
                     91:                if (verbose)
                     92:                        say("(Creating file %s...)\n",filename);
                     93:                makedirs(filename, TRUE);
                     94:                close(creat(filename, 0666));
                     95:                statfailed = stat(filename, &filestat);
                     96:        }
                     97:        /*
                     98:         * For nonexistent or read-only files, look for RCS or SCCS
                     99:         * versions.
                    100:         */
                    101:        if (statfailed ||
                    102:            /* No one can write to it. */
                    103:            (filestat.st_mode & 0222) == 0 ||
                    104:            /* I can't write to it. */
                    105:            ((filestat.st_mode & 0022) == 0 && filestat.st_uid != myuid)) {
                    106:                struct stat cstat;
1.14      kristerw  107:                const char *cs = NULL;
1.9       kristerw  108:                char *filebase;
1.11      kristerw  109:                size_t pathlen;
1.9       kristerw  110:
                    111:                filebase = basename(filename);
                    112:                pathlen = filebase - filename;
                    113:
                    114:                /*
                    115:                 * Put any leading path into `s'.
                    116:                 * Leave room in lbuf for the diff command.
                    117:                 */
                    118:                s = lbuf + 20;
                    119:                strncpy(s, filename, pathlen);
1.1       cgd       120:
                    121: #define try(f, a1, a2) (Sprintf(s + pathlen, f, a1, a2), stat(s, &cstat) == 0)
1.4       christos  122: #define try1(f, a1) (Sprintf(s + pathlen, f, a1), stat(s, &cstat) == 0)
1.9       kristerw  123:                if (try("RCS/%s%s", filebase, RCSSUFFIX) ||
                    124:                    try1("RCS/%s"  , filebase) ||
                    125:                    try("%s%s", filebase, RCSSUFFIX)) {
                    126:                        Sprintf(buf, CHECKOUT, filename);
                    127:                        Sprintf(lbuf, RCSDIFF, filename);
                    128:                        cs = "RCS";
                    129:                } else if (try("SCCS/%s%s", SCCSPREFIX, filebase) ||
                    130:                           try("%s%s", SCCSPREFIX, filebase)) {
                    131:                        Sprintf(buf, GET, s);
                    132:                        Sprintf(lbuf, SCCSDIFF, s, filename);
                    133:                        cs = "SCCS";
                    134:                } else if (statfailed)
                    135:                        fatal("can't find %s\n", filename);
                    136:                /*
                    137:                 * else we can't write to it but it's not under a version
                    138:                 * control system, so just proceed.
                    139:                 */
                    140:                if (cs) {
                    141:                        if (!statfailed) {
                    142:                                if ((filestat.st_mode & 0222) != 0)
                    143:                                        /* The owner can write to it.  */
                    144:                                        fatal(
                    145: "file %s seems to be locked by somebody else under %s\n",
                    146:                                              filename, cs);
                    147:                                /*
                    148:                                 * It might be checked out unlocked.  See if
                    149:                                 * it's safe to check out the default version
                    150:                                 * locked.
                    151:                                 */
                    152:                                if (verbose)
                    153:                                        say(
                    154: "Comparing file %s to default %s version...\n",
                    155:                                            filename, cs);
                    156:                                if (system(lbuf))
                    157:                                        fatal(
                    158: "can't check out file %s: differs from default %s version\n",
                    159:                                              filename, cs);
                    160:                        }
                    161:                        if (verbose)
                    162:                                say("Checking out file %s from %s...\n",
                    163:                                    filename, cs);
                    164:                        if (system(buf) || stat(filename, &filestat))
                    165:                                fatal("can't check out file %s from %s\n",
                    166:                                      filename, cs);
                    167:                }
                    168:        }
                    169:        if (old_file_is_dev_null &&
                    170:            ok_to_create_file &&
                    171:            (filestat.st_size != 0)) {
                    172:                fatal(
                    173: "patch creates new file but existing file %s not empty\n",
                    174:                      filename);
1.1       cgd       175:        }
1.6       sommerfe  176:
1.9       kristerw  177:        filemode = filestat.st_mode;
                    178:        if (!S_ISREG(filemode))
                    179:                fatal("%s is not a normal file--can't patch\n", filename);
                    180:        i_size = filestat.st_size;
                    181:
1.12      kristerw  182:        i_womp = xmalloc(i_size + 2);
1.9       kristerw  183:        if ((ifd = open(filename, 0)) < 0)
                    184:                pfatal("can't open file %s", filename);
1.13      kristerw  185:        if (read(ifd, i_womp, i_size) != i_size)
                    186:                pfatal("read error");
1.9       kristerw  187:        Close(ifd);
                    188:        if (i_size && i_womp[i_size - 1] != '\n')
                    189:                i_womp[i_size++] = '\n';
                    190:        i_womp[i_size] = '\0';
                    191:
                    192:        /*
                    193:         * Count the lines in the buffer so we know how many pointers we
                    194:         * need.
                    195:         */
                    196:        iline = 0;
                    197:        for (s = i_womp; *s; s++) {
                    198:                if (*s == '\n')
                    199:                        iline++;
                    200:        }
1.12      kristerw  201:        i_ptr = xmalloc((iline + 2) * sizeof(char *));
1.1       cgd       202:
1.9       kristerw  203:        /* Now scan the buffer and build pointer array. */
                    204:        iline = 1;
                    205:        i_ptr[iline] = i_womp;
                    206:        for (s = i_womp; *s; s++) {
                    207:                if (*s == '\n') {
                    208:                        /* These are NOT null terminated. */
                    209:                        i_ptr[++iline] = s + 1;
                    210:                }
                    211:        }
                    212:        input_lines = iline - 1;
1.1       cgd       213:
1.9       kristerw  214:        /* Now check for revision, if any. */
                    215:        if (revision != NULL) {
                    216:                if (!rev_in_string(i_womp)) {
                    217:                        if (force) {
                    218:                                if (verbose)
                    219:                                        say(
1.1       cgd       220: "Warning: this file doesn't appear to be the %s version--patching anyway.\n",
                    221:                        revision);
1.9       kristerw  222:                        } else if (batch) {
                    223:                                fatal(
1.1       cgd       224: "this file doesn't appear to be the %s version--aborting.\n", revision);
1.9       kristerw  225:                        } else {
                    226:                                ask(
1.1       cgd       227: "This file doesn't appear to be the %s version--patch anyway? [n] ",
                    228:                    revision);
1.9       kristerw  229:                                if (*buf != 'y')
                    230:                                        fatal("aborted\n");
                    231:                        }
                    232:                } else if (verbose)
                    233:                        say("Good.  This file appears to be the %s version.\n",
                    234:                            revision);
                    235:        }
1.1       cgd       236: }
                    237:
1.9       kristerw  238: /*
                    239:  * Fetch a line from the input file, \n terminated, not necessarily \0.
                    240:  */
1.14      kristerw  241: const char *
1.13      kristerw  242: ifetch(LINENUM line)
1.1       cgd       243: {
1.9       kristerw  244:        if (line < 1 || line > input_lines)
                    245:                return "";
1.13      kristerw  246:
                    247:        return i_ptr[line];
1.1       cgd       248: }
                    249:
1.9       kristerw  250: /*
                    251:  * True if the string argument contains the revision number we want.
                    252:  */
1.10      kristerw  253: static bool
1.7       kristerw  254: rev_in_string(char *string)
1.1       cgd       255: {
1.9       kristerw  256:        char *s;
1.11      kristerw  257:        size_t patlen;
1.1       cgd       258:
1.9       kristerw  259:        if (revision == NULL)
                    260:                return TRUE;
                    261:        patlen = strlen(revision);
                    262:        if (strnEQ(string,revision,patlen) &&
                    263:            isspace((unsigned char)string[patlen]))
                    264:                return TRUE;
                    265:        for (s = string; *s; s++) {
                    266:                if (isspace((unsigned char)*s) &&
                    267:                    strnEQ(s + 1, revision, patlen) &&
                    268:                    isspace((unsigned char)s[patlen + 1] )) {
                    269:                        return TRUE;
                    270:                }
1.1       cgd       271:        }
1.13      kristerw  272:        return FALSE;
1.1       cgd       273: }

CVSweb <webmaster@jp.NetBSD.org>