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

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