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

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