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