GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: patch.c,v 1.63 2016/01/04 14:09:46 gsoares Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* patch - a program to apply diffs to original files |
||
5 |
* |
||
6 |
* Copyright 1986, Larry Wall |
||
7 |
* |
||
8 |
* Redistribution and use in source and binary forms, with or without |
||
9 |
* modification, are permitted provided that the following condition is met: |
||
10 |
* 1. Redistributions of source code must retain the above copyright notice, |
||
11 |
* this condition and the following disclaimer. |
||
12 |
* |
||
13 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY |
||
14 |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
15 |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
16 |
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR |
||
17 |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
18 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||
19 |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||
20 |
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
21 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||
22 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||
23 |
* SUCH DAMAGE. |
||
24 |
* |
||
25 |
* -C option added in 1998, original code by Marc Espie, based on FreeBSD |
||
26 |
* behaviour |
||
27 |
*/ |
||
28 |
|||
29 |
#include <sys/types.h> |
||
30 |
#include <sys/stat.h> |
||
31 |
#include <unistd.h> |
||
32 |
|||
33 |
#include <ctype.h> |
||
34 |
#include <getopt.h> |
||
35 |
#include <limits.h> |
||
36 |
#include <stdio.h> |
||
37 |
#include <string.h> |
||
38 |
#include <stdlib.h> |
||
39 |
|||
40 |
#include "common.h" |
||
41 |
#include "util.h" |
||
42 |
#include "pch.h" |
||
43 |
#include "inp.h" |
||
44 |
#include "backupfile.h" |
||
45 |
#include "pathnames.h" |
||
46 |
#include "ed.h" |
||
47 |
|||
48 |
mode_t filemode = 0644; |
||
49 |
|||
50 |
char buf[MAXLINELEN]; /* general purpose buffer */ |
||
51 |
|||
52 |
bool using_plan_a = true; /* try to keep everything in memory */ |
||
53 |
bool out_of_mem = false; /* ran out of memory in plan a */ |
||
54 |
|||
55 |
#define MAXFILEC 2 |
||
56 |
|||
57 |
char *filearg[MAXFILEC]; |
||
58 |
bool ok_to_create_file = false; |
||
59 |
char *outname = NULL; |
||
60 |
char *origprae = NULL; |
||
61 |
char *TMPOUTNAME; |
||
62 |
char *TMPINNAME; |
||
63 |
char *TMPREJNAME; |
||
64 |
char *TMPPATNAME; |
||
65 |
bool toutkeep = false; |
||
66 |
bool trejkeep = false; |
||
67 |
bool warn_on_invalid_line; |
||
68 |
bool last_line_missing_eol; |
||
69 |
|||
70 |
#ifdef DEBUGGING |
||
71 |
int debug = 0; |
||
72 |
#endif |
||
73 |
|||
74 |
bool force = false; |
||
75 |
bool batch = false; |
||
76 |
bool verbose = true; |
||
77 |
bool reverse = false; |
||
78 |
bool noreverse = false; |
||
79 |
bool skip_rest_of_patch = false; |
||
80 |
int strippath = 957; |
||
81 |
bool canonicalize = false; |
||
82 |
bool check_only = false; |
||
83 |
int diff_type = 0; |
||
84 |
char *revision = NULL; /* prerequisite revision, if any */ |
||
85 |
LINENUM input_lines = 0; /* how long is input file in lines */ |
||
86 |
int posix = 0; /* strict POSIX mode? */ |
||
87 |
|||
88 |
static void reinitialize_almost_everything(void); |
||
89 |
static void get_some_switches(void); |
||
90 |
static LINENUM locate_hunk(LINENUM); |
||
91 |
static void abort_context_hunk(void); |
||
92 |
static void rej_line(int, LINENUM); |
||
93 |
static void abort_hunk(void); |
||
94 |
static void apply_hunk(LINENUM); |
||
95 |
static void init_output(const char *); |
||
96 |
static void init_reject(const char *); |
||
97 |
static void copy_till(LINENUM, bool); |
||
98 |
static void spew_output(void); |
||
99 |
static void dump_line(LINENUM, bool); |
||
100 |
static bool patch_match(LINENUM, LINENUM, LINENUM); |
||
101 |
static bool similar(const char *, const char *, int); |
||
102 |
static __dead void usage(void); |
||
103 |
|||
104 |
/* true if -E was specified on command line. */ |
||
105 |
static bool remove_empty_files = false; |
||
106 |
|||
107 |
/* true if -R was specified on command line. */ |
||
108 |
static bool reverse_flag_specified = false; |
||
109 |
|||
110 |
/* buffer holding the name of the rejected patch file. */ |
||
111 |
static char rejname[NAME_MAX + 1]; |
||
112 |
|||
113 |
/* how many input lines have been irretractibly output */ |
||
114 |
static LINENUM last_frozen_line = 0; |
||
115 |
|||
116 |
static int Argc; /* guess */ |
||
117 |
static char **Argv; |
||
118 |
static int Argc_last; /* for restarting plan_b */ |
||
119 |
static char **Argv_last; |
||
120 |
|||
121 |
static FILE *ofp = NULL; /* output file pointer */ |
||
122 |
static FILE *rejfp = NULL; /* reject file pointer */ |
||
123 |
|||
124 |
static int filec = 0; /* how many file arguments? */ |
||
125 |
static LINENUM last_offset = 0; |
||
126 |
static LINENUM maxfuzz = 2; |
||
127 |
|||
128 |
/* patch using ifdef, ifndef, etc. */ |
||
129 |
static bool do_defines = false; |
||
130 |
/* #ifdef xyzzy */ |
||
131 |
static char if_defined[128]; |
||
132 |
/* #ifndef xyzzy */ |
||
133 |
static char not_defined[128]; |
||
134 |
/* #else */ |
||
135 |
static const char else_defined[] = "#else\n"; |
||
136 |
/* #endif xyzzy */ |
||
137 |
static char end_defined[128]; |
||
138 |
|||
139 |
|||
140 |
/* Apply a set of diffs as appropriate. */ |
||
141 |
|||
142 |
int |
||
143 |
main(int argc, char *argv[]) |
||
144 |
60 |
{ |
|
145 |
60 |
int error = 0, hunk, failed, i, fd; |
|
146 |
bool patch_seen; |
||
147 |
60 |
LINENUM where = 0, newwhere, fuzz, mymaxfuzz; |
|
148 |
const char *tmpdir; |
||
149 |
char *v; |
||
150 |
|||
151 |
✗✓ | 60 |
if (pledge("stdio rpath wpath cpath tmppath fattr", NULL) == -1) { |
152 |
perror("pledge"); |
||
153 |
my_exit(2); |
||
154 |
} |
||
155 |
|||
156 |
60 |
setvbuf(stdout, NULL, _IOLBF, 0); |
|
157 |
60 |
setvbuf(stderr, NULL, _IOLBF, 0); |
|
158 |
✓✓ | 180 |
for (i = 0; i < MAXFILEC; i++) |
159 |
120 |
filearg[i] = NULL; |
|
160 |
|||
161 |
/* Cons up the names of the temporary files. */ |
||
162 |
✗✓✗✗ |
60 |
if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') |
163 |
60 |
tmpdir = _PATH_TMP; |
|
164 |
✓✗✓✓ |
60 |
for (i = strlen(tmpdir) - 1; i > 0 && tmpdir[i] == '/'; i--) |
165 |
; |
||
166 |
60 |
i++; |
|
167 |
✗✓ | 60 |
if (asprintf(&TMPOUTNAME, "%.*s/patchoXXXXXXXXXX", i, tmpdir) == -1) |
168 |
fatal("cannot allocate memory"); |
||
169 |
✗✓ | 60 |
if ((fd = mkstemp(TMPOUTNAME)) < 0) |
170 |
pfatal("can't create %s", TMPOUTNAME); |
||
171 |
60 |
close(fd); |
|
172 |
|||
173 |
✗✓ | 60 |
if (asprintf(&TMPINNAME, "%.*s/patchiXXXXXXXXXX", i, tmpdir) == -1) |
174 |
fatal("cannot allocate memory"); |
||
175 |
✗✓ | 60 |
if ((fd = mkstemp(TMPINNAME)) < 0) |
176 |
pfatal("can't create %s", TMPINNAME); |
||
177 |
60 |
close(fd); |
|
178 |
|||
179 |
✗✓ | 60 |
if (asprintf(&TMPREJNAME, "%.*s/patchrXXXXXXXXXX", i, tmpdir) == -1) |
180 |
fatal("cannot allocate memory"); |
||
181 |
✗✓ | 60 |
if ((fd = mkstemp(TMPREJNAME)) < 0) |
182 |
pfatal("can't create %s", TMPREJNAME); |
||
183 |
60 |
close(fd); |
|
184 |
|||
185 |
✗✓ | 60 |
if (asprintf(&TMPPATNAME, "%.*s/patchpXXXXXXXXXX", i, tmpdir) == -1) |
186 |
fatal("cannot allocate memory"); |
||
187 |
✗✓ | 60 |
if ((fd = mkstemp(TMPPATNAME)) < 0) |
188 |
pfatal("can't create %s", TMPPATNAME); |
||
189 |
60 |
close(fd); |
|
190 |
|||
191 |
60 |
v = getenv("SIMPLE_BACKUP_SUFFIX"); |
|
192 |
✗✓ | 60 |
if (v) |
193 |
simple_backup_suffix = v; |
||
194 |
else |
||
195 |
60 |
simple_backup_suffix = ORIGEXT; |
|
196 |
|||
197 |
/* parse switches */ |
||
198 |
60 |
Argc = argc; |
|
199 |
60 |
Argv = argv; |
|
200 |
60 |
get_some_switches(); |
|
201 |
|||
202 |
✗✓ | 60 |
if (backup_type == none) { |
203 |
if ((v = getenv("PATCH_VERSION_CONTROL")) == NULL) |
||
204 |
v = getenv("VERSION_CONTROL"); |
||
205 |
if (v != NULL || !posix) |
||
206 |
backup_type = get_version(v); /* OK to pass NULL. */ |
||
207 |
} |
||
208 |
|||
209 |
/* make sure we clean up /tmp in case of disaster */ |
||
210 |
60 |
set_signals(0); |
|
211 |
|||
212 |
60 |
patch_seen = false; |
|
213 |
✓✓ | 172 |
for (open_patch_file(filearg[1]); there_is_another_patch(); |
214 |
52 |
reinitialize_almost_everything()) { |
|
215 |
/* for each patch in patch file */ |
||
216 |
|||
217 |
52 |
patch_seen = true; |
|
218 |
|||
219 |
52 |
warn_on_invalid_line = true; |
|
220 |
|||
221 |
✓✗ | 52 |
if (outname == NULL) |
222 |
52 |
outname = xstrdup(filearg[0]); |
|
223 |
|||
224 |
/* initialize the patched file */ |
||
225 |
✓✗ | 52 |
if (!skip_rest_of_patch) |
226 |
52 |
init_output(TMPOUTNAME); |
|
227 |
|||
228 |
/* initialize reject file */ |
||
229 |
52 |
init_reject(TMPREJNAME); |
|
230 |
|||
231 |
/* find out where all the lines are */ |
||
232 |
✓✗ | 52 |
if (!skip_rest_of_patch) |
233 |
52 |
scan_input(filearg[0]); |
|
234 |
|||
235 |
/* for ed script just up and do it and exit */ |
||
236 |
✓✓ | 52 |
if (diff_type == ED_DIFF) { |
237 |
13 |
do_ed_script(); |
|
238 |
13 |
continue; |
|
239 |
} |
||
240 |
|||
241 |
/* from here on, open no standard i/o files, because malloc */ |
||
242 |
/* might misfire and we can't catch it easily */ |
||
243 |
|||
244 |
/* apply each hunk of patch */ |
||
245 |
39 |
hunk = 0; |
|
246 |
39 |
failed = 0; |
|
247 |
39 |
out_of_mem = false; |
|
248 |
✓✓ | 864 |
while (another_hunk()) { |
249 |
786 |
hunk++; |
|
250 |
786 |
fuzz = 0; |
|
251 |
786 |
mymaxfuzz = pch_context(); |
|
252 |
✓✓ | 786 |
if (maxfuzz < mymaxfuzz) |
253 |
218 |
mymaxfuzz = maxfuzz; |
|
254 |
✓✗ | 786 |
if (!skip_rest_of_patch) { |
255 |
do { |
||
256 |
786 |
where = locate_hunk(fuzz); |
|
257 |
✗✓✗✗ |
786 |
if (hunk == 1 && where == 0 && !force) { |
258 |
/* dwim for reversed patch? */ |
||
259 |
if (!pch_swap()) { |
||
260 |
if (fuzz == 0) |
||
261 |
say("Not enough memory to try swapped hunk! Assuming unswapped.\n"); |
||
262 |
continue; |
||
263 |
} |
||
264 |
reverse = !reverse; |
||
265 |
/* try again */ |
||
266 |
where = locate_hunk(fuzz); |
||
267 |
if (where == 0) { |
||
268 |
/* didn't find it swapped */ |
||
269 |
if (!pch_swap()) |
||
270 |
/* put it back to normal */ |
||
271 |
fatal("lost hunk on alloc error!\n"); |
||
272 |
reverse = !reverse; |
||
273 |
} else if (noreverse) { |
||
274 |
if (!pch_swap()) |
||
275 |
/* put it back to normal */ |
||
276 |
fatal("lost hunk on alloc error!\n"); |
||
277 |
reverse = !reverse; |
||
278 |
say("Ignoring previously applied (or reversed) patch.\n"); |
||
279 |
skip_rest_of_patch = true; |
||
280 |
} else if (batch) { |
||
281 |
if (verbose) |
||
282 |
say("%seversed (or previously applied) patch detected! %s -R.", |
||
283 |
reverse ? "R" : "Unr", |
||
284 |
reverse ? "Assuming" : "Ignoring"); |
||
285 |
} else { |
||
286 |
ask("%seversed (or previously applied) patch detected! %s -R? [y] ", |
||
287 |
reverse ? "R" : "Unr", |
||
288 |
reverse ? "Assume" : "Ignore"); |
||
289 |
if (*buf == 'n') { |
||
290 |
ask("Apply anyway? [n] "); |
||
291 |
if (*buf != 'y') |
||
292 |
skip_rest_of_patch = true; |
||
293 |
where = 0; |
||
294 |
reverse = !reverse; |
||
295 |
if (!pch_swap()) |
||
296 |
/* put it back to normal */ |
||
297 |
fatal("lost hunk on alloc error!\n"); |
||
298 |
} |
||
299 |
} |
||
300 |
} |
||
301 |
} while (!skip_rest_of_patch && where == 0 && |
||
302 |
✓✗✗✓ ✗✗ |
786 |
++fuzz <= mymaxfuzz); |
303 |
|||
304 |
✗✓ | 786 |
if (skip_rest_of_patch) { /* just got decided */ |
305 |
fclose(ofp); |
||
306 |
ofp = NULL; |
||
307 |
} |
||
308 |
} |
||
309 |
786 |
newwhere = pch_newfirst() + last_offset; |
|
310 |
✗✓ | 786 |
if (skip_rest_of_patch) { |
311 |
abort_hunk(); |
||
312 |
failed++; |
||
313 |
if (verbose) |
||
314 |
say("Hunk #%d ignored at %ld.\n", |
||
315 |
hunk, newwhere); |
||
316 |
✗✓ | 786 |
} else if (where == 0) { |
317 |
abort_hunk(); |
||
318 |
failed++; |
||
319 |
if (verbose) |
||
320 |
say("Hunk #%d failed at %ld.\n", |
||
321 |
hunk, newwhere); |
||
322 |
} else { |
||
323 |
786 |
apply_hunk(where); |
|
324 |
✗✓ | 786 |
if (verbose) { |
325 |
say("Hunk #%d succeeded at %ld", |
||
326 |
hunk, newwhere); |
||
327 |
if (fuzz != 0) |
||
328 |
say(" with fuzz %ld", fuzz); |
||
329 |
if (last_offset) |
||
330 |
say(" (offset %ld line%s)", |
||
331 |
last_offset, |
||
332 |
last_offset == 1L ? "" : "s"); |
||
333 |
say(".\n"); |
||
334 |
} |
||
335 |
} |
||
336 |
} |
||
337 |
|||
338 |
✗✓✗✗ |
39 |
if (out_of_mem && using_plan_a) { |
339 |
Argc = Argc_last; |
||
340 |
Argv = Argv_last; |
||
341 |
say("\n\nRan out of memory using Plan A--trying again...\n\n"); |
||
342 |
if (ofp) |
||
343 |
fclose(ofp); |
||
344 |
ofp = NULL; |
||
345 |
if (rejfp) |
||
346 |
fclose(rejfp); |
||
347 |
rejfp = NULL; |
||
348 |
continue; |
||
349 |
} |
||
350 |
✗✓ | 39 |
if (hunk == 0) |
351 |
fatal("Internal error: hunk should not be 0\n"); |
||
352 |
|||
353 |
/* finish spewing out the new file */ |
||
354 |
✓✗ | 39 |
if (!skip_rest_of_patch) |
355 |
39 |
spew_output(); |
|
356 |
|||
357 |
/* and put the output where desired */ |
||
358 |
39 |
ignore_signals(); |
|
359 |
✓✗ | 39 |
if (!skip_rest_of_patch) { |
360 |
struct stat statbuf; |
||
361 |
39 |
char *realout = outname; |
|
362 |
|||
363 |
✓✗ | 39 |
if (!check_only) { |
364 |
✗✓ | 39 |
if (move_file(TMPOUTNAME, outname) < 0) { |
365 |
toutkeep = true; |
||
366 |
realout = TMPOUTNAME; |
||
367 |
chmod(TMPOUTNAME, filemode); |
||
368 |
} else |
||
369 |
39 |
chmod(outname, filemode); |
|
370 |
|||
371 |
✗✓✗✗ ✗✗ |
39 |
if (remove_empty_files && |
372 |
stat(realout, &statbuf) == 0 && |
||
373 |
statbuf.st_size == 0) { |
||
374 |
if (verbose) |
||
375 |
say("Removing %s (empty after patching).\n", |
||
376 |
realout); |
||
377 |
unlink(realout); |
||
378 |
} |
||
379 |
} |
||
380 |
} |
||
381 |
39 |
fclose(rejfp); |
|
382 |
39 |
rejfp = NULL; |
|
383 |
✗✓ | 39 |
if (failed) { |
384 |
error = 1; |
||
385 |
if (*rejname == '\0') { |
||
386 |
if (strlcpy(rejname, outname, |
||
387 |
sizeof(rejname)) >= sizeof(rejname)) |
||
388 |
fatal("filename %s is too long\n", outname); |
||
389 |
if (strlcat(rejname, REJEXT, |
||
390 |
sizeof(rejname)) >= sizeof(rejname)) |
||
391 |
fatal("filename %s is too long\n", outname); |
||
392 |
} |
||
393 |
if (!check_only) |
||
394 |
say("%d out of %d hunks %s--saving rejects to %s\n", |
||
395 |
failed, hunk, skip_rest_of_patch ? "ignored" : "failed", rejname); |
||
396 |
else |
||
397 |
say("%d out of %d hunks %s\n", |
||
398 |
failed, hunk, skip_rest_of_patch ? "ignored" : "failed"); |
||
399 |
if (!check_only && move_file(TMPREJNAME, rejname) < 0) |
||
400 |
trejkeep = true; |
||
401 |
} |
||
402 |
39 |
set_signals(1); |
|
403 |
} |
||
404 |
|||
405 |
✓✓ | 60 |
if (!patch_seen) |
406 |
8 |
error = 2; |
|
407 |
|||
408 |
60 |
my_exit(error); |
|
409 |
/* NOTREACHED */ |
||
410 |
} |
||
411 |
|||
412 |
/* Prepare to find the next patch to do in the patch file. */ |
||
413 |
|||
414 |
static void |
||
415 |
reinitialize_almost_everything(void) |
||
416 |
52 |
{ |
|
417 |
52 |
re_patch(); |
|
418 |
52 |
re_input(); |
|
419 |
|||
420 |
52 |
input_lines = 0; |
|
421 |
52 |
last_frozen_line = 0; |
|
422 |
|||
423 |
52 |
filec = 0; |
|
424 |
✓✗ | 52 |
if (!out_of_mem) { |
425 |
52 |
free(filearg[0]); |
|
426 |
52 |
filearg[0] = NULL; |
|
427 |
} |
||
428 |
|||
429 |
52 |
free(outname); |
|
430 |
52 |
outname = NULL; |
|
431 |
|||
432 |
52 |
last_offset = 0; |
|
433 |
52 |
diff_type = 0; |
|
434 |
|||
435 |
52 |
free(revision); |
|
436 |
52 |
revision = NULL; |
|
437 |
|||
438 |
52 |
reverse = reverse_flag_specified; |
|
439 |
52 |
skip_rest_of_patch = false; |
|
440 |
|||
441 |
52 |
get_some_switches(); |
|
442 |
52 |
} |
|
443 |
|||
444 |
/* Process switches and filenames. */ |
||
445 |
|||
446 |
static void |
||
447 |
get_some_switches(void) |
||
448 |
112 |
{ |
|
449 |
112 |
const char *options = "b::B:cCd:D:eEfF:i:lnNo:p:r:RstuvV:x:z:"; |
|
450 |
static struct option longopts[] = { |
||
451 |
{"backup", no_argument, 0, 'b'}, |
||
452 |
{"batch", no_argument, 0, 't'}, |
||
453 |
{"check", no_argument, 0, 'C'}, |
||
454 |
{"context", no_argument, 0, 'c'}, |
||
455 |
{"debug", required_argument, 0, 'x'}, |
||
456 |
{"directory", required_argument, 0, 'd'}, |
||
457 |
{"ed", no_argument, 0, 'e'}, |
||
458 |
{"force", no_argument, 0, 'f'}, |
||
459 |
{"forward", no_argument, 0, 'N'}, |
||
460 |
{"fuzz", required_argument, 0, 'F'}, |
||
461 |
{"ifdef", required_argument, 0, 'D'}, |
||
462 |
{"input", required_argument, 0, 'i'}, |
||
463 |
{"ignore-whitespace", no_argument, 0, 'l'}, |
||
464 |
{"normal", no_argument, 0, 'n'}, |
||
465 |
{"output", required_argument, 0, 'o'}, |
||
466 |
{"prefix", required_argument, 0, 'B'}, |
||
467 |
{"quiet", no_argument, 0, 's'}, |
||
468 |
{"reject-file", required_argument, 0, 'r'}, |
||
469 |
{"remove-empty-files", no_argument, 0, 'E'}, |
||
470 |
{"reverse", no_argument, 0, 'R'}, |
||
471 |
{"silent", no_argument, 0, 's'}, |
||
472 |
{"strip", required_argument, 0, 'p'}, |
||
473 |
{"suffix", required_argument, 0, 'z'}, |
||
474 |
{"unified", no_argument, 0, 'u'}, |
||
475 |
{"version", no_argument, 0, 'v'}, |
||
476 |
{"version-control", required_argument, 0, 'V'}, |
||
477 |
{"posix", no_argument, &posix, 1}, |
||
478 |
{NULL, 0, 0, 0} |
||
479 |
}; |
||
480 |
int ch; |
||
481 |
|||
482 |
112 |
rejname[0] = '\0'; |
|
483 |
112 |
Argc_last = Argc; |
|
484 |
112 |
Argv_last = Argv; |
|
485 |
✓✓ | 112 |
if (!Argc) |
486 |
52 |
return; |
|
487 |
60 |
optreset = optind = 1; |
|
488 |
✓✓ | 240 |
while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) { |
489 |
✓✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✗✗✗✗ ✗✗ |
120 |
switch (ch) { |
490 |
case 'b': |
||
491 |
✓✗ | 60 |
if (backup_type == none) |
492 |
60 |
backup_type = numbered_existing; |
|
493 |
✗✓ | 60 |
if (optarg == NULL) |
494 |
60 |
break; |
|
495 |
if (verbose) |
||
496 |
say("Warning, the ``-b suffix'' option has been" |
||
497 |
" obsoleted by the -z option.\n"); |
||
498 |
/* FALLTHROUGH */ |
||
499 |
case 'z': |
||
500 |
/* must directly follow 'b' case for backwards compat */ |
||
501 |
simple_backup_suffix = xstrdup(optarg); |
||
502 |
break; |
||
503 |
case 'B': |
||
504 |
origprae = xstrdup(optarg); |
||
505 |
break; |
||
506 |
case 'c': |
||
507 |
diff_type = CONTEXT_DIFF; |
||
508 |
break; |
||
509 |
case 'C': |
||
510 |
check_only = true; |
||
511 |
break; |
||
512 |
case 'd': |
||
513 |
if (chdir(optarg) < 0) |
||
514 |
pfatal("can't cd to %s", optarg); |
||
515 |
break; |
||
516 |
case 'D': |
||
517 |
do_defines = true; |
||
518 |
if (!isalpha((unsigned char)*optarg) && *optarg != '_') |
||
519 |
fatal("argument to -D is not an identifier\n"); |
||
520 |
snprintf(if_defined, sizeof if_defined, |
||
521 |
"#ifdef %s\n", optarg); |
||
522 |
snprintf(not_defined, sizeof not_defined, |
||
523 |
"#ifndef %s\n", optarg); |
||
524 |
snprintf(end_defined, sizeof end_defined, |
||
525 |
"#endif /* %s */\n", optarg); |
||
526 |
break; |
||
527 |
case 'e': |
||
528 |
diff_type = ED_DIFF; |
||
529 |
break; |
||
530 |
case 'E': |
||
531 |
remove_empty_files = true; |
||
532 |
break; |
||
533 |
case 'f': |
||
534 |
force = true; |
||
535 |
break; |
||
536 |
case 'F': |
||
537 |
maxfuzz = atoi(optarg); |
||
538 |
break; |
||
539 |
case 'i': |
||
540 |
if (++filec == MAXFILEC) |
||
541 |
fatal("too many file arguments\n"); |
||
542 |
filearg[filec] = xstrdup(optarg); |
||
543 |
break; |
||
544 |
case 'l': |
||
545 |
canonicalize = true; |
||
546 |
break; |
||
547 |
case 'n': |
||
548 |
diff_type = NORMAL_DIFF; |
||
549 |
break; |
||
550 |
case 'N': |
||
551 |
noreverse = true; |
||
552 |
break; |
||
553 |
case 'o': |
||
554 |
outname = xstrdup(optarg); |
||
555 |
break; |
||
556 |
case 'p': |
||
557 |
strippath = atoi(optarg); |
||
558 |
break; |
||
559 |
case 'r': |
||
560 |
if (strlcpy(rejname, optarg, |
||
561 |
sizeof(rejname)) >= sizeof(rejname)) |
||
562 |
fatal("argument for -r is too long\n"); |
||
563 |
break; |
||
564 |
case 'R': |
||
565 |
reverse = true; |
||
566 |
reverse_flag_specified = true; |
||
567 |
break; |
||
568 |
case 's': |
||
569 |
60 |
verbose = false; |
|
570 |
60 |
break; |
|
571 |
case 't': |
||
572 |
batch = true; |
||
573 |
break; |
||
574 |
case 'u': |
||
575 |
diff_type = UNI_DIFF; |
||
576 |
break; |
||
577 |
case 'v': |
||
578 |
version(); |
||
579 |
break; |
||
580 |
case 'V': |
||
581 |
backup_type = get_version(optarg); |
||
582 |
break; |
||
583 |
#ifdef DEBUGGING |
||
584 |
case 'x': |
||
585 |
debug = atoi(optarg); |
||
586 |
break; |
||
587 |
#endif |
||
588 |
default: |
||
589 |
if (ch != '\0') |
||
590 |
usage(); |
||
591 |
break; |
||
592 |
} |
||
593 |
} |
||
594 |
60 |
Argc -= optind; |
|
595 |
60 |
Argv += optind; |
|
596 |
|||
597 |
✓✗ | 60 |
if (Argc > 0) { |
598 |
60 |
filearg[0] = xstrdup(*Argv++); |
|
599 |
60 |
Argc--; |
|
600 |
✓✓ | 180 |
while (Argc > 0) { |
601 |
✗✓ | 60 |
if (++filec == MAXFILEC) |
602 |
fatal("too many file arguments\n"); |
||
603 |
60 |
filearg[filec] = xstrdup(*Argv++); |
|
604 |
60 |
Argc--; |
|
605 |
} |
||
606 |
} |
||
607 |
|||
608 |
✗✓ | 60 |
if (getenv("POSIXLY_CORRECT") != NULL) |
609 |
posix = 1; |
||
610 |
} |
||
611 |
|||
612 |
static __dead void |
||
613 |
usage(void) |
||
614 |
{ |
||
615 |
fprintf(stderr, |
||
616 |
"usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory]\n" |
||
617 |
" [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count]\n" |
||
618 |
" [-r rej-name] [-V t | nil | never] [-x number] [-z backup-ext]\n" |
||
619 |
" [--posix] [origfile [patchfile]]\n" |
||
620 |
" patch <patchfile\n"); |
||
621 |
my_exit(2); |
||
622 |
} |
||
623 |
|||
624 |
/* |
||
625 |
* Attempt to find the right place to apply this hunk of patch. |
||
626 |
*/ |
||
627 |
static LINENUM |
||
628 |
locate_hunk(LINENUM fuzz) |
||
629 |
786 |
{ |
|
630 |
786 |
LINENUM first_guess = pch_first() + last_offset; |
|
631 |
LINENUM offset; |
||
632 |
786 |
LINENUM pat_lines = pch_ptrn_lines(); |
|
633 |
786 |
LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1; |
|
634 |
786 |
LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context(); |
|
635 |
|||
636 |
✓✓ | 786 |
if (pat_lines == 0) { /* null range matches always */ |
637 |
✗✓✗✗ ✗✗✗✗ |
126 |
if (verbose && fuzz == 0 && (diff_type == CONTEXT_DIFF |
638 |
|| diff_type == NEW_CONTEXT_DIFF |
||
639 |
|| diff_type == UNI_DIFF)) { |
||
640 |
say("Empty context always matches.\n"); |
||
641 |
} |
||
642 |
126 |
return (first_guess); |
|
643 |
} |
||
644 |
✓✓ | 660 |
if (max_neg_offset >= first_guess) /* do not try lines < 0 */ |
645 |
22 |
max_neg_offset = first_guess - 1; |
|
646 |
✓✗✓✗ |
660 |
if (first_guess <= input_lines && patch_match(first_guess, 0, fuzz)) |
647 |
660 |
return first_guess; |
|
648 |
for (offset = 1; ; offset++) { |
||
649 |
bool check_after = (offset <= max_pos_offset); |
||
650 |
bool check_before = (offset <= max_neg_offset); |
||
651 |
|||
652 |
if (check_after && patch_match(first_guess, offset, fuzz)) { |
||
653 |
#ifdef DEBUGGING |
||
654 |
if (debug & 1) |
||
655 |
say("Offset changing from %ld to %ld\n", |
||
656 |
last_offset, offset); |
||
657 |
#endif |
||
658 |
last_offset = offset; |
||
659 |
return first_guess + offset; |
||
660 |
} else if (check_before && patch_match(first_guess, -offset, fuzz)) { |
||
661 |
#ifdef DEBUGGING |
||
662 |
if (debug & 1) |
||
663 |
say("Offset changing from %ld to %ld\n", |
||
664 |
last_offset, -offset); |
||
665 |
#endif |
||
666 |
last_offset = -offset; |
||
667 |
return first_guess - offset; |
||
668 |
} else if (!check_before && !check_after) |
||
669 |
return 0; |
||
670 |
} |
||
671 |
} |
||
672 |
|||
673 |
/* We did not find the pattern, dump out the hunk so they can handle it. */ |
||
674 |
|||
675 |
static void |
||
676 |
abort_context_hunk(void) |
||
677 |
{ |
||
678 |
LINENUM i; |
||
679 |
const LINENUM pat_end = pch_end(); |
||
680 |
/* |
||
681 |
* add in last_offset to guess the same as the previous successful |
||
682 |
* hunk |
||
683 |
*/ |
||
684 |
const LINENUM oldfirst = pch_first() + last_offset; |
||
685 |
const LINENUM newfirst = pch_newfirst() + last_offset; |
||
686 |
const LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1; |
||
687 |
const LINENUM newlast = newfirst + pch_repl_lines() - 1; |
||
688 |
const char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : ""); |
||
689 |
const char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----"); |
||
690 |
|||
691 |
fprintf(rejfp, "***************\n"); |
||
692 |
for (i = 0; i <= pat_end; i++) { |
||
693 |
switch (pch_char(i)) { |
||
694 |
case '*': |
||
695 |
if (oldlast < oldfirst) |
||
696 |
fprintf(rejfp, "*** 0%s\n", stars); |
||
697 |
else if (oldlast == oldfirst) |
||
698 |
fprintf(rejfp, "*** %ld%s\n", oldfirst, stars); |
||
699 |
else |
||
700 |
fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, |
||
701 |
oldlast, stars); |
||
702 |
break; |
||
703 |
case '=': |
||
704 |
if (newlast < newfirst) |
||
705 |
fprintf(rejfp, "--- 0%s\n", minuses); |
||
706 |
else if (newlast == newfirst) |
||
707 |
fprintf(rejfp, "--- %ld%s\n", newfirst, minuses); |
||
708 |
else |
||
709 |
fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, |
||
710 |
newlast, minuses); |
||
711 |
break; |
||
712 |
case '\n': |
||
713 |
fprintf(rejfp, "%s", pfetch(i)); |
||
714 |
break; |
||
715 |
case ' ': |
||
716 |
case '-': |
||
717 |
case '+': |
||
718 |
case '!': |
||
719 |
fprintf(rejfp, "%c %s", pch_char(i), pfetch(i)); |
||
720 |
break; |
||
721 |
default: |
||
722 |
fatal("fatal internal error in abort_context_hunk\n"); |
||
723 |
} |
||
724 |
} |
||
725 |
} |
||
726 |
|||
727 |
static void |
||
728 |
rej_line(int ch, LINENUM i) |
||
729 |
{ |
||
730 |
size_t len; |
||
731 |
const char *line = pfetch(i); |
||
732 |
|||
733 |
len = strlen(line); |
||
734 |
|||
735 |
fprintf(rejfp, "%c%s", ch, line); |
||
736 |
if (len == 0 || line[len-1] != '\n') |
||
737 |
fprintf(rejfp, "\n\\ No newline at end of file\n"); |
||
738 |
} |
||
739 |
|||
740 |
static void |
||
741 |
abort_hunk(void) |
||
742 |
{ |
||
743 |
LINENUM i, j, split; |
||
744 |
int ch1, ch2; |
||
745 |
const LINENUM pat_end = pch_end(); |
||
746 |
const LINENUM oldfirst = pch_first() + last_offset; |
||
747 |
const LINENUM newfirst = pch_newfirst() + last_offset; |
||
748 |
|||
749 |
if (diff_type != UNI_DIFF) { |
||
750 |
abort_context_hunk(); |
||
751 |
return; |
||
752 |
} |
||
753 |
split = -1; |
||
754 |
for (i = 0; i <= pat_end; i++) { |
||
755 |
if (pch_char(i) == '=') { |
||
756 |
split = i; |
||
757 |
break; |
||
758 |
} |
||
759 |
} |
||
760 |
if (split == -1) { |
||
761 |
fprintf(rejfp, "malformed hunk: no split found\n"); |
||
762 |
return; |
||
763 |
} |
||
764 |
i = 0; |
||
765 |
j = split + 1; |
||
766 |
fprintf(rejfp, "@@ -%ld,%ld +%ld,%ld @@\n", |
||
767 |
pch_ptrn_lines() ? oldfirst : 0, |
||
768 |
pch_ptrn_lines(), newfirst, pch_repl_lines()); |
||
769 |
while (i < split || j <= pat_end) { |
||
770 |
ch1 = i < split ? pch_char(i) : -1; |
||
771 |
ch2 = j <= pat_end ? pch_char(j) : -1; |
||
772 |
if (ch1 == '-') { |
||
773 |
rej_line('-', i); |
||
774 |
i++; |
||
775 |
} else if (ch1 == ' ' && ch2 == ' ') { |
||
776 |
rej_line(' ', i); |
||
777 |
i++; |
||
778 |
j++; |
||
779 |
} else if (ch1 == '!' && ch2 == '!') { |
||
780 |
while (i < split && ch1 == '!') { |
||
781 |
rej_line('-', i); |
||
782 |
i++; |
||
783 |
ch1 = i < split ? pch_char(i) : -1; |
||
784 |
} |
||
785 |
while (j <= pat_end && ch2 == '!') { |
||
786 |
rej_line('+', j); |
||
787 |
j++; |
||
788 |
ch2 = j <= pat_end ? pch_char(j) : -1; |
||
789 |
} |
||
790 |
} else if (ch1 == '*') { |
||
791 |
i++; |
||
792 |
} else if (ch2 == '+' || ch2 == ' ') { |
||
793 |
rej_line(ch2, j); |
||
794 |
j++; |
||
795 |
} else { |
||
796 |
fprintf(rejfp, "internal error on (%ld %ld %ld)\n", |
||
797 |
i, split, j); |
||
798 |
rej_line(ch1, i); |
||
799 |
rej_line(ch2, j); |
||
800 |
return; |
||
801 |
} |
||
802 |
} |
||
803 |
} |
||
804 |
|||
805 |
/* We found where to apply it (we hope), so do it. */ |
||
806 |
|||
807 |
static void |
||
808 |
apply_hunk(LINENUM where) |
||
809 |
786 |
{ |
|
810 |
786 |
LINENUM old = 1; |
|
811 |
786 |
const LINENUM lastline = pch_ptrn_lines(); |
|
812 |
786 |
LINENUM new = lastline + 1; |
|
813 |
#define OUTSIDE 0 |
||
814 |
#define IN_IFNDEF 1 |
||
815 |
#define IN_IFDEF 2 |
||
816 |
#define IN_ELSE 3 |
||
817 |
786 |
int def_state = OUTSIDE; |
|
818 |
786 |
const LINENUM pat_end = pch_end(); |
|
819 |
|||
820 |
786 |
where--; |
|
821 |
✓✓✗✓ |
2358 |
while (pch_char(new) == '=' || pch_char(new) == '\n') |
822 |
786 |
new++; |
|
823 |
|||
824 |
✓✓ | 9168 |
while (old <= lastline) { |
825 |
✓✓ | 8382 |
if (pch_char(old) == '-') { |
826 |
2449 |
copy_till(where + old - 1, false); |
|
827 |
✗✓ | 2449 |
if (do_defines) { |
828 |
if (def_state == OUTSIDE) { |
||
829 |
fputs(not_defined, ofp); |
||
830 |
def_state = IN_IFNDEF; |
||
831 |
} else if (def_state == IN_IFDEF) { |
||
832 |
fputs(else_defined, ofp); |
||
833 |
def_state = IN_ELSE; |
||
834 |
} |
||
835 |
fputs(pfetch(old), ofp); |
||
836 |
} |
||
837 |
2449 |
last_frozen_line++; |
|
838 |
2449 |
old++; |
|
839 |
✗✓ | 5933 |
} else if (new > pat_end) { |
840 |
break; |
||
841 |
✓✓ | 5933 |
} else if (pch_char(new) == '+') { |
842 |
2651 |
copy_till(where + old - 1, false); |
|
843 |
✗✓ | 2651 |
if (do_defines) { |
844 |
if (def_state == IN_IFNDEF) { |
||
845 |
fputs(else_defined, ofp); |
||
846 |
def_state = IN_ELSE; |
||
847 |
} else if (def_state == OUTSIDE) { |
||
848 |
fputs(if_defined, ofp); |
||
849 |
def_state = IN_IFDEF; |
||
850 |
} |
||
851 |
} |
||
852 |
2651 |
fputs(pfetch(new), ofp); |
|
853 |
2651 |
new++; |
|
854 |
✗✓ | 3282 |
} else if (pch_char(new) != pch_char(old)) { |
855 |
say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n", |
||
856 |
pch_hunk_beg() + old, |
||
857 |
pch_hunk_beg() + new); |
||
858 |
#ifdef DEBUGGING |
||
859 |
say("oldchar = '%c', newchar = '%c'\n", |
||
860 |
pch_char(old), pch_char(new)); |
||
861 |
#endif |
||
862 |
my_exit(2); |
||
863 |
✓✓ | 3282 |
} else if (pch_char(new) == '!') { |
864 |
412 |
copy_till(where + old - 1, false); |
|
865 |
✗✓ | 412 |
if (do_defines) { |
866 |
fputs(not_defined, ofp); |
||
867 |
def_state = IN_IFNDEF; |
||
868 |
} |
||
869 |
✓✓ | 1467 |
while (pch_char(old) == '!') { |
870 |
✗✓ | 1055 |
if (do_defines) { |
871 |
fputs(pfetch(old), ofp); |
||
872 |
} |
||
873 |
1055 |
last_frozen_line++; |
|
874 |
1055 |
old++; |
|
875 |
} |
||
876 |
✗✓ | 412 |
if (do_defines) { |
877 |
fputs(else_defined, ofp); |
||
878 |
def_state = IN_ELSE; |
||
879 |
} |
||
880 |
✓✓ | 1448 |
while (pch_char(new) == '!') { |
881 |
1036 |
fputs(pfetch(new), ofp); |
|
882 |
1036 |
new++; |
|
883 |
} |
||
884 |
} else { |
||
885 |
✗✓ | 2870 |
if (pch_char(new) != ' ') |
886 |
fatal("Internal error: expected ' '\n"); |
||
887 |
2870 |
old++; |
|
888 |
2870 |
new++; |
|
889 |
✗✓✗✗ |
2870 |
if (do_defines && def_state != OUTSIDE) { |
890 |
fputs(end_defined, ofp); |
||
891 |
def_state = OUTSIDE; |
||
892 |
} |
||
893 |
} |
||
894 |
} |
||
895 |
✓✓✓✗ |
786 |
if (new <= pat_end && pch_char(new) == '+') { |
896 |
548 |
copy_till(where + old - 1, false); |
|
897 |
✗✓ | 548 |
if (do_defines) { |
898 |
if (def_state == OUTSIDE) { |
||
899 |
fputs(if_defined, ofp); |
||
900 |
def_state = IN_IFDEF; |
||
901 |
} else if (def_state == IN_IFNDEF) { |
||
902 |
fputs(else_defined, ofp); |
||
903 |
def_state = IN_ELSE; |
||
904 |
} |
||
905 |
} |
||
906 |
✓✓✓✗ |
4265 |
while (new <= pat_end && pch_char(new) == '+') { |
907 |
3717 |
fputs(pfetch(new), ofp); |
|
908 |
3717 |
new++; |
|
909 |
} |
||
910 |
} |
||
911 |
✗✓✗✗ |
786 |
if (do_defines && def_state != OUTSIDE) { |
912 |
fputs(end_defined, ofp); |
||
913 |
} |
||
914 |
786 |
} |
|
915 |
|||
916 |
/* |
||
917 |
* Open the new file. |
||
918 |
*/ |
||
919 |
static void |
||
920 |
init_output(const char *name) |
||
921 |
52 |
{ |
|
922 |
52 |
ofp = fopen(name, "w"); |
|
923 |
✗✓ | 52 |
if (ofp == NULL) |
924 |
pfatal("can't create %s", name); |
||
925 |
52 |
} |
|
926 |
|||
927 |
/* |
||
928 |
* Open a file to put hunks we can't locate. |
||
929 |
*/ |
||
930 |
static void |
||
931 |
init_reject(const char *name) |
||
932 |
52 |
{ |
|
933 |
52 |
rejfp = fopen(name, "w"); |
|
934 |
✗✓ | 52 |
if (rejfp == NULL) |
935 |
pfatal("can't create %s", name); |
||
936 |
52 |
} |
|
937 |
|||
938 |
/* |
||
939 |
* Copy input file to output, up to wherever hunk is to be applied. |
||
940 |
* If endoffile is true, treat the last line specially since it may |
||
941 |
* lack a newline. |
||
942 |
*/ |
||
943 |
static void |
||
944 |
copy_till(LINENUM lastline, bool endoffile) |
||
945 |
6096 |
{ |
|
946 |
✗✓ | 6096 |
if (last_frozen_line > lastline) |
947 |
fatal("misordered hunks! output would be garbled\n"); |
||
948 |
✓✓ | 13197 |
while (last_frozen_line < lastline) { |
949 |
✓✓✓✓ |
7110 |
if (++last_frozen_line == lastline && endoffile) |
950 |
9 |
dump_line(last_frozen_line, !last_line_missing_eol); |
|
951 |
else |
||
952 |
7092 |
dump_line(last_frozen_line, true); |
|
953 |
} |
||
954 |
6096 |
} |
|
955 |
|||
956 |
/* |
||
957 |
* Finish copying the input file to the output file. |
||
958 |
*/ |
||
959 |
static void |
||
960 |
spew_output(void) |
||
961 |
39 |
{ |
|
962 |
#ifdef DEBUGGING |
||
963 |
✗✓ | 39 |
if (debug & 256) |
964 |
say("il=%ld lfl=%ld\n", input_lines, last_frozen_line); |
||
965 |
#endif |
||
966 |
✓✓ | 39 |
if (input_lines) |
967 |
36 |
copy_till(input_lines, true); /* dump remainder of file */ |
|
968 |
39 |
fclose(ofp); |
|
969 |
39 |
ofp = NULL; |
|
970 |
39 |
} |
|
971 |
|||
972 |
/* |
||
973 |
* Copy one line from input to output. |
||
974 |
*/ |
||
975 |
static void |
||
976 |
dump_line(LINENUM line, bool write_newline) |
||
977 |
7101 |
{ |
|
978 |
char *s; |
||
979 |
|||
980 |
7101 |
s = ifetch(line, 0); |
|
981 |
✗✓ | 7101 |
if (s == NULL) |
982 |
return; |
||
983 |
/* Note: string is not NUL terminated. */ |
||
984 |
✓✓ | 160881 |
for (; *s != '\n'; s++) |
985 |
✓✗ | 160881 |
putc(*s, ofp); |
986 |
✓✓ | 7101 |
if (write_newline) |
987 |
✓✗ | 7098 |
putc('\n', ofp); |
988 |
} |
||
989 |
|||
990 |
/* |
||
991 |
* Does the patch pattern match at line base+offset? |
||
992 |
*/ |
||
993 |
static bool |
||
994 |
patch_match(LINENUM base, LINENUM offset, LINENUM fuzz) |
||
995 |
660 |
{ |
|
996 |
660 |
LINENUM pline = 1 + fuzz; |
|
997 |
LINENUM iline; |
||
998 |
660 |
LINENUM pat_lines = pch_ptrn_lines() - fuzz; |
|
999 |
const char *ilineptr; |
||
1000 |
const char *plineptr; |
||
1001 |
short plinelen; |
||
1002 |
|||
1003 |
✓✓ | 7034 |
for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) { |
1004 |
6374 |
ilineptr = ifetch(iline, offset >= 0); |
|
1005 |
✗✓ | 6374 |
if (ilineptr == NULL) |
1006 |
return false; |
||
1007 |
6374 |
plineptr = pfetch(pline); |
|
1008 |
6374 |
plinelen = pch_line_len(pline); |
|
1009 |
✗✓ | 6374 |
if (canonicalize) { |
1010 |
if (!similar(ilineptr, plineptr, plinelen)) |
||
1011 |
return false; |
||
1012 |
✗✓ | 6374 |
} else if (strnNE(ilineptr, plineptr, plinelen)) |
1013 |
return false; |
||
1014 |
✓✓ | 6374 |
if (iline == input_lines) { |
1015 |
/* |
||
1016 |
* We are looking at the last line of the file. |
||
1017 |
* If the file has no eol, the patch line should |
||
1018 |
* not have one either and vice-versa. Note that |
||
1019 |
* plinelen > 0. |
||
1020 |
*/ |
||
1021 |
✓✓ | 28 |
if (last_line_missing_eol) { |
1022 |
✗✓ | 12 |
if (plineptr[plinelen - 1] == '\n') |
1023 |
return false; |
||
1024 |
} else { |
||
1025 |
✗✓ | 16 |
if (plineptr[plinelen - 1] != '\n') |
1026 |
return false; |
||
1027 |
} |
||
1028 |
} |
||
1029 |
} |
||
1030 |
660 |
return true; |
|
1031 |
} |
||
1032 |
|||
1033 |
/* |
||
1034 |
* Do two lines match with canonicalized white space? |
||
1035 |
*/ |
||
1036 |
static bool |
||
1037 |
similar(const char *a, const char *b, int len) |
||
1038 |
{ |
||
1039 |
while (len) { |
||
1040 |
if (isspace((unsigned char)*b)) { /* whitespace (or \n) to match? */ |
||
1041 |
if (!isspace((unsigned char)*a)) |
||
1042 |
return false; /* no corresponding whitespace */ |
||
1043 |
while (len && isspace((unsigned char)*b) && *b != '\n') |
||
1044 |
b++, len--; /* skip pattern whitespace */ |
||
1045 |
while (isspace((unsigned char)*a) && *a != '\n') |
||
1046 |
a++; /* skip target whitespace */ |
||
1047 |
if (*a == '\n' || *b == '\n') |
||
1048 |
return (*a == *b); /* should end in sync */ |
||
1049 |
} else if (*a++ != *b++) /* match non-whitespace chars */ |
||
1050 |
return false; |
||
1051 |
else |
||
1052 |
len--; /* probably not necessary */ |
||
1053 |
} |
||
1054 |
return true; /* actually, this is not reached */ |
||
1055 |
/* since there is always a \n */ |
||
1056 |
} |
Generated by: GCOVR (Version 3.3) |