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