diff options
author | cvs2svn <cvs2svn@FreeBSD.org> | 2006-06-26 17:25:23 +0000 |
---|---|---|
committer | cvs2svn <cvs2svn@FreeBSD.org> | 2006-06-26 17:25:23 +0000 |
commit | eb5270bf8fb2f273b3a610d551484384417ac307 (patch) | |
tree | 3abcd9cb9fc2eae412e6cb927b04ecc4db559d3e /usr.bin/patch | |
parent | 257c55772da29a31a2986189e9cff6b3d3b1516d (diff) |
Notes
Diffstat (limited to 'usr.bin/patch')
-rw-r--r-- | usr.bin/patch/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/patch/README | 123 | ||||
-rw-r--r-- | usr.bin/patch/backupfile.c | 238 | ||||
-rw-r--r-- | usr.bin/patch/backupfile.h | 38 | ||||
-rw-r--r-- | usr.bin/patch/common.h | 114 | ||||
-rw-r--r-- | usr.bin/patch/inp.c | 473 | ||||
-rw-r--r-- | usr.bin/patch/inp.h | 31 | ||||
-rw-r--r-- | usr.bin/patch/patch.1 | 641 | ||||
-rw-r--r-- | usr.bin/patch/patch.c | 974 | ||||
-rw-r--r-- | usr.bin/patch/pathnames.h | 11 | ||||
-rw-r--r-- | usr.bin/patch/pch.c | 1549 | ||||
-rw-r--r-- | usr.bin/patch/pch.h | 56 | ||||
-rw-r--r-- | usr.bin/patch/util.c | 425 | ||||
-rw-r--r-- | usr.bin/patch/util.h | 47 |
14 files changed, 0 insertions, 4726 deletions
diff --git a/usr.bin/patch/Makefile b/usr.bin/patch/Makefile deleted file mode 100644 index 9c54a925f50d5..0000000000000 --- a/usr.bin/patch/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# $OpenBSD: Makefile,v 1.3 2003/07/18 02:00:09 deraadt Exp $ - -PROG= patch -SRCS= patch.c pch.c inp.c util.c backupfile.c - -.include <bsd.prog.mk> diff --git a/usr.bin/patch/README b/usr.bin/patch/README deleted file mode 100644 index 72c10644d17a4..0000000000000 --- a/usr.bin/patch/README +++ /dev/null @@ -1,123 +0,0 @@ -this version modified to fit in with the 386bsd release. -this isn't gnu software, so we're not obligated to give -you the original sources -- if you want them, get them -from prep.ai.mit.edu:pub/gnu/patch-2.0.12u8.tar.z - - -- cgd - -####################################################################### - - -This version of patch contains modifications made by the Free Software -Foundation, summarized in the file ChangeLog. Primarily they are to -support the unified context diff format that GNU diff can produce, and -to support making GNU Emacs-style backup files. They also include -fixes for some bugs. - -There are two GNU variants of patch: this one, which retains Larry -Wall's interactive Configure script and has patchlevels starting with -`12u'; and another one that has a GNU-style non-interactive configure -script and accepts long-named options, and has patchlevels starting -with `12g'. Unlike the 12g variant, the 12u variant contains no -copylefted code, for the paranoid. The two variants are otherwise the -same. They should be available from the same places. - -The FSF is distributing this version of patch independently because as -of this writing, Larry Wall has not released a new version of patch -since mid-1988. I have heard that he has been too busy working on -other things, like Perl. - -Here is a wish list of some projects to improve patch: - -1. Correctly handle files and patchfiles that contain NUL characters. -This is hard to do straightforwardly; it would be less work to -adopt a kind of escape encoding internally. -Let ESC be a "control prefix". ESC @ stands for NUL. ESC [ stands for ESC. -You need to crunch this when reading input (replace fgets), -and when writing the output file (replace fputs), -but otherwise everything can go along as it does now. -Be careful to handle reject files correctly; -I think they are currently created using `write', not `fputs'. - -2. Correctly handle patches produced by GNU diff for files that do -not end with a newline. - -Please send bug reports for this version of patch to -bug-gnu-utils@prep.ai.mit.edu as well as to Larry Wall (lwall@netlabs.com). - --djm@gnu.ai.mit.edu (David MacKenzie) - - Patch Kit, Version 2.0 - - Copyright (c) 1988, 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. --------------------------------------------------------------------------- - -Please read all the directions below before you proceed any further, and -then follow them carefully. Failure to do so may void your warranty. :-) - -After you have unpacked your kit, you should have all the files listed -in MANIFEST. - -Installation - -1) Run Configure. This will figure out various things about your system. - Some things Configure will figure out for itself, other things it will - ask you about. It will then proceed to make config.h, config.sh, and - Makefile. - - You might possibly have to trim # comments from the front of Configure - if your sh doesn't handle them, but all other # comments will be taken - care of. - - If you don't have sh, you'll have to rip the prototype of config.h out - of Configure and generate the defines by hand. - -2) Glance through config.h to make sure system dependencies are correct. - Most of them should have been taken care of by running the - Configure script. - - If you have any additional changes to make to the C definitions, they - can be done in the Makefile, or in config.h. Bear in mind that they may - get undone next time you run Configure. - -3) make - - This will attempt to make patch in the current directory. - -4) make install - - This will put patch into a public directory (normally /usr/local/bin). - It will also try to put the man pages in a reasonable place. It will not - nroff the man page, however. - -5) Read the manual entry before running patch. - -6) IMPORTANT! Help save the world! Communicate any problems and - suggested patches to me, lwall@netlabs.com (Larry Wall), - so we can keep the world in sync. If you have a problem, there's - someone else out there who either has had or will have the same problem. - - If possible, send in patches such that the patch program will apply them. - Context diffs are the best, then normal diffs. Don't send ed scripts-- - I've probably changed my copy since the version you have. - - Watch for patch patches in comp.sources.bugs. Patches will generally be - in a form usable by the patch program. Your current patch level - is shown in patchlevel.h. diff --git a/usr.bin/patch/backupfile.c b/usr.bin/patch/backupfile.c deleted file mode 100644 index 5863e9b1b147f..0000000000000 --- a/usr.bin/patch/backupfile.c +++ /dev/null @@ -1,238 +0,0 @@ -/* $OpenBSD: backupfile.c,v 1.17 2003/08/01 20:30:48 otto Exp $ */ - -/* - * backupfile.c -- make Emacs style backup file names Copyright (C) 1990 Free - * Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * without restriction. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - */ - -/* - * David MacKenzie <djm@ai.mit.edu>. Some algorithms adapted from GNU Emacs. - */ - -#ifndef lint -static const char rcsid[] = "$OpenBSD: backupfile.c,v 1.17 2003/08/01 20:30:48 otto Exp $"; -#endif /* not lint */ - -#include <ctype.h> -#include <dirent.h> -#include <libgen.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "backupfile.h" - - -#define ISDIGIT(c) (isascii (c) && isdigit (c)) - -/* Which type of backup file names are generated. */ -enum backup_type backup_type = none; - -/* - * The extension added to file names to produce a simple (as opposed to - * numbered) backup file name. - */ -char *simple_backup_suffix = "~"; - -static char *concat(const char *, const char *); -static char *make_version_name(const char *, int); -static int max_backup_version(const char *, const char *); -static int version_number(const char *, const char *, int); -static int argmatch(const char *, const char **); -static void invalid_arg(const char *, const char *, int); - -/* - * Return the name of the new backup file for file FILE, allocated with - * malloc. Return 0 if out of memory. FILE must not end with a '/' unless it - * is the root directory. Do not call this function if backup_type == none. - */ -char * -find_backup_file_name(const char *file) -{ - char *dir, *base_versions; - int highest_backup; - - if (backup_type == simple) - return concat(file, simple_backup_suffix); - base_versions = concat(basename(file), ".~"); - if (base_versions == NULL) - return NULL; - dir = dirname(file); - if (dir == NULL) { - free(base_versions); - return NULL; - } - highest_backup = max_backup_version(base_versions, dir); - free(base_versions); - if (backup_type == numbered_existing && highest_backup == 0) - return concat(file, simple_backup_suffix); - return make_version_name(file, highest_backup + 1); -} - -/* - * Return the number of the highest-numbered backup file for file FILE in - * directory DIR. If there are no numbered backups of FILE in DIR, or an - * error occurs reading DIR, return 0. FILE should already have ".~" appended - * to it. - */ -static int -max_backup_version(const char *file, const char *dir) -{ - DIR *dirp; - struct dirent *dp; - int highest_version, this_version, file_name_length; - - dirp = opendir(dir); - if (dirp == NULL) - return 0; - - highest_version = 0; - file_name_length = strlen(file); - - while ((dp = readdir(dirp)) != NULL) { - if (dp->d_namlen <= file_name_length) - continue; - - this_version = version_number(file, dp->d_name, file_name_length); - if (this_version > highest_version) - highest_version = this_version; - } - closedir(dirp); - return highest_version; -} - -/* - * Return a string, allocated with malloc, containing "FILE.~VERSION~". - * Return 0 if out of memory. - */ -static char * -make_version_name(const char *file, int version) -{ - char *backup_name; - - if (asprintf(&backup_name, "%s.~%d~", file, version) == -1) - return NULL; - return backup_name; -} - -/* - * If BACKUP is a numbered backup of BASE, return its version number; - * otherwise return 0. BASE_LENGTH is the length of BASE. BASE should - * already have ".~" appended to it. - */ -static int -version_number(const char *base, const char *backup, int base_length) -{ - int version; - const char *p; - - version = 0; - if (!strncmp(base, backup, base_length) && ISDIGIT(backup[base_length])) { - for (p = &backup[base_length]; ISDIGIT(*p); ++p) - version = version * 10 + *p - '0'; - if (p[0] != '~' || p[1]) - version = 0; - } - return version; -} - -/* - * Return the newly-allocated concatenation of STR1 and STR2. If out of - * memory, return 0. - */ -static char * -concat(const char *str1, const char *str2) -{ - char *newstr; - - if (asprintf(&newstr, "%s%s", str1, str2) == -1) - return NULL; - return newstr; -} - -/* - * If ARG is an unambiguous match for an element of the null-terminated array - * OPTLIST, return the index in OPTLIST of the matched element, else -1 if it - * does not match any element or -2 if it is ambiguous (is a prefix of more - * than one element). - */ -static int -argmatch(const char *arg, const char **optlist) -{ - int i; /* Temporary index in OPTLIST. */ - size_t arglen; /* Length of ARG. */ - int matchind = -1; /* Index of first nonexact match. */ - int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */ - - arglen = strlen(arg); - - /* Test all elements for either exact match or abbreviated matches. */ - for (i = 0; optlist[i]; i++) { - if (!strncmp(optlist[i], arg, arglen)) { - if (strlen(optlist[i]) == arglen) - /* Exact match found. */ - return i; - else if (matchind == -1) - /* First nonexact match found. */ - matchind = i; - else - /* Second nonexact match found. */ - ambiguous = 1; - } - } - if (ambiguous) - return -2; - else - return matchind; -} - -/* - * Error reporting for argmatch. KIND is a description of the type of entity - * that was being matched. VALUE is the invalid value that was given. PROBLEM - * is the return value from argmatch. - */ -static void -invalid_arg(const char *kind, const char *value, int problem) -{ - fprintf(stderr, "patch: "); - if (problem == -1) - fprintf(stderr, "invalid"); - else /* Assume -2. */ - fprintf(stderr, "ambiguous"); - fprintf(stderr, " %s `%s'\n", kind, value); -} - -static const char *backup_args[] = { - "never", "simple", "nil", "existing", "t", "numbered", 0 -}; - -static enum backup_type backup_types[] = { - simple, simple, numbered_existing, - numbered_existing, numbered, numbered -}; - -/* - * Return the type of backup indicated by VERSION. Unique abbreviations are - * accepted. - */ -enum backup_type -get_version(const char *version) -{ - int i; - - if (version == NULL || *version == '\0') - return numbered_existing; - i = argmatch(version, backup_args); - if (i >= 0) - return backup_types[i]; - invalid_arg("version control type", version, i); - exit(2); -} diff --git a/usr.bin/patch/backupfile.h b/usr.bin/patch/backupfile.h deleted file mode 100644 index 7c20ddb4bc557..0000000000000 --- a/usr.bin/patch/backupfile.h +++ /dev/null @@ -1,38 +0,0 @@ -/* $OpenBSD: backupfile.h,v 1.6 2003/07/28 18:35:36 otto Exp $ */ - -/* - * backupfile.h -- declarations for making Emacs style backup file names - * Copyright (C) 1990 Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * without restriction. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -/* When to make backup files. */ -enum backup_type { - /* Never make backups. */ - none, - - /* Make simple backups of every file. */ - simple, - - /* - * Make numbered backups of files that already have numbered backups, - * and simple backups of the others. - */ - numbered_existing, - - /* Make numbered backups of every file. */ - numbered -}; - -extern enum backup_type backup_type; -extern char *simple_backup_suffix; - -char *find_backup_file_name(const char *file); -enum backup_type get_version(const char *version); diff --git a/usr.bin/patch/common.h b/usr.bin/patch/common.h deleted file mode 100644 index 4101a5757470d..0000000000000 --- a/usr.bin/patch/common.h +++ /dev/null @@ -1,114 +0,0 @@ -/* $OpenBSD: common.h,v 1.25 2003/10/31 20:20:45 millert 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 - */ - -#include <stdbool.h> - -#define DEBUGGING - -/* constants */ - -#define MAXHUNKSIZE 100000 /* is this enough lines? */ -#define INITHUNKMAX 125 /* initial dynamic allocation size */ -#define MAXLINELEN 8192 -#define BUFFERSIZE 1024 - -#define SCCSPREFIX "s." -#define GET "get -e %s" -#define SCCSDIFF "get -p %s | diff - %s >/dev/null" - -#define RCSSUFFIX ",v" -#define CHECKOUT "co -l %s" -#define RCSDIFF "rcsdiff %s > /dev/null" - -#define ORIGEXT ".orig" -#define REJEXT ".rej" - -/* handy definitions */ - -#define strNE(s1,s2) (strcmp(s1, s2)) -#define strEQ(s1,s2) (!strcmp(s1, s2)) -#define strnNE(s1,s2,l) (strncmp(s1, s2, l)) -#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l)) - -/* typedefs */ - -typedef long LINENUM; /* must be signed */ - -/* globals */ - -extern int filemode; - -extern char buf[MAXLINELEN];/* general purpose buffer */ - -extern bool using_plan_a; /* try to keep everything in memory */ -extern bool out_of_mem; /* ran out of memory in plan a */ - -#define MAXFILEC 2 - -extern char *filearg[MAXFILEC]; -extern bool ok_to_create_file; -extern char *outname; -extern char *origprae; - -extern char *TMPOUTNAME; -extern char *TMPINNAME; -extern char *TMPREJNAME; -extern char *TMPPATNAME; -extern bool toutkeep; -extern bool trejkeep; - -#ifdef DEBUGGING -extern int debug; -#endif - -extern bool force; -extern bool batch; -extern bool verbose; -extern bool reverse; -extern bool noreverse; -extern bool skip_rest_of_patch; -extern int strippath; -extern bool canonicalize; -/* TRUE if -C was specified on command line. */ -extern bool check_only; -extern bool warn_on_invalid_line; -extern bool last_line_missing_eol; - - -#define CONTEXT_DIFF 1 -#define NORMAL_DIFF 2 -#define ED_DIFF 3 -#define NEW_CONTEXT_DIFF 4 -#define UNI_DIFF 5 - -extern int diff_type; -extern char *revision; /* prerequisite revision, if any */ -extern LINENUM input_lines; /* how long is input file in lines */ - -extern int posix; - diff --git a/usr.bin/patch/inp.c b/usr.bin/patch/inp.c deleted file mode 100644 index 3326843ad0080..0000000000000 --- a/usr.bin/patch/inp.c +++ /dev/null @@ -1,473 +0,0 @@ -/* $OpenBSD: inp.c,v 1.31 2003/12/08 22:44:18 mickey 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: inp.c,v 1.31 2003/12/08 22:44:18 mickey Exp $"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include <ctype.h> -#include <libgen.h> -#include <limits.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "common.h" -#include "util.h" -#include "pch.h" -#include "inp.h" - - -/* Input-file-with-indexable-lines abstract type */ - -static off_t i_size; /* size of the input file */ -static char *i_womp; /* plan a buffer for entire file */ -static char **i_ptr; /* pointers to lines in i_womp */ - -static int tifd = -1; /* plan b virtual string array */ -static char *tibuf[2]; /* plan b buffers */ -static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */ -static LINENUM lines_per_buf; /* how many lines per buffer */ -static int tireclen; /* length of records in tmp file */ - -static bool rev_in_string(const char *); -static bool reallocate_lines(size_t *); - -/* returns false if insufficient memory */ -static bool plan_a(const char *); - -static void plan_b(const char *); - -/* New patch--prepare to edit another file. */ - -void -re_input(void) -{ - if (using_plan_a) { - i_size = 0; - free(i_ptr); - i_ptr = NULL; - if (i_womp != NULL) { - munmap(i_womp, i_size); - i_womp = NULL; - } - } else { - using_plan_a = true; /* maybe the next one is smaller */ - close(tifd); - tifd = -1; - free(tibuf[0]); - free(tibuf[1]); - tibuf[0] = tibuf[1] = NULL; - tiline[0] = tiline[1] = -1; - tireclen = 0; - } -} - -/* Constuct the line index, somehow or other. */ - -void -scan_input(const char *filename) -{ - if (!plan_a(filename)) - plan_b(filename); - if (verbose) { - say("Patching file %s using Plan %s...\n", filename, - (using_plan_a ? "A" : "B")); - } -} - -static bool -reallocate_lines(size_t *lines_allocated) -{ - char **p; - size_t new_size; - - new_size = *lines_allocated * 3 / 2; - p = realloc(i_ptr, (new_size + 2) * sizeof(char *)); - if (p == NULL) { /* shucks, it was a near thing */ - munmap(i_womp, i_size); - i_womp = NULL; - free(i_ptr); - i_ptr = NULL; - *lines_allocated = 0; - return false; - } - *lines_allocated = new_size; - i_ptr = p; - return true; -} - -/* Try keeping everything in memory. */ - -static bool -plan_a(const char *filename) -{ - int ifd, statfailed; - char *p, *s, lbuf[MAXLINELEN]; - LINENUM iline; - struct stat filestat; - off_t i; - ptrdiff_t sz; - size_t lines_allocated; - -#ifdef DEBUGGING - if (debug & 8) - return false; -#endif - - if (filename == NULL || *filename == '\0') - return false; - - statfailed = stat(filename, &filestat); - if (statfailed && ok_to_create_file) { - if (verbose) - say("(Creating file %s...)\n", filename); - - /* - * in check_patch case, we still display `Creating file' even - * though we're not. The rule is that -C should be as similar - * to normal patch behavior as possible - */ - if (check_only) - return true; - makedirs(filename, true); - close(creat(filename, 0666)); - statfailed = stat(filename, &filestat); - } - if (statfailed && check_only) - fatal("%s not found, -C mode, can't probe further\n", filename); - /* For nonexistent or read-only files, look for RCS or SCCS versions. */ - if (statfailed || - /* No one can write to it. */ - (filestat.st_mode & 0222) == 0 || - /* I can't write to it. */ - ((filestat.st_mode & 0022) == 0 && filestat.st_uid != getuid())) { - char *cs = NULL, *filebase, *filedir; - struct stat cstat; - - filebase = basename(filename); - filedir = dirname(filename); - - /* Leave room in lbuf for the diff command. */ - s = lbuf + 20; - -#define try(f, a1, a2, a3) \ - (snprintf(s, sizeof lbuf - 20, f, a1, a2, a3), stat(s, &cstat) == 0) - - if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) || - try("%s/RCS/%s%s", filedir, filebase, "") || - try("%s/%s%s", filedir, filebase, RCSSUFFIX)) { - snprintf(buf, sizeof buf, CHECKOUT, filename); - snprintf(lbuf, sizeof lbuf, RCSDIFF, filename); - cs = "RCS"; - } else if (try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) || - try("%s/%s%s", filedir, SCCSPREFIX, filebase)) { - snprintf(buf, sizeof buf, GET, s); - snprintf(lbuf, sizeof lbuf, SCCSDIFF, s, filename); - cs = "SCCS"; - } else if (statfailed) - fatal("can't find %s\n", filename); - /* - * else we can't write to it but it's not under a version - * control system, so just proceed. - */ - if (cs) { - if (!statfailed) { - if ((filestat.st_mode & 0222) != 0) - /* The owner can write to it. */ - fatal("file %s seems to be locked " - "by somebody else under %s\n", - filename, cs); - /* - * It might be checked out unlocked. See if - * it's safe to check out the default version - * locked. - */ - if (verbose) - say("Comparing file %s to default " - "%s version...\n", - filename, cs); - if (system(lbuf)) - fatal("can't check out file %s: " - "differs from default %s version\n", - filename, cs); - } - if (verbose) - say("Checking out file %s from %s...\n", - filename, cs); - if (system(buf) || stat(filename, &filestat)) - fatal("can't check out file %s from %s\n", - filename, cs); - } - } - filemode = filestat.st_mode; - if (!S_ISREG(filemode)) - fatal("%s is not a normal file--can't patch\n", filename); - i_size = filestat.st_size; - if (out_of_mem) { - set_hunkmax(); /* make sure dynamic arrays are allocated */ - out_of_mem = false; - return false; /* force plan b because plan a bombed */ - } - if (i_size > SIZE_MAX) { - say("block too large to mmap\n"); - return false; - } - if ((ifd = open(filename, O_RDONLY)) < 0) - pfatal("can't open file %s", filename); - - i_womp = mmap(NULL, i_size, PROT_READ, MAP_PRIVATE, ifd, 0); - if (i_womp == MAP_FAILED) { - perror("mmap failed"); - i_womp = NULL; - close(ifd); - return false; - } - - close(ifd); - if (i_size) - madvise(i_womp, i_size, MADV_SEQUENTIAL); - - /* estimate the number of lines */ - lines_allocated = i_size / 25; - if (lines_allocated < 100) - lines_allocated = 100; - - if (!reallocate_lines(&lines_allocated)) - return false; - - /* now scan the buffer and build pointer array */ - iline = 1; - i_ptr[iline] = i_womp; - /* test for NUL too, to maintain the behavior of the original code */ - for (s = i_womp, i = 0; i < i_size && *s != '\0'; s++, i++) { - if (*s == '\n') { - if (iline == lines_allocated) { - if (!reallocate_lines(&lines_allocated)) - return false; - } - /* these are NOT NUL terminated */ - i_ptr[++iline] = s + 1; - } - } - /* if the last line contains no EOL, append one */ - if (i_size > 0 && i_womp[i_size - 1] != '\n') { - last_line_missing_eol = true; - /* fix last line */ - sz = s - i_ptr[iline]; - p = malloc(sz + 1); - if (p == NULL) { - free(i_ptr); - i_ptr = NULL; - munmap(i_womp, i_size); - i_womp = NULL; - return false; - } - - memcpy(p, i_ptr[iline], sz); - p[sz] = '\n'; - i_ptr[iline] = p; - /* count the extra line and make it point to some valid mem */ - i_ptr[++iline] = ""; - } else - last_line_missing_eol = false; - - input_lines = iline - 1; - - /* now check for revision, if any */ - - if (revision != NULL) { - if (!rev_in_string(i_womp)) { - if (force) { - if (verbose) - say("Warning: this file doesn't appear " - "to be the %s version--patching anyway.\n", - revision); - } else if (batch) { - fatal("this file doesn't appear to be the " - "%s version--aborting.\n", - revision); - } else { - ask("This file doesn't appear to be the " - "%s version--patch anyway? [n] ", - revision); - if (*buf != 'y') - fatal("aborted\n"); - } - } else if (verbose) - say("Good. This file appears to be the %s version.\n", - revision); - } - return true; /* plan a will work */ -} - -/* Keep (virtually) nothing in memory. */ - -static void -plan_b(const char *filename) -{ - FILE *ifp; - int i = 0, j, maxlen = 1; - char *p; - bool found_revision = (revision == NULL); - - using_plan_a = false; - if ((ifp = fopen(filename, "r")) == NULL) - pfatal("can't open file %s", filename); - (void) unlink(TMPINNAME); - if ((tifd = open(TMPINNAME, O_EXCL | O_CREAT | O_WRONLY, 0666)) < 0) - pfatal("can't open file %s", TMPINNAME); - while (fgets(buf, sizeof buf, ifp) != NULL) { - if (revision != NULL && !found_revision && rev_in_string(buf)) - found_revision = true; - if ((i = strlen(buf)) > maxlen) - maxlen = i; /* find longest line */ - } - last_line_missing_eol = i > 0 && buf[i - 1] != '\n'; - if (last_line_missing_eol && maxlen == i) - maxlen++; - - if (revision != NULL) { - if (!found_revision) { - if (force) { - if (verbose) - say("Warning: this file doesn't appear " - "to be the %s version--patching anyway.\n", - revision); - } else if (batch) { - fatal("this file doesn't appear to be the " - "%s version--aborting.\n", - revision); - } else { - ask("This file doesn't appear to be the %s " - "version--patch anyway? [n] ", - revision); - if (*buf != 'y') - fatal("aborted\n"); - } - } else if (verbose) - say("Good. This file appears to be the %s version.\n", - revision); - } - fseek(ifp, 0L, SEEK_SET); /* rewind file */ - lines_per_buf = BUFFERSIZE / maxlen; - tireclen = maxlen; - tibuf[0] = malloc(BUFFERSIZE + 1); - if (tibuf[0] == NULL) - fatal("out of memory\n"); - tibuf[1] = malloc(BUFFERSIZE + 1); - if (tibuf[1] == NULL) - fatal("out of memory\n"); - for (i = 1;; i++) { - p = tibuf[0] + maxlen * (i % lines_per_buf); - if (i % lines_per_buf == 0) /* new block */ - if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE) - pfatal("can't write temp file"); - if (fgets(p, maxlen + 1, ifp) == NULL) { - input_lines = i - 1; - if (i % lines_per_buf != 0) - if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE) - pfatal("can't write temp file"); - break; - } - j = strlen(p); - /* These are '\n' terminated strings, so no need to add a NUL */ - if (j == 0 || p[j - 1] != '\n') - p[j] = '\n'; - } - fclose(ifp); - close(tifd); - if ((tifd = open(TMPINNAME, O_RDONLY)) < 0) - pfatal("can't reopen file %s", TMPINNAME); -} - -/* - * Fetch a line from the input file, \n terminated, not necessarily \0. - */ -char * -ifetch(LINENUM line, int whichbuf) -{ - if (line < 1 || line > input_lines) { - if (warn_on_invalid_line) { - say("No such line %ld in input file, ignoring\n", line); - warn_on_invalid_line = false; - } - return NULL; - } - if (using_plan_a) - return i_ptr[line]; - else { - LINENUM offline = line % lines_per_buf; - LINENUM baseline = line - offline; - - if (tiline[0] == baseline) - whichbuf = 0; - else if (tiline[1] == baseline) - whichbuf = 1; - else { - tiline[whichbuf] = baseline; - - lseek(tifd, (off_t) (baseline / lines_per_buf * - BUFFERSIZE), SEEK_SET); - - if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0) - pfatal("error reading tmp file %s", TMPINNAME); - } - return tibuf[whichbuf] + (tireclen * offline); - } -} - -/* - * True if the string argument contains the revision number we want. - */ -static bool -rev_in_string(const char *string) -{ - const char *s; - int patlen; - - if (revision == NULL) - return true; - patlen = strlen(revision); - if (strnEQ(string, revision, patlen) && isspace(string[patlen])) - return true; - for (s = string; *s; s++) { - if (isspace(*s) && strnEQ(s + 1, revision, patlen) && - isspace(s[patlen + 1])) { - return true; - } - } - return false; -} diff --git a/usr.bin/patch/inp.h b/usr.bin/patch/inp.h deleted file mode 100644 index aa66208fdc8b2..0000000000000 --- a/usr.bin/patch/inp.h +++ /dev/null @@ -1,31 +0,0 @@ -/* $OpenBSD: inp.h,v 1.8 2003/08/15 08:00:51 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 - */ - -void re_input(void); -void scan_input(const char *); -char *ifetch(LINENUM, int); diff --git a/usr.bin/patch/patch.1 b/usr.bin/patch/patch.1 deleted file mode 100644 index 9d12b8b12bd77..0000000000000 --- a/usr.bin/patch/patch.1 +++ /dev/null @@ -1,641 +0,0 @@ -.\" $OpenBSD: patch.1,v 1.17 2003/10/31 20:20:45 millert Exp $ -.\" 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. -.\" -.Dd July 23, 2003 -.Dt PATCH 1 -.Os -.Sh NAME -.Nm patch -.Nd apply a diff file to an original -.Sh SYNOPSIS -.Nm patch -.Op Cm options -.Op Ar origfile Op Ar patchfile -.Nm patch -.Pf \*(Lt Ar patchfile -.Sh DESCRIPTION -.Nm -will take a patch file containing any of the four forms of difference -listing produced by the -.Xr diff 1 -program and apply those differences to an original file, -producing a patched version. -If -.Ar patchfile -is omitted, or is a hyphen, the patch will be read from the standard input. -.Pp -.Nm -will attempt to determine the type of the diff listing, unless over-ruled by a -.Fl c , -.Fl e , -.Fl n , -or -.Fl u -option. -Context diffs (old-style, new-style, and unified) and -normal diffs are applied directly by the -.Nm -program itself, whereas ed diffs are simply fed to the -.Xr ed 1 -editor via a pipe. -.Pp -If the -.Ar patchfile -contains more than one patch, -.Nm -will try to apply each of them as if they came from separate patch files. -This means, among other things, that it is assumed that the name of the file -to patch must be determined for each diff listing, and that the garbage before -each diff listing will be examined for interesting things such as file names -and revision level (see the section on -.Sx Filename Determination -below). -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl b , Fl Fl backup -Save a backup copy of the file before it is modified. -By default the original file is saved with a backup extension of -.Qq .orig -unless the file already has a numbered backup, in which case a numbered -backup is made. -This is equivalent to specifying -.Qo Fl V Ar existing Qc . -This option is currently the default but that will change in a future release. -.It Fl B , Fl Fl prefix -Causes the next argument to be interpreted as a prefix to the backup file -name. -If this argument is specified, any argument to -.Fl z -will be ignored. -.It Fl c , Fl Fl context -Forces -.Nm -to interpret the patch file as a context diff. -.It Fl C , Fl Fl check -Checks that the patch would apply cleanly, but does not modify anything. -.It Fl d , Fl Fl directory -Causes -.Nm -to interpret the next argument as a directory, and -.Xr cd 1 -to it before doing anything else. -.It Fl D , Fl Fl ifdef -Causes -.Nm -to use the -.Qq #ifdef...#endif -construct to mark changes. -The argument following will be used as the differentiating symbol. -Note that, unlike the C compiler, there must be a space between the -.Fl D -and the argument. -.It Fl e , Fl Fl ed -Forces -.Nm -to interpret the patch file as an -.Xr ed 1 -script. -.It Fl E , Fl Fl remove-empty-files -Causes -.Nm -to remove output files that are empty after the patches have been applied. -This option is useful when applying patches that create or remove files. -.It Fl f , Fl Fl force -Forces -.Nm -to assume that the user knows exactly what he or she is doing, and to not -ask any questions. -It assumes the following: -skip patches for which a file to patch can't be found; -patch files even though they have the wrong version for the -.Qq Prereq: -line in the patch; -and assume that patches are not reversed even if they look like they are. -This option does not suppress commentary; use -.Fl s -for that. -.It Xo -.Fl F Ns Aq Ar number , -.Fl Fl fuzz Aq Ar number -.Xc -Sets the maximum fuzz factor. -This option only applies to context diffs, and causes -.Nm -to ignore up to that many lines in looking for places to install a hunk. -Note that a larger fuzz factor increases the odds of a faulty patch. -The default fuzz factor is 2, and it may not be set to more than -the number of lines of context in the context diff, ordinarily 3. -.It Fl i , Fl Fl input -Causes the next argument to be interpreted as the input file name -(i.e. a patchfile). -This option may be specified multiple times. -.It Fl l , Fl Fl ignore-whitespace -Causes the pattern matching to be done loosely, in case the tabs and -spaces have been munged in your input file. -Any sequence of whitespace in the pattern line will match any sequence -in the input file. -Normal characters must still match exactly. -Each line of the context must still match a line in the input file. -.It Fl n , Fl Fl normal -Forces -.Nm -to interpret the patch file as a normal diff. -.It Fl N , Fl Fl forward -Causes -.Nm -to ignore patches that it thinks are reversed or already applied. -See also -.Fl R . -.It Fl o , Fl Fl output -Causes the next argument to be interpreted as the output file name. -.It Xo -.Fl p Ns Aq Ar number , -.Fl Fl strip Aq Ar number -.Xc -Sets the pathname strip count, -which controls how pathnames found in the patch file are treated, -in case you keep your files in a different directory than the person who sent -out the patch. -The strip count specifies how many slashes are to be stripped from -the front of the pathname. -(Any intervening directory names also go away.) -For example, supposing the file name in the patch file was -.Pa /u/howard/src/blurfl/blurfl.c : -.Pp -Setting -.Fl p Ns Ar 0 -gives the entire pathname unmodified. -.Pp -.Fl p Ns Ar 1 -gives -.Pp -.D1 Pa u/howard/src/blurfl/blurfl.c -.Pp -without the leading slash. -.Pp -.Fl p Ns Ar 4 -gives -.Pp -.D1 Pa blurfl/blurfl.c -.Pp -Not specifying -.Fl p -at all just gives you -.Pa blurfl.c , -unless all of the directories in the leading path -.Pq Pa u/howard/src/blurfl -exist and that path is relative, -in which case you get the entire pathname unmodified. -Whatever you end up with is looked for either in the current directory, -or the directory specified by the -.Fl d -option. -.It Fl r , Fl Fl reject-file -Causes the next argument to be interpreted as the reject file name. -.It Fl R , Fl Fl reverse -Tells -.Nm -that this patch was created with the old and new files swapped. -(Yes, I'm afraid that does happen occasionally, human nature being what it -is.) -.Nm -will attempt to swap each hunk around before applying it. -Rejects will come out in the swapped format. -The -.Fl R -option will not work with ed diff scripts because there is too little -information to reconstruct the reverse operation. -.Pp -If the first hunk of a patch fails, -.Nm -will reverse the hunk to see if it can be applied that way. -If it can, you will be asked if you want to have the -.Fl R -option set. -If it can't, the patch will continue to be applied normally. -(Note: this method cannot detect a reversed patch if it is a normal diff -and if the first command is an append (i.e. it should have been a delete) -since appends always succeed, due to the fact that a null context will match -anywhere. -Luckily, most patches add or change lines rather than delete them, so most -reversed normal diffs will begin with a delete, which will fail, triggering -the heuristic.) -.It Xo -.Fl s , Fl Fl quiet , -.Fl Fl silent -.Xc -Makes -.Nm -do its work silently, unless an error occurs. -.It Fl t , Fl Fl batch -Similar to -.Fl f , -in that it suppresses questions, but makes some different assumptions: -skip patches for which a file to patch can't be found (the same as -.Fl f ) ; -skip patches for which the file has the wrong version for the -.Qq Prereq: -line in the patch; -and assume that patches are reversed if they look like they are. -.It Fl u , Fl Fl unified -Forces -.Nm -to interpret the patch file as a unified context diff (a unidiff). -.It Fl v , Fl Fl version -Causes -.Nm -to print out its revision header and patch level. -.It Fl V , Fl Fl version-control -Causes the next argument to be interpreted as a method for creating -backup file names. -The type of backups made can also be given in the -.Ev PATCH_VERSION_CONTROL -or -.Ev VERSION_CONTROL -environment variables, which are overridden by this option. -The -.Fl B -option overrides this option, causing the prefix to always be used for -making backup file names. -The values of the -.Ev PATCH_VERSION_CONTROL -and -.Ev VERSION_CONTROL -environment variables and the argument to the -.Fl V -option are like the GNU Emacs -.Dq version-control -variable; they also recognize synonyms that are more descriptive. -The valid values are (unique abbreviations are accepted): -.Bl -tag -width Ds -offset indent -.It t , numbered -Always make numbered backups. -.It nil , existing -Make numbered backups of files that already have them, -simple backups of the others. -.It never , simple -Always make simple backups. -.El -.It Xo -.Fl x Ns Aq Ar number , -.Fl Fl debug Aq Ar number -.Xc -Sets internal debugging flags, and is of interest only to -.Nm -patchers. -.It Fl z , Fl Fl suffix -Causes the next argument to be interpreted as the backup extension, to be -used in place of -.Qq .orig . -.It Fl Fl posix -Enables strict -.St -p1003.2 -conformance, specifically: -.Bl -enum -.It -Backup files are not created unless the -.Fl b -option is specified. -.It -If unspecified, the file name used is the first of the old, new and -index files that exists. -.El -.El -.Ss Patch Application -.Nm -will try to skip any leading garbage, apply the diff, -and then skip any trailing garbage. -Thus you could feed an article or message containing a -diff listing to -.Nm patch , -and it should work. -If the entire diff is indented by a consistent amount, -this will be taken into account. -.Pp -With context diffs, and to a lesser extent with normal diffs, -.Nm -can detect when the line numbers mentioned in the patch are incorrect, -and will attempt to find the correct place to apply each hunk of the patch. -As a first guess, it takes the line number mentioned for the hunk, plus or -minus any offset used in applying the previous hunk. -If that is not the correct place, -.Nm -will scan both forwards and backwards for a set of lines matching the context -given in the hunk. -First -.Nm -looks for a place where all lines of the context match. -If no such place is found, and it's a context diff, and the maximum fuzz factor -is set to 1 or more, then another scan takes place ignoring the first and last -line of context. -If that fails, and the maximum fuzz factor is set to 2 or more, -the first two and last two lines of context are ignored, -and another scan is made. -.Pq The default maximum fuzz factor is 2. -.Pp -If -.Nm -cannot find a place to install that hunk of the patch, it will put the hunk -out to a reject file, which normally is the name of the output file plus -.Qq .rej . -(Note that the rejected hunk will come out in context diff form whether the -input patch was a context diff or a normal diff. -If the input was a normal diff, many of the contexts will simply be null.) -The line numbers on the hunks in the reject file may be different than -in the patch file: they reflect the approximate location patch thinks the -failed hunks belong in the new file rather than the old one. -.Pp -As each hunk is completed, you will be told whether the hunk succeeded or -failed, and which line (in the new file) -.Nm -thought the hunk should go on. -If this is different from the line number specified in the diff, -you will be told the offset. -A single large offset MAY be an indication that a hunk was installed in the -wrong place. -You will also be told if a fuzz factor was used to make the match, in which -case you should also be slightly suspicious. -.Ss Filename Determination -If no original file is specified on the command line, -.Nm -will try to figure out from the leading garbage what the name of the file -to edit is. -When checking a prospective file name, pathname components are stripped -as specified by the -.Fl p -option and the file's existence and writability are checked relative -to the current working directory (or the directory specified by the -.Fl d -option). -.Pp -If the diff is a context or unified diff, -.Nm -is able to determine the old and new file names from the diff header. -For context diffs, the -.Dq old -file is specified in the line beginning with -.Qq *** -and the -.Dq new -file is specified in the line beginning with -.Qq --- . -For a unified diff, the -.Dq old -file is specified in the line beginning with -.Qq --- -and the -.Dq new -file is specified in the line beginning with -.Qq +++ . -If there is an -.Qq Index: -line in the leading garbage (regardless of the diff type), -.Nm -will use the file name from that line as the -.Dq index -file. -.Pp -.Nm -will choose the file name by performing the following steps, with the first -match used: -.Bl -enum -.It -If -.Nm -is operating in strict -.St -p1003.2 -mode, the first of the -.Dq old , -.Dq new -and -.Dq index -file names that exist is used. -Otherwise, -.Nm -will examine either the -.Dq old -and -.Dq new -file names or, for a non-context diff, the -.Dq index -file name, and choose the file name with the fewest path components, -the shortest basename, and the shortest total file name length (in that order). -.It -If no file exists, -.Nm -checks for the existence of the files in an SCCS or RCS directory -(using the appropriate prefix or suffix) using the criteria specified -above. -If found, -.Nm -will attempt to get or check out the file. -.It -If no suitable file was found to patch, the patch file is a context or -unified diff, and the old file was zero length, the new file name is -created and used. -.It -If the file name still cannot be determined, -.Nm -will prompt the user for the file name to use. -.El -.Pp -Additionally, if the leading garbage contains a -.Qq Prereq:\ \& -line, -.Nm -will take the first word from the prerequisites line (normally a version -number) and check the input file to see if that word can be found. -If not, -.Nm -will ask for confirmation before proceeding. -.Pp -The upshot of all this is that you should be able to say, while in a news -interface, the following: -.Pp -.Dl | patch -d /usr/src/local/blurfl -.Pp -and patch a file in the blurfl directory directly from the article containing -the patch. -.Ss Backup Files -By default, the patched version is put in place of the original, with -the original file backed up to the same name with the extension -.Qq .orig , -or as specified by the -.Fl B , -.Fl V , -or -.Fl z -options. -The extension used for making backup files may also be specified in the -.Ev SIMPLE_BACKUP_SUFFIX -environment variable, which is overridden by the options above. -.Pp -If the backup file is a symbolic or hard link to the original file, -.Nm -creates a new backup file name by changing the first lowercase letter -in the last component of the file's name into uppercase. -If there are no more lowercase letters in the name, -it removes the first character from the name. -It repeats this process until it comes up with a -backup file that does not already exist or is not linked to the original file. -.Pp -You may also specify where you want the output to go with the -.Fl o -option; if that file already exists, it is backed up first. -.Ss Notes For Patch Senders -There are several things you should bear in mind if you are going to -be sending out patches: -.Pp -First, you can save people a lot of grief by keeping a -.Pa patchlevel.h -file which is patched to increment the patch level as the first diff in the -patch file you send out. -If you put a -.Qq Prereq: -line in with the patch, it won't let them apply -patches out of order without some warning. -.Pp -Second, make sure you've specified the file names right, either in a -context diff header, or with an -.Qq Index: -line. -If you are patching something in a subdirectory, be sure to tell the patch -user to specify a -.Fl p -option as needed. -.Pp -Third, you can create a file by sending out a diff that compares a -null file to the file you want to create. -This will only work if the file you want to create doesn't exist already in -the target directory. -.Pp -Fourth, take care not to send out reversed patches, since it makes people wonder -whether they already applied the patch. -.Pp -Fifth, while you may be able to get away with putting 582 diff listings into -one file, it is probably wiser to group related patches into separate files in -case something goes haywire. -.Sh ENVIRONMENT -.Bl -tag -width "PATCH_VERSION_CONTROL" -compact -.It Ev POSIXLY_CORRECT -When set, -.Nm -behaves as if the -.Fl Fl posix -option has been specified. -.It Ev SIMPLE_BACKUP_SUFFIX -Extension to use for backup file names instead of -.Qq .orig . -.It Ev TMPDIR -Directory to put temporary files in; default is -.Pa /tmp . -.It Ev PATCH_VERSION_CONTROL -Selects when numbered backup files are made. -.It Ev VERSION_CONTROL -Same as -.Ev PATCH_VERSION_CONTROL . -.El -.Sh FILES -.Bl -tag -width "$TMPDIR/patch*" -compact -.It Pa $TMPDIR/patch* -.Nm -temporary files -.It Pa /dev/tty -used to read input when -.Nm -prompts the user -.El -.Sh DIAGNOSTICS -Too many to list here, but generally indicative that -.Nm -couldn't parse your patch file. -.Pp -The message -.Qq Hmm... -indicates that there is unprocessed text in the patch file and that -.Nm -is attempting to intuit whether there is a patch in that text and, if so, -what kind of patch it is. -.Pp -The -.Nm -utility exits with one of the following values: -.Pp -.Bl -tag -width Ds -compact -offset indent -.It \&0 -Successful completion. -.It \&1 -One or more lines were written to a reject file. -.It \*[Gt]\&1 -An error occurred. -.El -.Pp -When applying a set of patches in a loop it behooves you to check this -exit status so you don't apply a later patch to a partially patched file. -.Sh SEE ALSO -.Xr diff 1 -.Sh AUTHORS -.An Larry Wall -with many other contributors. -.Sh CAVEATS -.Nm -cannot tell if the line numbers are off in an ed script, and can only detect -bad line numbers in a normal diff when it finds a -.Qq change -or a -.Qq delete -command. -A context diff using fuzz factor 3 may have the same problem. -Until a suitable interactive interface is added, you should probably do -a context diff in these cases to see if the changes made sense. -Of course, compiling without errors is a pretty good indication that the patch -worked, but not always. -.Pp -.Nm -usually produces the correct results, even when it has to do a lot of -guessing. -However, the results are guaranteed to be correct only when the patch is -applied to exactly the same version of the file that the patch was -generated from. -.Sh BUGS -Could be smarter about partial matches, excessively deviant offsets and -swapped code, but that would take an extra pass. -.Pp -Check patch mode -.Pq Fl C -will fail if you try to check several patches in succession that build on -each other. -The entire -.Nm -code would have to be restructured to keep temporary files around so that it -can handle this situation. -.Pp -If code has been duplicated (for instance with #ifdef OLDCODE ... #else ... -#endif), -.Nm -is incapable of patching both versions, and, if it works at all, will likely -patch the wrong one, and tell you that it succeeded to boot. -.Pp -If you apply a patch you've already applied, -.Nm -will think it is a reversed patch, and offer to un-apply the patch. -This could be construed as a feature. 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 */ -} diff --git a/usr.bin/patch/pathnames.h b/usr.bin/patch/pathnames.h deleted file mode 100644 index 397e3fabe372f..0000000000000 --- a/usr.bin/patch/pathnames.h +++ /dev/null @@ -1,11 +0,0 @@ -/* $OpenBSD: pathnames.h,v 1.1 2003/07/29 20:10:17 millert Exp $ */ - -/* - * Placed in the public domain by Todd C. Miller <Todd.Miller@courtesan.com> - * on July 29, 2003. - */ - -#include <paths.h> - -#define _PATH_ED "/bin/ed" -#define _PATH_MKDIR "/bin/mkdir" diff --git a/usr.bin/patch/pch.c b/usr.bin/patch/pch.c deleted file mode 100644 index bfdb176301007..0000000000000 --- a/usr.bin/patch/pch.c +++ /dev/null @@ -1,1549 +0,0 @@ -/* $OpenBSD: pch.c,v 1.34 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: pch.c,v 1.34 2004/07/09 19:13:46 otto Exp $"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <libgen.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "common.h" -#include "util.h" -#include "pch.h" -#include "pathnames.h" - -/* Patch (diff listing) abstract type. */ - -static long p_filesize; /* size of the patch file */ -static LINENUM p_first; /* 1st line number */ -static LINENUM p_newfirst; /* 1st line number of replacement */ -static LINENUM p_ptrn_lines; /* # lines in pattern */ -static LINENUM p_repl_lines; /* # lines in replacement text */ -static LINENUM p_end = -1; /* last line in hunk */ -static LINENUM p_max; /* max allowed value of p_end */ -static LINENUM p_context = 3; /* # of context lines */ -static LINENUM p_input_line = 0; /* current line # from patch file */ -static char **p_line = NULL;/* the text of the hunk */ -static short *p_len = NULL; /* length of each line */ -static char *p_char = NULL; /* +, -, and ! */ -static int hunkmax = INITHUNKMAX; /* size of above arrays to begin with */ -static int p_indent; /* indent to patch */ -static LINENUM p_base; /* where to intuit this time */ -static LINENUM p_bline; /* line # of p_base */ -static LINENUM p_start; /* where intuit found a patch */ -static LINENUM p_sline; /* and the line number for it */ -static LINENUM p_hunk_beg; /* line number of current hunk */ -static LINENUM p_efake = -1; /* end of faked up lines--don't free */ -static LINENUM p_bfake = -1; /* beg of faked up lines */ -static FILE *pfp = NULL; /* patch file pointer */ -static char *bestguess = NULL; /* guess at correct filename */ - -static void grow_hunkmax(void); -static int intuit_diff_type(void); -static void next_intuit_at(LINENUM, LINENUM); -static void skip_to(LINENUM, LINENUM); -static char *pgets(char *, int, FILE *); -static char *best_name(const struct file_name *, bool); -static char *posix_name(const struct file_name *, bool); -static size_t num_components(const char *); - -/* - * Prepare to look for the next patch in the patch file. - */ -void -re_patch(void) -{ - p_first = 0; - p_newfirst = 0; - p_ptrn_lines = 0; - p_repl_lines = 0; - p_end = (LINENUM) - 1; - p_max = 0; - p_indent = 0; -} - -/* - * Open the patch file at the beginning of time. - */ -void -open_patch_file(const char *filename) -{ - struct stat filestat; - - if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) { - pfp = fopen(TMPPATNAME, "w"); - if (pfp == NULL) - pfatal("can't create %s", TMPPATNAME); - while (fgets(buf, sizeof buf, stdin) != NULL) - fputs(buf, pfp); - fclose(pfp); - filename = TMPPATNAME; - } - pfp = fopen(filename, "r"); - if (pfp == NULL) - pfatal("patch file %s not found", filename); - fstat(fileno(pfp), &filestat); - p_filesize = filestat.st_size; - next_intuit_at(0L, 1L); /* start at the beginning */ - set_hunkmax(); -} - -/* - * Make sure our dynamically realloced tables are malloced to begin with. - */ -void -set_hunkmax(void) -{ - if (p_line == NULL) - p_line = malloc((size_t) hunkmax * sizeof(char *)); - if (p_len == NULL) - p_len = malloc((size_t) hunkmax * sizeof(short)); - if (p_char == NULL) - p_char = malloc((size_t) hunkmax * sizeof(char)); -} - -/* - * Enlarge the arrays containing the current hunk of patch. - */ -static void -grow_hunkmax(void) -{ - int new_hunkmax; - char **new_p_line; - short *new_p_len; - char *new_p_char; - - new_hunkmax = hunkmax * 2; - - if (p_line == NULL || p_len == NULL || p_char == NULL) - fatal("Internal memory allocation error\n"); - - new_p_line = realloc(p_line, new_hunkmax * sizeof(char *)); - if (new_p_line == NULL) - free(p_line); - - new_p_len = realloc(p_len, new_hunkmax * sizeof(short)); - if (new_p_len == NULL) - free(p_len); - - new_p_char = realloc(p_char, new_hunkmax * sizeof(char)); - if (new_p_char == NULL) - free(p_char); - - p_char = new_p_char; - p_len = new_p_len; - p_line = new_p_line; - - if (p_line != NULL && p_len != NULL && p_char != NULL) { - hunkmax = new_hunkmax; - return; - } - - if (!using_plan_a) - fatal("out of memory\n"); - out_of_mem = true; /* whatever is null will be allocated again */ - /* from within plan_a(), of all places */ -} - -/* True if the remainder of the patch file contains a diff of some sort. */ - -bool -there_is_another_patch(void) -{ - bool exists = false; - - if (p_base != 0L && p_base >= p_filesize) { - if (verbose) - say("done\n"); - return false; - } - if (verbose) - say("Hmm..."); - diff_type = intuit_diff_type(); - if (!diff_type) { - if (p_base != 0L) { - if (verbose) - say(" Ignoring the trailing garbage.\ndone\n"); - } else - say(" I can't seem to find a patch in there anywhere.\n"); - return false; - } - if (verbose) - say(" %sooks like %s to me...\n", - (p_base == 0L ? "L" : "The next patch l"), - diff_type == UNI_DIFF ? "a unified diff" : - diff_type == CONTEXT_DIFF ? "a context diff" : - diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : - diff_type == NORMAL_DIFF ? "a normal diff" : - "an ed script"); - if (p_indent && verbose) - say("(Patch is indented %d space%s.)\n", p_indent, - p_indent == 1 ? "" : "s"); - skip_to(p_start, p_sline); - while (filearg[0] == NULL) { - if (force || batch) { - say("No file to patch. Skipping...\n"); - filearg[0] = savestr(bestguess); - skip_rest_of_patch = true; - return true; - } - ask("File to patch: "); - if (*buf != '\n') { - free(bestguess); - bestguess = savestr(buf); - filearg[0] = fetchname(buf, &exists, 0); - } - if (!exists) { - ask("No file found--skip this patch? [n] "); - if (*buf != 'y') - continue; - if (verbose) - say("Skipping patch...\n"); - free(filearg[0]); - filearg[0] = fetchname(bestguess, &exists, 0); - skip_rest_of_patch = true; - return true; - } - } - return true; -} - -/* Determine what kind of diff is in the remaining part of the patch file. */ - -static int -intuit_diff_type(void) -{ - long this_line = 0, previous_line; - long first_command_line = -1; - LINENUM fcl_line = -1; - bool last_line_was_command = false, this_is_a_command = false; - bool stars_last_line = false, stars_this_line = false; - char *s, *t; - int indent, retval; - struct file_name names[MAX_FILE]; - - memset(names, 0, sizeof(names)); - ok_to_create_file = false; - fseek(pfp, p_base, SEEK_SET); - p_input_line = p_bline - 1; - for (;;) { - previous_line = this_line; - last_line_was_command = this_is_a_command; - stars_last_line = stars_this_line; - this_line = ftell(pfp); - indent = 0; - p_input_line++; - if (fgets(buf, sizeof buf, pfp) == NULL) { - if (first_command_line >= 0L) { - /* nothing but deletes!? */ - p_start = first_command_line; - p_sline = fcl_line; - retval = ED_DIFF; - goto scan_exit; - } else { - p_start = this_line; - p_sline = p_input_line; - retval = 0; - goto scan_exit; - } - } - for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) { - if (*s == '\t') - indent += 8 - (indent % 8); - else - indent++; - } - for (t = s; isdigit(*t) || *t == ','; t++) - ; - this_is_a_command = (isdigit(*s) && - (*t == 'd' || *t == 'c' || *t == 'a')); - if (first_command_line < 0L && this_is_a_command) { - first_command_line = this_line; - fcl_line = p_input_line; - p_indent = indent; /* assume this for now */ - } - if (!stars_last_line && strnEQ(s, "*** ", 4)) - names[OLD_FILE].path = fetchname(s + 4, - &names[OLD_FILE].exists, strippath); - else if (strnEQ(s, "--- ", 4)) - names[NEW_FILE].path = fetchname(s + 4, - &names[NEW_FILE].exists, strippath); - else if (strnEQ(s, "+++ ", 4)) - /* pretend it is the old name */ - names[OLD_FILE].path = fetchname(s + 4, - &names[OLD_FILE].exists, strippath); - else if (strnEQ(s, "Index:", 6)) - names[INDEX_FILE].path = fetchname(s + 6, - &names[INDEX_FILE].exists, strippath); - else if (strnEQ(s, "Prereq:", 7)) { - for (t = s + 7; isspace(*t); t++) - ; - revision = savestr(t); - for (t = revision; *t && !isspace(*t); t++) - ; - *t = '\0'; - if (*revision == '\0') { - free(revision); - revision = NULL; - } - } - if ((!diff_type || diff_type == ED_DIFF) && - first_command_line >= 0L && - strEQ(s, ".\n")) { - p_indent = indent; - p_start = first_command_line; - p_sline = fcl_line; - retval = ED_DIFF; - goto scan_exit; - } - if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) { - if (strnEQ(s + 4, "0,0", 3)) - ok_to_create_file = true; - p_indent = indent; - p_start = this_line; - p_sline = p_input_line; - retval = UNI_DIFF; - goto scan_exit; - } - stars_this_line = strnEQ(s, "********", 8); - if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line && - strnEQ(s, "*** ", 4)) { - if (atol(s + 4) == 0) - ok_to_create_file = true; - /* - * If this is a new context diff the character just - * before the newline is a '*'. - */ - while (*s != '\n') - s++; - p_indent = indent; - p_start = previous_line; - p_sline = p_input_line - 1; - retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); - goto scan_exit; - } - if ((!diff_type || diff_type == NORMAL_DIFF) && - last_line_was_command && - (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) { - p_start = previous_line; - p_sline = p_input_line - 1; - p_indent = indent; - retval = NORMAL_DIFF; - goto scan_exit; - } - } -scan_exit: - if (retval == UNI_DIFF) { - /* unswap old and new */ - struct file_name tmp = names[OLD_FILE]; - names[OLD_FILE] = names[NEW_FILE]; - names[NEW_FILE] = tmp; - } - if (filearg[0] == NULL) { - if (posix) - filearg[0] = posix_name(names, ok_to_create_file); - else { - /* Ignore the Index: name for context diffs, like GNU */ - if (names[OLD_FILE].path != NULL || - names[NEW_FILE].path != NULL) { - free(names[INDEX_FILE].path); - names[INDEX_FILE].path = NULL; - } - filearg[0] = best_name(names, ok_to_create_file); - } - } - - free(bestguess); - bestguess = NULL; - if (filearg[0] != NULL) - bestguess = savestr(filearg[0]); - else if (!ok_to_create_file) { - /* - * We don't want to create a new file but we need a - * filename to set bestguess. Avoid setting filearg[0] - * so the file is not created automatically. - */ - if (posix) - bestguess = posix_name(names, true); - else - bestguess = best_name(names, true); - } - free(names[OLD_FILE].path); - free(names[NEW_FILE].path); - free(names[INDEX_FILE].path); - return retval; -} - -/* - * Remember where this patch ends so we know where to start up again. - */ -static void -next_intuit_at(LINENUM file_pos, LINENUM file_line) -{ - p_base = file_pos; - p_bline = file_line; -} - -/* - * Basically a verbose fseek() to the actual diff listing. - */ -static void -skip_to(LINENUM file_pos, LINENUM file_line) -{ - char *ret; - - if (p_base > file_pos) - fatal("Internal error: seek %ld>%ld\n", p_base, file_pos); - if (verbose && p_base < file_pos) { - fseek(pfp, p_base, SEEK_SET); - say("The text leading up to this was:\n--------------------------\n"); - while (ftell(pfp) < file_pos) { - ret = fgets(buf, sizeof buf, pfp); - if (ret == NULL) - fatal("Unexpected end of file\n"); - say("|%s", buf); - } - say("--------------------------\n"); - } else - fseek(pfp, file_pos, SEEK_SET); - p_input_line = file_line - 1; -} - -/* Make this a function for better debugging. */ -static void -malformed(void) -{ - fatal("malformed patch at line %ld: %s", p_input_line, buf); - /* about as informative as "Syntax error" in C */ -} - -/* - * True if the line has been discarded (i.e. it is a line saying - * "\ No newline at end of file".) - */ -static bool -remove_special_line(void) -{ - int c; - - c = fgetc(pfp); - if (c == '\\') { - do { - c = fgetc(pfp); - } while (c != EOF && c != '\n'); - - return true; - } - if (c != EOF) - fseek(pfp, -1L, SEEK_CUR); - - return false; -} - -/* - * True if there is more of the current diff listing to process. - */ -bool -another_hunk(void) -{ - long line_beginning; /* file pos of the current line */ - LINENUM repl_beginning; /* index of --- line */ - LINENUM fillcnt; /* #lines of missing ptrn or repl */ - LINENUM fillsrc; /* index of first line to copy */ - LINENUM filldst; /* index of first missing line */ - bool ptrn_spaces_eaten; /* ptrn was slightly misformed */ - bool repl_could_be_missing; /* no + or ! lines in this hunk */ - bool repl_missing; /* we are now backtracking */ - long repl_backtrack_position; /* file pos of first repl line */ - LINENUM repl_patch_line; /* input line number for same */ - LINENUM ptrn_copiable; /* # of copiable lines in ptrn */ - char *s, *ret; - int context = 0; - - while (p_end >= 0) { - if (p_end == p_efake) - p_end = p_bfake; /* don't free twice */ - else - free(p_line[p_end]); - p_end--; - } - p_efake = -1; - - p_max = hunkmax; /* gets reduced when --- found */ - if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) { - line_beginning = ftell(pfp); - repl_beginning = 0; - fillcnt = 0; - ptrn_spaces_eaten = false; - repl_could_be_missing = true; - repl_missing = false; - repl_backtrack_position = 0; - ptrn_copiable = 0; - - ret = pgets(buf, sizeof buf, pfp); - p_input_line++; - if (ret == NULL || strnNE(buf, "********", 8)) { - next_intuit_at(line_beginning, p_input_line); - return false; - } - p_context = 100; - p_hunk_beg = p_input_line + 1; - while (p_end < p_max) { - line_beginning = ftell(pfp); - ret = pgets(buf, sizeof buf, pfp); - p_input_line++; - if (ret == NULL) { - if (p_max - p_end < 4) { - /* assume blank lines got chopped */ - strlcpy(buf, " \n", sizeof buf); - } else { - if (repl_beginning && repl_could_be_missing) { - repl_missing = true; - goto hunk_done; - } - fatal("unexpected end of file in patch\n"); - } - } - p_end++; - if (p_end >= hunkmax) - fatal("Internal error: hunk larger than hunk " - "buffer size"); - p_char[p_end] = *buf; - p_line[p_end] = NULL; - switch (*buf) { - case '*': - if (strnEQ(buf, "********", 8)) { - if (repl_beginning && repl_could_be_missing) { - repl_missing = true; - goto hunk_done; - } else - fatal("unexpected end of hunk " - "at line %ld\n", - p_input_line); - } - if (p_end != 0) { - if (repl_beginning && repl_could_be_missing) { - repl_missing = true; - goto hunk_done; - } - fatal("unexpected *** at line %ld: %s", - p_input_line, buf); - } - context = 0; - p_line[p_end] = savestr(buf); - if (out_of_mem) { - p_end--; - return false; - } - for (s = buf; *s && !isdigit(*s); s++) - ; - if (!*s) - malformed(); - if (strnEQ(s, "0,0", 3)) - memmove(s, s + 2, strlen(s + 2) + 1); - p_first = (LINENUM) atol(s); - while (isdigit(*s)) - s++; - if (*s == ',') { - for (; *s && !isdigit(*s); s++) - ; - if (!*s) - malformed(); - p_ptrn_lines = ((LINENUM) atol(s)) - p_first + 1; - } else if (p_first) - p_ptrn_lines = 1; - else { - p_ptrn_lines = 0; - p_first = 1; - } - - /* we need this much at least */ - p_max = p_ptrn_lines + 6; - while (p_max >= hunkmax) - grow_hunkmax(); - p_max = hunkmax; - break; - case '-': - if (buf[1] == '-') { - if (repl_beginning || - (p_end != p_ptrn_lines + 1 + - (p_char[p_end - 1] == '\n'))) { - if (p_end == 1) { - /* - * `old' lines were omitted; - * set up to fill them in - * from 'new' context lines. - */ - p_end = p_ptrn_lines + 1; - fillsrc = p_end + 1; - filldst = 1; - fillcnt = p_ptrn_lines; - } else { - if (repl_beginning) { - if (repl_could_be_missing) { - repl_missing = true; - goto hunk_done; - } - fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n", - p_input_line, p_hunk_beg + repl_beginning); - } else { - fatal("%s \"---\" at line %ld--check line numbers at line %ld\n", - (p_end <= p_ptrn_lines - ? "Premature" - : "Overdue"), - p_input_line, p_hunk_beg); - } - } - } - repl_beginning = p_end; - repl_backtrack_position = ftell(pfp); - repl_patch_line = p_input_line; - p_line[p_end] = savestr(buf); - if (out_of_mem) { - p_end--; - return false; - } - p_char[p_end] = '='; - for (s = buf; *s && !isdigit(*s); s++) - ; - if (!*s) - malformed(); - p_newfirst = (LINENUM) atol(s); - while (isdigit(*s)) - s++; - if (*s == ',') { - for (; *s && !isdigit(*s); s++) - ; - if (!*s) - malformed(); - p_repl_lines = ((LINENUM) atol(s)) - - p_newfirst + 1; - } else if (p_newfirst) - p_repl_lines = 1; - else { - p_repl_lines = 0; - p_newfirst = 1; - } - p_max = p_repl_lines + p_end; - if (p_max > MAXHUNKSIZE) - fatal("hunk too large (%ld lines) at line %ld: %s", - p_max, p_input_line, buf); - while (p_max >= hunkmax) - grow_hunkmax(); - if (p_repl_lines != ptrn_copiable && - (p_context != 0 || p_repl_lines != 1)) - repl_could_be_missing = false; - break; - } - goto change_line; - case '+': - case '!': - repl_could_be_missing = false; - change_line: - if (buf[1] == '\n' && canonicalize) - strlcpy(buf + 1, " \n", sizeof buf - 1); - if (!isspace(buf[1]) && buf[1] != '>' && - buf[1] != '<' && - repl_beginning && repl_could_be_missing) { - repl_missing = true; - goto hunk_done; - } - if (context >= 0) { - if (context < p_context) - p_context = context; - context = -1000; - } - p_line[p_end] = savestr(buf + 2); - if (out_of_mem) { - p_end--; - return false; - } - if (p_end == p_ptrn_lines) { - if (remove_special_line()) { - int len; - - len = strlen(p_line[p_end]) - 1; - (p_line[p_end])[len] = 0; - } - } - break; - case '\t': - case '\n': /* assume the 2 spaces got eaten */ - if (repl_beginning && repl_could_be_missing && - (!ptrn_spaces_eaten || - diff_type == NEW_CONTEXT_DIFF)) { - repl_missing = true; - goto hunk_done; - } - p_line[p_end] = savestr(buf); - if (out_of_mem) { - p_end--; - return false; - } - if (p_end != p_ptrn_lines + 1) { - ptrn_spaces_eaten |= (repl_beginning != 0); - context++; - if (!repl_beginning) - ptrn_copiable++; - p_char[p_end] = ' '; - } - break; - case ' ': - if (!isspace(buf[1]) && - repl_beginning && repl_could_be_missing) { - repl_missing = true; - goto hunk_done; - } - context++; - if (!repl_beginning) - ptrn_copiable++; - p_line[p_end] = savestr(buf + 2); - if (out_of_mem) { - p_end--; - return false; - } - break; - default: - if (repl_beginning && repl_could_be_missing) { - repl_missing = true; - goto hunk_done; - } - malformed(); - } - /* set up p_len for strncmp() so we don't have to */ - /* assume null termination */ - if (p_line[p_end]) - p_len[p_end] = strlen(p_line[p_end]); - else - p_len[p_end] = 0; - } - -hunk_done: - if (p_end >= 0 && !repl_beginning) - fatal("no --- found in patch at line %ld\n", pch_hunk_beg()); - - if (repl_missing) { - - /* reset state back to just after --- */ - p_input_line = repl_patch_line; - for (p_end--; p_end > repl_beginning; p_end--) - free(p_line[p_end]); - fseek(pfp, repl_backtrack_position, SEEK_SET); - - /* redundant 'new' context lines were omitted - set */ - /* up to fill them in from the old file context */ - if (!p_context && p_repl_lines == 1) { - p_repl_lines = 0; - p_max--; - } - fillsrc = 1; - filldst = repl_beginning + 1; - fillcnt = p_repl_lines; - p_end = p_max; - } else if (!p_context && fillcnt == 1) { - /* the first hunk was a null hunk with no context */ - /* and we were expecting one line -- fix it up. */ - while (filldst < p_end) { - p_line[filldst] = p_line[filldst + 1]; - p_char[filldst] = p_char[filldst + 1]; - p_len[filldst] = p_len[filldst + 1]; - filldst++; - } -#if 0 - repl_beginning--; /* this doesn't need to be fixed */ -#endif - p_end--; - p_first++; /* do append rather than insert */ - fillcnt = 0; - p_ptrn_lines = 0; - } - if (diff_type == CONTEXT_DIFF && - (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) { - if (verbose) - say("%s\n%s\n%s\n", - "(Fascinating--this is really a new-style context diff but without", - "the telltale extra asterisks on the *** line that usually indicate", - "the new style...)"); - diff_type = NEW_CONTEXT_DIFF; - } - /* if there were omitted context lines, fill them in now */ - if (fillcnt) { - p_bfake = filldst; /* remember where not to free() */ - p_efake = filldst + fillcnt - 1; - while (fillcnt-- > 0) { - while (fillsrc <= p_end && p_char[fillsrc] != ' ') - fillsrc++; - if (fillsrc > p_end) - fatal("replacement text or line numbers mangled in hunk at line %ld\n", - p_hunk_beg); - p_line[filldst] = p_line[fillsrc]; - p_char[filldst] = p_char[fillsrc]; - p_len[filldst] = p_len[fillsrc]; - fillsrc++; - filldst++; - } - while (fillsrc <= p_end && fillsrc != repl_beginning && - p_char[fillsrc] != ' ') - fillsrc++; -#ifdef DEBUGGING - if (debug & 64) - printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n", - fillsrc, filldst, repl_beginning, p_end + 1); -#endif - if (fillsrc != p_end + 1 && fillsrc != repl_beginning) - malformed(); - if (filldst != p_end + 1 && filldst != repl_beginning) - malformed(); - } - if (p_line[p_end] != NULL) { - if (remove_special_line()) { - p_len[p_end] -= 1; - (p_line[p_end])[p_len[p_end]] = 0; - } - } - } else if (diff_type == UNI_DIFF) { - long line_beginning = ftell(pfp); /* file pos of the current line */ - LINENUM fillsrc; /* index of old lines */ - LINENUM filldst; /* index of new lines */ - char ch; - - ret = pgets(buf, sizeof buf, pfp); - p_input_line++; - if (ret == NULL || strnNE(buf, "@@ -", 4)) { - next_intuit_at(line_beginning, p_input_line); - return false; - } - s = buf + 4; - if (!*s) - malformed(); - p_first = (LINENUM) atol(s); - while (isdigit(*s)) - s++; - if (*s == ',') { - p_ptrn_lines = (LINENUM) atol(++s); - while (isdigit(*s)) - s++; - } else - p_ptrn_lines = 1; - if (*s == ' ') - s++; - if (*s != '+' || !*++s) - malformed(); - p_newfirst = (LINENUM) atol(s); - while (isdigit(*s)) - s++; - if (*s == ',') { - p_repl_lines = (LINENUM) atol(++s); - while (isdigit(*s)) - s++; - } else - p_repl_lines = 1; - if (*s == ' ') - s++; - if (*s != '@') - malformed(); - if (!p_ptrn_lines) - p_first++; /* do append rather than insert */ - p_max = p_ptrn_lines + p_repl_lines + 1; - while (p_max >= hunkmax) - grow_hunkmax(); - fillsrc = 1; - filldst = fillsrc + p_ptrn_lines; - p_end = filldst + p_repl_lines; - snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first, - p_first + p_ptrn_lines - 1); - p_line[0] = savestr(buf); - if (out_of_mem) { - p_end = -1; - return false; - } - p_char[0] = '*'; - snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst, - p_newfirst + p_repl_lines - 1); - p_line[filldst] = savestr(buf); - if (out_of_mem) { - p_end = 0; - return false; - } - p_char[filldst++] = '='; - p_context = 100; - context = 0; - p_hunk_beg = p_input_line + 1; - while (fillsrc <= p_ptrn_lines || filldst <= p_end) { - line_beginning = ftell(pfp); - ret = pgets(buf, sizeof buf, pfp); - p_input_line++; - if (ret == NULL) { - if (p_max - filldst < 3) { - /* assume blank lines got chopped */ - strlcpy(buf, " \n", sizeof buf); - } else { - fatal("unexpected end of file in patch\n"); - } - } - if (*buf == '\t' || *buf == '\n') { - ch = ' '; /* assume the space got eaten */ - s = savestr(buf); - } else { - ch = *buf; - s = savestr(buf + 1); - } - if (out_of_mem) { - while (--filldst > p_ptrn_lines) - free(p_line[filldst]); - p_end = fillsrc - 1; - return false; - } - switch (ch) { - case '-': - if (fillsrc > p_ptrn_lines) { - free(s); - p_end = filldst - 1; - malformed(); - } - p_char[fillsrc] = ch; - p_line[fillsrc] = s; - p_len[fillsrc++] = strlen(s); - if (fillsrc > p_ptrn_lines) { - if (remove_special_line()) { - p_len[fillsrc - 1] -= 1; - s[p_len[fillsrc - 1]] = 0; - } - } - break; - case '=': - ch = ' '; - /* FALL THROUGH */ - case ' ': - if (fillsrc > p_ptrn_lines) { - free(s); - while (--filldst > p_ptrn_lines) - free(p_line[filldst]); - p_end = fillsrc - 1; - malformed(); - } - context++; - p_char[fillsrc] = ch; - p_line[fillsrc] = s; - p_len[fillsrc++] = strlen(s); - s = savestr(s); - if (out_of_mem) { - while (--filldst > p_ptrn_lines) - free(p_line[filldst]); - p_end = fillsrc - 1; - return false; - } - if (fillsrc > p_ptrn_lines) { - if (remove_special_line()) { - p_len[fillsrc - 1] -= 1; - s[p_len[fillsrc - 1]] = 0; - } - } - /* FALL THROUGH */ - case '+': - if (filldst > p_end) { - free(s); - while (--filldst > p_ptrn_lines) - free(p_line[filldst]); - p_end = fillsrc - 1; - malformed(); - } - p_char[filldst] = ch; - p_line[filldst] = s; - p_len[filldst++] = strlen(s); - if (fillsrc > p_ptrn_lines) { - if (remove_special_line()) { - p_len[filldst - 1] -= 1; - s[p_len[filldst - 1]] = 0; - } - } - break; - default: - p_end = filldst; - malformed(); - } - if (ch != ' ' && context > 0) { - if (context < p_context) - p_context = context; - context = -1000; - } - } /* while */ - } else { /* normal diff--fake it up */ - char hunk_type; - int i; - LINENUM min, max; - long line_beginning = ftell(pfp); - - p_context = 0; - ret = pgets(buf, sizeof buf, pfp); - p_input_line++; - if (ret == NULL || !isdigit(*buf)) { - next_intuit_at(line_beginning, p_input_line); - return false; - } - p_first = (LINENUM) atol(buf); - for (s = buf; isdigit(*s); s++) - ; - if (*s == ',') { - p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1; - while (isdigit(*s)) - s++; - } else - p_ptrn_lines = (*s != 'a'); - hunk_type = *s; - if (hunk_type == 'a') - p_first++; /* do append rather than insert */ - min = (LINENUM) atol(++s); - for (; isdigit(*s); s++) - ; - if (*s == ',') - max = (LINENUM) atol(++s); - else - max = min; - if (hunk_type == 'd') - min++; - p_end = p_ptrn_lines + 1 + max - min + 1; - if (p_end > MAXHUNKSIZE) - fatal("hunk too large (%ld lines) at line %ld: %s", - p_end, p_input_line, buf); - while (p_end >= hunkmax) - grow_hunkmax(); - p_newfirst = min; - p_repl_lines = max - min + 1; - snprintf(buf, sizeof buf, "*** %ld,%ld\n", p_first, - p_first + p_ptrn_lines - 1); - p_line[0] = savestr(buf); - if (out_of_mem) { - p_end = -1; - return false; - } - p_char[0] = '*'; - for (i = 1; i <= p_ptrn_lines; i++) { - ret = pgets(buf, sizeof buf, pfp); - p_input_line++; - if (ret == NULL) - fatal("unexpected end of file in patch at line %ld\n", - p_input_line); - if (*buf != '<') - fatal("< expected at line %ld of patch\n", - p_input_line); - p_line[i] = savestr(buf + 2); - if (out_of_mem) { - p_end = i - 1; - return false; - } - p_len[i] = strlen(p_line[i]); - p_char[i] = '-'; - } - - if (remove_special_line()) { - p_len[i - 1] -= 1; - (p_line[i - 1])[p_len[i - 1]] = 0; - } - if (hunk_type == 'c') { - ret = pgets(buf, sizeof buf, pfp); - p_input_line++; - if (ret == NULL) - fatal("unexpected end of file in patch at line %ld\n", - p_input_line); - if (*buf != '-') - fatal("--- expected at line %ld of patch\n", - p_input_line); - } - snprintf(buf, sizeof(buf), "--- %ld,%ld\n", min, max); - p_line[i] = savestr(buf); - if (out_of_mem) { - p_end = i - 1; - return false; - } - p_char[i] = '='; - for (i++; i <= p_end; i++) { - ret = pgets(buf, sizeof buf, pfp); - p_input_line++; - if (ret == NULL) - fatal("unexpected end of file in patch at line %ld\n", - p_input_line); - if (*buf != '>') - fatal("> expected at line %ld of patch\n", - p_input_line); - p_line[i] = savestr(buf + 2); - if (out_of_mem) { - p_end = i - 1; - return false; - } - p_len[i] = strlen(p_line[i]); - p_char[i] = '+'; - } - - if (remove_special_line()) { - p_len[i - 1] -= 1; - (p_line[i - 1])[p_len[i - 1]] = 0; - } - } - if (reverse) /* backwards patch? */ - if (!pch_swap()) - say("Not enough memory to swap next hunk!\n"); -#ifdef DEBUGGING - if (debug & 2) { - int i; - char special; - - for (i = 0; i <= p_end; i++) { - if (i == p_ptrn_lines) - special = '^'; - else - special = ' '; - fprintf(stderr, "%3d %c %c %s", i, p_char[i], - special, p_line[i]); - fflush(stderr); - } - } -#endif - if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */ - p_char[p_end + 1] = '^'; /* add a stopper for apply_hunk */ - return true; -} - -/* - * Input a line from the patch file, worrying about indentation. - */ -static char * -pgets(char *bf, int sz, FILE *fp) -{ - char *s, *ret = fgets(bf, sz, fp); - int indent = 0; - - if (p_indent && ret != NULL) { - for (s = buf; - indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X'); - s++) { - if (*s == '\t') - indent += 8 - (indent % 7); - else - indent++; - } - if (buf != s && strlcpy(buf, s, sizeof(buf)) >= sizeof(buf)) - fatal("buffer too small in pgets()\n"); - } - return ret; -} - -/* - * Reverse the old and new portions of the current hunk. - */ -bool -pch_swap(void) -{ - char **tp_line; /* the text of the hunk */ - short *tp_len; /* length of each line */ - char *tp_char; /* +, -, and ! */ - LINENUM i; - LINENUM n; - bool blankline = false; - char *s; - - i = p_first; - p_first = p_newfirst; - p_newfirst = i; - - /* make a scratch copy */ - - tp_line = p_line; - tp_len = p_len; - tp_char = p_char; - p_line = NULL; /* force set_hunkmax to allocate again */ - p_len = NULL; - p_char = NULL; - set_hunkmax(); - if (p_line == NULL || p_len == NULL || p_char == NULL) { - - free(p_line); - p_line = tp_line; - free(p_len); - p_len = tp_len; - free(p_char); - p_char = tp_char; - return false; /* not enough memory to swap hunk! */ - } - /* now turn the new into the old */ - - i = p_ptrn_lines + 1; - if (tp_char[i] == '\n') { /* account for possible blank line */ - blankline = true; - i++; - } - if (p_efake >= 0) { /* fix non-freeable ptr range */ - if (p_efake <= i) - n = p_end - i + 1; - else - n = -i; - p_efake += n; - p_bfake += n; - } - for (n = 0; i <= p_end; i++, n++) { - p_line[n] = tp_line[i]; - p_char[n] = tp_char[i]; - if (p_char[n] == '+') - p_char[n] = '-'; - p_len[n] = tp_len[i]; - } - if (blankline) { - i = p_ptrn_lines + 1; - p_line[n] = tp_line[i]; - p_char[n] = tp_char[i]; - p_len[n] = tp_len[i]; - n++; - } - if (p_char[0] != '=') - fatal("Malformed patch at line %ld: expected '=' found '%c'\n", - p_input_line, p_char[0]); - p_char[0] = '*'; - for (s = p_line[0]; *s; s++) - if (*s == '-') - *s = '*'; - - /* now turn the old into the new */ - - if (p_char[0] != '*') - fatal("Malformed patch at line %ld: expected '*' found '%c'\n", - p_input_line, p_char[0]); - tp_char[0] = '='; - for (s = tp_line[0]; *s; s++) - if (*s == '*') - *s = '-'; - for (i = 0; n <= p_end; i++, n++) { - p_line[n] = tp_line[i]; - p_char[n] = tp_char[i]; - if (p_char[n] == '-') - p_char[n] = '+'; - p_len[n] = tp_len[i]; - } - - if (i != p_ptrn_lines + 1) - fatal("Malformed patch at line %ld: expected %ld lines, " - "got %ld\n", - p_input_line, p_ptrn_lines + 1, i); - - i = p_ptrn_lines; - p_ptrn_lines = p_repl_lines; - p_repl_lines = i; - - free(tp_line); - free(tp_len); - free(tp_char); - - return true; -} - -/* - * Return the specified line position in the old file of the old context. - */ -LINENUM -pch_first(void) -{ - return p_first; -} - -/* - * Return the number of lines of old context. - */ -LINENUM -pch_ptrn_lines(void) -{ - return p_ptrn_lines; -} - -/* - * Return the probable line position in the new file of the first line. - */ -LINENUM -pch_newfirst(void) -{ - return p_newfirst; -} - -/* - * Return the number of lines in the replacement text including context. - */ -LINENUM -pch_repl_lines(void) -{ - return p_repl_lines; -} - -/* - * Return the number of lines in the whole hunk. - */ -LINENUM -pch_end(void) -{ - return p_end; -} - -/* - * Return the number of context lines before the first changed line. - */ -LINENUM -pch_context(void) -{ - return p_context; -} - -/* - * Return the length of a particular patch line. - */ -short -pch_line_len(LINENUM line) -{ - return p_len[line]; -} - -/* - * Return the control character (+, -, *, !, etc) for a patch line. - */ -char -pch_char(LINENUM line) -{ - return p_char[line]; -} - -/* - * Return a pointer to a particular patch line. - */ -char * -pfetch(LINENUM line) -{ - return p_line[line]; -} - -/* - * Return where in the patch file this hunk began, for error messages. - */ -LINENUM -pch_hunk_beg(void) -{ - return p_hunk_beg; -} - -/* - * Apply an ed script by feeding ed itself. - */ -void -do_ed_script(void) -{ - char *t; - long beginning_of_this_line; - FILE *pipefp; - - pipefp = NULL; - if (!skip_rest_of_patch) { - if (copy_file(filearg[0], TMPOUTNAME) < 0) { - unlink(TMPOUTNAME); - fatal("can't create temp file %s", TMPOUTNAME); - } - snprintf(buf, sizeof buf, "%s%s%s", _PATH_ED, - verbose ? " " : " -s ", TMPOUTNAME); - pipefp = popen(buf, "w"); - } - for (;;) { - beginning_of_this_line = ftell(pfp); - if (pgets(buf, sizeof buf, pfp) == NULL) { - next_intuit_at(beginning_of_this_line, p_input_line); - break; - } - p_input_line++; - for (t = buf; isdigit(*t) || *t == ','; t++) - ; - /* POSIX defines allowed commands as {a,c,d,i,s} */ - if (isdigit(*buf) && (*t == 'a' || *t == 'c' || *t == 'd' || - *t == 'i' || *t == 's')) { - if (pipefp != NULL) - fputs(buf, pipefp); - if (*t != 'd') { - while (pgets(buf, sizeof buf, pfp) != NULL) { - p_input_line++; - if (pipefp != NULL) - fputs(buf, pipefp); - if (strEQ(buf, ".\n")) - break; - } - } - } else { - next_intuit_at(beginning_of_this_line, p_input_line); - break; - } - } - if (pipefp == NULL) - return; - fprintf(pipefp, "w\n"); - fprintf(pipefp, "q\n"); - fflush(pipefp); - pclose(pipefp); - ignore_signals(); - if (!check_only) { - if (move_file(TMPOUTNAME, outname) < 0) { - toutkeep = true; - chmod(TMPOUTNAME, filemode); - } else - chmod(outname, filemode); - } - set_signals(1); -} - -/* - * Choose the name of the file to be patched based on POSIX rules. - * NOTE: the POSIX rules are amazingly stupid and we only follow them - * if the user specified --posix or set POSIXLY_CORRECT. - */ -static char * -posix_name(const struct file_name *names, bool assume_exists) -{ - char *path = NULL; - int i; - - /* - * POSIX states that the filename will be chosen from one - * of the old, new and index names (in that order) if - * the file exists relative to CWD after -p stripping. - */ - for (i = 0; i < MAX_FILE; i++) { - if (names[i].path != NULL && names[i].exists) { - path = names[i].path; - break; - } - } - if (path == NULL && !assume_exists) { - /* - * No files found, look for something we can checkout from - * RCS/SCCS dirs. Same order as above. - */ - for (i = 0; i < MAX_FILE; i++) { - if (names[i].path != NULL && - (path = checked_in(names[i].path)) != NULL) - break; - } - /* - * Still no match? Check to see if the diff could be creating - * a new file. - */ - if (path == NULL && ok_to_create_file && - names[NEW_FILE].path != NULL) - path = names[NEW_FILE].path; - } - - return path ? savestr(path) : NULL; -} - -/* - * Choose the name of the file to be patched based the "best" one - * available. - */ -static char * -best_name(const struct file_name *names, bool assume_exists) -{ - size_t min_components, min_baselen, min_len, tmp; - char *best = NULL; - int i; - - /* - * The "best" name is the one with the fewest number of path - * components, the shortest basename length, and the shortest - * overall length (in that order). We only use the Index: file - * if neither of the old or new files could be intuited from - * the diff header. - */ - min_components = min_baselen = min_len = SIZE_MAX; - for (i = INDEX_FILE; i >= OLD_FILE; i--) { - if (names[i].path == NULL || - (!names[i].exists && !assume_exists)) - continue; - if ((tmp = num_components(names[i].path)) > min_components) - continue; - min_components = tmp; - if ((tmp = strlen(basename(names[i].path))) > min_baselen) - continue; - min_baselen = tmp; - if ((tmp = strlen(names[i].path)) > min_len) - continue; - min_len = tmp; - best = names[i].path; - } - if (best == NULL) { - /* - * No files found, look for something we can checkout from - * RCS/SCCS dirs. Logic is identical to that above... - */ - min_components = min_baselen = min_len = SIZE_MAX; - for (i = INDEX_FILE; i >= OLD_FILE; i--) { - if (names[i].path == NULL || - checked_in(names[i].path) == NULL) - continue; - if ((tmp = num_components(names[i].path)) > min_components) - continue; - min_components = tmp; - if ((tmp = strlen(basename(names[i].path))) > min_baselen) - continue; - min_baselen = tmp; - if ((tmp = strlen(names[i].path)) > min_len) - continue; - min_len = tmp; - best = names[i].path; - } - /* - * Still no match? Check to see if the diff could be creating - * a new file. - */ - if (best == NULL && ok_to_create_file && - names[NEW_FILE].path != NULL) - best = names[NEW_FILE].path; - } - - return best ? savestr(best) : NULL; -} - -static size_t -num_components(const char *path) -{ - size_t n; - const char *cp; - - for (n = 0, cp = path; (cp = strchr(cp, '/')) != NULL; n++, cp++) { - while (*cp == '/') - cp++; /* skip consecutive slashes */ - } - return n; -} diff --git a/usr.bin/patch/pch.h b/usr.bin/patch/pch.h deleted file mode 100644 index b7bf8e8a224ec..0000000000000 --- a/usr.bin/patch/pch.h +++ /dev/null @@ -1,56 +0,0 @@ -/* $OpenBSD: pch.h,v 1.9 2003/10/31 20:20:45 millert 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 - */ - -#define OLD_FILE 0 -#define NEW_FILE 1 -#define INDEX_FILE 2 -#define MAX_FILE 3 - -struct file_name { - char *path; - bool exists; -}; - -void re_patch(void); -void open_patch_file(const char *); -void set_hunkmax(void); -bool there_is_another_patch(void); -bool another_hunk(void); -bool pch_swap(void); -char *pfetch(LINENUM); -short pch_line_len(LINENUM); -LINENUM pch_first(void); -LINENUM pch_ptrn_lines(void); -LINENUM pch_newfirst(void); -LINENUM pch_repl_lines(void); -LINENUM pch_end(void); -LINENUM pch_context(void); -LINENUM pch_hunk_beg(void); -char pch_char(LINENUM); -char *pfetch(LINENUM); -void do_ed_script(void); diff --git a/usr.bin/patch/util.c b/usr.bin/patch/util.c deleted file mode 100644 index 23a22b17078f5..0000000000000 --- a/usr.bin/patch/util.c +++ /dev/null @@ -1,425 +0,0 @@ -/* $OpenBSD: util.c,v 1.27 2003/10/31 20:20:45 millert 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: util.c,v 1.27 2003/10/31 20:20:45 millert Exp $"; -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <libgen.h> -#include <paths.h> -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include "common.h" -#include "util.h" -#include "backupfile.h" -#include "pathnames.h" - - -/* Rename a file, copying it if necessary. */ - -int -move_file(const char *from, const char *to) -{ - int fromfd; - ssize_t i; - - /* to stdout? */ - - if (strEQ(to, "-")) { -#ifdef DEBUGGING - if (debug & 4) - say("Moving %s to stdout.\n", from); -#endif - fromfd = open(from, O_RDONLY); - if (fromfd < 0) - pfatal("internal error, can't reopen %s", from); - while ((i = read(fromfd, buf, sizeof buf)) > 0) - if (write(STDOUT_FILENO, buf, i) != i) - pfatal("write failed"); - close(fromfd); - return 0; - } - if (backup_file(to) < 0) { - say("Can't backup %s, output is in %s: %s\n", to, from, - strerror(errno)); - return -1; - } -#ifdef DEBUGGING - if (debug & 4) - say("Moving %s to %s.\n", from, to); -#endif - if (rename(from, to) < 0) { - if (errno != EXDEV || copy_file(from, to) < 0) { - say("Can't create %s, output is in %s: %s\n", - to, from, strerror(errno)); - return -1; - } - } - return 0; -} - -/* Backup the original file. */ - -int -backup_file(const char *orig) -{ - struct stat filestat; - char bakname[MAXPATHLEN], *s, *simplename; - dev_t orig_device; - ino_t orig_inode; - - if (backup_type == none || stat(orig, &filestat) != 0) - return 0; /* nothing to do */ - orig_device = filestat.st_dev; - orig_inode = filestat.st_ino; - - if (origprae) { - if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) || - strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname)) - fatal("filename %s too long for buffer\n", origprae); - } else { - if ((s = find_backup_file_name(orig)) == NULL) - fatal("out of memory\n"); - if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname)) - fatal("filename %s too long for buffer\n", s); - free(s); - } - - if ((simplename = strrchr(bakname, '/')) != NULL) - simplename = simplename + 1; - else - simplename = bakname; - - /* - * Find a backup name that is not the same file. Change the - * first lowercase char into uppercase; if that isn't - * sufficient, chop off the first char and try again. - */ - while (stat(bakname, &filestat) == 0 && - orig_device == filestat.st_dev && orig_inode == filestat.st_ino) { - /* Skip initial non-lowercase chars. */ - for (s = simplename; *s && !islower(*s); s++) - ; - if (*s) - *s = toupper(*s); - else - memmove(simplename, simplename + 1, - strlen(simplename + 1) + 1); - } -#ifdef DEBUGGING - if (debug & 4) - say("Moving %s to %s.\n", orig, bakname); -#endif - if (rename(orig, bakname) < 0) { - if (errno != EXDEV || copy_file(orig, bakname) < 0) - return -1; - } - return 0; -} - -/* - * Copy a file. - */ -int -copy_file(const char *from, const char *to) -{ - int tofd, fromfd; - ssize_t i; - - tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666); - if (tofd < 0) - return -1; - fromfd = open(from, O_RDONLY, 0); - if (fromfd < 0) - pfatal("internal error, can't reopen %s", from); - while ((i = read(fromfd, buf, sizeof buf)) > 0) - if (write(tofd, buf, i) != i) - pfatal("write to %s failed", to); - close(fromfd); - close(tofd); - return 0; -} - -/* - * Allocate a unique area for a string. - */ -char * -savestr(const char *s) -{ - char *rv; - - if (!s) - s = "Oops"; - rv = strdup(s); - if (rv == NULL) { - if (using_plan_a) - out_of_mem = true; - else - fatal("out of memory\n"); - } - return rv; -} - -/* - * Vanilla terminal output (buffered). - */ -void -say(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fflush(stderr); -} - -/* - * Terminal output, pun intended. - */ -void -fatal(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "patch: **** "); - vfprintf(stderr, fmt, ap); - va_end(ap); - my_exit(2); -} - -/* - * Say something from patch, something from the system, then silence . . . - */ -void -pfatal(const char *fmt, ...) -{ - va_list ap; - int errnum = errno; - - fprintf(stderr, "patch: **** "); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, ": %s\n", strerror(errnum)); - my_exit(2); -} - -/* - * Get a response from the user via /dev/tty - */ -void -ask(const char *fmt, ...) -{ - va_list ap; - ssize_t nr; - static int ttyfd = -1; - - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - fflush(stdout); - if (ttyfd < 0) - ttyfd = open(_PATH_TTY, O_RDONLY); - if (ttyfd >= 0) { - if ((nr = read(ttyfd, buf, sizeof(buf))) > 0 && - buf[nr - 1] == '\n') - buf[nr - 1] = '\0'; - } - if (ttyfd < 0 || nr <= 0) { - /* no tty or error reading, pretend user entered 'return' */ - putchar('\n'); - buf[0] = '\0'; - } -} - -/* - * How to handle certain events when not in a critical region. - */ -void -set_signals(int reset) -{ - static sig_t hupval, intval; - - if (!reset) { - hupval = signal(SIGHUP, SIG_IGN); - if (hupval != SIG_IGN) - hupval = (sig_t) my_exit; - intval = signal(SIGINT, SIG_IGN); - if (intval != SIG_IGN) - intval = (sig_t) my_exit; - } - signal(SIGHUP, hupval); - signal(SIGINT, intval); -} - -/* - * How to handle certain events when in a critical region. - */ -void -ignore_signals(void) -{ - signal(SIGHUP, SIG_IGN); - signal(SIGINT, SIG_IGN); -} - -/* - * Make sure we'll have the directories to create a file. If `striplast' is - * true, ignore the last element of `filename'. - */ - -void -makedirs(const char *filename, bool striplast) -{ - char *tmpbuf; - - if ((tmpbuf = strdup(filename)) == NULL) - fatal("out of memory\n"); - - if (striplast) { - char *s = strrchr(tmpbuf, '/'); - if (s == NULL) - return; /* nothing to be done */ - *s = '\0'; - } - if (snprintf(buf, sizeof(buf), "%s -p %s", _PATH_MKDIR, tmpbuf) - >= sizeof(buf)) - fatal("buffer too small to hold %.20s...\n", tmpbuf); - - if (system(buf)) - pfatal("%.40s failed", buf); -} - -/* - * Make filenames more reasonable. - */ -char * -fetchname(const char *at, bool *exists, int strip_leading) -{ - char *fullname, *name, *t; - int sleading; - struct stat filestat; - - if (at == NULL || *at == '\0') - return NULL; - while (isspace(*at)) - at++; -#ifdef DEBUGGING - if (debug & 128) - say("fetchname %s %d\n", at, strip_leading); -#endif - /* So files can be created by diffing against /dev/null. */ - if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1)) - return NULL; - name = fullname = t = savestr(at); - - /* Strip off up to `strip_leading' path components and NUL terminate. */ - for (sleading = strip_leading; *t != '\0' && !isspace(*t); t++) { - if (t[0] == '/' && t[1] != '/' && t[1] != '\0') - if (--sleading >= 0) - name = t + 1; - } - *t = '\0'; - - /* - * If no -p option was given (957 is the default value!), we were - * given a relative pathname, and the leading directories that we - * just stripped off all exist, put them back on. - */ - if (strip_leading == 957 && name != fullname && *fullname != '/') { - name[-1] = '\0'; - if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) { - name[-1] = '/'; - name = fullname; - } - } - name = savestr(name); - free(fullname); - - *exists = stat(name, &filestat) == 0; - return name; -} - -/* - * Takes the name returned by fetchname and looks in RCS/SCCS directories - * for a checked in version. - */ -char * -checked_in(char *file) -{ - char *filebase, *filedir, tmpbuf[MAXPATHLEN]; - struct stat filestat; - - filebase = basename(file); - filedir = dirname(file); - -#define try(f, a1, a2, a3) \ -(snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0) - - if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) || - try("%s/RCS/%s%s", filedir, filebase, "") || - try("%s/%s%s", filedir, filebase, RCSSUFFIX) || - try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) || - try("%s/%s%s", filedir, SCCSPREFIX, filebase)) - return file; - - return NULL; -} - -void -version(void) -{ - fprintf(stderr, "Patch version 2.0-12u8-OpenBSD\n"); - my_exit(EXIT_SUCCESS); -} - -/* - * Exit with cleanup. - */ -void -my_exit(int status) -{ - unlink(TMPINNAME); - if (!toutkeep) - unlink(TMPOUTNAME); - if (!trejkeep) - unlink(TMPREJNAME); - unlink(TMPPATNAME); - exit(status); -} diff --git a/usr.bin/patch/util.h b/usr.bin/patch/util.h deleted file mode 100644 index 0ec187028b9b1..0000000000000 --- a/usr.bin/patch/util.h +++ /dev/null @@ -1,47 +0,0 @@ -/* $OpenBSD: util.h,v 1.12 2003/10/31 20:20:45 millert 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 - */ - -char *fetchname(const char *, bool *, int); -char *checked_in(char *); -int backup_file(const char *); -int move_file(const char *, const char *); -int copy_file(const char *, const char *); -void say(const char *, ...) - __attribute__((__format__(__printf__, 1, 2))); -void fatal(const char *, ...) - __attribute__((__format__(__printf__, 1, 2))); -void pfatal(const char *, ...) - __attribute__((__format__(__printf__, 1, 2))); -void ask(const char *, ...) - __attribute__((__format__(__printf__, 1, 2))); -char *savestr(const char *); -void set_signals(int); -void ignore_signals(void); -void makedirs(const char *, bool); -void version(void); -void my_exit(int) __attribute__((noreturn)); |