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