[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     ! 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: }