Annotation of src/usr.bin/patch/patch.c, Revision 1.62
1.62 ! gsoares 1: /* $OpenBSD: patch.c,v 1.61 2015/11/11 02:52:46 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:
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.60 tobias 46: #include "ed.h"
1.1 deraadt 47:
1.44 otto 48: mode_t filemode = 0644;
1.29 otto 49:
50: char buf[MAXLINELEN]; /* general purpose buffer */
51:
1.35 otto 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 */
1.29 otto 54:
55: #define MAXFILEC 2
56:
57: char *filearg[MAXFILEC];
1.35 otto 58: bool ok_to_create_file = false;
1.29 otto 59: char *outname = NULL;
60: char *origprae = NULL;
61: char *TMPOUTNAME;
62: char *TMPINNAME;
63: char *TMPREJNAME;
64: char *TMPPATNAME;
1.35 otto 65: bool toutkeep = false;
66: bool trejkeep = false;
1.33 otto 67: bool warn_on_invalid_line;
1.37 otto 68: bool last_line_missing_eol;
1.29 otto 69:
70: #ifdef DEBUGGING
1.30 deraadt 71: int debug = 0;
1.29 otto 72: #endif
73:
1.35 otto 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;
1.29 otto 80: int strippath = 957;
1.35 otto 81: bool canonicalize = false;
82: bool check_only = false;
1.29 otto 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 */
1.38 millert 86: int posix = 0; /* strict POSIX mode? */
1.23 otto 87:
88: static void reinitialize_almost_everything(void);
89: static void get_some_switches(void);
90: static LINENUM locate_hunk(LINENUM);
1.43 otto 91: static void abort_context_hunk(void);
92: static void rej_line(int, LINENUM);
1.23 otto 93: static void abort_hunk(void);
94: static void apply_hunk(LINENUM);
1.29 otto 95: static void init_output(const char *);
96: static void init_reject(const char *);
1.37 otto 97: static void copy_till(LINENUM, bool);
1.23 otto 98: static void spew_output(void);
1.37 otto 99: static void dump_line(LINENUM, bool);
1.23 otto 100: static bool patch_match(LINENUM, LINENUM, LINENUM);
1.29 otto 101: static bool similar(const char *, const char *, int);
1.24 millert 102: static __dead void usage(void);
1.1 deraadt 103:
1.35 otto 104: /* true if -E was specified on command line. */
105: static bool remove_empty_files = false;
1.1 deraadt 106:
1.35 otto 107: /* true if -R was specified on command line. */
108: static bool reverse_flag_specified = false;
1.1 deraadt 109:
1.25 millert 110: /* buffer holding the name of the rejected patch file. */
111: static char rejname[NAME_MAX + 1];
112:
1.29 otto 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. */
1.35 otto 129: static bool do_defines = false;
1.29 otto 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:
1.11 espie 139:
1.1 deraadt 140: /* Apply a set of diffs as appropriate. */
141:
142: int
1.19 deraadt 143: main(int argc, char *argv[])
1.1 deraadt 144: {
1.42 deraadt 145: int error = 0, hunk, failed, i, fd;
1.47 stsp 146: bool patch_seen;
1.35 otto 147: LINENUM where = 0, newwhere, fuzz, mymaxfuzz;
1.31 millert 148: const char *tmpdir;
149: char *v;
1.55 deraadt 150:
1.61 deraadt 151: if (pledge("stdio rpath wpath cpath tmppath fattr", NULL) == -1) {
1.59 deraadt 152: perror("pledge");
1.62 ! gsoares 153: my_exit(2);
1.61 deraadt 154: }
1.20 deraadt 155:
1.52 millert 156: setvbuf(stdout, NULL, _IOLBF, 0);
157: setvbuf(stderr, NULL, _IOLBF, 0);
1.20 deraadt 158: for (i = 0; i < MAXFILEC; i++)
1.23 otto 159: filearg[i] = NULL;
1.20 deraadt 160:
161: /* Cons up the names of the temporary files. */
1.31 millert 162: if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
163: tmpdir = _PATH_TMP;
164: for (i = strlen(tmpdir) - 1; i > 0 && tmpdir[i] == '/'; i--)
165: ;
166: i++;
167: if (asprintf(&TMPOUTNAME, "%.*s/patchoXXXXXXXXXX", i, tmpdir) == -1)
1.20 deraadt 168: fatal("cannot allocate memory");
1.31 millert 169: if ((fd = mkstemp(TMPOUTNAME)) < 0)
1.20 deraadt 170: pfatal("can't create %s", TMPOUTNAME);
1.31 millert 171: close(fd);
1.20 deraadt 172:
1.31 millert 173: if (asprintf(&TMPINNAME, "%.*s/patchiXXXXXXXXXX", i, tmpdir) == -1)
1.20 deraadt 174: fatal("cannot allocate memory");
1.31 millert 175: if ((fd = mkstemp(TMPINNAME)) < 0)
1.20 deraadt 176: pfatal("can't create %s", TMPINNAME);
1.31 millert 177: close(fd);
1.20 deraadt 178:
1.31 millert 179: if (asprintf(&TMPREJNAME, "%.*s/patchrXXXXXXXXXX", i, tmpdir) == -1)
1.20 deraadt 180: fatal("cannot allocate memory");
1.31 millert 181: if ((fd = mkstemp(TMPREJNAME)) < 0)
1.20 deraadt 182: pfatal("can't create %s", TMPREJNAME);
1.31 millert 183: close(fd);
1.20 deraadt 184:
1.31 millert 185: if (asprintf(&TMPPATNAME, "%.*s/patchpXXXXXXXXXX", i, tmpdir) == -1)
1.20 deraadt 186: fatal("cannot allocate memory");
1.31 millert 187: if ((fd = mkstemp(TMPPATNAME)) < 0)
1.20 deraadt 188: pfatal("can't create %s", TMPPATNAME);
1.31 millert 189: close(fd);
1.20 deraadt 190:
191: v = getenv("SIMPLE_BACKUP_SUFFIX");
192: if (v)
193: simple_backup_suffix = v;
194: else
195: simple_backup_suffix = ORIGEXT;
196:
197: /* parse switches */
198: Argc = argc;
199: Argv = argv;
200: get_some_switches();
201:
1.27 millert 202: if (backup_type == none) {
1.38 millert 203: if ((v = getenv("PATCH_VERSION_CONTROL")) == NULL)
204: v = getenv("VERSION_CONTROL");
205: if (v != NULL || !posix)
1.27 millert 206: backup_type = get_version(v); /* OK to pass NULL. */
207: }
208:
1.20 deraadt 209: /* make sure we clean up /tmp in case of disaster */
210: set_signals(0);
211:
1.47 stsp 212: patch_seen = false;
1.20 deraadt 213: for (open_patch_file(filearg[1]); there_is_another_patch();
214: reinitialize_almost_everything()) {
215: /* for each patch in patch file */
1.53 deraadt 216:
1.47 stsp 217: patch_seen = true;
1.20 deraadt 218:
1.35 otto 219: warn_on_invalid_line = true;
1.20 deraadt 220:
1.23 otto 221: if (outname == NULL)
1.54 tobias 222: outname = xstrdup(filearg[0]);
1.1 deraadt 223:
1.20 deraadt 224: /* initialize the patched file */
225: if (!skip_rest_of_patch)
226: init_output(TMPOUTNAME);
227:
228: /* initialize reject file */
229: init_reject(TMPREJNAME);
230:
231: /* find out where all the lines are */
232: if (!skip_rest_of_patch)
233: scan_input(filearg[0]);
1.60 tobias 234:
235: /* for ed script just up and do it and exit */
236: if (diff_type == ED_DIFF) {
237: do_ed_script();
238: continue;
239: }
1.20 deraadt 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: hunk = 0;
246: failed = 0;
1.35 otto 247: out_of_mem = false;
1.20 deraadt 248: while (another_hunk()) {
249: hunk++;
1.29 otto 250: fuzz = 0;
1.20 deraadt 251: mymaxfuzz = pch_context();
252: if (maxfuzz < mymaxfuzz)
253: mymaxfuzz = maxfuzz;
254: if (!skip_rest_of_patch) {
255: do {
256: where = locate_hunk(fuzz);
1.29 otto 257: if (hunk == 1 && where == 0 && !force) {
1.1 deraadt 258: /* dwim for reversed patch? */
1.20 deraadt 259: if (!pch_swap()) {
1.29 otto 260: if (fuzz == 0)
1.20 deraadt 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);
1.29 otto 267: if (where == 0) {
1.20 deraadt 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");
1.35 otto 279: skip_rest_of_patch = true;
1.20 deraadt 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')
1.35 otto 292: skip_rest_of_patch = true;
1.29 otto 293: where = 0;
1.20 deraadt 294: reverse = !reverse;
295: if (!pch_swap())
296: /* put it back to normal */
297: fatal("lost hunk on alloc error!\n");
298: }
299: }
300: }
1.29 otto 301: } while (!skip_rest_of_patch && where == 0 &&
1.30 deraadt 302: ++fuzz <= mymaxfuzz);
1.20 deraadt 303:
304: if (skip_rest_of_patch) { /* just got decided */
305: fclose(ofp);
1.23 otto 306: ofp = NULL;
1.20 deraadt 307: }
308: }
309: newwhere = pch_newfirst() + last_offset;
310: if (skip_rest_of_patch) {
311: abort_hunk();
312: failed++;
313: if (verbose)
314: say("Hunk #%d ignored at %ld.\n",
315: hunk, newwhere);
1.29 otto 316: } else if (where == 0) {
1.20 deraadt 317: abort_hunk();
318: failed++;
319: if (verbose)
320: say("Hunk #%d failed at %ld.\n",
321: hunk, newwhere);
322: } else {
323: apply_hunk(where);
324: if (verbose) {
325: say("Hunk #%d succeeded at %ld",
326: hunk, newwhere);
1.29 otto 327: if (fuzz != 0)
1.20 deraadt 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: 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);
1.23 otto 344: ofp = NULL;
1.20 deraadt 345: if (rejfp)
346: fclose(rejfp);
1.23 otto 347: rejfp = NULL;
1.20 deraadt 348: continue;
1.11 espie 349: }
1.35 otto 350: if (hunk == 0)
351: fatal("Internal error: hunk should not be 0\n");
1.1 deraadt 352:
1.20 deraadt 353: /* finish spewing out the new file */
354: if (!skip_rest_of_patch)
355: spew_output();
356:
357: /* and put the output where desired */
358: ignore_signals();
359: if (!skip_rest_of_patch) {
360: struct stat statbuf;
361: char *realout = outname;
362:
363: if (!check_only) {
364: if (move_file(TMPOUTNAME, outname) < 0) {
1.35 otto 365: toutkeep = true;
1.20 deraadt 366: realout = TMPOUTNAME;
367: chmod(TMPOUTNAME, filemode);
368: } else
369: chmod(outname, filemode);
370:
371: 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: fclose(rejfp);
1.23 otto 382: rejfp = NULL;
1.20 deraadt 383: if (failed) {
1.28 millert 384: error = 1;
1.29 otto 385: if (*rejname == '\0') {
1.20 deraadt 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: }
1.50 millert 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");
1.20 deraadt 399: if (!check_only && move_file(TMPREJNAME, rejname) < 0)
1.35 otto 400: trejkeep = true;
1.20 deraadt 401: }
402: set_signals(1);
403: }
1.53 deraadt 404:
1.47 stsp 405: if (!patch_seen)
406: error = 2;
407:
1.28 millert 408: my_exit(error);
1.20 deraadt 409: /* NOTREACHED */
1.1 deraadt 410: }
411:
412: /* Prepare to find the next patch to do in the patch file. */
413:
1.23 otto 414: static void
1.20 deraadt 415: reinitialize_almost_everything(void)
1.1 deraadt 416: {
1.20 deraadt 417: re_patch();
418: re_input();
1.1 deraadt 419:
1.20 deraadt 420: input_lines = 0;
421: last_frozen_line = 0;
1.1 deraadt 422:
1.20 deraadt 423: filec = 0;
1.35 otto 424: if (!out_of_mem) {
1.20 deraadt 425: free(filearg[0]);
1.23 otto 426: filearg[0] = NULL;
1.20 deraadt 427: }
1.35 otto 428:
429: free(outname);
430: outname = NULL;
431:
1.20 deraadt 432: last_offset = 0;
1.35 otto 433: diff_type = 0;
1.1 deraadt 434:
1.35 otto 435: free(revision);
436: revision = NULL;
1.1 deraadt 437:
1.20 deraadt 438: reverse = reverse_flag_specified;
1.35 otto 439: skip_rest_of_patch = false;
1.1 deraadt 440:
1.20 deraadt 441: get_some_switches();
1.1 deraadt 442: }
443:
1.24 millert 444: /* Process switches and filenames. */
1.1 deraadt 445:
1.23 otto 446: static void
1.20 deraadt 447: get_some_switches(void)
1.1 deraadt 448: {
1.34 millert 449: const char *options = "b::B:cCd:D:eEfF:i:lnNo:p:r:RstuvV:x:z:";
1.24 millert 450: static struct option longopts[] = {
1.27 millert 451: {"backup", no_argument, 0, 'b'},
1.24 millert 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'},
1.32 millert 462: {"input", required_argument, 0, 'i'},
1.24 millert 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'},
1.34 millert 472: {"strip", required_argument, 0, 'p'},
1.27 millert 473: {"suffix", required_argument, 0, 'z'},
1.24 millert 474: {"unified", no_argument, 0, 'u'},
475: {"version", no_argument, 0, 'v'},
476: {"version-control", required_argument, 0, 'V'},
1.38 millert 477: {"posix", no_argument, &posix, 1},
1.24 millert 478: {NULL, 0, 0, 0}
479: };
480: int ch;
1.1 deraadt 481:
1.20 deraadt 482: rejname[0] = '\0';
483: Argc_last = Argc;
484: Argv_last = Argv;
485: if (!Argc)
486: return;
1.24 millert 487: optreset = optind = 1;
488: while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) {
489: switch (ch) {
490: case 'b':
1.27 millert 491: if (backup_type == none)
492: backup_type = numbered_existing;
493: if (optarg == NULL)
494: 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 */
1.54 tobias 501: simple_backup_suffix = xstrdup(optarg);
1.24 millert 502: break;
503: case 'B':
1.54 tobias 504: origprae = xstrdup(optarg);
1.24 millert 505: break;
506: case 'c':
507: diff_type = CONTEXT_DIFF;
508: break;
509: case 'C':
1.35 otto 510: check_only = true;
1.24 millert 511: break;
512: case 'd':
513: if (chdir(optarg) < 0)
514: pfatal("can't cd to %s", optarg);
515: break;
516: case 'D':
1.35 otto 517: do_defines = true;
1.51 deraadt 518: if (!isalpha((unsigned char)*optarg) && *optarg != '_')
1.24 millert 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':
1.35 otto 531: remove_empty_files = true;
1.24 millert 532: break;
533: case 'f':
1.35 otto 534: force = true;
1.24 millert 535: break;
536: case 'F':
537: maxfuzz = atoi(optarg);
538: break;
1.32 millert 539: case 'i':
540: if (++filec == MAXFILEC)
541: fatal("too many file arguments\n");
1.54 tobias 542: filearg[filec] = xstrdup(optarg);
1.32 millert 543: break;
1.24 millert 544: case 'l':
1.35 otto 545: canonicalize = true;
1.24 millert 546: break;
547: case 'n':
548: diff_type = NORMAL_DIFF;
549: break;
550: case 'N':
1.35 otto 551: noreverse = true;
1.24 millert 552: break;
553: case 'o':
1.54 tobias 554: outname = xstrdup(optarg);
1.24 millert 555: break;
556: case 'p':
1.34 millert 557: strippath = atoi(optarg);
1.24 millert 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':
1.35 otto 565: reverse = true;
566: reverse_flag_specified = true;
1.24 millert 567: break;
568: case 's':
1.35 otto 569: verbose = false;
1.24 millert 570: break;
571: case 't':
1.35 otto 572: batch = true;
1.24 millert 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;
1.1 deraadt 583: #ifdef DEBUGGING
1.24 millert 584: case 'x':
585: debug = atoi(optarg);
586: break;
1.1 deraadt 587: #endif
1.24 millert 588: default:
1.38 millert 589: if (ch != '\0')
590: usage();
1.24 millert 591: break;
1.20 deraadt 592: }
1.1 deraadt 593: }
1.24 millert 594: Argc -= optind;
595: Argv += optind;
596:
1.32 millert 597: if (Argc > 0) {
1.54 tobias 598: filearg[0] = xstrdup(*Argv++);
1.24 millert 599: Argc--;
1.32 millert 600: while (Argc > 0) {
601: if (++filec == MAXFILEC)
602: fatal("too many file arguments\n");
1.54 tobias 603: filearg[filec] = xstrdup(*Argv++);
1.32 millert 604: Argc--;
605: }
1.24 millert 606: }
1.38 millert 607:
608: if (getenv("POSIXLY_CORRECT") != NULL)
609: posix = 1;
1.24 millert 610: }
611:
612: static __dead void
613: usage(void)
614: {
615: fprintf(stderr,
1.45 sobrado 616: "usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory]\n"
1.34 millert 617: " [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count]\n"
1.45 sobrado 618: " [-r rej-name] [-V t | nil | never] [-x number] [-z backup-ext]\n"
619: " [--posix] [origfile [patchfile]]\n"
620: " patch <patchfile\n");
1.28 millert 621: my_exit(EXIT_SUCCESS);
1.1 deraadt 622: }
623:
1.20 deraadt 624: /*
625: * Attempt to find the right place to apply this hunk of patch.
626: */
1.23 otto 627: static LINENUM
1.20 deraadt 628: locate_hunk(LINENUM fuzz)
1.1 deraadt 629: {
1.20 deraadt 630: LINENUM first_guess = pch_first() + last_offset;
631: LINENUM offset;
632: LINENUM pat_lines = pch_ptrn_lines();
633: LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1;
634: LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context();
635:
1.36 otto 636: if (pat_lines == 0) { /* null range matches always */
1.39 otto 637: if (verbose && fuzz == 0 && (diff_type == CONTEXT_DIFF
1.36 otto 638: || diff_type == NEW_CONTEXT_DIFF
639: || diff_type == UNI_DIFF)) {
640: say("Empty context always matches.\n");
641: }
1.46 otto 642: return (first_guess);
1.36 otto 643: }
1.20 deraadt 644: if (max_neg_offset >= first_guess) /* do not try lines < 0 */
645: max_neg_offset = first_guess - 1;
1.29 otto 646: if (first_guess <= input_lines && patch_match(first_guess, 0, fuzz))
1.20 deraadt 647: return first_guess;
648: for (offset = 1; ; offset++) {
649: bool check_after = (offset <= max_pos_offset);
650: bool check_before = (offset <= max_neg_offset);
1.1 deraadt 651:
1.20 deraadt 652: if (check_after && patch_match(first_guess, offset, fuzz)) {
1.1 deraadt 653: #ifdef DEBUGGING
1.20 deraadt 654: if (debug & 1)
655: say("Offset changing from %ld to %ld\n",
656: last_offset, offset);
1.1 deraadt 657: #endif
1.20 deraadt 658: last_offset = offset;
659: return first_guess + offset;
660: } else if (check_before && patch_match(first_guess, -offset, fuzz)) {
1.1 deraadt 661: #ifdef DEBUGGING
1.20 deraadt 662: if (debug & 1)
663: say("Offset changing from %ld to %ld\n",
664: last_offset, -offset);
1.1 deraadt 665: #endif
1.20 deraadt 666: last_offset = -offset;
667: return first_guess - offset;
668: } else if (!check_before && !check_after)
1.29 otto 669: return 0;
1.1 deraadt 670: }
671: }
672:
673: /* We did not find the pattern, dump out the hunk so they can handle it. */
674:
1.23 otto 675: static void
1.43 otto 676: abort_context_hunk(void)
1.1 deraadt 677: {
1.20 deraadt 678: LINENUM i;
1.29 otto 679: const LINENUM pat_end = pch_end();
1.20 deraadt 680: /*
681: * add in last_offset to guess the same as the previous successful
682: * hunk
683: */
1.29 otto 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 ? " ----" : " -----");
1.20 deraadt 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:
1.43 otto 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;
1.20 deraadt 801: }
1.1 deraadt 802: }
803: }
804:
805: /* We found where to apply it (we hope), so do it. */
806:
1.23 otto 807: static void
1.20 deraadt 808: apply_hunk(LINENUM where)
1.1 deraadt 809: {
1.29 otto 810: LINENUM old = 1;
811: const LINENUM lastline = pch_ptrn_lines();
812: LINENUM new = lastline + 1;
1.1 deraadt 813: #define OUTSIDE 0
814: #define IN_IFNDEF 1
815: #define IN_IFDEF 2
816: #define IN_ELSE 3
1.29 otto 817: int def_state = OUTSIDE;
818: const LINENUM pat_end = pch_end();
1.20 deraadt 819:
820: where--;
821: while (pch_char(new) == '=' || pch_char(new) == '\n')
822: new++;
823:
824: while (old <= lastline) {
825: if (pch_char(old) == '-') {
1.37 otto 826: copy_till(where + old - 1, false);
1.29 otto 827: if (do_defines) {
1.20 deraadt 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: last_frozen_line++;
838: old++;
839: } else if (new > pat_end) {
840: break;
841: } else if (pch_char(new) == '+') {
1.37 otto 842: copy_till(where + old - 1, false);
1.29 otto 843: if (do_defines) {
1.20 deraadt 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: fputs(pfetch(new), ofp);
853: new++;
854: } 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);
1.1 deraadt 858: #ifdef DEBUGGING
1.20 deraadt 859: say("oldchar = '%c', newchar = '%c'\n",
860: pch_char(old), pch_char(new));
1.1 deraadt 861: #endif
1.28 millert 862: my_exit(2);
1.20 deraadt 863: } else if (pch_char(new) == '!') {
1.37 otto 864: copy_till(where + old - 1, false);
1.29 otto 865: if (do_defines) {
1.20 deraadt 866: fputs(not_defined, ofp);
867: def_state = IN_IFNDEF;
868: }
869: while (pch_char(old) == '!') {
1.29 otto 870: if (do_defines) {
1.20 deraadt 871: fputs(pfetch(old), ofp);
872: }
873: last_frozen_line++;
874: old++;
875: }
1.29 otto 876: if (do_defines) {
1.20 deraadt 877: fputs(else_defined, ofp);
878: def_state = IN_ELSE;
879: }
880: while (pch_char(new) == '!') {
881: fputs(pfetch(new), ofp);
882: new++;
883: }
884: } else {
1.35 otto 885: if (pch_char(new) != ' ')
886: fatal("Internal error: expected ' '\n");
1.20 deraadt 887: old++;
888: new++;
1.29 otto 889: if (do_defines && def_state != OUTSIDE) {
1.20 deraadt 890: fputs(end_defined, ofp);
891: def_state = OUTSIDE;
892: }
893: }
1.1 deraadt 894: }
1.20 deraadt 895: if (new <= pat_end && pch_char(new) == '+') {
1.37 otto 896: copy_till(where + old - 1, false);
1.29 otto 897: if (do_defines) {
1.20 deraadt 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: while (new <= pat_end && pch_char(new) == '+') {
907: fputs(pfetch(new), ofp);
908: new++;
1.1 deraadt 909: }
910: }
1.29 otto 911: if (do_defines && def_state != OUTSIDE) {
1.1 deraadt 912: fputs(end_defined, ofp);
913: }
914: }
915:
1.20 deraadt 916: /*
917: * Open the new file.
918: */
1.23 otto 919: static void
1.29 otto 920: init_output(const char *name)
1.1 deraadt 921: {
1.20 deraadt 922: ofp = fopen(name, "w");
1.23 otto 923: if (ofp == NULL)
1.20 deraadt 924: pfatal("can't create %s", name);
1.1 deraadt 925: }
926:
1.20 deraadt 927: /*
928: * Open a file to put hunks we can't locate.
929: */
1.23 otto 930: static void
1.29 otto 931: init_reject(const char *name)
1.1 deraadt 932: {
1.20 deraadt 933: rejfp = fopen(name, "w");
1.23 otto 934: if (rejfp == NULL)
1.20 deraadt 935: pfatal("can't create %s", name);
1.1 deraadt 936: }
937:
1.20 deraadt 938: /*
939: * Copy input file to output, up to wherever hunk is to be applied.
1.37 otto 940: * If endoffile is true, treat the last line specially since it may
941: * lack a newline.
1.20 deraadt 942: */
1.23 otto 943: static void
1.37 otto 944: copy_till(LINENUM lastline, bool endoffile)
1.1 deraadt 945: {
1.29 otto 946: if (last_frozen_line > lastline)
1.20 deraadt 947: fatal("misordered hunks! output would be garbled\n");
1.37 otto 948: while (last_frozen_line < lastline) {
949: if (++last_frozen_line == lastline && endoffile)
950: dump_line(last_frozen_line, !last_line_missing_eol);
951: else
952: dump_line(last_frozen_line, true);
953: }
1.1 deraadt 954: }
955:
1.20 deraadt 956: /*
957: * Finish copying the input file to the output file.
958: */
1.23 otto 959: static void
1.20 deraadt 960: spew_output(void)
1.1 deraadt 961: {
962: #ifdef DEBUGGING
1.20 deraadt 963: if (debug & 256)
964: say("il=%ld lfl=%ld\n", input_lines, last_frozen_line);
1.1 deraadt 965: #endif
1.20 deraadt 966: if (input_lines)
1.37 otto 967: copy_till(input_lines, true); /* dump remainder of file */
1.20 deraadt 968: fclose(ofp);
1.23 otto 969: ofp = NULL;
1.1 deraadt 970: }
971:
1.20 deraadt 972: /*
973: * Copy one line from input to output.
974: */
1.23 otto 975: static void
1.37 otto 976: dump_line(LINENUM line, bool write_newline)
1.1 deraadt 977: {
1.29 otto 978: char *s;
1.1 deraadt 979:
1.26 otto 980: s = ifetch(line, 0);
981: if (s == NULL)
982: return;
1.30 deraadt 983: /* Note: string is not NUL terminated. */
1.37 otto 984: for (; *s != '\n'; s++)
985: putc(*s, ofp);
986: if (write_newline)
987: putc('\n', ofp);
1.1 deraadt 988: }
989:
1.20 deraadt 990: /*
991: * Does the patch pattern match at line base+offset?
992: */
1.23 otto 993: static bool
1.20 deraadt 994: patch_match(LINENUM base, LINENUM offset, LINENUM fuzz)
995: {
1.29 otto 996: LINENUM pline = 1 + fuzz;
997: LINENUM iline;
998: LINENUM pat_lines = pch_ptrn_lines() - fuzz;
999: const char *ilineptr;
1.30 deraadt 1000: const char *plineptr;
1001: short plinelen;
1.20 deraadt 1002:
1003: for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) {
1.26 otto 1004: ilineptr = ifetch(iline, offset >= 0);
1005: if (ilineptr == NULL)
1.35 otto 1006: return false;
1.26 otto 1007: plineptr = pfetch(pline);
1008: plinelen = pch_line_len(pline);
1.20 deraadt 1009: if (canonicalize) {
1.26 otto 1010: if (!similar(ilineptr, plineptr, plinelen))
1.35 otto 1011: return false;
1.26 otto 1012: } else if (strnNE(ilineptr, plineptr, plinelen))
1.35 otto 1013: return false;
1.41 otto 1014: 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: if (last_line_missing_eol) {
1022: if (plineptr[plinelen - 1] == '\n')
1023: return false;
1024: } else {
1025: if (plineptr[plinelen - 1] != '\n')
1026: return false;
1027: }
1028: }
1.1 deraadt 1029: }
1.35 otto 1030: return true;
1.1 deraadt 1031: }
1032:
1.20 deraadt 1033: /*
1034: * Do two lines match with canonicalized white space?
1035: */
1.23 otto 1036: static bool
1.29 otto 1037: similar(const char *a, const char *b, int len)
1.20 deraadt 1038: {
1039: while (len) {
1.51 deraadt 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')
1.20 deraadt 1044: b++, len--; /* skip pattern whitespace */
1.51 deraadt 1045: while (isspace((unsigned char)*a) && *a != '\n')
1.20 deraadt 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 */
1.35 otto 1050: return false;
1.20 deraadt 1051: else
1052: len--; /* probably not necessary */
1.1 deraadt 1053: }
1.35 otto 1054: return true; /* actually, this is not reached */
1.20 deraadt 1055: /* since there is always a \n */
1.1 deraadt 1056: }