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