1 | /* reading patches */
|
---|
2 |
|
---|
3 | /* $Id: pch.c,v 1.44 2003/05/20 14:03:17 eggert Exp $ */
|
---|
4 |
|
---|
5 | /* Copyright (C) 1986, 1987, 1988 Larry Wall
|
---|
6 |
|
---|
7 | Copyright (C) 1990, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2001,
|
---|
8 | 2002, 2003 Free Software Foundation, Inc.
|
---|
9 |
|
---|
10 | This program is free software; you can redistribute it and/or modify
|
---|
11 | it under the terms of the GNU General Public License as published by
|
---|
12 | the Free Software Foundation; either version 2, or (at your option)
|
---|
13 | any later version.
|
---|
14 |
|
---|
15 | This program is distributed in the hope that it will be useful,
|
---|
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
18 | GNU General Public License for more details.
|
---|
19 |
|
---|
20 | You should have received a copy of the GNU General Public License
|
---|
21 | along with this program; see the file COPYING.
|
---|
22 | If not, write to the Free Software Foundation,
|
---|
23 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
---|
24 |
|
---|
25 | #define XTERN extern
|
---|
26 | #include <common.h>
|
---|
27 | #include <backupfile.h>
|
---|
28 | #include <dirname.h>
|
---|
29 | #include <inp.h>
|
---|
30 | #include <quotearg.h>
|
---|
31 | #include <util.h>
|
---|
32 | #undef XTERN
|
---|
33 | #define XTERN
|
---|
34 | #include <pch.h>
|
---|
35 |
|
---|
36 | #define INITHUNKMAX 125 /* initial dynamic allocation size */
|
---|
37 |
|
---|
38 | /* Patch (diff listing) abstract type. */
|
---|
39 |
|
---|
40 | static FILE *pfp; /* patch file pointer */
|
---|
41 | static int p_says_nonexistent[2]; /* [0] for old file, [1] for new:
|
---|
42 | 0 for existent and nonempty,
|
---|
43 | 1 for existent and probably (but not necessarily) empty,
|
---|
44 | 2 for nonexistent */
|
---|
45 | static int p_rfc934_nesting; /* RFC 934 nesting level */
|
---|
46 | static time_t p_timestamp[2]; /* timestamps in patch headers */
|
---|
47 | static off_t p_filesize; /* size of the patch file */
|
---|
48 | static LINENUM p_first; /* 1st line number */
|
---|
49 | static LINENUM p_newfirst; /* 1st line number of replacement */
|
---|
50 | static LINENUM p_ptrn_lines; /* # lines in pattern */
|
---|
51 | static LINENUM p_repl_lines; /* # lines in replacement text */
|
---|
52 | static LINENUM p_end = -1; /* last line in hunk */
|
---|
53 | static LINENUM p_max; /* max allowed value of p_end */
|
---|
54 | static LINENUM p_prefix_context; /* # of prefix context lines */
|
---|
55 | static LINENUM p_suffix_context; /* # of suffix context lines */
|
---|
56 | static LINENUM p_input_line; /* current line # from patch file */
|
---|
57 | static char **p_line; /* the text of the hunk */
|
---|
58 | static size_t *p_len; /* line length including \n if any */
|
---|
59 | static char *p_Char; /* +, -, and ! */
|
---|
60 | static LINENUM hunkmax = INITHUNKMAX; /* size of above arrays */
|
---|
61 | static int p_indent; /* indent to patch */
|
---|
62 | static bool p_strip_trailing_cr; /* true if stripping trailing \r */
|
---|
63 | static bool p_pass_comments_through; /* true if not ignoring # lines */
|
---|
64 | static file_offset p_base; /* where to intuit this time */
|
---|
65 | static LINENUM p_bline; /* line # of p_base */
|
---|
66 | static file_offset p_start; /* where intuit found a patch */
|
---|
67 | static LINENUM p_sline; /* and the line number for it */
|
---|
68 | static LINENUM p_hunk_beg; /* line number of current hunk */
|
---|
69 | static LINENUM p_efake = -1; /* end of faked up lines--don't free */
|
---|
70 | static LINENUM p_bfake = -1; /* beg of faked up lines */
|
---|
71 |
|
---|
72 | enum nametype { OLD, NEW, INDEX, NONE };
|
---|
73 |
|
---|
74 | static char *scan_linenum (char *, LINENUM *);
|
---|
75 | static enum diff intuit_diff_type (void);
|
---|
76 | static enum nametype best_name (char * const *, int const *);
|
---|
77 | static int prefix_components (char *, bool);
|
---|
78 | static size_t pget_line (int, int, bool, bool);
|
---|
79 | static size_t get_line (void);
|
---|
80 | static bool incomplete_line (void);
|
---|
81 | static bool grow_hunkmax (void);
|
---|
82 | static void malformed (void) __attribute__ ((noreturn));
|
---|
83 | static void next_intuit_at (file_offset, LINENUM);
|
---|
84 | static void skip_to (file_offset, LINENUM);
|
---|
85 | static char get_ed_command_letter (char const *);
|
---|
86 |
|
---|
87 | /* Prepare to look for the next patch in the patch file. */
|
---|
88 |
|
---|
89 | void
|
---|
90 | re_patch (void)
|
---|
91 | {
|
---|
92 | p_first = 0;
|
---|
93 | p_newfirst = 0;
|
---|
94 | p_ptrn_lines = 0;
|
---|
95 | p_repl_lines = 0;
|
---|
96 | p_end = -1;
|
---|
97 | p_max = 0;
|
---|
98 | p_indent = 0;
|
---|
99 | p_strip_trailing_cr = false;
|
---|
100 | }
|
---|
101 |
|
---|
102 | /* Open the patch file at the beginning of time. */
|
---|
103 |
|
---|
104 | void
|
---|
105 | open_patch_file (char const *filename)
|
---|
106 | {
|
---|
107 | file_offset file_pos = 0;
|
---|
108 | struct stat st;
|
---|
109 | if (!filename || !*filename || strEQ (filename, "-"))
|
---|
110 | {
|
---|
111 | file_offset stdin_pos;
|
---|
112 | #if HAVE_SETMODE_DOS
|
---|
113 | if (binary_transput)
|
---|
114 | {
|
---|
115 | if (isatty (STDIN_FILENO))
|
---|
116 | fatal ("cannot read binary data from tty on this platform");
|
---|
117 | setmode (STDIN_FILENO, O_BINARY);
|
---|
118 | }
|
---|
119 | #endif
|
---|
120 | if (fstat (STDIN_FILENO, &st) != 0)
|
---|
121 | pfatal ("fstat");
|
---|
122 | if (S_ISREG (st.st_mode) && (stdin_pos = file_tell (stdin)) != -1)
|
---|
123 | {
|
---|
124 | pfp = stdin;
|
---|
125 | file_pos = stdin_pos;
|
---|
126 | }
|
---|
127 | else
|
---|
128 | {
|
---|
129 | size_t charsread;
|
---|
130 | int exclusive = TMPPATNAME_needs_removal ? 0 : O_EXCL;
|
---|
131 | TMPPATNAME_needs_removal = 1;
|
---|
132 | pfp = fdopen (create_file (TMPPATNAME,
|
---|
133 | O_RDWR | O_BINARY | exclusive,
|
---|
134 | (mode_t) 0),
|
---|
135 | "w+b");
|
---|
136 | if (!pfp)
|
---|
137 | pfatal ("Can't open stream for file %s", quotearg (TMPPATNAME));
|
---|
138 | for (st.st_size = 0;
|
---|
139 | (charsread = fread (buf, 1, bufsize, stdin)) != 0;
|
---|
140 | st.st_size += charsread)
|
---|
141 | if (fwrite (buf, 1, charsread, pfp) != charsread)
|
---|
142 | write_fatal ();
|
---|
143 | if (ferror (stdin) || fclose (stdin) != 0)
|
---|
144 | read_fatal ();
|
---|
145 | if (fflush (pfp) != 0
|
---|
146 | || file_seek (pfp, (file_offset) 0, SEEK_SET) != 0)
|
---|
147 | write_fatal ();
|
---|
148 | }
|
---|
149 | }
|
---|
150 | else
|
---|
151 | {
|
---|
152 | pfp = fopen (filename, binary_transput ? "rb" : "r");
|
---|
153 | if (!pfp)
|
---|
154 | pfatal ("Can't open patch file %s", quotearg (filename));
|
---|
155 | if (fstat (fileno (pfp), &st) != 0)
|
---|
156 | pfatal ("fstat");
|
---|
157 | }
|
---|
158 | p_filesize = st.st_size;
|
---|
159 | if (p_filesize != (file_offset) p_filesize)
|
---|
160 | fatal ("patch file is too long");
|
---|
161 | next_intuit_at (file_pos, (LINENUM) 1);
|
---|
162 | set_hunkmax();
|
---|
163 | }
|
---|
164 |
|
---|
165 | /* Make sure our dynamically realloced tables are malloced to begin with. */
|
---|
166 |
|
---|
167 | void
|
---|
168 | set_hunkmax (void)
|
---|
169 | {
|
---|
170 | if (!p_line)
|
---|
171 | p_line = (char **) malloc (hunkmax * sizeof *p_line);
|
---|
172 | if (!p_len)
|
---|
173 | p_len = (size_t *) malloc (hunkmax * sizeof *p_len);
|
---|
174 | if (!p_Char)
|
---|
175 | p_Char = malloc (hunkmax * sizeof *p_Char);
|
---|
176 | }
|
---|
177 |
|
---|
178 | /* Enlarge the arrays containing the current hunk of patch. */
|
---|
179 |
|
---|
180 | static bool
|
---|
181 | grow_hunkmax (void)
|
---|
182 | {
|
---|
183 | hunkmax *= 2;
|
---|
184 | assert (p_line && p_len && p_Char);
|
---|
185 | if ((p_line = (char **) realloc (p_line, hunkmax * sizeof (*p_line)))
|
---|
186 | && (p_len = (size_t *) realloc (p_len, hunkmax * sizeof (*p_len)))
|
---|
187 | && (p_Char = realloc (p_Char, hunkmax * sizeof (*p_Char))))
|
---|
188 | return true;
|
---|
189 | if (!using_plan_a)
|
---|
190 | memory_fatal ();
|
---|
191 | /* Don't free previous values of p_line etc.,
|
---|
192 | since some broken implementations free them for us.
|
---|
193 | Whatever is null will be allocated again from within plan_a (),
|
---|
194 | of all places. */
|
---|
195 | return false;
|
---|
196 | }
|
---|
197 |
|
---|
198 | /* True if the remainder of the patch file contains a diff of some sort. */
|
---|
199 |
|
---|
200 | bool
|
---|
201 | there_is_another_patch (void)
|
---|
202 | {
|
---|
203 | if (p_base != 0 && p_base >= p_filesize) {
|
---|
204 | if (verbosity == VERBOSE)
|
---|
205 | say ("done\n");
|
---|
206 | return false;
|
---|
207 | }
|
---|
208 | if (verbosity == VERBOSE)
|
---|
209 | say ("Hmm...");
|
---|
210 | diff_type = intuit_diff_type();
|
---|
211 | if (diff_type == NO_DIFF) {
|
---|
212 | if (verbosity == VERBOSE)
|
---|
213 | say (p_base
|
---|
214 | ? " Ignoring the trailing garbage.\ndone\n"
|
---|
215 | : " I can't seem to find a patch in there anywhere.\n");
|
---|
216 | if (! p_base && p_filesize)
|
---|
217 | fatal ("Only garbage was found in the patch input.");
|
---|
218 | return false;
|
---|
219 | }
|
---|
220 | if (skip_rest_of_patch)
|
---|
221 | {
|
---|
222 | Fseek (pfp, p_start, SEEK_SET);
|
---|
223 | p_input_line = p_sline - 1;
|
---|
224 | return true;
|
---|
225 | }
|
---|
226 | if (verbosity == VERBOSE)
|
---|
227 | say (" %sooks like %s to me...\n",
|
---|
228 | (p_base == 0 ? "L" : "The next patch l"),
|
---|
229 | diff_type == UNI_DIFF ? "a unified diff" :
|
---|
230 | diff_type == CONTEXT_DIFF ? "a context diff" :
|
---|
231 | diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
|
---|
232 | diff_type == NORMAL_DIFF ? "a normal diff" :
|
---|
233 | "an ed script" );
|
---|
234 |
|
---|
235 | if (verbosity != SILENT)
|
---|
236 | {
|
---|
237 | if (p_indent)
|
---|
238 | say ("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s");
|
---|
239 | if (p_strip_trailing_cr)
|
---|
240 | say ("(Stripping trailing CRs from patch.)\n");
|
---|
241 | if (! inname)
|
---|
242 | {
|
---|
243 | char numbuf[LINENUM_LENGTH_BOUND + 1];
|
---|
244 | say ("can't find file to patch at input line %s\n",
|
---|
245 | format_linenum (numbuf, p_sline));
|
---|
246 | if (diff_type != ED_DIFF)
|
---|
247 | say (strippath == -1
|
---|
248 | ? "Perhaps you should have used the -p or --strip option?\n"
|
---|
249 | : "Perhaps you used the wrong -p or --strip option?\n");
|
---|
250 | }
|
---|
251 | }
|
---|
252 |
|
---|
253 | skip_to(p_start,p_sline);
|
---|
254 | while (!inname) {
|
---|
255 | if (force | batch) {
|
---|
256 | say ("No file to patch. Skipping patch.\n");
|
---|
257 | skip_rest_of_patch = true;
|
---|
258 | return true;
|
---|
259 | }
|
---|
260 | ask ("File to patch: ");
|
---|
261 | inname = fetchname (buf, 0, (time_t *) 0);
|
---|
262 | if (inname)
|
---|
263 | {
|
---|
264 | if (stat (inname, &instat) == 0)
|
---|
265 | {
|
---|
266 | inerrno = 0;
|
---|
267 | invc = -1;
|
---|
268 | }
|
---|
269 | else
|
---|
270 | {
|
---|
271 | perror (inname);
|
---|
272 | fflush (stderr);
|
---|
273 | free (inname);
|
---|
274 | inname = 0;
|
---|
275 | }
|
---|
276 | }
|
---|
277 | if (!inname) {
|
---|
278 | ask ("Skip this patch? [y] ");
|
---|
279 | if (*buf != 'n') {
|
---|
280 | if (verbosity != SILENT)
|
---|
281 | say ("Skipping patch.\n");
|
---|
282 | skip_rest_of_patch = true;
|
---|
283 | return true;
|
---|
284 | }
|
---|
285 | }
|
---|
286 | }
|
---|
287 | return true;
|
---|
288 | }
|
---|
289 |
|
---|
290 | /* Determine what kind of diff is in the remaining part of the patch file. */
|
---|
291 |
|
---|
292 | static enum diff
|
---|
293 | intuit_diff_type (void)
|
---|
294 | {
|
---|
295 | register file_offset this_line = 0;
|
---|
296 | register file_offset first_command_line = -1;
|
---|
297 | char first_ed_command_letter = 0;
|
---|
298 | LINENUM fcl_line = 0; /* Pacify `gcc -W'. */
|
---|
299 | register bool this_is_a_command = false;
|
---|
300 | register bool stars_this_line = false;
|
---|
301 | enum nametype i;
|
---|
302 | char *name[3];
|
---|
303 | struct stat st[3];
|
---|
304 | int stat_errno[3];
|
---|
305 | int version_controlled[3];
|
---|
306 | register enum diff retval;
|
---|
307 |
|
---|
308 | name[OLD] = name[NEW] = name[INDEX] = 0;
|
---|
309 | version_controlled[OLD] = -1;
|
---|
310 | version_controlled[NEW] = -1;
|
---|
311 | version_controlled[INDEX] = -1;
|
---|
312 | p_rfc934_nesting = 0;
|
---|
313 | p_timestamp[OLD] = p_timestamp[NEW] = (time_t) -1;
|
---|
314 | p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0;
|
---|
315 | Fseek (pfp, p_base, SEEK_SET);
|
---|
316 | p_input_line = p_bline - 1;
|
---|
317 | for (;;) {
|
---|
318 | register char *s;
|
---|
319 | register char *t;
|
---|
320 | register file_offset previous_line = this_line;
|
---|
321 | register bool last_line_was_command = this_is_a_command;
|
---|
322 | register bool stars_last_line = stars_this_line;
|
---|
323 | register int indent = 0;
|
---|
324 | char ed_command_letter;
|
---|
325 | bool strip_trailing_cr;
|
---|
326 | size_t chars_read;
|
---|
327 |
|
---|
328 | this_line = file_tell (pfp);
|
---|
329 | chars_read = pget_line (0, 0, false, false);
|
---|
330 | if (chars_read == (size_t) -1)
|
---|
331 | memory_fatal ();
|
---|
332 | if (! chars_read) {
|
---|
333 | if (first_ed_command_letter) {
|
---|
334 | /* nothing but deletes!? */
|
---|
335 | p_start = first_command_line;
|
---|
336 | p_sline = fcl_line;
|
---|
337 | retval = ED_DIFF;
|
---|
338 | goto scan_exit;
|
---|
339 | }
|
---|
340 | else {
|
---|
341 | p_start = this_line;
|
---|
342 | p_sline = p_input_line;
|
---|
343 | return NO_DIFF;
|
---|
344 | }
|
---|
345 | }
|
---|
346 | strip_trailing_cr = 2 <= chars_read && buf[chars_read - 2] == '\r';
|
---|
347 | for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
|
---|
348 | if (*s == '\t')
|
---|
349 | indent = (indent + 8) & ~7;
|
---|
350 | else
|
---|
351 | indent++;
|
---|
352 | }
|
---|
353 | for (t = s; ISDIGIT (*t) || *t == ','; t++)
|
---|
354 | continue;
|
---|
355 | this_is_a_command = (ISDIGIT (*s) &&
|
---|
356 | (*t == 'd' || *t == 'c' || *t == 'a') );
|
---|
357 | if (first_command_line < 0
|
---|
358 | && ((ed_command_letter = get_ed_command_letter (s))
|
---|
359 | || this_is_a_command)) {
|
---|
360 | first_command_line = this_line;
|
---|
361 | first_ed_command_letter = ed_command_letter;
|
---|
362 | fcl_line = p_input_line;
|
---|
363 | p_indent = indent; /* assume this for now */
|
---|
364 | p_strip_trailing_cr = strip_trailing_cr;
|
---|
365 | }
|
---|
366 | if (!stars_last_line && strnEQ(s, "*** ", 4))
|
---|
367 | name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
|
---|
368 | else if (strnEQ(s, "+++ ", 4))
|
---|
369 | /* Swap with NEW below. */
|
---|
370 | name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
|
---|
371 | else if (strnEQ(s, "Index:", 6))
|
---|
372 | name[INDEX] = fetchname (s+6, strippath, (time_t *) 0);
|
---|
373 | else if (strnEQ(s, "Prereq:", 7)) {
|
---|
374 | for (t = s + 7; ISSPACE ((unsigned char) *t); t++)
|
---|
375 | continue;
|
---|
376 | revision = t;
|
---|
377 | for (t = revision; *t; t++)
|
---|
378 | if (ISSPACE ((unsigned char) *t))
|
---|
379 | {
|
---|
380 | char const *u;
|
---|
381 | for (u = t + 1; ISSPACE ((unsigned char) *u); u++)
|
---|
382 | continue;
|
---|
383 | if (*u)
|
---|
384 | {
|
---|
385 | char numbuf[LINENUM_LENGTH_BOUND + 1];
|
---|
386 | say ("Prereq: with multiple words at line %s of patch\n",
|
---|
387 | format_linenum (numbuf, this_line));
|
---|
388 | }
|
---|
389 | break;
|
---|
390 | }
|
---|
391 | if (t == revision)
|
---|
392 | revision = 0;
|
---|
393 | else {
|
---|
394 | char oldc = *t;
|
---|
395 | *t = '\0';
|
---|
396 | revision = savestr (revision);
|
---|
397 | *t = oldc;
|
---|
398 | }
|
---|
399 | } else
|
---|
400 | {
|
---|
401 | for (t = s; t[0] == '-' && t[1] == ' '; t += 2)
|
---|
402 | continue;
|
---|
403 | if (strnEQ(t, "--- ", 4))
|
---|
404 | {
|
---|
405 | time_t timestamp = (time_t) -1;
|
---|
406 | name[NEW] = fetchname (t+4, strippath, ×tamp);
|
---|
407 | if (timestamp != (time_t) -1)
|
---|
408 | {
|
---|
409 | p_timestamp[NEW] = timestamp;
|
---|
410 | p_rfc934_nesting = (t - s) >> 1;
|
---|
411 | }
|
---|
412 | }
|
---|
413 | }
|
---|
414 | if ((diff_type == NO_DIFF || diff_type == ED_DIFF) &&
|
---|
415 | first_command_line >= 0 &&
|
---|
416 | strEQ(s, ".\n") ) {
|
---|
417 | p_start = first_command_line;
|
---|
418 | p_sline = fcl_line;
|
---|
419 | retval = ED_DIFF;
|
---|
420 | goto scan_exit;
|
---|
421 | }
|
---|
422 | if ((diff_type == NO_DIFF || diff_type == UNI_DIFF)
|
---|
423 | && strnEQ(s, "@@ -", 4)) {
|
---|
424 |
|
---|
425 | /* `name' and `p_timestamp' are backwards; swap them. */
|
---|
426 | time_t ti = p_timestamp[OLD];
|
---|
427 | p_timestamp[OLD] = p_timestamp[NEW];
|
---|
428 | p_timestamp[NEW] = ti;
|
---|
429 | t = name[OLD];
|
---|
430 | name[OLD] = name[NEW];
|
---|
431 | name[NEW] = t;
|
---|
432 |
|
---|
433 | s += 4;
|
---|
434 | if (s[0] == '0' && !ISDIGIT (s[1]))
|
---|
435 | p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD];
|
---|
436 | while (*s != ' ' && *s != '\n')
|
---|
437 | s++;
|
---|
438 | while (*s == ' ')
|
---|
439 | s++;
|
---|
440 | if (s[0] == '+' && s[1] == '0' && !ISDIGIT (s[2]))
|
---|
441 | p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW];
|
---|
442 | p_indent = indent;
|
---|
443 | p_start = this_line;
|
---|
444 | p_sline = p_input_line;
|
---|
445 | retval = UNI_DIFF;
|
---|
446 | if (! ((name[OLD] || ! p_timestamp[OLD])
|
---|
447 | && (name[NEW] || ! p_timestamp[NEW]))
|
---|
448 | && ! name[INDEX])
|
---|
449 | {
|
---|
450 | char numbuf[LINENUM_LENGTH_BOUND + 1];
|
---|
451 | say ("missing header for unified diff at line %s of patch\n",
|
---|
452 | format_linenum (numbuf, p_sline));
|
---|
453 | }
|
---|
454 | goto scan_exit;
|
---|
455 | }
|
---|
456 | stars_this_line = strnEQ(s, "********", 8);
|
---|
457 | if ((diff_type == NO_DIFF
|
---|
458 | || diff_type == CONTEXT_DIFF
|
---|
459 | || diff_type == NEW_CONTEXT_DIFF)
|
---|
460 | && stars_last_line && strnEQ (s, "*** ", 4)) {
|
---|
461 | s += 4;
|
---|
462 | if (s[0] == '0' && !ISDIGIT (s[1]))
|
---|
463 | p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD];
|
---|
464 | /* if this is a new context diff the character just before */
|
---|
465 | /* the newline is a '*'. */
|
---|
466 | while (*s != '\n')
|
---|
467 | s++;
|
---|
468 | p_indent = indent;
|
---|
469 | p_strip_trailing_cr = strip_trailing_cr;
|
---|
470 | p_start = previous_line;
|
---|
471 | p_sline = p_input_line - 1;
|
---|
472 | retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
|
---|
473 |
|
---|
474 | {
|
---|
475 | /* Scan the first hunk to see whether the file contents
|
---|
476 | appear to have been deleted. */
|
---|
477 | file_offset saved_p_base = p_base;
|
---|
478 | LINENUM saved_p_bline = p_bline;
|
---|
479 | Fseek (pfp, previous_line, SEEK_SET);
|
---|
480 | p_input_line -= 2;
|
---|
481 | if (another_hunk (retval, false)
|
---|
482 | && ! p_repl_lines && p_newfirst == 1)
|
---|
483 | p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW];
|
---|
484 | next_intuit_at (saved_p_base, saved_p_bline);
|
---|
485 | }
|
---|
486 |
|
---|
487 | if (! ((name[OLD] || ! p_timestamp[OLD])
|
---|
488 | && (name[NEW] || ! p_timestamp[NEW]))
|
---|
489 | && ! name[INDEX])
|
---|
490 | {
|
---|
491 | char numbuf[LINENUM_LENGTH_BOUND + 1];
|
---|
492 | say ("missing header for context diff at line %s of patch\n",
|
---|
493 | format_linenum (numbuf, p_sline));
|
---|
494 | }
|
---|
495 | goto scan_exit;
|
---|
496 | }
|
---|
497 | if ((diff_type == NO_DIFF || diff_type == NORMAL_DIFF) &&
|
---|
498 | last_line_was_command &&
|
---|
499 | (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {
|
---|
500 | p_start = previous_line;
|
---|
501 | p_sline = p_input_line - 1;
|
---|
502 | p_indent = indent;
|
---|
503 | p_strip_trailing_cr = strip_trailing_cr;
|
---|
504 | retval = NORMAL_DIFF;
|
---|
505 | goto scan_exit;
|
---|
506 | }
|
---|
507 | }
|
---|
508 |
|
---|
509 | scan_exit:
|
---|
510 |
|
---|
511 | /* To intuit `inname', the name of the file to patch,
|
---|
512 | use the algorithm specified by POSIX 1003.1-2001 XCU lines 25680-26599
|
---|
513 | (with some modifications if posixly_correct is zero):
|
---|
514 |
|
---|
515 | - Take the old and new names from the context header if present,
|
---|
516 | and take the index name from the `Index:' line if present and
|
---|
517 | if either the old and new names are both absent
|
---|
518 | or posixly_correct is nonzero.
|
---|
519 | Consider the file names to be in the order (old, new, index).
|
---|
520 | - If some named files exist, use the first one if posixly_correct
|
---|
521 | is nonzero, the best one otherwise.
|
---|
522 | - If patch_get is nonzero, and no named files exist,
|
---|
523 | but an RCS or SCCS master file exists,
|
---|
524 | use the first named file with an RCS or SCCS master.
|
---|
525 | - If no named files exist, no RCS or SCCS master was found,
|
---|
526 | some names are given, posixly_correct is zero,
|
---|
527 | and the patch appears to create a file, then use the best name
|
---|
528 | requiring the creation of the fewest directories.
|
---|
529 | - Otherwise, report failure by setting `inname' to 0;
|
---|
530 | this causes our invoker to ask the user for a file name. */
|
---|
531 |
|
---|
532 | i = NONE;
|
---|
533 |
|
---|
534 | if (!inname)
|
---|
535 | {
|
---|
536 | enum nametype i0 = NONE;
|
---|
537 |
|
---|
538 | if (! posixly_correct && (name[OLD] || name[NEW]) && name[INDEX])
|
---|
539 | {
|
---|
540 | free (name[INDEX]);
|
---|
541 | name[INDEX] = 0;
|
---|
542 | }
|
---|
543 |
|
---|
544 | for (i = OLD; i <= INDEX; i++)
|
---|
545 | if (name[i])
|
---|
546 | {
|
---|
547 | if (i0 != NONE && strcmp (name[i0], name[i]) == 0)
|
---|
548 | {
|
---|
549 | /* It's the same name as before; reuse stat results. */
|
---|
550 | stat_errno[i] = stat_errno[i0];
|
---|
551 | if (! stat_errno[i])
|
---|
552 | st[i] = st[i0];
|
---|
553 | }
|
---|
554 | else if (stat (name[i], &st[i]) != 0)
|
---|
555 | stat_errno[i] = errno;
|
---|
556 | else
|
---|
557 | {
|
---|
558 | stat_errno[i] = 0;
|
---|
559 | if (posixly_correct)
|
---|
560 | break;
|
---|
561 | }
|
---|
562 | i0 = i;
|
---|
563 | }
|
---|
564 |
|
---|
565 | if (! posixly_correct)
|
---|
566 | {
|
---|
567 | bool is_empty;
|
---|
568 |
|
---|
569 | i = best_name (name, stat_errno);
|
---|
570 |
|
---|
571 | if (i == NONE && patch_get)
|
---|
572 | {
|
---|
573 | enum nametype nope = NONE;
|
---|
574 |
|
---|
575 | for (i = OLD; i <= INDEX; i++)
|
---|
576 | if (name[i])
|
---|
577 | {
|
---|
578 | char const *cs;
|
---|
579 | char *getbuf;
|
---|
580 | char *diffbuf;
|
---|
581 | bool readonly = (outfile
|
---|
582 | && strcmp (outfile, name[i]) != 0);
|
---|
583 |
|
---|
584 | if (nope == NONE || strcmp (name[nope], name[i]) != 0)
|
---|
585 | {
|
---|
586 | cs = (version_controller
|
---|
587 | (name[i], readonly, (struct stat *) 0,
|
---|
588 | &getbuf, &diffbuf));
|
---|
589 | version_controlled[i] = !! cs;
|
---|
590 | if (cs)
|
---|
591 | {
|
---|
592 | if (version_get (name[i], cs, false, readonly,
|
---|
593 | getbuf, &st[i]))
|
---|
594 | stat_errno[i] = 0;
|
---|
595 | else
|
---|
596 | version_controlled[i] = 0;
|
---|
597 |
|
---|
598 | free (getbuf);
|
---|
599 | if (diffbuf)
|
---|
600 | free (diffbuf);
|
---|
601 |
|
---|
602 | if (! stat_errno[i])
|
---|
603 | break;
|
---|
604 | }
|
---|
605 | }
|
---|
606 |
|
---|
607 | nope = i;
|
---|
608 | }
|
---|
609 | }
|
---|
610 |
|
---|
611 | is_empty = i == NONE || st[i].st_size == 0;
|
---|
612 | if ((! is_empty) < p_says_nonexistent[reverse ^ is_empty])
|
---|
613 | {
|
---|
614 | assert (i0 != NONE);
|
---|
615 | reverse ^=
|
---|
616 | ok_to_reverse
|
---|
617 | ("The next patch%s would %s the file %s,\nwhich %s!",
|
---|
618 | reverse ? ", when reversed," : "",
|
---|
619 | (i == NONE ? "delete"
|
---|
620 | : st[i].st_size == 0 ? "empty out"
|
---|
621 | : "create"),
|
---|
622 | quotearg (name[i == NONE || st[i].st_size == 0 ? i0 : i]),
|
---|
623 | (i == NONE ? "does not exist"
|
---|
624 | : st[i].st_size == 0 ? "is already empty"
|
---|
625 | : "already exists"));
|
---|
626 | }
|
---|
627 |
|
---|
628 | if (i == NONE && p_says_nonexistent[reverse])
|
---|
629 | {
|
---|
630 | int newdirs[3];
|
---|
631 | int newdirs_min = INT_MAX;
|
---|
632 | int distance_from_minimum[3];
|
---|
633 |
|
---|
634 | for (i = OLD; i <= INDEX; i++)
|
---|
635 | if (name[i])
|
---|
636 | {
|
---|
637 | newdirs[i] = (prefix_components (name[i], false)
|
---|
638 | - prefix_components (name[i], true));
|
---|
639 | if (newdirs[i] < newdirs_min)
|
---|
640 | newdirs_min = newdirs[i];
|
---|
641 | }
|
---|
642 |
|
---|
643 | for (i = OLD; i <= INDEX; i++)
|
---|
644 | if (name[i])
|
---|
645 | distance_from_minimum[i] = newdirs[i] - newdirs_min;
|
---|
646 |
|
---|
647 | i = best_name (name, distance_from_minimum);
|
---|
648 | }
|
---|
649 | }
|
---|
650 | }
|
---|
651 |
|
---|
652 | if (i == NONE)
|
---|
653 | inerrno = -1;
|
---|
654 | else
|
---|
655 | {
|
---|
656 | inname = name[i];
|
---|
657 | name[i] = 0;
|
---|
658 | inerrno = stat_errno[i];
|
---|
659 | invc = version_controlled[i];
|
---|
660 | instat = st[i];
|
---|
661 | }
|
---|
662 |
|
---|
663 | for (i = OLD; i <= INDEX; i++)
|
---|
664 | if (name[i])
|
---|
665 | free (name[i]);
|
---|
666 |
|
---|
667 | return retval;
|
---|
668 | }
|
---|
669 |
|
---|
670 | /* Count the path name components in FILENAME's prefix.
|
---|
671 | If CHECKDIRS is true, count only existing directories. */
|
---|
672 | static int
|
---|
673 | prefix_components (char *filename, bool checkdirs)
|
---|
674 | {
|
---|
675 | int count = 0;
|
---|
676 | struct stat stat_buf;
|
---|
677 | int stat_result;
|
---|
678 | char *f = filename + FILESYSTEM_PREFIX_LEN (filename);
|
---|
679 |
|
---|
680 | if (*f)
|
---|
681 | while (*++f)
|
---|
682 | if (ISSLASH (f[0]) && ! ISSLASH (f[-1]))
|
---|
683 | {
|
---|
684 | if (checkdirs)
|
---|
685 | {
|
---|
686 | *f = '\0';
|
---|
687 | stat_result = stat (filename, &stat_buf);
|
---|
688 | *f = '/';
|
---|
689 | if (! (stat_result == 0 && S_ISDIR (stat_buf.st_mode)))
|
---|
690 | break;
|
---|
691 | }
|
---|
692 |
|
---|
693 | count++;
|
---|
694 | }
|
---|
695 |
|
---|
696 | return count;
|
---|
697 | }
|
---|
698 |
|
---|
699 | /* Return the index of the best of NAME[OLD], NAME[NEW], and NAME[INDEX].
|
---|
700 | Ignore null names, and ignore NAME[i] if IGNORE[i] is nonzero.
|
---|
701 | Return NONE if all names are ignored. */
|
---|
702 | static enum nametype
|
---|
703 | best_name (char *const *name, int const *ignore)
|
---|
704 | {
|
---|
705 | enum nametype i;
|
---|
706 | int components[3];
|
---|
707 | int components_min = INT_MAX;
|
---|
708 | size_t basename_len[3];
|
---|
709 | size_t basename_len_min = SIZE_MAX;
|
---|
710 | size_t len[3];
|
---|
711 | size_t len_min = SIZE_MAX;
|
---|
712 |
|
---|
713 | for (i = OLD; i <= INDEX; i++)
|
---|
714 | if (name[i] && !ignore[i])
|
---|
715 | {
|
---|
716 | /* Take the names with the fewest prefix components. */
|
---|
717 | components[i] = prefix_components (name[i], false);
|
---|
718 | if (components_min < components[i])
|
---|
719 | continue;
|
---|
720 | components_min = components[i];
|
---|
721 |
|
---|
722 | /* Of those, take the names with the shortest basename. */
|
---|
723 | basename_len[i] = strlen (base_name (name[i]));
|
---|
724 | if (basename_len_min < basename_len[i])
|
---|
725 | continue;
|
---|
726 | basename_len_min = basename_len[i];
|
---|
727 |
|
---|
728 | /* Of those, take the shortest names. */
|
---|
729 | len[i] = strlen (name[i]);
|
---|
730 | if (len_min < len[i])
|
---|
731 | continue;
|
---|
732 | len_min = len[i];
|
---|
733 | }
|
---|
734 |
|
---|
735 | /* Of those, take the first name. */
|
---|
736 | for (i = OLD; i <= INDEX; i++)
|
---|
737 | if (name[i] && !ignore[i]
|
---|
738 | && components[i] == components_min
|
---|
739 | && basename_len[i] == basename_len_min
|
---|
740 | && len[i] == len_min)
|
---|
741 | break;
|
---|
742 |
|
---|
743 | return i;
|
---|
744 | }
|
---|
745 |
|
---|
746 | /* Remember where this patch ends so we know where to start up again. */
|
---|
747 |
|
---|
748 | static void
|
---|
749 | next_intuit_at (file_offset file_pos, LINENUM file_line)
|
---|
750 | {
|
---|
751 | p_base = file_pos;
|
---|
752 | p_bline = file_line;
|
---|
753 | }
|
---|
754 |
|
---|
755 | /* Basically a verbose fseek() to the actual diff listing. */
|
---|
756 |
|
---|
757 | static void
|
---|
758 | skip_to (file_offset file_pos, LINENUM file_line)
|
---|
759 | {
|
---|
760 | register FILE *i = pfp;
|
---|
761 | register FILE *o = stdout;
|
---|
762 | register int c;
|
---|
763 |
|
---|
764 | assert(p_base <= file_pos);
|
---|
765 | if ((verbosity == VERBOSE || !inname) && p_base < file_pos) {
|
---|
766 | Fseek (i, p_base, SEEK_SET);
|
---|
767 | say ("The text leading up to this was:\n--------------------------\n");
|
---|
768 |
|
---|
769 | while (file_tell (i) < file_pos)
|
---|
770 | {
|
---|
771 | putc ('|', o);
|
---|
772 | do
|
---|
773 | {
|
---|
774 | if ((c = getc (i)) == EOF)
|
---|
775 | read_fatal ();
|
---|
776 | putc (c, o);
|
---|
777 | }
|
---|
778 | while (c != '\n');
|
---|
779 | }
|
---|
780 |
|
---|
781 | say ("--------------------------\n");
|
---|
782 | }
|
---|
783 | else
|
---|
784 | Fseek (i, file_pos, SEEK_SET);
|
---|
785 | p_input_line = file_line - 1;
|
---|
786 | }
|
---|
787 |
|
---|
788 | /* Make this a function for better debugging. */
|
---|
789 | static void
|
---|
790 | malformed (void)
|
---|
791 | {
|
---|
792 | char numbuf[LINENUM_LENGTH_BOUND + 1];
|
---|
793 | fatal ("malformed patch at line %s: %s",
|
---|
794 | format_linenum (numbuf, p_input_line), buf);
|
---|
795 | /* about as informative as "Syntax error" in C */
|
---|
796 | }
|
---|
797 |
|
---|
798 | /* Parse a line number from a string.
|
---|
799 | Return the address of the first char after the number. */
|
---|
800 | static char *
|
---|
801 | scan_linenum (char *s0, LINENUM *linenum)
|
---|
802 | {
|
---|
803 | char *s;
|
---|
804 | LINENUM n = 0;
|
---|
805 | bool overflow = false;
|
---|
806 | char numbuf[LINENUM_LENGTH_BOUND + 1];
|
---|
807 |
|
---|
808 | for (s = s0; ISDIGIT (*s); s++)
|
---|
809 | {
|
---|
810 | LINENUM new_n = 10 * n + (*s - '0');
|
---|
811 | overflow |= new_n / 10 != n;
|
---|
812 | n = new_n;
|
---|
813 | }
|
---|
814 |
|
---|
815 | if (s == s0)
|
---|
816 | fatal ("missing line number at line %s: %s",
|
---|
817 | format_linenum (numbuf, p_input_line), buf);
|
---|
818 |
|
---|
819 | if (overflow)
|
---|
820 | fatal ("line number %.*s is too large at line %s: %s",
|
---|
821 | (int) (s - s0), s0, format_linenum (numbuf, p_input_line), buf);
|
---|
822 |
|
---|
823 | *linenum = n;
|
---|
824 | return s;
|
---|
825 | }
|
---|
826 |
|
---|
827 | /* 1 if there is more of the current diff listing to process;
|
---|
828 | 0 if not; -1 if ran out of memory. */
|
---|
829 |
|
---|
830 | int
|
---|
831 | another_hunk (enum diff difftype, bool rev)
|
---|
832 | {
|
---|
833 | register char *s;
|
---|
834 | register LINENUM context = 0;
|
---|
835 | register size_t chars_read;
|
---|
836 | char numbuf0[LINENUM_LENGTH_BOUND + 1];
|
---|
837 | char numbuf1[LINENUM_LENGTH_BOUND + 1];
|
---|
838 | char numbuf2[LINENUM_LENGTH_BOUND + 1];
|
---|
839 | char numbuf3[LINENUM_LENGTH_BOUND + 1];
|
---|
840 |
|
---|
841 | while (p_end >= 0) {
|
---|
842 | if (p_end == p_efake)
|
---|
843 | p_end = p_bfake; /* don't free twice */
|
---|
844 | else
|
---|
845 | free(p_line[p_end]);
|
---|
846 | p_end--;
|
---|
847 | }
|
---|
848 | assert(p_end == -1);
|
---|
849 | p_efake = -1;
|
---|
850 |
|
---|
851 | p_max = hunkmax; /* gets reduced when --- found */
|
---|
852 | if (difftype == CONTEXT_DIFF || difftype == NEW_CONTEXT_DIFF) {
|
---|
853 | file_offset line_beginning = file_tell (pfp);
|
---|
854 | /* file pos of the current line */
|
---|
855 | LINENUM repl_beginning = 0; /* index of --- line */
|
---|
856 | register LINENUM fillcnt = 0; /* #lines of missing ptrn or repl */
|
---|
857 | register LINENUM fillsrc; /* index of first line to copy */
|
---|
858 | register LINENUM filldst; /* index of first missing line */
|
---|
859 | bool ptrn_spaces_eaten = false; /* ptrn was slightly misformed */
|
---|
860 | bool some_context = false; /* (perhaps internal) context seen */
|
---|
861 | register bool repl_could_be_missing = true;
|
---|
862 | bool ptrn_missing = false; /* The pattern was missing. */
|
---|
863 | bool repl_missing = false; /* Likewise for replacement. */
|
---|
864 | file_offset repl_backtrack_position = 0;
|
---|
865 | /* file pos of first repl line */
|
---|
866 | LINENUM repl_patch_line; /* input line number for same */
|
---|
867 | LINENUM repl_context; /* context for same */
|
---|
868 | LINENUM ptrn_prefix_context = -1; /* lines in pattern prefix context */
|
---|
869 | LINENUM ptrn_suffix_context = -1; /* lines in pattern suffix context */
|
---|
870 | LINENUM repl_prefix_context = -1; /* lines in replac. prefix context */
|
---|
871 | LINENUM ptrn_copiable = 0; /* # of copiable lines in ptrn */
|
---|
872 | LINENUM repl_copiable = 0; /* Likewise for replacement. */
|
---|
873 |
|
---|
874 | /* Pacify `gcc -Wall'. */
|
---|
875 | fillsrc = filldst = repl_patch_line = repl_context = 0;
|
---|
876 |
|
---|
877 | chars_read = get_line ();
|
---|
878 | if (chars_read == (size_t) -1
|
---|
879 | || chars_read <= 8
|
---|
880 | || strncmp (buf, "********", 8) != 0) {
|
---|
881 | next_intuit_at(line_beginning,p_input_line);
|
---|
882 | return chars_read == (size_t) -1 ? -1 : 0;
|
---|
883 | }
|
---|
884 | p_hunk_beg = p_input_line + 1;
|
---|
885 | while (p_end < p_max) {
|
---|
886 | chars_read = get_line ();
|
---|
887 | if (chars_read == (size_t) -1)
|
---|
888 | return -1;
|
---|
889 | if (!chars_read) {
|
---|
890 | if (repl_beginning && repl_could_be_missing) {
|
---|
891 | repl_missing = true;
|
---|
892 | goto hunk_done;
|
---|
893 | }
|
---|
894 | if (p_max - p_end < 4) {
|
---|
895 | strcpy (buf, " \n"); /* assume blank lines got chopped */
|
---|
896 | chars_read = 3;
|
---|
897 | } else {
|
---|
898 | fatal ("unexpected end of file in patch");
|
---|
899 | }
|
---|
900 | }
|
---|
901 | p_end++;
|
---|
902 | if (p_end == hunkmax)
|
---|
903 | fatal ("unterminated hunk starting at line %s; giving up at line %s: %s",
|
---|
904 | format_linenum (numbuf0, pch_hunk_beg ()),
|
---|
905 | format_linenum (numbuf1, p_input_line), buf);
|
---|
906 | assert(p_end < hunkmax);
|
---|
907 | p_Char[p_end] = *buf;
|
---|
908 | p_len[p_end] = 0;
|
---|
909 | p_line[p_end] = 0;
|
---|
910 | switch (*buf) {
|
---|
911 | case '*':
|
---|
912 | if (strnEQ(buf, "********", 8)) {
|
---|
913 | if (repl_beginning && repl_could_be_missing) {
|
---|
914 | repl_missing = true;
|
---|
915 | goto hunk_done;
|
---|
916 | }
|
---|
917 | else
|
---|
918 | fatal ("unexpected end of hunk at line %s",
|
---|
919 | format_linenum (numbuf0, p_input_line));
|
---|
920 | }
|
---|
921 | if (p_end != 0) {
|
---|
922 | if (repl_beginning && repl_could_be_missing) {
|
---|
923 | repl_missing = true;
|
---|
924 | goto hunk_done;
|
---|
925 | }
|
---|
926 | fatal ("unexpected `***' at line %s: %s",
|
---|
927 | format_linenum (numbuf0, p_input_line), buf);
|
---|
928 | }
|
---|
929 | context = 0;
|
---|
930 | p_len[p_end] = strlen (buf);
|
---|
931 | if (! (p_line[p_end] = savestr (buf))) {
|
---|
932 | p_end--;
|
---|
933 | return -1;
|
---|
934 | }
|
---|
935 | for (s = buf; *s && !ISDIGIT (*s); s++)
|
---|
936 | continue;
|
---|
937 | if (strnEQ(s,"0,0",3))
|
---|
938 | remove_prefix (s, 2);
|
---|
939 | s = scan_linenum (s, &p_first);
|
---|
940 | if (*s == ',') {
|
---|
941 | while (*s && !ISDIGIT (*s))
|
---|
942 | s++;
|
---|
943 | scan_linenum (s, &p_ptrn_lines);
|
---|
944 | p_ptrn_lines += 1 - p_first;
|
---|
945 | }
|
---|
946 | else if (p_first)
|
---|
947 | p_ptrn_lines = 1;
|
---|
948 | else {
|
---|
949 | p_ptrn_lines = 0;
|
---|
950 | p_first = 1;
|
---|
951 | }
|
---|
952 | p_max = p_ptrn_lines + 6; /* we need this much at least */
|
---|
953 | while (p_max >= hunkmax)
|
---|
954 | if (! grow_hunkmax ())
|
---|
955 | return -1;
|
---|
956 | p_max = hunkmax;
|
---|
957 | break;
|
---|
958 | case '-':
|
---|
959 | if (buf[1] != '-')
|
---|
960 | goto change_line;
|
---|
961 | if (ptrn_prefix_context == -1)
|
---|
962 | ptrn_prefix_context = context;
|
---|
963 | ptrn_suffix_context = context;
|
---|
964 | if (repl_beginning
|
---|
965 | || (p_end
|
---|
966 | != p_ptrn_lines + 1 + (p_Char[p_end - 1] == '\n')))
|
---|
967 | {
|
---|
968 | if (p_end == 1)
|
---|
969 | {
|
---|
970 | /* `Old' lines were omitted. Set up to fill
|
---|
971 | them in from `new' context lines. */
|
---|
972 | ptrn_missing = true;
|
---|
973 | p_end = p_ptrn_lines + 1;
|
---|
974 | ptrn_prefix_context = ptrn_suffix_context = -1;
|
---|
975 | fillsrc = p_end + 1;
|
---|
976 | filldst = 1;
|
---|
977 | fillcnt = p_ptrn_lines;
|
---|
978 | }
|
---|
979 | else if (! repl_beginning)
|
---|
980 | fatal ("%s `---' at line %s; check line numbers at line %s",
|
---|
981 | (p_end <= p_ptrn_lines
|
---|
982 | ? "Premature"
|
---|
983 | : "Overdue"),
|
---|
984 | format_linenum (numbuf0, p_input_line),
|
---|
985 | format_linenum (numbuf1, p_hunk_beg));
|
---|
986 | else if (! repl_could_be_missing)
|
---|
987 | fatal ("duplicate `---' at line %s; check line numbers at line %s",
|
---|
988 | format_linenum (numbuf0, p_input_line),
|
---|
989 | format_linenum (numbuf1,
|
---|
990 | p_hunk_beg + repl_beginning));
|
---|
991 | else
|
---|
992 | {
|
---|
993 | repl_missing = true;
|
---|
994 | goto hunk_done;
|
---|
995 | }
|
---|
996 | }
|
---|
997 | repl_beginning = p_end;
|
---|
998 | repl_backtrack_position = file_tell (pfp);
|
---|
999 | repl_patch_line = p_input_line;
|
---|
1000 | repl_context = context;
|
---|
1001 | p_len[p_end] = strlen (buf);
|
---|
1002 | if (! (p_line[p_end] = savestr (buf)))
|
---|
1003 | {
|
---|
1004 | p_end--;
|
---|
1005 | return -1;
|
---|
1006 | }
|
---|
1007 | p_Char[p_end] = '=';
|
---|
1008 | for (s = buf; *s && ! ISDIGIT (*s); s++)
|
---|
1009 | continue;
|
---|
1010 | s = scan_linenum (s, &p_newfirst);
|
---|
1011 | if (*s == ',')
|
---|
1012 | {
|
---|
1013 | do
|
---|
1014 | {
|
---|
1015 | if (!*++s)
|
---|
1016 | malformed ();
|
---|
1017 | }
|
---|
1018 | while (! ISDIGIT (*s));
|
---|
1019 | scan_linenum (s, &p_repl_lines);
|
---|
1020 | p_repl_lines += 1 - p_newfirst;
|
---|
1021 | }
|
---|
1022 | else if (p_newfirst)
|
---|
1023 | p_repl_lines = 1;
|
---|
1024 | else
|
---|
1025 | {
|
---|
1026 | p_repl_lines = 0;
|
---|
1027 | p_newfirst = 1;
|
---|
1028 | }
|
---|
1029 | p_max = p_repl_lines + p_end;
|
---|
1030 | while (p_max >= hunkmax)
|
---|
1031 | if (! grow_hunkmax ())
|
---|
1032 | return -1;
|
---|
1033 | if (p_repl_lines != ptrn_copiable
|
---|
1034 | && (p_prefix_context != 0
|
---|
1035 | || context != 0
|
---|
1036 | || p_repl_lines != 1))
|
---|
1037 | repl_could_be_missing = false;
|
---|
1038 | context = 0;
|
---|
1039 | break;
|
---|
1040 | case '+': case '!':
|
---|
1041 | repl_could_be_missing = false;
|
---|
1042 | change_line:
|
---|
1043 | s = buf + 1;
|
---|
1044 | chars_read--;
|
---|
1045 | if (*s == '\n' && canonicalize) {
|
---|
1046 | strcpy (s, " \n");
|
---|
1047 | chars_read = 2;
|
---|
1048 | }
|
---|
1049 | if (*s == ' ' || *s == '\t') {
|
---|
1050 | s++;
|
---|
1051 | chars_read--;
|
---|
1052 | } else if (repl_beginning && repl_could_be_missing) {
|
---|
1053 | repl_missing = true;
|
---|
1054 | goto hunk_done;
|
---|
1055 | }
|
---|
1056 | if (! repl_beginning)
|
---|
1057 | {
|
---|
1058 | if (ptrn_prefix_context == -1)
|
---|
1059 | ptrn_prefix_context = context;
|
---|
1060 | }
|
---|
1061 | else
|
---|
1062 | {
|
---|
1063 | if (repl_prefix_context == -1)
|
---|
1064 | repl_prefix_context = context;
|
---|
1065 | }
|
---|
1066 | chars_read -=
|
---|
1067 | (1 < chars_read
|
---|
1068 | && p_end == (repl_beginning ? p_max : p_ptrn_lines)
|
---|
1069 | && incomplete_line ());
|
---|
1070 | p_len[p_end] = chars_read;
|
---|
1071 | if (! (p_line[p_end] = savebuf (s, chars_read))) {
|
---|
1072 | p_end--;
|
---|
1073 | return -1;
|
---|
1074 | }
|
---|
1075 | context = 0;
|
---|
1076 | break;
|
---|
1077 | case '\t': case '\n': /* assume spaces got eaten */
|
---|
1078 | s = buf;
|
---|
1079 | if (*buf == '\t') {
|
---|
1080 | s++;
|
---|
1081 | chars_read--;
|
---|
1082 | }
|
---|
1083 | if (repl_beginning && repl_could_be_missing &&
|
---|
1084 | (!ptrn_spaces_eaten || difftype == NEW_CONTEXT_DIFF) ) {
|
---|
1085 | repl_missing = true;
|
---|
1086 | goto hunk_done;
|
---|
1087 | }
|
---|
1088 | chars_read -=
|
---|
1089 | (1 < chars_read
|
---|
1090 | && p_end == (repl_beginning ? p_max : p_ptrn_lines)
|
---|
1091 | && incomplete_line ());
|
---|
1092 | p_len[p_end] = chars_read;
|
---|
1093 | if (! (p_line[p_end] = savebuf (buf, chars_read))) {
|
---|
1094 | p_end--;
|
---|
1095 | return -1;
|
---|
1096 | }
|
---|
1097 | if (p_end != p_ptrn_lines + 1) {
|
---|
1098 | ptrn_spaces_eaten |= (repl_beginning != 0);
|
---|
1099 | some_context = true;
|
---|
1100 | context++;
|
---|
1101 | if (repl_beginning)
|
---|
1102 | repl_copiable++;
|
---|
1103 | else
|
---|
1104 | ptrn_copiable++;
|
---|
1105 | p_Char[p_end] = ' ';
|
---|
1106 | }
|
---|
1107 | break;
|
---|
1108 | case ' ':
|
---|
1109 | s = buf + 1;
|
---|
1110 | chars_read--;
|
---|
1111 | if (*s == '\n' && canonicalize) {
|
---|
1112 | strcpy (s, "\n");
|
---|
1113 | chars_read = 2;
|
---|
1114 | }
|
---|
1115 | if (*s == ' ' || *s == '\t') {
|
---|
1116 | s++;
|
---|
1117 | chars_read--;
|
---|
1118 | } else if (repl_beginning && repl_could_be_missing) {
|
---|
1119 | repl_missing = true;
|
---|
1120 | goto hunk_done;
|
---|
1121 | }
|
---|
1122 | some_context = true;
|
---|
1123 | context++;
|
---|
1124 | if (repl_beginning)
|
---|
1125 | repl_copiable++;
|
---|
1126 | else
|
---|
1127 | ptrn_copiable++;
|
---|
1128 | chars_read -=
|
---|
1129 | (1 < chars_read
|
---|
1130 | && p_end == (repl_beginning ? p_max : p_ptrn_lines)
|
---|
1131 | && incomplete_line ());
|
---|
1132 | p_len[p_end] = chars_read;
|
---|
1133 | if (! (p_line[p_end] = savebuf (buf + 2, chars_read))) {
|
---|
1134 | p_end--;
|
---|
1135 | return -1;
|
---|
1136 | }
|
---|
1137 | break;
|
---|
1138 | default:
|
---|
1139 | if (repl_beginning && repl_could_be_missing) {
|
---|
1140 | repl_missing = true;
|
---|
1141 | goto hunk_done;
|
---|
1142 | }
|
---|
1143 | malformed ();
|
---|
1144 | }
|
---|
1145 | }
|
---|
1146 |
|
---|
1147 | hunk_done:
|
---|
1148 | if (p_end >=0 && !repl_beginning)
|
---|
1149 | fatal ("no `---' found in patch at line %s",
|
---|
1150 | format_linenum (numbuf0, pch_hunk_beg ()));
|
---|
1151 |
|
---|
1152 | if (repl_missing) {
|
---|
1153 |
|
---|
1154 | /* reset state back to just after --- */
|
---|
1155 | p_input_line = repl_patch_line;
|
---|
1156 | context = repl_context;
|
---|
1157 | for (p_end--; p_end > repl_beginning; p_end--)
|
---|
1158 | free(p_line[p_end]);
|
---|
1159 | Fseek (pfp, repl_backtrack_position, SEEK_SET);
|
---|
1160 |
|
---|
1161 | /* redundant 'new' context lines were omitted - set */
|
---|
1162 | /* up to fill them in from the old file context */
|
---|
1163 | fillsrc = 1;
|
---|
1164 | filldst = repl_beginning+1;
|
---|
1165 | fillcnt = p_repl_lines;
|
---|
1166 | p_end = p_max;
|
---|
1167 | }
|
---|
1168 | else if (! ptrn_missing && ptrn_copiable != repl_copiable)
|
---|
1169 | fatal ("context mangled in hunk at line %s",
|
---|
1170 | format_linenum (numbuf0, p_hunk_beg));
|
---|
1171 | else if (!some_context && fillcnt == 1) {
|
---|
1172 | /* the first hunk was a null hunk with no context */
|
---|
1173 | /* and we were expecting one line -- fix it up. */
|
---|
1174 | while (filldst < p_end) {
|
---|
1175 | p_line[filldst] = p_line[filldst+1];
|
---|
1176 | p_Char[filldst] = p_Char[filldst+1];
|
---|
1177 | p_len[filldst] = p_len[filldst+1];
|
---|
1178 | filldst++;
|
---|
1179 | }
|
---|
1180 | #if 0
|
---|
1181 | repl_beginning--; /* this doesn't need to be fixed */
|
---|
1182 | #endif
|
---|
1183 | p_end--;
|
---|
1184 | p_first++; /* do append rather than insert */
|
---|
1185 | fillcnt = 0;
|
---|
1186 | p_ptrn_lines = 0;
|
---|
1187 | }
|
---|
1188 |
|
---|
1189 | p_prefix_context = ((repl_prefix_context == -1
|
---|
1190 | || (ptrn_prefix_context != -1
|
---|
1191 | && ptrn_prefix_context < repl_prefix_context))
|
---|
1192 | ? ptrn_prefix_context : repl_prefix_context);
|
---|
1193 | p_suffix_context = ((ptrn_suffix_context != -1
|
---|
1194 | && ptrn_suffix_context < context)
|
---|
1195 | ? ptrn_suffix_context : context);
|
---|
1196 | assert (p_prefix_context != -1 && p_suffix_context != -1);
|
---|
1197 |
|
---|
1198 | if (difftype == CONTEXT_DIFF
|
---|
1199 | && (fillcnt
|
---|
1200 | || (p_first > 1
|
---|
1201 | && p_prefix_context + p_suffix_context < ptrn_copiable))) {
|
---|
1202 | if (verbosity == VERBOSE)
|
---|
1203 | say ("%s\n%s\n%s\n",
|
---|
1204 | "(Fascinating -- this is really a new-style context diff but without",
|
---|
1205 | "the telltale extra asterisks on the *** line that usually indicate",
|
---|
1206 | "the new style...)");
|
---|
1207 | diff_type = difftype = NEW_CONTEXT_DIFF;
|
---|
1208 | }
|
---|
1209 |
|
---|
1210 | /* if there were omitted context lines, fill them in now */
|
---|
1211 | if (fillcnt) {
|
---|
1212 | p_bfake = filldst; /* remember where not to free() */
|
---|
1213 | p_efake = filldst + fillcnt - 1;
|
---|
1214 | while (fillcnt-- > 0) {
|
---|
1215 | while (fillsrc <= p_end && fillsrc != repl_beginning
|
---|
1216 | && p_Char[fillsrc] != ' ')
|
---|
1217 | fillsrc++;
|
---|
1218 | if (p_end < fillsrc || fillsrc == repl_beginning)
|
---|
1219 | {
|
---|
1220 | fatal ("replacement text or line numbers mangled in hunk at line %s",
|
---|
1221 | format_linenum (numbuf0, p_hunk_beg));
|
---|
1222 | }
|
---|
1223 | p_line[filldst] = p_line[fillsrc];
|
---|
1224 | p_Char[filldst] = p_Char[fillsrc];
|
---|
1225 | p_len[filldst] = p_len[fillsrc];
|
---|
1226 | fillsrc++; filldst++;
|
---|
1227 | }
|
---|
1228 | while (fillsrc <= p_end && fillsrc != repl_beginning)
|
---|
1229 | {
|
---|
1230 | if (p_Char[fillsrc] == ' ')
|
---|
1231 | fatal ("replacement text or line numbers mangled in hunk at line %s",
|
---|
1232 | format_linenum (numbuf0, p_hunk_beg));
|
---|
1233 | fillsrc++;
|
---|
1234 | }
|
---|
1235 | if (debug & 64)
|
---|
1236 | printf ("fillsrc %s, filldst %s, rb %s, e+1 %s\n",
|
---|
1237 | format_linenum (numbuf0, fillsrc),
|
---|
1238 | format_linenum (numbuf1, filldst),
|
---|
1239 | format_linenum (numbuf2, repl_beginning),
|
---|
1240 | format_linenum (numbuf3, p_end + 1));
|
---|
1241 | assert(fillsrc==p_end+1 || fillsrc==repl_beginning);
|
---|
1242 | assert(filldst==p_end+1 || filldst==repl_beginning);
|
---|
1243 | }
|
---|
1244 | }
|
---|
1245 | else if (difftype == UNI_DIFF) {
|
---|
1246 | file_offset line_beginning = file_tell (pfp);
|
---|
1247 | /* file pos of the current line */
|
---|
1248 | register LINENUM fillsrc; /* index of old lines */
|
---|
1249 | register LINENUM filldst; /* index of new lines */
|
---|
1250 | char ch = '\0';
|
---|
1251 |
|
---|
1252 | chars_read = get_line ();
|
---|
1253 | if (chars_read == (size_t) -1
|
---|
1254 | || chars_read <= 4
|
---|
1255 | || strncmp (buf, "@@ -", 4) != 0) {
|
---|
1256 | next_intuit_at(line_beginning,p_input_line);
|
---|
1257 | return chars_read == (size_t) -1 ? -1 : 0;
|
---|
1258 | }
|
---|
1259 | s = scan_linenum (buf + 4, &p_first);
|
---|
1260 | if (*s == ',')
|
---|
1261 | s = scan_linenum (s + 1, &p_ptrn_lines);
|
---|
1262 | else
|
---|
1263 | p_ptrn_lines = 1;
|
---|
1264 | if (*s == ' ') s++;
|
---|
1265 | if (*s != '+')
|
---|
1266 | malformed ();
|
---|
1267 | s = scan_linenum (s + 1, &p_newfirst);
|
---|
1268 | if (*s == ',')
|
---|
1269 | s = scan_linenum (s + 1, &p_repl_lines);
|
---|
1270 | else
|
---|
1271 | p_repl_lines = 1;
|
---|
1272 | if (*s == ' ') s++;
|
---|
1273 | if (*s != '@')
|
---|
1274 | malformed ();
|
---|
1275 | if (!p_ptrn_lines)
|
---|
1276 | p_first++; /* do append rather than insert */
|
---|
1277 | if (!p_repl_lines)
|
---|
1278 | p_newfirst++;
|
---|
1279 | p_max = p_ptrn_lines + p_repl_lines + 1;
|
---|
1280 | while (p_max >= hunkmax)
|
---|
1281 | if (! grow_hunkmax ())
|
---|
1282 | return -1;
|
---|
1283 | fillsrc = 1;
|
---|
1284 | filldst = fillsrc + p_ptrn_lines;
|
---|
1285 | p_end = filldst + p_repl_lines;
|
---|
1286 | sprintf (buf, "*** %s,%s ****\n",
|
---|
1287 | format_linenum (numbuf0, p_first),
|
---|
1288 | format_linenum (numbuf1, p_first + p_ptrn_lines - 1));
|
---|
1289 | p_len[0] = strlen (buf);
|
---|
1290 | if (! (p_line[0] = savestr (buf))) {
|
---|
1291 | p_end = -1;
|
---|
1292 | return -1;
|
---|
1293 | }
|
---|
1294 | p_Char[0] = '*';
|
---|
1295 | sprintf (buf, "--- %s,%s ----\n",
|
---|
1296 | format_linenum (numbuf0, p_newfirst),
|
---|
1297 | format_linenum (numbuf1, p_newfirst + p_repl_lines - 1));
|
---|
1298 | p_len[filldst] = strlen (buf);
|
---|
1299 | if (! (p_line[filldst] = savestr (buf))) {
|
---|
1300 | p_end = 0;
|
---|
1301 | return -1;
|
---|
1302 | }
|
---|
1303 | p_Char[filldst++] = '=';
|
---|
1304 | p_prefix_context = -1;
|
---|
1305 | p_hunk_beg = p_input_line + 1;
|
---|
1306 | while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
|
---|
1307 | chars_read = get_line ();
|
---|
1308 | if (!chars_read) {
|
---|
1309 | if (p_max - filldst < 3) {
|
---|
1310 | strcpy (buf, " \n"); /* assume blank lines got chopped */
|
---|
1311 | chars_read = 2;
|
---|
1312 | } else {
|
---|
1313 | fatal ("unexpected end of file in patch");
|
---|
1314 | }
|
---|
1315 | }
|
---|
1316 | if (chars_read == (size_t) -1)
|
---|
1317 | s = 0;
|
---|
1318 | else if (*buf == '\t' || *buf == '\n') {
|
---|
1319 | ch = ' '; /* assume the space got eaten */
|
---|
1320 | s = savebuf (buf, chars_read);
|
---|
1321 | }
|
---|
1322 | else {
|
---|
1323 | ch = *buf;
|
---|
1324 | s = savebuf (buf+1, --chars_read);
|
---|
1325 | }
|
---|
1326 | if (!s) {
|
---|
1327 | while (--filldst > p_ptrn_lines)
|
---|
1328 | free(p_line[filldst]);
|
---|
1329 | p_end = fillsrc-1;
|
---|
1330 | return -1;
|
---|
1331 | }
|
---|
1332 | switch (ch) {
|
---|
1333 | case '-':
|
---|
1334 | if (fillsrc > p_ptrn_lines) {
|
---|
1335 | free(s);
|
---|
1336 | p_end = filldst-1;
|
---|
1337 | malformed ();
|
---|
1338 | }
|
---|
1339 | chars_read -= fillsrc == p_ptrn_lines && incomplete_line ();
|
---|
1340 | p_Char[fillsrc] = ch;
|
---|
1341 | p_line[fillsrc] = s;
|
---|
1342 | p_len[fillsrc++] = chars_read;
|
---|
1343 | break;
|
---|
1344 | case '=':
|
---|
1345 | ch = ' ';
|
---|
1346 | /* FALL THROUGH */
|
---|
1347 | case ' ':
|
---|
1348 | if (fillsrc > p_ptrn_lines) {
|
---|
1349 | free(s);
|
---|
1350 | while (--filldst > p_ptrn_lines)
|
---|
1351 | free(p_line[filldst]);
|
---|
1352 | p_end = fillsrc-1;
|
---|
1353 | malformed ();
|
---|
1354 | }
|
---|
1355 | context++;
|
---|
1356 | chars_read -= fillsrc == p_ptrn_lines && incomplete_line ();
|
---|
1357 | p_Char[fillsrc] = ch;
|
---|
1358 | p_line[fillsrc] = s;
|
---|
1359 | p_len[fillsrc++] = chars_read;
|
---|
1360 | s = savebuf (s, chars_read);
|
---|
1361 | if (!s) {
|
---|
1362 | while (--filldst > p_ptrn_lines)
|
---|
1363 | free(p_line[filldst]);
|
---|
1364 | p_end = fillsrc-1;
|
---|
1365 | return -1;
|
---|
1366 | }
|
---|
1367 | /* FALL THROUGH */
|
---|
1368 | case '+':
|
---|
1369 | if (filldst > p_end) {
|
---|
1370 | free(s);
|
---|
1371 | while (--filldst > p_ptrn_lines)
|
---|
1372 | free(p_line[filldst]);
|
---|
1373 | p_end = fillsrc-1;
|
---|
1374 | malformed ();
|
---|
1375 | }
|
---|
1376 | chars_read -= filldst == p_end && incomplete_line ();
|
---|
1377 | p_Char[filldst] = ch;
|
---|
1378 | p_line[filldst] = s;
|
---|
1379 | p_len[filldst++] = chars_read;
|
---|
1380 | break;
|
---|
1381 | default:
|
---|
1382 | p_end = filldst;
|
---|
1383 | malformed ();
|
---|
1384 | }
|
---|
1385 | if (ch != ' ') {
|
---|
1386 | if (p_prefix_context == -1)
|
---|
1387 | p_prefix_context = context;
|
---|
1388 | context = 0;
|
---|
1389 | }
|
---|
1390 | }/* while */
|
---|
1391 | if (p_prefix_context == -1)
|
---|
1392 | malformed ();
|
---|
1393 | p_suffix_context = context;
|
---|
1394 | }
|
---|
1395 | else { /* normal diff--fake it up */
|
---|
1396 | char hunk_type;
|
---|
1397 | register int i;
|
---|
1398 | LINENUM min, max;
|
---|
1399 | file_offset line_beginning = file_tell (pfp);
|
---|
1400 |
|
---|
1401 | p_prefix_context = p_suffix_context = 0;
|
---|
1402 | chars_read = get_line ();
|
---|
1403 | if (chars_read == (size_t) -1 || !chars_read || !ISDIGIT (*buf)) {
|
---|
1404 | next_intuit_at(line_beginning,p_input_line);
|
---|
1405 | return chars_read == (size_t) -1 ? -1 : 0;
|
---|
1406 | }
|
---|
1407 | s = scan_linenum (buf, &p_first);
|
---|
1408 | if (*s == ',') {
|
---|
1409 | s = scan_linenum (s + 1, &p_ptrn_lines);
|
---|
1410 | p_ptrn_lines += 1 - p_first;
|
---|
1411 | }
|
---|
1412 | else
|
---|
1413 | p_ptrn_lines = (*s != 'a');
|
---|
1414 | hunk_type = *s;
|
---|
1415 | if (hunk_type == 'a')
|
---|
1416 | p_first++; /* do append rather than insert */
|
---|
1417 | s = scan_linenum (s + 1, &min);
|
---|
1418 | if (*s == ',')
|
---|
1419 | scan_linenum (s + 1, &max);
|
---|
1420 | else
|
---|
1421 | max = min;
|
---|
1422 | if (hunk_type == 'd')
|
---|
1423 | min++;
|
---|
1424 | p_end = p_ptrn_lines + 1 + max - min + 1;
|
---|
1425 | while (p_end >= hunkmax)
|
---|
1426 | if (! grow_hunkmax ())
|
---|
1427 | {
|
---|
1428 | p_end = -1;
|
---|
1429 | return -1;
|
---|
1430 | }
|
---|
1431 | p_newfirst = min;
|
---|
1432 | p_repl_lines = max - min + 1;
|
---|
1433 | sprintf (buf, "*** %s,%s\n",
|
---|
1434 | format_linenum (numbuf0, p_first),
|
---|
1435 | format_linenum (numbuf1, p_first + p_ptrn_lines - 1));
|
---|
1436 | p_len[0] = strlen (buf);
|
---|
1437 | if (! (p_line[0] = savestr (buf))) {
|
---|
1438 | p_end = -1;
|
---|
1439 | return -1;
|
---|
1440 | }
|
---|
1441 | p_Char[0] = '*';
|
---|
1442 | for (i=1; i<=p_ptrn_lines; i++) {
|
---|
1443 | chars_read = get_line ();
|
---|
1444 | if (chars_read == (size_t) -1)
|
---|
1445 | {
|
---|
1446 | p_end = i - 1;
|
---|
1447 | return -1;
|
---|
1448 | }
|
---|
1449 | if (!chars_read)
|
---|
1450 | fatal ("unexpected end of file in patch at line %s",
|
---|
1451 | format_linenum (numbuf0, p_input_line));
|
---|
1452 | if (buf[0] != '<' || (buf[1] != ' ' && buf[1] != '\t'))
|
---|
1453 | fatal ("`<' expected at line %s of patch",
|
---|
1454 | format_linenum (numbuf0, p_input_line));
|
---|
1455 | chars_read -= 2 + (i == p_ptrn_lines && incomplete_line ());
|
---|
1456 | p_len[i] = chars_read;
|
---|
1457 | if (! (p_line[i] = savebuf (buf + 2, chars_read))) {
|
---|
1458 | p_end = i-1;
|
---|
1459 | return -1;
|
---|
1460 | }
|
---|
1461 | p_Char[i] = '-';
|
---|
1462 | }
|
---|
1463 | if (hunk_type == 'c') {
|
---|
1464 | chars_read = get_line ();
|
---|
1465 | if (chars_read == (size_t) -1)
|
---|
1466 | {
|
---|
1467 | p_end = i - 1;
|
---|
1468 | return -1;
|
---|
1469 | }
|
---|
1470 | if (! chars_read)
|
---|
1471 | fatal ("unexpected end of file in patch at line %s",
|
---|
1472 | format_linenum (numbuf0, p_input_line));
|
---|
1473 | if (*buf != '-')
|
---|
1474 | fatal ("`---' expected at line %s of patch",
|
---|
1475 | format_linenum (numbuf0, p_input_line));
|
---|
1476 | }
|
---|
1477 | sprintf (buf, "--- %s,%s\n",
|
---|
1478 | format_linenum (numbuf0, min),
|
---|
1479 | format_linenum (numbuf1, max));
|
---|
1480 | p_len[i] = strlen (buf);
|
---|
1481 | if (! (p_line[i] = savestr (buf))) {
|
---|
1482 | p_end = i-1;
|
---|
1483 | return -1;
|
---|
1484 | }
|
---|
1485 | p_Char[i] = '=';
|
---|
1486 | for (i++; i<=p_end; i++) {
|
---|
1487 | chars_read = get_line ();
|
---|
1488 | if (chars_read == (size_t) -1)
|
---|
1489 | {
|
---|
1490 | p_end = i - 1;
|
---|
1491 | return -1;
|
---|
1492 | }
|
---|
1493 | if (!chars_read)
|
---|
1494 | fatal ("unexpected end of file in patch at line %s",
|
---|
1495 | format_linenum (numbuf0, p_input_line));
|
---|
1496 | if (buf[0] != '>' || (buf[1] != ' ' && buf[1] != '\t'))
|
---|
1497 | fatal ("`>' expected at line %s of patch",
|
---|
1498 | format_linenum (numbuf0, p_input_line));
|
---|
1499 | chars_read -= 2 + (i == p_end && incomplete_line ());
|
---|
1500 | p_len[i] = chars_read;
|
---|
1501 | if (! (p_line[i] = savebuf (buf + 2, chars_read))) {
|
---|
1502 | p_end = i-1;
|
---|
1503 | return -1;
|
---|
1504 | }
|
---|
1505 | p_Char[i] = '+';
|
---|
1506 | }
|
---|
1507 | }
|
---|
1508 | if (rev) /* backwards patch? */
|
---|
1509 | if (!pch_swap())
|
---|
1510 | say ("Not enough memory to swap next hunk!\n");
|
---|
1511 | if (debug & 2) {
|
---|
1512 | LINENUM i;
|
---|
1513 | char special;
|
---|
1514 |
|
---|
1515 | for (i=0; i <= p_end; i++) {
|
---|
1516 | if (i == p_ptrn_lines)
|
---|
1517 | special = '^';
|
---|
1518 | else
|
---|
1519 | special = ' ';
|
---|
1520 | fprintf (stderr, "%s %c %c ", format_linenum (numbuf0, i),
|
---|
1521 | p_Char[i], special);
|
---|
1522 | pch_write_line (i, stderr);
|
---|
1523 | fflush (stderr);
|
---|
1524 | }
|
---|
1525 | }
|
---|
1526 | if (p_end+1 < hunkmax) /* paranoia reigns supreme... */
|
---|
1527 | p_Char[p_end+1] = '^'; /* add a stopper for apply_hunk */
|
---|
1528 | return 1;
|
---|
1529 | }
|
---|
1530 |
|
---|
1531 | static size_t
|
---|
1532 | get_line (void)
|
---|
1533 | {
|
---|
1534 | return pget_line (p_indent, p_rfc934_nesting, p_strip_trailing_cr,
|
---|
1535 | p_pass_comments_through);
|
---|
1536 | }
|
---|
1537 |
|
---|
1538 | /* Input a line from the patch file, worrying about indentation.
|
---|
1539 | Strip up to INDENT characters' worth of leading indentation.
|
---|
1540 | Then remove up to RFC934_NESTING instances of leading "- ".
|
---|
1541 | If STRIP_TRAILING_CR is true, remove any trailing carriage-return.
|
---|
1542 | Unless PASS_COMMENTS_THROUGH is true, ignore any resulting lines
|
---|
1543 | that begin with '#'; they're comments.
|
---|
1544 | Ignore any partial lines at end of input, but warn about them.
|
---|
1545 | Succeed if a line was read; it is terminated by "\n\0" for convenience.
|
---|
1546 | Return the number of characters read, including '\n' but not '\0'.
|
---|
1547 | Return -1 if we ran out of memory. */
|
---|
1548 |
|
---|
1549 | static size_t
|
---|
1550 | pget_line (int indent, int rfc934_nesting, bool strip_trailing_cr,
|
---|
1551 | bool pass_comments_through)
|
---|
1552 | {
|
---|
1553 | register FILE *fp = pfp;
|
---|
1554 | register int c;
|
---|
1555 | register int i;
|
---|
1556 | register char *b;
|
---|
1557 | register size_t s;
|
---|
1558 |
|
---|
1559 | do
|
---|
1560 | {
|
---|
1561 | i = 0;
|
---|
1562 | for (;;)
|
---|
1563 | {
|
---|
1564 | c = getc (fp);
|
---|
1565 | if (c == EOF)
|
---|
1566 | {
|
---|
1567 | if (ferror (fp))
|
---|
1568 | read_fatal ();
|
---|
1569 | return 0;
|
---|
1570 | }
|
---|
1571 | if (indent <= i)
|
---|
1572 | break;
|
---|
1573 | if (c == ' ' || c == 'X')
|
---|
1574 | i++;
|
---|
1575 | else if (c == '\t')
|
---|
1576 | i = (i + 8) & ~7;
|
---|
1577 | else
|
---|
1578 | break;
|
---|
1579 | }
|
---|
1580 |
|
---|
1581 | i = 0;
|
---|
1582 | b = buf;
|
---|
1583 |
|
---|
1584 | while (c == '-' && 0 <= --rfc934_nesting)
|
---|
1585 | {
|
---|
1586 | c = getc (fp);
|
---|
1587 | if (c == EOF)
|
---|
1588 | goto patch_ends_in_middle_of_line;
|
---|
1589 | if (c != ' ')
|
---|
1590 | {
|
---|
1591 | i = 1;
|
---|
1592 | b[0] = '-';
|
---|
1593 | break;
|
---|
1594 | }
|
---|
1595 | c = getc (fp);
|
---|
1596 | if (c == EOF)
|
---|
1597 | goto patch_ends_in_middle_of_line;
|
---|
1598 | }
|
---|
1599 |
|
---|
1600 | s = bufsize;
|
---|
1601 |
|
---|
1602 | for (;;)
|
---|
1603 | {
|
---|
1604 | if (i == s - 1)
|
---|
1605 | {
|
---|
1606 | s *= 2;
|
---|
1607 | b = realloc (b, s);
|
---|
1608 | if (!b)
|
---|
1609 | {
|
---|
1610 | if (!using_plan_a)
|
---|
1611 | memory_fatal ();
|
---|
1612 | return (size_t) -1;
|
---|
1613 | }
|
---|
1614 | buf = b;
|
---|
1615 | bufsize = s;
|
---|
1616 | }
|
---|
1617 | b[i++] = c;
|
---|
1618 | if (c == '\n')
|
---|
1619 | break;
|
---|
1620 | c = getc (fp);
|
---|
1621 | if (c == EOF)
|
---|
1622 | goto patch_ends_in_middle_of_line;
|
---|
1623 | }
|
---|
1624 |
|
---|
1625 | p_input_line++;
|
---|
1626 | }
|
---|
1627 | while (*b == '#' && !pass_comments_through);
|
---|
1628 |
|
---|
1629 | if (strip_trailing_cr && 2 <= i && b[i - 2] == '\r')
|
---|
1630 | b[i-- - 2] = '\n';
|
---|
1631 | b[i] = '\0';
|
---|
1632 | return i;
|
---|
1633 |
|
---|
1634 | patch_ends_in_middle_of_line:
|
---|
1635 | if (ferror (fp))
|
---|
1636 | read_fatal ();
|
---|
1637 | say ("patch unexpectedly ends in middle of line\n");
|
---|
1638 | return 0;
|
---|
1639 | }
|
---|
1640 |
|
---|
1641 | static bool
|
---|
1642 | incomplete_line (void)
|
---|
1643 | {
|
---|
1644 | register FILE *fp = pfp;
|
---|
1645 | register int c;
|
---|
1646 | register file_offset line_beginning = file_tell (fp);
|
---|
1647 |
|
---|
1648 | if (getc (fp) == '\\')
|
---|
1649 | {
|
---|
1650 | while ((c = getc (fp)) != '\n' && c != EOF)
|
---|
1651 | continue;
|
---|
1652 | return true;
|
---|
1653 | }
|
---|
1654 | else
|
---|
1655 | {
|
---|
1656 | /* We don't trust ungetc. */
|
---|
1657 | Fseek (pfp, line_beginning, SEEK_SET);
|
---|
1658 | return false;
|
---|
1659 | }
|
---|
1660 | }
|
---|
1661 |
|
---|
1662 | /* Reverse the old and new portions of the current hunk. */
|
---|
1663 |
|
---|
1664 | bool
|
---|
1665 | pch_swap (void)
|
---|
1666 | {
|
---|
1667 | char **tp_line; /* the text of the hunk */
|
---|
1668 | size_t *tp_len; /* length of each line */
|
---|
1669 | char *tp_char; /* +, -, and ! */
|
---|
1670 | register LINENUM i;
|
---|
1671 | register LINENUM n;
|
---|
1672 | bool blankline = false;
|
---|
1673 | register char *s;
|
---|
1674 |
|
---|
1675 | i = p_first;
|
---|
1676 | p_first = p_newfirst;
|
---|
1677 | p_newfirst = i;
|
---|
1678 |
|
---|
1679 | /* make a scratch copy */
|
---|
1680 |
|
---|
1681 | tp_line = p_line;
|
---|
1682 | tp_len = p_len;
|
---|
1683 | tp_char = p_Char;
|
---|
1684 | p_line = 0; /* force set_hunkmax to allocate again */
|
---|
1685 | p_len = 0;
|
---|
1686 | p_Char = 0;
|
---|
1687 | set_hunkmax();
|
---|
1688 | if (!p_line || !p_len || !p_Char) {
|
---|
1689 | if (p_line)
|
---|
1690 | free (p_line);
|
---|
1691 | p_line = tp_line;
|
---|
1692 | if (p_len)
|
---|
1693 | free (p_len);
|
---|
1694 | p_len = tp_len;
|
---|
1695 | if (p_Char)
|
---|
1696 | free (p_Char);
|
---|
1697 | p_Char = tp_char;
|
---|
1698 | return false; /* not enough memory to swap hunk! */
|
---|
1699 | }
|
---|
1700 |
|
---|
1701 | /* now turn the new into the old */
|
---|
1702 |
|
---|
1703 | i = p_ptrn_lines + 1;
|
---|
1704 | if (tp_char[i] == '\n') { /* account for possible blank line */
|
---|
1705 | blankline = true;
|
---|
1706 | i++;
|
---|
1707 | }
|
---|
1708 | if (p_efake >= 0) { /* fix non-freeable ptr range */
|
---|
1709 | if (p_efake <= i)
|
---|
1710 | n = p_end - i + 1;
|
---|
1711 | else
|
---|
1712 | n = -i;
|
---|
1713 | p_efake += n;
|
---|
1714 | p_bfake += n;
|
---|
1715 | }
|
---|
1716 | for (n=0; i <= p_end; i++,n++) {
|
---|
1717 | p_line[n] = tp_line[i];
|
---|
1718 | p_Char[n] = tp_char[i];
|
---|
1719 | if (p_Char[n] == '+')
|
---|
1720 | p_Char[n] = '-';
|
---|
1721 | p_len[n] = tp_len[i];
|
---|
1722 | }
|
---|
1723 | if (blankline) {
|
---|
1724 | i = p_ptrn_lines + 1;
|
---|
1725 | p_line[n] = tp_line[i];
|
---|
1726 | p_Char[n] = tp_char[i];
|
---|
1727 | p_len[n] = tp_len[i];
|
---|
1728 | n++;
|
---|
1729 | }
|
---|
1730 | assert(p_Char[0] == '=');
|
---|
1731 | p_Char[0] = '*';
|
---|
1732 | for (s=p_line[0]; *s; s++)
|
---|
1733 | if (*s == '-')
|
---|
1734 | *s = '*';
|
---|
1735 |
|
---|
1736 | /* now turn the old into the new */
|
---|
1737 |
|
---|
1738 | assert(tp_char[0] == '*');
|
---|
1739 | tp_char[0] = '=';
|
---|
1740 | for (s=tp_line[0]; *s; s++)
|
---|
1741 | if (*s == '*')
|
---|
1742 | *s = '-';
|
---|
1743 | for (i=0; n <= p_end; i++,n++) {
|
---|
1744 | p_line[n] = tp_line[i];
|
---|
1745 | p_Char[n] = tp_char[i];
|
---|
1746 | if (p_Char[n] == '-')
|
---|
1747 | p_Char[n] = '+';
|
---|
1748 | p_len[n] = tp_len[i];
|
---|
1749 | }
|
---|
1750 | assert(i == p_ptrn_lines + 1);
|
---|
1751 | i = p_ptrn_lines;
|
---|
1752 | p_ptrn_lines = p_repl_lines;
|
---|
1753 | p_repl_lines = i;
|
---|
1754 | if (tp_line)
|
---|
1755 | free (tp_line);
|
---|
1756 | if (tp_len)
|
---|
1757 | free (tp_len);
|
---|
1758 | if (tp_char)
|
---|
1759 | free (tp_char);
|
---|
1760 | return true;
|
---|
1761 | }
|
---|
1762 |
|
---|
1763 | /* Return whether file WHICH (false = old, true = new) appears to nonexistent.
|
---|
1764 | Return 1 for empty, 2 for nonexistent. */
|
---|
1765 |
|
---|
1766 | int
|
---|
1767 | pch_says_nonexistent (bool which)
|
---|
1768 | {
|
---|
1769 | return p_says_nonexistent[which];
|
---|
1770 | }
|
---|
1771 |
|
---|
1772 | /* Return timestamp of patch header for file WHICH (false = old, true = new),
|
---|
1773 | or -1 if there was no timestamp or an error in the timestamp. */
|
---|
1774 |
|
---|
1775 | time_t
|
---|
1776 | pch_timestamp (bool which)
|
---|
1777 | {
|
---|
1778 | return p_timestamp[which];
|
---|
1779 | }
|
---|
1780 |
|
---|
1781 | /* Return the specified line position in the old file of the old context. */
|
---|
1782 |
|
---|
1783 | LINENUM
|
---|
1784 | pch_first (void)
|
---|
1785 | {
|
---|
1786 | return p_first;
|
---|
1787 | }
|
---|
1788 |
|
---|
1789 | /* Return the number of lines of old context. */
|
---|
1790 |
|
---|
1791 | LINENUM
|
---|
1792 | pch_ptrn_lines (void)
|
---|
1793 | {
|
---|
1794 | return p_ptrn_lines;
|
---|
1795 | }
|
---|
1796 |
|
---|
1797 | /* Return the probable line position in the new file of the first line. */
|
---|
1798 |
|
---|
1799 | LINENUM
|
---|
1800 | pch_newfirst (void)
|
---|
1801 | {
|
---|
1802 | return p_newfirst;
|
---|
1803 | }
|
---|
1804 |
|
---|
1805 | /* Return the number of lines in the replacement text including context. */
|
---|
1806 |
|
---|
1807 | LINENUM
|
---|
1808 | pch_repl_lines (void)
|
---|
1809 | {
|
---|
1810 | return p_repl_lines;
|
---|
1811 | }
|
---|
1812 |
|
---|
1813 | /* Return the number of lines in the whole hunk. */
|
---|
1814 |
|
---|
1815 | LINENUM
|
---|
1816 | pch_end (void)
|
---|
1817 | {
|
---|
1818 | return p_end;
|
---|
1819 | }
|
---|
1820 |
|
---|
1821 | /* Return the number of context lines before the first changed line. */
|
---|
1822 |
|
---|
1823 | LINENUM
|
---|
1824 | pch_prefix_context (void)
|
---|
1825 | {
|
---|
1826 | return p_prefix_context;
|
---|
1827 | }
|
---|
1828 |
|
---|
1829 | /* Return the number of context lines after the last changed line. */
|
---|
1830 |
|
---|
1831 | LINENUM
|
---|
1832 | pch_suffix_context (void)
|
---|
1833 | {
|
---|
1834 | return p_suffix_context;
|
---|
1835 | }
|
---|
1836 |
|
---|
1837 | /* Return the length of a particular patch line. */
|
---|
1838 |
|
---|
1839 | size_t
|
---|
1840 | pch_line_len (LINENUM line)
|
---|
1841 | {
|
---|
1842 | return p_len[line];
|
---|
1843 | }
|
---|
1844 |
|
---|
1845 | /* Return the control character (+, -, *, !, etc) for a patch line. */
|
---|
1846 |
|
---|
1847 | char
|
---|
1848 | pch_char (LINENUM line)
|
---|
1849 | {
|
---|
1850 | return p_Char[line];
|
---|
1851 | }
|
---|
1852 |
|
---|
1853 | /* Return a pointer to a particular patch line. */
|
---|
1854 |
|
---|
1855 | char *
|
---|
1856 | pfetch (LINENUM line)
|
---|
1857 | {
|
---|
1858 | return p_line[line];
|
---|
1859 | }
|
---|
1860 |
|
---|
1861 | /* Output a patch line. */
|
---|
1862 |
|
---|
1863 | bool
|
---|
1864 | pch_write_line (LINENUM line, FILE *file)
|
---|
1865 | {
|
---|
1866 | bool after_newline = p_line[line][p_len[line] - 1] == '\n';
|
---|
1867 | if (! fwrite (p_line[line], sizeof (*p_line[line]), p_len[line], file))
|
---|
1868 | write_fatal ();
|
---|
1869 | return after_newline;
|
---|
1870 | }
|
---|
1871 |
|
---|
1872 | /* Return where in the patch file this hunk began, for error messages. */
|
---|
1873 |
|
---|
1874 | LINENUM
|
---|
1875 | pch_hunk_beg (void)
|
---|
1876 | {
|
---|
1877 | return p_hunk_beg;
|
---|
1878 | }
|
---|
1879 |
|
---|
1880 | /* Is the newline-terminated line a valid `ed' command for patch
|
---|
1881 | input? If so, return the command character; if not, return 0.
|
---|
1882 | This accepts accepts just a subset of the valid commands, but it's
|
---|
1883 | good enough in practice. */
|
---|
1884 |
|
---|
1885 | static char
|
---|
1886 | get_ed_command_letter (char const *line)
|
---|
1887 | {
|
---|
1888 | char const *p = line;
|
---|
1889 | char letter;
|
---|
1890 | bool pair = false;
|
---|
1891 | if (! ISDIGIT (*p))
|
---|
1892 | return 0;
|
---|
1893 | while (ISDIGIT (*++p))
|
---|
1894 | continue;
|
---|
1895 | if (*p == ',')
|
---|
1896 | {
|
---|
1897 | if (! ISDIGIT (*++p))
|
---|
1898 | return 0;
|
---|
1899 | while (ISDIGIT (*++p))
|
---|
1900 | continue;
|
---|
1901 | pair = true;
|
---|
1902 | }
|
---|
1903 | letter = *p++;
|
---|
1904 |
|
---|
1905 | switch (letter)
|
---|
1906 | {
|
---|
1907 | case 'a':
|
---|
1908 | case 'i':
|
---|
1909 | if (pair)
|
---|
1910 | return 0;
|
---|
1911 | break;
|
---|
1912 |
|
---|
1913 | case 'c':
|
---|
1914 | case 'd':
|
---|
1915 | break;
|
---|
1916 |
|
---|
1917 | case 's':
|
---|
1918 | if (strncmp (p, "/.//", 4) != 0)
|
---|
1919 | return 0;
|
---|
1920 | p += 4;
|
---|
1921 | break;
|
---|
1922 |
|
---|
1923 | default:
|
---|
1924 | return 0;
|
---|
1925 | }
|
---|
1926 |
|
---|
1927 | while (*p == ' ' || *p == '\t')
|
---|
1928 | p++;
|
---|
1929 | if (*p == '\n')
|
---|
1930 | return letter;
|
---|
1931 | return 0;
|
---|
1932 | }
|
---|
1933 |
|
---|
1934 | /* Apply an ed script by feeding ed itself. */
|
---|
1935 |
|
---|
1936 | void
|
---|
1937 | do_ed_script (FILE *ofp)
|
---|
1938 | {
|
---|
1939 | static char const ed_program[] = ed_PROGRAM;
|
---|
1940 |
|
---|
1941 | register file_offset beginning_of_this_line;
|
---|
1942 | register FILE *pipefp = 0;
|
---|
1943 | register size_t chars_read;
|
---|
1944 |
|
---|
1945 | if (! dry_run && ! skip_rest_of_patch) {
|
---|
1946 | int exclusive = TMPOUTNAME_needs_removal ? 0 : O_EXCL;
|
---|
1947 | assert (! inerrno);
|
---|
1948 | TMPOUTNAME_needs_removal = 1;
|
---|
1949 | copy_file (inname, TMPOUTNAME, exclusive, instat.st_mode);
|
---|
1950 | sprintf (buf, "%s %s%s", ed_program, verbosity == VERBOSE ? "" : "- ",
|
---|
1951 | TMPOUTNAME);
|
---|
1952 | fflush (stdout);
|
---|
1953 | pipefp = popen(buf, binary_transput ? "wb" : "w");
|
---|
1954 | if (!pipefp)
|
---|
1955 | pfatal ("Can't open pipe to %s", quotearg (buf));
|
---|
1956 | }
|
---|
1957 | for (;;) {
|
---|
1958 | char ed_command_letter;
|
---|
1959 | beginning_of_this_line = file_tell (pfp);
|
---|
1960 | chars_read = get_line ();
|
---|
1961 | if (! chars_read) {
|
---|
1962 | next_intuit_at(beginning_of_this_line,p_input_line);
|
---|
1963 | break;
|
---|
1964 | }
|
---|
1965 | ed_command_letter = get_ed_command_letter (buf);
|
---|
1966 | if (ed_command_letter) {
|
---|
1967 | if (pipefp)
|
---|
1968 | if (! fwrite (buf, sizeof *buf, chars_read, pipefp))
|
---|
1969 | write_fatal ();
|
---|
1970 | if (ed_command_letter != 'd' && ed_command_letter != 's') {
|
---|
1971 | p_pass_comments_through = true;
|
---|
1972 | while ((chars_read = get_line ()) != 0) {
|
---|
1973 | if (pipefp)
|
---|
1974 | if (! fwrite (buf, sizeof *buf, chars_read, pipefp))
|
---|
1975 | write_fatal ();
|
---|
1976 | if (chars_read == 2 && strEQ (buf, ".\n"))
|
---|
1977 | break;
|
---|
1978 | }
|
---|
1979 | p_pass_comments_through = false;
|
---|
1980 | }
|
---|
1981 | }
|
---|
1982 | else {
|
---|
1983 | next_intuit_at(beginning_of_this_line,p_input_line);
|
---|
1984 | break;
|
---|
1985 | }
|
---|
1986 | }
|
---|
1987 | if (!pipefp)
|
---|
1988 | return;
|
---|
1989 | if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, pipefp) == 0
|
---|
1990 | || fflush (pipefp) != 0)
|
---|
1991 | write_fatal ();
|
---|
1992 | if (pclose (pipefp) != 0)
|
---|
1993 | fatal ("%s FAILED", ed_program);
|
---|
1994 |
|
---|
1995 | if (ofp)
|
---|
1996 | {
|
---|
1997 | FILE *ifp = fopen (TMPOUTNAME, binary_transput ? "rb" : "r");
|
---|
1998 | int c;
|
---|
1999 | if (!ifp)
|
---|
2000 | pfatal ("can't open `%s'", TMPOUTNAME);
|
---|
2001 | while ((c = getc (ifp)) != EOF)
|
---|
2002 | if (putc (c, ofp) == EOF)
|
---|
2003 | write_fatal ();
|
---|
2004 | if (ferror (ifp) || fclose (ifp) != 0)
|
---|
2005 | read_fatal ();
|
---|
2006 | }
|
---|
2007 | }
|
---|