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