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

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

1.11    ! deraadt     1: /*     $OpenBSD: inp.c,v 1.10 2003/07/16 16:06:53 otto Exp $   */
1.2       niklas      2:
1.1       deraadt     3: #ifndef lint
1.11    ! deraadt     4: static char rcsid[] = "$OpenBSD: inp.c,v 1.10 2003/07/16 16:06:53 otto Exp $";
1.1       deraadt     5: #endif /* not lint */
                      6:
                      7: #include "EXTERN.h"
                      8: #include "common.h"
                      9: #include "util.h"
                     10: #include "pch.h"
                     11: #include "INTERN.h"
                     12: #include "inp.h"
                     13:
1.7       espie      14: extern bool check_only;
                     15:
1.1       deraadt    16: /* Input-file-with-indexable-lines abstract type */
                     17:
1.6       millert    18: static off_t i_size;                   /* size of the input file */
1.1       deraadt    19: static char *i_womp;                   /* plan a buffer for entire file */
                     20: static char **i_ptr;                   /* pointers to lines in i_womp */
                     21:
                     22: static int tifd = -1;                  /* plan b virtual string array */
                     23: static char *tibuf[2];                 /* plan b buffers */
                     24: static LINENUM tiline[2] = {-1, -1};   /* 1st line in each buffer */
                     25: static LINENUM lines_per_buf;          /* how many lines per buffer */
                     26: static int tireclen;                   /* length of records in tmp file */
                     27:
1.11    ! deraadt    28: void re_input(void);
        !            29:
1.1       deraadt    30: /* New patch--prepare to edit another file. */
                     31:
                     32: void
1.11    ! deraadt    33: re_input(void)
1.1       deraadt    34: {
                     35:     if (using_plan_a) {
                     36:        i_size = 0;
                     37: #ifndef lint
                     38:        if (i_ptr != Null(char**))
                     39:            free((char *)i_ptr);
                     40: #endif
                     41:        if (i_womp != Nullch)
                     42:            free(i_womp);
                     43:        i_womp = Nullch;
                     44:        i_ptr = Null(char **);
                     45:     }
                     46:     else {
                     47:        using_plan_a = TRUE;            /* maybe the next one is smaller */
1.11    ! deraadt    48:        close(tifd);
1.1       deraadt    49:        tifd = -1;
                     50:        free(tibuf[0]);
                     51:        free(tibuf[1]);
                     52:        tibuf[0] = tibuf[1] = Nullch;
                     53:        tiline[0] = tiline[1] = -1;
                     54:        tireclen = 0;
                     55:     }
                     56: }
                     57:
                     58: /* Constuct the line index, somehow or other. */
                     59:
                     60: void
                     61: scan_input(filename)
                     62: char *filename;
                     63: {
                     64:     if (!plan_a(filename))
                     65:        plan_b(filename);
                     66:     if (verbose) {
1.11    ! deraadt    67:        say("Patching file %s using Plan %s...\n", filename,
1.1       deraadt    68:          (using_plan_a ? "A" : "B") );
                     69:     }
                     70: }
                     71:
                     72: /* Try keeping everything in memory. */
                     73:
                     74: bool
                     75: plan_a(filename)
                     76: char *filename;
                     77: {
                     78:     int ifd, statfailed;
1.11    ! deraadt    79:     char *s;
        !            80:     LINENUM iline;
1.1       deraadt    81:     char lbuf[MAXLINELEN];
                     82:
1.8       millert    83:     if (!filename || *filename == '\0')
                     84:        return FALSE;
                     85:
1.1       deraadt    86:     statfailed = stat(filename, &filestat);
                     87:     if (statfailed && ok_to_create_file) {
                     88:        if (verbose)
1.11    ! deraadt    89:            say("(Creating file %s...)\n",filename);
1.7       espie      90:            /* in check_patch case, we still display `Creating file' even
                     91:               though we're not. The rule is that -C should be as similar
                     92:               to normal patch behavior as possible
                     93:             */
1.11    ! deraadt    94:        if (check_only)
1.7       espie      95:            return TRUE;
1.1       deraadt    96:        makedirs(filename, TRUE);
                     97:        close(creat(filename, 0666));
                     98:        statfailed = stat(filename, &filestat);
                     99:     }
1.7       espie     100:     if (statfailed && check_only)
1.11    ! deraadt   101:         fatal("%s not found, -C mode, can't probe further\n", filename);
1.1       deraadt   102:     /* For nonexistent or read-only files, look for RCS or SCCS versions.  */
                    103:     if (statfailed
                    104:        /* No one can write to it.  */
                    105:        || (filestat.st_mode & 0222) == 0
                    106:        /* I can't write to it.  */
                    107:        || ((filestat.st_mode & 0022) == 0 && filestat.st_uid != myuid)) {
                    108:        struct stat cstat;
                    109:        char *cs = Nullch;
1.8       millert   110:        char *filebase, *filedir;
1.1       deraadt   111:
                    112:        filebase = basename(filename);
1.8       millert   113:        filedir = dirname(filename);
1.1       deraadt   114:
1.8       millert   115:        /* Leave room in lbuf for the diff command.  */
1.1       deraadt   116:        s = lbuf + 20;
                    117:
1.11    ! deraadt   118: #define try(f, a1, a2, a3) (snprintf(s, sizeof lbuf - 20, f, a1, a2, a3), stat(s, &cstat) == 0)
1.8       millert   119:        if (   try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX)
                    120:            || try("%s/RCS/%s%s", filedir, filebase,         "")
                    121:            || try(    "%s/%s%s", filedir, filebase, RCSSUFFIX)) {
1.11    ! deraadt   122:            snprintf(buf, sizeof buf, CHECKOUT, filename);
        !           123:            snprintf(lbuf, sizeof lbuf, RCSDIFF, filename);
1.1       deraadt   124:            cs = "RCS";
1.8       millert   125:        } else if (   try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase)
                    126:                   || try(     "%s/%s%s", filedir, SCCSPREFIX, filebase)) {
1.11    ! deraadt   127:            snprintf(buf, sizeof buf, GET, s);
        !           128:            snprintf(lbuf, sizeof lbuf, SCCSDIFF, s, filename);
1.1       deraadt   129:            cs = "SCCS";
                    130:        } else if (statfailed)
1.11    ! deraadt   131:            fatal("can't find %s\n", filename);
1.1       deraadt   132:        /* else we can't write to it but it's not under a version
                    133:           control system, so just proceed.  */
                    134:        if (cs) {
                    135:            if (!statfailed) {
                    136:                if ((filestat.st_mode & 0222) != 0)
                    137:                    /* The owner can write to it.  */
1.11    ! deraadt   138:                    fatal("file %s seems to be locked by somebody else under %s\n",
1.1       deraadt   139:                           filename, cs);
                    140:                /* It might be checked out unlocked.  See if it's safe to
                    141:                   check out the default version locked.  */
                    142:                if (verbose)
1.11    ! deraadt   143:                    say("Comparing file %s to default %s version...\n",
1.1       deraadt   144:                         filename, cs);
                    145:                if (system(lbuf))
1.11    ! deraadt   146:                    fatal("can't check out file %s: differs from default %s version\n",
1.1       deraadt   147:                           filename, cs);
                    148:            }
                    149:            if (verbose)
1.11    ! deraadt   150:                say("Checking out file %s from %s...\n", filename, cs);
1.1       deraadt   151:            if (system(buf) || stat(filename, &filestat))
1.11    ! deraadt   152:                fatal("can't check out file %s from %s\n", filename, cs);
1.1       deraadt   153:        }
                    154:     }
                    155:     filemode = filestat.st_mode;
                    156:     if (!S_ISREG(filemode))
1.11    ! deraadt   157:        fatal("%s is not a normal file--can't patch\n", filename);
1.1       deraadt   158:     i_size = filestat.st_size;
                    159:     if (out_of_mem) {
                    160:        set_hunkmax();          /* make sure dynamic arrays are allocated */
                    161:        out_of_mem = FALSE;
                    162:        return FALSE;                   /* force plan b because plan a bombed */
                    163:     }
                    164: #ifdef lint
                    165:     i_womp = Nullch;
                    166: #else
                    167:     i_womp = malloc((MEM)(i_size+2));  /* lint says this may alloc less than */
                    168:                                        /* i_size, but that's okay, I think. */
                    169: #endif
                    170:     if (i_womp == Nullch)
                    171:        return FALSE;
1.6       millert   172:     if ((ifd = open(filename, O_RDONLY)) < 0)
1.11    ! deraadt   173:        pfatal("can't open file %s", filename);
1.1       deraadt   174: #ifndef lint
1.6       millert   175:     if (read(ifd, i_womp, (size_t)i_size) != i_size) {
1.11    ! deraadt   176:        close(ifd);     /* probably means i_size > 15 or 16 bits worth */
1.1       deraadt   177:        free(i_womp);   /* at this point it doesn't matter if i_womp was */
                    178:        return FALSE;   /*   undersized. */
                    179:     }
                    180: #endif
1.11    ! deraadt   181:     close(ifd);
1.1       deraadt   182:     if (i_size && i_womp[i_size-1] != '\n')
                    183:        i_womp[i_size++] = '\n';
                    184:     i_womp[i_size] = '\0';
                    185:
                    186:     /* count the lines in the buffer so we know how many pointers we need */
                    187:
                    188:     iline = 0;
                    189:     for (s=i_womp; *s; s++) {
                    190:        if (*s == '\n')
                    191:            iline++;
                    192:     }
                    193: #ifdef lint
                    194:     i_ptr = Null(char**);
                    195: #else
                    196:     i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
                    197: #endif
                    198:     if (i_ptr == Null(char **)) {      /* shucks, it was a near thing */
                    199:        free((char *)i_womp);
                    200:        return FALSE;
                    201:     }
1.11    ! deraadt   202:
1.1       deraadt   203:     /* now scan the buffer and build pointer array */
                    204:
                    205:     iline = 1;
                    206:     i_ptr[iline] = i_womp;
                    207:     for (s=i_womp; *s; s++) {
                    208:        if (*s == '\n')
                    209:            i_ptr[++iline] = s+1;       /* these are NOT null terminated */
                    210:     }
                    211:     input_lines = iline - 1;
                    212:
                    213:     /* now check for revision, if any */
                    214:
1.11    ! deraadt   215:     if (revision != Nullch) {
1.1       deraadt   216:        if (!rev_in_string(i_womp)) {
                    217:            if (force) {
                    218:                if (verbose)
1.11    ! deraadt   219:                    say(
1.1       deraadt   220: "Warning: this file doesn't appear to be the %s version--patching anyway.\n",
                    221:                        revision);
                    222:            }
                    223:            else if (batch) {
1.11    ! deraadt   224:                fatal(
1.1       deraadt   225: "this file doesn't appear to be the %s version--aborting.\n", revision);
                    226:            }
                    227:            else {
1.11    ! deraadt   228:                ask(
1.1       deraadt   229: "This file doesn't appear to be the %s version--patch anyway? [n] ",
                    230:                    revision);
                    231:            if (*buf != 'y')
1.11    ! deraadt   232:                fatal("aborted\n");
1.1       deraadt   233:            }
                    234:        }
                    235:        else if (verbose)
1.11    ! deraadt   236:            say("Good.  This file appears to be the %s version.\n",
1.1       deraadt   237:                revision);
                    238:     }
                    239:     return TRUE;                       /* plan a will work */
                    240: }
                    241:
                    242: /* Keep (virtually) nothing in memory. */
                    243:
                    244: void
                    245: plan_b(filename)
                    246: char *filename;
                    247: {
1.11    ! deraadt   248:     FILE *ifp;
        !           249:     int i = 0;
        !           250:     int maxlen = 1;
        !           251:     bool found_revision = (revision == Nullch);
1.1       deraadt   252:
                    253:     using_plan_a = FALSE;
                    254:     if ((ifp = fopen(filename, "r")) == Nullfp)
1.11    ! deraadt   255:        pfatal("can't open file %s", filename);
1.4       deraadt   256:     (void) unlink(TMPINNAME);
1.3       deraadt   257:     if ((tifd = open(TMPINNAME, O_EXCL|O_CREAT|O_WRONLY, 0666)) < 0)
1.11    ! deraadt   258:        pfatal("can't open file %s", TMPINNAME);
1.1       deraadt   259:     while (fgets(buf, sizeof buf, ifp) != Nullch) {
                    260:        if (revision != Nullch && !found_revision && rev_in_string(buf))
                    261:            found_revision = TRUE;
                    262:        if ((i = strlen(buf)) > maxlen)
                    263:            maxlen = i;                 /* find longest line */
                    264:     }
                    265:     if (revision != Nullch) {
                    266:        if (!found_revision) {
                    267:            if (force) {
                    268:                if (verbose)
1.11    ! deraadt   269:                    say(
1.1       deraadt   270: "Warning: this file doesn't appear to be the %s version--patching anyway.\n",
                    271:                        revision);
                    272:            }
                    273:            else if (batch) {
1.11    ! deraadt   274:                fatal(
1.1       deraadt   275: "this file doesn't appear to be the %s version--aborting.\n", revision);
                    276:            }
                    277:            else {
1.11    ! deraadt   278:                ask(
1.1       deraadt   279: "This file doesn't appear to be the %s version--patch anyway? [n] ",
                    280:                    revision);
                    281:                if (*buf != 'y')
1.11    ! deraadt   282:                    fatal("aborted\n");
1.1       deraadt   283:            }
                    284:        }
                    285:        else if (verbose)
1.11    ! deraadt   286:            say("Good.  This file appears to be the %s version.\n",
1.1       deraadt   287:                revision);
                    288:     }
1.11    ! deraadt   289:     fseek(ifp, 0L, 0);         /* rewind file */
1.1       deraadt   290:     lines_per_buf = BUFFERSIZE / maxlen;
                    291:     tireclen = maxlen;
                    292:     tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
1.9       deraadt   293:     if (tibuf[0] == Nullch)
1.11    ! deraadt   294:        fatal("out of memory\n");
1.1       deraadt   295:     tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
                    296:     if (tibuf[1] == Nullch)
1.11    ! deraadt   297:        fatal("out of memory\n");
1.1       deraadt   298:     for (i=1; ; i++) {
                    299:        if (! (i % lines_per_buf))      /* new block */
                    300:            if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
1.11    ! deraadt   301:                pfatal("can't write temp file");
1.1       deraadt   302:        if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
                    303:          == Nullch) {
                    304:            input_lines = i - 1;
                    305:            if (i % lines_per_buf)
                    306:                if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
1.11    ! deraadt   307:                    pfatal("can't write temp file");
1.1       deraadt   308:            break;
                    309:        }
                    310:     }
1.11    ! deraadt   311:     fclose(ifp);
        !           312:     close(tifd);
1.6       millert   313:     if ((tifd = open(TMPINNAME, O_RDONLY)) < 0) {
1.11    ! deraadt   314:        pfatal("can't reopen file %s", TMPINNAME);
1.1       deraadt   315:     }
                    316: }
                    317:
                    318: /* Fetch a line from the input file, \n terminated, not necessarily \0. */
                    319:
                    320: char *
                    321: ifetch(line,whichbuf)
1.11    ! deraadt   322: LINENUM line;
1.1       deraadt   323: int whichbuf;                          /* ignored when file in memory */
                    324: {
1.10      otto      325:     if (line < 1 || line > input_lines) {
1.11    ! deraadt   326:        say("No such line %ld in input file, ignoring\n", line);
1.10      otto      327:        return NULL;
                    328:     }
1.1       deraadt   329:     if (using_plan_a)
                    330:        return i_ptr[line];
                    331:     else {
                    332:        LINENUM offline = line % lines_per_buf;
                    333:        LINENUM baseline = line - offline;
                    334:
                    335:        if (tiline[0] == baseline)
                    336:            whichbuf = 0;
                    337:        else if (tiline[1] == baseline)
                    338:            whichbuf = 1;
                    339:        else {
                    340:            tiline[whichbuf] = baseline;
                    341: #ifndef lint           /* complains of long accuracy */
1.11    ! deraadt   342:            lseek(tifd, (off_t)(baseline / lines_per_buf * BUFFERSIZE), 0);
1.1       deraadt   343: #endif
                    344:            if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
1.11    ! deraadt   345:                pfatal("error reading tmp file %s", TMPINNAME);
1.1       deraadt   346:        }
                    347:        return tibuf[whichbuf] + (tireclen*offline);
                    348:     }
                    349: }
                    350:
                    351: /* True if the string argument contains the revision number we want. */
                    352:
                    353: bool
                    354: rev_in_string(string)
                    355: char *string;
                    356: {
1.11    ! deraadt   357:     char *s;
        !           358:     int patlen;
1.1       deraadt   359:
                    360:     if (revision == Nullch)
                    361:        return TRUE;
                    362:     patlen = strlen(revision);
                    363:     if (strnEQ(string,revision,patlen) && isspace(string[patlen]))
                    364:        return TRUE;
                    365:     for (s = string; *s; s++) {
1.11    ! deraadt   366:        if (isspace(*s) && strnEQ(s+1, revision, patlen) &&
1.1       deraadt   367:                isspace(s[patlen+1] )) {
                    368:            return TRUE;
                    369:        }
                    370:     }
                    371:     return FALSE;
                    372: }