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

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