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