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