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