diff options
Diffstat (limited to 'usr.bin/patch/patch.c')
-rw-r--r-- | usr.bin/patch/patch.c | 974 |
1 files changed, 0 insertions, 974 deletions
diff --git a/usr.bin/patch/patch.c b/usr.bin/patch/patch.c deleted file mode 100644 index 7b754871ba9bf..0000000000000 --- a/usr.bin/patch/patch.c +++ /dev/null @@ -1,974 +0,0 @@ -/* $OpenBSD: patch.c,v 1.41 2004/07/09 19:13:46 otto Exp $ */ - -/* - * patch - a program to apply diffs to original files - * - * Copyright 1986, Larry Wall - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * 1. Redistributions of source code must retain the above copyright notice, - * this condition and the following disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * -C option added in 1998, original code by Marc Espie, based on FreeBSD - * behaviour - */ - -#ifndef lint -static const char rcsid[] = "$OpenBSD: patch.c,v 1.41 2004/07/09 19:13:46 otto Exp $"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <ctype.h> -#include <getopt.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#include "common.h" -#include "util.h" -#include "pch.h" -#include "inp.h" -#include "backupfile.h" -#include "pathnames.h" - -int filemode = 0644; - -char buf[MAXLINELEN]; /* general purpose buffer */ - -bool using_plan_a = true; /* try to keep everything in memory */ -bool out_of_mem = false; /* ran out of memory in plan a */ - -#define MAXFILEC 2 - -char *filearg[MAXFILEC]; -bool ok_to_create_file = false; -char *outname = NULL; -char *origprae = NULL; -char *TMPOUTNAME; -char *TMPINNAME; -char *TMPREJNAME; -char *TMPPATNAME; -bool toutkeep = false; -bool trejkeep = false; -bool warn_on_invalid_line; -bool last_line_missing_eol; - -#ifdef DEBUGGING -int debug = 0; -#endif - -bool force = false; -bool batch = false; -bool verbose = true; -bool reverse = false; -bool noreverse = false; -bool skip_rest_of_patch = false; -int strippath = 957; -bool canonicalize = false; -bool check_only = false; -int diff_type = 0; -char *revision = NULL; /* prerequisite revision, if any */ -LINENUM input_lines = 0; /* how long is input file in lines */ -int posix = 0; /* strict POSIX mode? */ - -static void reinitialize_almost_everything(void); -static void get_some_switches(void); -static LINENUM locate_hunk(LINENUM); -static void abort_hunk(void); -static void apply_hunk(LINENUM); -static void init_output(const char *); -static void init_reject(const char *); -static void copy_till(LINENUM, bool); -static void spew_output(void); -static void dump_line(LINENUM, bool); -static bool patch_match(LINENUM, LINENUM, LINENUM); -static bool similar(const char *, const char *, int); -static __dead void usage(void); - -/* true if -E was specified on command line. */ -static bool remove_empty_files = false; - -/* true if -R was specified on command line. */ -static bool reverse_flag_specified = false; - -/* buffer holding the name of the rejected patch file. */ -static char rejname[NAME_MAX + 1]; - -/* buffer for stderr */ -static char serrbuf[BUFSIZ]; - -/* how many input lines have been irretractibly output */ -static LINENUM last_frozen_line = 0; - -static int Argc; /* guess */ -static char **Argv; -static int Argc_last; /* for restarting plan_b */ -static char **Argv_last; - -static FILE *ofp = NULL; /* output file pointer */ -static FILE *rejfp = NULL; /* reject file pointer */ - -static int filec = 0; /* how many file arguments? */ -static LINENUM last_offset = 0; -static LINENUM maxfuzz = 2; - -/* patch using ifdef, ifndef, etc. */ -static bool do_defines = false; -/* #ifdef xyzzy */ -static char if_defined[128]; -/* #ifndef xyzzy */ -static char not_defined[128]; -/* #else */ -static const char else_defined[] = "#else\n"; -/* #endif xyzzy */ -static char end_defined[128]; - - -/* Apply a set of diffs as appropriate. */ - -int -main(int argc, char *argv[]) -{ - int error = 0, hunk, failed, patch_seen = 0, i, fd; - LINENUM where = 0, newwhere, fuzz, mymaxfuzz; - const char *tmpdir; - char *v; - - setbuf(stderr, serrbuf); - for (i = 0; i < MAXFILEC; i++) - filearg[i] = NULL; - - /* Cons up the names of the temporary files. */ - if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') - tmpdir = _PATH_TMP; - for (i = strlen(tmpdir) - 1; i > 0 && tmpdir[i] == '/'; i--) - ; - i++; - if (asprintf(&TMPOUTNAME, "%.*s/patchoXXXXXXXXXX", i, tmpdir) == -1) - fatal("cannot allocate memory"); - if ((fd = mkstemp(TMPOUTNAME)) < 0) - pfatal("can't create %s", TMPOUTNAME); - close(fd); - - if (asprintf(&TMPINNAME, "%.*s/patchiXXXXXXXXXX", i, tmpdir) == -1) - fatal("cannot allocate memory"); - if ((fd = mkstemp(TMPINNAME)) < 0) - pfatal("can't create %s", TMPINNAME); - close(fd); - - if (asprintf(&TMPREJNAME, "%.*s/patchrXXXXXXXXXX", i, tmpdir) == -1) - fatal("cannot allocate memory"); - if ((fd = mkstemp(TMPREJNAME)) < 0) - pfatal("can't create %s", TMPREJNAME); - close(fd); - - if (asprintf(&TMPPATNAME, "%.*s/patchpXXXXXXXXXX", i, tmpdir) == -1) - fatal("cannot allocate memory"); - if ((fd = mkstemp(TMPPATNAME)) < 0) - pfatal("can't create %s", TMPPATNAME); - close(fd); - - v = getenv("SIMPLE_BACKUP_SUFFIX"); - if (v) - simple_backup_suffix = v; - else - simple_backup_suffix = ORIGEXT; - - /* parse switches */ - Argc = argc; - Argv = argv; - get_some_switches(); - - if (backup_type == none) { - if ((v = getenv("PATCH_VERSION_CONTROL")) == NULL) - v = getenv("VERSION_CONTROL"); - if (v != NULL || !posix) - backup_type = get_version(v); /* OK to pass NULL. */ - } - - /* make sure we clean up /tmp in case of disaster */ - set_signals(0); - - for (open_patch_file(filearg[1]); there_is_another_patch(); - reinitialize_almost_everything()) { - /* for each patch in patch file */ - - patch_seen = true; - warn_on_invalid_line = true; - - if (outname == NULL) - outname = savestr(filearg[0]); - - /* for ed script just up and do it and exit */ - if (diff_type == ED_DIFF) { - do_ed_script(); - continue; - } - /* initialize the patched file */ - if (!skip_rest_of_patch) - init_output(TMPOUTNAME); - - /* initialize reject file */ - init_reject(TMPREJNAME); - - /* find out where all the lines are */ - if (!skip_rest_of_patch) - scan_input(filearg[0]); - - /* from here on, open no standard i/o files, because malloc */ - /* might misfire and we can't catch it easily */ - - /* apply each hunk of patch */ - hunk = 0; - failed = 0; - out_of_mem = false; - while (another_hunk()) { - hunk++; - fuzz = 0; - mymaxfuzz = pch_context(); - if (maxfuzz < mymaxfuzz) - mymaxfuzz = maxfuzz; - if (!skip_rest_of_patch) { - do { - where = locate_hunk(fuzz); - if (hunk == 1 && where == 0 && !force) { - /* dwim for reversed patch? */ - if (!pch_swap()) { - if (fuzz == 0) - say("Not enough memory to try swapped hunk! Assuming unswapped.\n"); - continue; - } - reverse = !reverse; - /* try again */ - where = locate_hunk(fuzz); - if (where == 0) { - /* didn't find it swapped */ - if (!pch_swap()) - /* put it back to normal */ - fatal("lost hunk on alloc error!\n"); - reverse = !reverse; - } else if (noreverse) { - if (!pch_swap()) - /* put it back to normal */ - fatal("lost hunk on alloc error!\n"); - reverse = !reverse; - say("Ignoring previously applied (or reversed) patch.\n"); - skip_rest_of_patch = true; - } else if (batch) { - if (verbose) - say("%seversed (or previously applied) patch detected! %s -R.", - reverse ? "R" : "Unr", - reverse ? "Assuming" : "Ignoring"); - } else { - ask("%seversed (or previously applied) patch detected! %s -R? [y] ", - reverse ? "R" : "Unr", - reverse ? "Assume" : "Ignore"); - if (*buf == 'n') { - ask("Apply anyway? [n] "); - if (*buf != 'y') - skip_rest_of_patch = true; - where = 0; - reverse = !reverse; - if (!pch_swap()) - /* put it back to normal */ - fatal("lost hunk on alloc error!\n"); - } - } - } - } while (!skip_rest_of_patch && where == 0 && - ++fuzz <= mymaxfuzz); - - if (skip_rest_of_patch) { /* just got decided */ - fclose(ofp); - ofp = NULL; - } - } - newwhere = pch_newfirst() + last_offset; - if (skip_rest_of_patch) { - abort_hunk(); - failed++; - if (verbose) - say("Hunk #%d ignored at %ld.\n", - hunk, newwhere); - } else if (where == 0) { - abort_hunk(); - failed++; - if (verbose) - say("Hunk #%d failed at %ld.\n", - hunk, newwhere); - } else { - apply_hunk(where); - if (verbose) { - say("Hunk #%d succeeded at %ld", - hunk, newwhere); - if (fuzz != 0) - say(" with fuzz %ld", fuzz); - if (last_offset) - say(" (offset %ld line%s)", - last_offset, - last_offset == 1L ? "" : "s"); - say(".\n"); - } - } - } - - if (out_of_mem && using_plan_a) { - Argc = Argc_last; - Argv = Argv_last; - say("\n\nRan out of memory using Plan A--trying again...\n\n"); - if (ofp) - fclose(ofp); - ofp = NULL; - if (rejfp) - fclose(rejfp); - rejfp = NULL; - continue; - } - if (hunk == 0) - fatal("Internal error: hunk should not be 0\n"); - - /* finish spewing out the new file */ - if (!skip_rest_of_patch) - spew_output(); - - /* and put the output where desired */ - ignore_signals(); - if (!skip_rest_of_patch) { - struct stat statbuf; - char *realout = outname; - - if (!check_only) { - if (move_file(TMPOUTNAME, outname) < 0) { - toutkeep = true; - realout = TMPOUTNAME; - chmod(TMPOUTNAME, filemode); - } else - chmod(outname, filemode); - - if (remove_empty_files && - stat(realout, &statbuf) == 0 && - statbuf.st_size == 0) { - if (verbose) - say("Removing %s (empty after patching).\n", - realout); - unlink(realout); - } - } - } - fclose(rejfp); - rejfp = NULL; - if (failed) { - error = 1; - if (*rejname == '\0') { - if (strlcpy(rejname, outname, - sizeof(rejname)) >= sizeof(rejname)) - fatal("filename %s is too long\n", outname); - if (strlcat(rejname, REJEXT, - sizeof(rejname)) >= sizeof(rejname)) - fatal("filename %s is too long\n", outname); - } - if (skip_rest_of_patch) { - say("%d out of %d hunks ignored--saving rejects to %s\n", - failed, hunk, rejname); - } else { - say("%d out of %d hunks failed--saving rejects to %s\n", - failed, hunk, rejname); - } - if (!check_only && move_file(TMPREJNAME, rejname) < 0) - trejkeep = true; - } - set_signals(1); - } - my_exit(error); - /* NOTREACHED */ -} - -/* Prepare to find the next patch to do in the patch file. */ - -static void -reinitialize_almost_everything(void) -{ - re_patch(); - re_input(); - - input_lines = 0; - last_frozen_line = 0; - - filec = 0; - if (!out_of_mem) { - free(filearg[0]); - filearg[0] = NULL; - } - - free(outname); - outname = NULL; - - last_offset = 0; - diff_type = 0; - - free(revision); - revision = NULL; - - reverse = reverse_flag_specified; - skip_rest_of_patch = false; - - get_some_switches(); -} - -/* Process switches and filenames. */ - -static void -get_some_switches(void) -{ - const char *options = "b::B:cCd:D:eEfF:i:lnNo:p:r:RstuvV:x:z:"; - static struct option longopts[] = { - {"backup", no_argument, 0, 'b'}, - {"batch", no_argument, 0, 't'}, - {"check", no_argument, 0, 'C'}, - {"context", no_argument, 0, 'c'}, - {"debug", required_argument, 0, 'x'}, - {"directory", required_argument, 0, 'd'}, - {"ed", no_argument, 0, 'e'}, - {"force", no_argument, 0, 'f'}, - {"forward", no_argument, 0, 'N'}, - {"fuzz", required_argument, 0, 'F'}, - {"ifdef", required_argument, 0, 'D'}, - {"input", required_argument, 0, 'i'}, - {"ignore-whitespace", no_argument, 0, 'l'}, - {"normal", no_argument, 0, 'n'}, - {"output", required_argument, 0, 'o'}, - {"prefix", required_argument, 0, 'B'}, - {"quiet", no_argument, 0, 's'}, - {"reject-file", required_argument, 0, 'r'}, - {"remove-empty-files", no_argument, 0, 'E'}, - {"reverse", no_argument, 0, 'R'}, - {"silent", no_argument, 0, 's'}, - {"strip", required_argument, 0, 'p'}, - {"suffix", required_argument, 0, 'z'}, - {"unified", no_argument, 0, 'u'}, - {"version", no_argument, 0, 'v'}, - {"version-control", required_argument, 0, 'V'}, - {"posix", no_argument, &posix, 1}, - {NULL, 0, 0, 0} - }; - int ch; - - rejname[0] = '\0'; - Argc_last = Argc; - Argv_last = Argv; - if (!Argc) - return; - optreset = optind = 1; - while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) { - switch (ch) { - case 'b': - if (backup_type == none) - backup_type = numbered_existing; - if (optarg == NULL) - break; - if (verbose) - say("Warning, the ``-b suffix'' option has been" - " obsoleted by the -z option.\n"); - /* FALLTHROUGH */ - case 'z': - /* must directly follow 'b' case for backwards compat */ - simple_backup_suffix = savestr(optarg); - break; - case 'B': - origprae = savestr(optarg); - break; - case 'c': - diff_type = CONTEXT_DIFF; - break; - case 'C': - check_only = true; - break; - case 'd': - if (chdir(optarg) < 0) - pfatal("can't cd to %s", optarg); - break; - case 'D': - do_defines = true; - if (!isalpha(*optarg) && *optarg != '_') - fatal("argument to -D is not an identifier\n"); - snprintf(if_defined, sizeof if_defined, - "#ifdef %s\n", optarg); - snprintf(not_defined, sizeof not_defined, - "#ifndef %s\n", optarg); - snprintf(end_defined, sizeof end_defined, - "#endif /* %s */\n", optarg); - break; - case 'e': - diff_type = ED_DIFF; - break; - case 'E': - remove_empty_files = true; - break; - case 'f': - force = true; - break; - case 'F': - maxfuzz = atoi(optarg); - break; - case 'i': - if (++filec == MAXFILEC) - fatal("too many file arguments\n"); - filearg[filec] = savestr(optarg); - break; - case 'l': - canonicalize = true; - break; - case 'n': - diff_type = NORMAL_DIFF; - break; - case 'N': - noreverse = true; - break; - case 'o': - outname = savestr(optarg); - break; - case 'p': - strippath = atoi(optarg); - break; - case 'r': - if (strlcpy(rejname, optarg, - sizeof(rejname)) >= sizeof(rejname)) - fatal("argument for -r is too long\n"); - break; - case 'R': - reverse = true; - reverse_flag_specified = true; - break; - case 's': - verbose = false; - break; - case 't': - batch = true; - break; - case 'u': - diff_type = UNI_DIFF; - break; - case 'v': - version(); - break; - case 'V': - backup_type = get_version(optarg); - break; -#ifdef DEBUGGING - case 'x': - debug = atoi(optarg); - break; -#endif - default: - if (ch != '\0') - usage(); - break; - } - } - Argc -= optind; - Argv += optind; - - if (Argc > 0) { - filearg[0] = savestr(*Argv++); - Argc--; - while (Argc > 0) { - if (++filec == MAXFILEC) - fatal("too many file arguments\n"); - filearg[filec] = savestr(*Argv++); - Argc--; - } - } - - if (getenv("POSIXLY_CORRECT") != NULL) - posix = 1; -} - -static __dead void -usage(void) -{ - fprintf(stderr, -"usage: patch [-bcCeEflnNRstuv] [-B backup-prefix] [-d directory] [-D symbol]\n" -" [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count]\n" -" [-r rej-name] [-V {numbered,existing,simple}] [-z backup-ext]\n" -" [origfile [patchfile]]\n"); - my_exit(EXIT_SUCCESS); -} - -/* - * Attempt to find the right place to apply this hunk of patch. - */ -static LINENUM -locate_hunk(LINENUM fuzz) -{ - LINENUM first_guess = pch_first() + last_offset; - LINENUM offset; - LINENUM pat_lines = pch_ptrn_lines(); - LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1; - LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context(); - - if (pat_lines == 0) { /* null range matches always */ - if (verbose && fuzz == 0 && (diff_type == CONTEXT_DIFF - || diff_type == NEW_CONTEXT_DIFF - || diff_type == UNI_DIFF)) { - say("Empty context always matches.\n"); - } - if (diff_type == CONTEXT_DIFF - || diff_type == NEW_CONTEXT_DIFF - || diff_type == UNI_DIFF) { - if (fuzz == 0) - return (input_lines == 0 ? first_guess : 0); - } else - return (first_guess); - } - if (max_neg_offset >= first_guess) /* do not try lines < 0 */ - max_neg_offset = first_guess - 1; - if (first_guess <= input_lines && patch_match(first_guess, 0, fuzz)) - return first_guess; - for (offset = 1; ; offset++) { - bool check_after = (offset <= max_pos_offset); - bool check_before = (offset <= max_neg_offset); - - if (check_after && patch_match(first_guess, offset, fuzz)) { -#ifdef DEBUGGING - if (debug & 1) - say("Offset changing from %ld to %ld\n", - last_offset, offset); -#endif - last_offset = offset; - return first_guess + offset; - } else if (check_before && patch_match(first_guess, -offset, fuzz)) { -#ifdef DEBUGGING - if (debug & 1) - say("Offset changing from %ld to %ld\n", - last_offset, -offset); -#endif - last_offset = -offset; - return first_guess - offset; - } else if (!check_before && !check_after) - return 0; - } -} - -/* We did not find the pattern, dump out the hunk so they can handle it. */ - -static void -abort_hunk(void) -{ - LINENUM i; - const LINENUM pat_end = pch_end(); - /* - * add in last_offset to guess the same as the previous successful - * hunk - */ - const LINENUM oldfirst = pch_first() + last_offset; - const LINENUM newfirst = pch_newfirst() + last_offset; - const LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1; - const LINENUM newlast = newfirst + pch_repl_lines() - 1; - const char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : ""); - const char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----"); - - fprintf(rejfp, "***************\n"); - for (i = 0; i <= pat_end; i++) { - switch (pch_char(i)) { - case '*': - if (oldlast < oldfirst) - fprintf(rejfp, "*** 0%s\n", stars); - else if (oldlast == oldfirst) - fprintf(rejfp, "*** %ld%s\n", oldfirst, stars); - else - fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, - oldlast, stars); - break; - case '=': - if (newlast < newfirst) - fprintf(rejfp, "--- 0%s\n", minuses); - else if (newlast == newfirst) - fprintf(rejfp, "--- %ld%s\n", newfirst, minuses); - else - fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, - newlast, minuses); - break; - case '\n': - fprintf(rejfp, "%s", pfetch(i)); - break; - case ' ': - case '-': - case '+': - case '!': - fprintf(rejfp, "%c %s", pch_char(i), pfetch(i)); - break; - default: - fatal("fatal internal error in abort_hunk\n"); - } - } -} - -/* We found where to apply it (we hope), so do it. */ - -static void -apply_hunk(LINENUM where) -{ - LINENUM old = 1; - const LINENUM lastline = pch_ptrn_lines(); - LINENUM new = lastline + 1; -#define OUTSIDE 0 -#define IN_IFNDEF 1 -#define IN_IFDEF 2 -#define IN_ELSE 3 - int def_state = OUTSIDE; - const LINENUM pat_end = pch_end(); - - where--; - while (pch_char(new) == '=' || pch_char(new) == '\n') - new++; - - while (old <= lastline) { - if (pch_char(old) == '-') { - copy_till(where + old - 1, false); - if (do_defines) { - if (def_state == OUTSIDE) { - fputs(not_defined, ofp); - def_state = IN_IFNDEF; - } else if (def_state == IN_IFDEF) { - fputs(else_defined, ofp); - def_state = IN_ELSE; - } - fputs(pfetch(old), ofp); - } - last_frozen_line++; - old++; - } else if (new > pat_end) { - break; - } else if (pch_char(new) == '+') { - copy_till(where + old - 1, false); - if (do_defines) { - if (def_state == IN_IFNDEF) { - fputs(else_defined, ofp); - def_state = IN_ELSE; - } else if (def_state == OUTSIDE) { - fputs(if_defined, ofp); - def_state = IN_IFDEF; - } - } - fputs(pfetch(new), ofp); - new++; - } else if (pch_char(new) != pch_char(old)) { - say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n", - pch_hunk_beg() + old, - pch_hunk_beg() + new); -#ifdef DEBUGGING - say("oldchar = '%c', newchar = '%c'\n", - pch_char(old), pch_char(new)); -#endif - my_exit(2); - } else if (pch_char(new) == '!') { - copy_till(where + old - 1, false); - if (do_defines) { - fputs(not_defined, ofp); - def_state = IN_IFNDEF; - } - while (pch_char(old) == '!') { - if (do_defines) { - fputs(pfetch(old), ofp); - } - last_frozen_line++; - old++; - } - if (do_defines) { - fputs(else_defined, ofp); - def_state = IN_ELSE; - } - while (pch_char(new) == '!') { - fputs(pfetch(new), ofp); - new++; - } - } else { - if (pch_char(new) != ' ') - fatal("Internal error: expected ' '\n"); - old++; - new++; - if (do_defines && def_state != OUTSIDE) { - fputs(end_defined, ofp); - def_state = OUTSIDE; - } - } - } - if (new <= pat_end && pch_char(new) == '+') { - copy_till(where + old - 1, false); - if (do_defines) { - if (def_state == OUTSIDE) { - fputs(if_defined, ofp); - def_state = IN_IFDEF; - } else if (def_state == IN_IFNDEF) { - fputs(else_defined, ofp); - def_state = IN_ELSE; - } - } - while (new <= pat_end && pch_char(new) == '+') { - fputs(pfetch(new), ofp); - new++; - } - } - if (do_defines && def_state != OUTSIDE) { - fputs(end_defined, ofp); - } -} - -/* - * Open the new file. - */ -static void -init_output(const char *name) -{ - ofp = fopen(name, "w"); - if (ofp == NULL) - pfatal("can't create %s", name); -} - -/* - * Open a file to put hunks we can't locate. - */ -static void -init_reject(const char *name) -{ - rejfp = fopen(name, "w"); - if (rejfp == NULL) - pfatal("can't create %s", name); -} - -/* - * Copy input file to output, up to wherever hunk is to be applied. - * If endoffile is true, treat the last line specially since it may - * lack a newline. - */ -static void -copy_till(LINENUM lastline, bool endoffile) -{ - if (last_frozen_line > lastline) - fatal("misordered hunks! output would be garbled\n"); - while (last_frozen_line < lastline) { - if (++last_frozen_line == lastline && endoffile) - dump_line(last_frozen_line, !last_line_missing_eol); - else - dump_line(last_frozen_line, true); - } -} - -/* - * Finish copying the input file to the output file. - */ -static void -spew_output(void) -{ -#ifdef DEBUGGING - if (debug & 256) - say("il=%ld lfl=%ld\n", input_lines, last_frozen_line); -#endif - if (input_lines) - copy_till(input_lines, true); /* dump remainder of file */ - fclose(ofp); - ofp = NULL; -} - -/* - * Copy one line from input to output. - */ -static void -dump_line(LINENUM line, bool write_newline) -{ - char *s; - - s = ifetch(line, 0); - if (s == NULL) - return; - /* Note: string is not NUL terminated. */ - for (; *s != '\n'; s++) - putc(*s, ofp); - if (write_newline) - putc('\n', ofp); -} - -/* - * Does the patch pattern match at line base+offset? - */ -static bool -patch_match(LINENUM base, LINENUM offset, LINENUM fuzz) -{ - LINENUM pline = 1 + fuzz; - LINENUM iline; - LINENUM pat_lines = pch_ptrn_lines() - fuzz; - const char *ilineptr; - const char *plineptr; - short plinelen; - - for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) { - ilineptr = ifetch(iline, offset >= 0); - if (ilineptr == NULL) - return false; - plineptr = pfetch(pline); - plinelen = pch_line_len(pline); - if (canonicalize) { - if (!similar(ilineptr, plineptr, plinelen)) - return false; - } else if (strnNE(ilineptr, plineptr, plinelen)) - return false; - if (iline == input_lines) { - /* - * We are looking at the last line of the file. - * If the file has no eol, the patch line should - * not have one either and vice-versa. Note that - * plinelen > 0. - */ - if (last_line_missing_eol) { - if (plineptr[plinelen - 1] == '\n') - return false; - } else { - if (plineptr[plinelen - 1] != '\n') - return false; - } - } - } - return true; -} - -/* - * Do two lines match with canonicalized white space? - */ -static bool -similar(const char *a, const char *b, int len) -{ - while (len) { - if (isspace(*b)) { /* whitespace (or \n) to match? */ - if (!isspace(*a)) /* no corresponding whitespace? */ - return false; - while (len && isspace(*b) && *b != '\n') - b++, len--; /* skip pattern whitespace */ - while (isspace(*a) && *a != '\n') - a++; /* skip target whitespace */ - if (*a == '\n' || *b == '\n') - return (*a == *b); /* should end in sync */ - } else if (*a++ != *b++) /* match non-whitespace chars */ - return false; - else - len--; /* probably not necessary */ - } - return true; /* actually, this is not reached */ - /* since there is always a \n */ -} |