From 9261e57ffedb3dbd9e46963b27194ae53899498b Mon Sep 17 00:00:00 2001 From: gildea Date: Fri, 9 Sep 1994 19:30:54 +0000 Subject: patch 2.0.12u9 --- xc/util/patch/ChangeLog | 290 ++++++++++++++++++++++++++++ xc/util/patch/MANIFEST | 27 +++ xc/util/patch/README | 98 ++++++++++ xc/util/patch/backupfile.c | 338 ++++++++++++++++++++++++++++++++ xc/util/patch/backupfile.h | 37 ++++ xc/util/patch/config.H | 33 ++++ xc/util/patch/config.h.SH | 146 ++++++++++++++ xc/util/patch/malloc.c | 467 +++++++++++++++++++++++++++++++++++++++++++++ xc/util/patch/util.c | 450 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1886 insertions(+) create mode 100644 xc/util/patch/ChangeLog create mode 100644 xc/util/patch/MANIFEST create mode 100644 xc/util/patch/README create mode 100644 xc/util/patch/backupfile.c create mode 100644 xc/util/patch/backupfile.h create mode 100644 xc/util/patch/config.H create mode 100644 xc/util/patch/config.h.SH create mode 100644 xc/util/patch/malloc.c create mode 100644 xc/util/patch/util.c diff --git a/xc/util/patch/ChangeLog b/xc/util/patch/ChangeLog new file mode 100644 index 000000000..305293787 --- /dev/null +++ b/xc/util/patch/ChangeLog @@ -0,0 +1,290 @@ +Mon May 31 00:49:40 1993 Paul Eggert (eggert@twinsun.com) + + * patchlevel.h: PATCHLEVEL 12u9. + + * inp.c (plan_a): Don't lock the checked-out file if `patch -o' + redirected the output elsewhere. + * common.h (CHECKOUT_LOCKED, GET_LOCKED): New macros. GET and + CHECKOUT now just checkout unlocked copies. + + * Makefile (dist): Use gzip, not compress. + +Fri May 28 08:44:50 1993 Paul Eggert (eggert@twinsun.com) + + * backupfile.c (basename): Define even if NODIR isn't defined. + * patch.c (main): Ask just once to apply a reversed patch. + +Tue Sep 15 00:36:15 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * patchlevel.h: PATCHLEVEL 12u8. + +Mon Sep 14 22:01:23 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * Makefile.SH: Add uninstall target. Simplify install target. + + * util.c (fatal, pfatal): Add some asterisks to make fatal + messages stand out more. + +Tue Aug 25 22:13:36 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * patch.c (main, get_some_switches), common.h, inp.c (plan_a, + plan_b), pch.c (there_is_another_patch): Add -t option, + similar to -f. + +Mon Jul 27 11:27:07 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * inp.c (plan_a, util.c (fetchname): Use a macro to simplify code. + * common.h: Define SCCSDIFF and RCSDIFF. + * inp.c (plan_a): Use them to make sure it's safe to check out + the default RCS or SCCS version. + From Paul Eggert. + +Wed Jul 22 14:37:08 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * patch.man: Use the standard comment syntax -- '\" -- instead + of '''. + +Tue Jul 21 15:26:01 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * Configure: Add /etc /usr/lib /lib to pth. + +Mon Jul 20 14:10:32 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * util.h: Declare basename. + * inp.c (plan_a), util.c (fetchname): Use it to isolate the + leading path when testing for RCS and SCCS files. + +Sat Jul 11 18:03:26 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * Configure: Use the user's PATH and build pth from it. + +Fri Jul 10 16:03:23 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * Configure: Change cc -S to cc -c and tr '[ - ]' '[\012-\012]' + to tr ' ' '\012' for AIX 3.2. + From chip@tct.com (Chip Salzenberg). + + * util.c (makedirs): Only make the directories that don't exist. + From chip@tct.com (Chip Salzenberg). + +Wed Jul 8 01:21:15 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * util.c (fatal, pfatal): Print "patch: " before message. + * pch.c, inp.c, patch.c, util.c: Remove "patch: " from the + callers that had it. + + * util.c (pfatal): New function. + * util.h: Declare it and pfatal[1-4] macros. + * various files: Use it instead of fatal where appropriate. + + * Configure: Make /usr/local/man/man1 the first choice for the + man pages. + + * patch.c (main): Open ofp after checking for ed script. + Close ofp and rejfp before trying plan B. + From epang@sfu.ca (Eugene Pang). + + * backupfile.h: Declare get_version. + + * Move decls of rindex and popen to common.h. + + * common.h (myuid): New variable. + * patch.c (main): Initialize it. + * inp.c (myuid): Function removed. + (plan_a): Use the variable, not the function. + + * patch.c: Reinstate -E option. + +Tue Jul 7 23:19:28 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * inp.c (myuid): New function. + (plan_a): Call it. Optimize stat calls. Be smarter about + detecting checked out RCS and SCCS files. + From Paul Eggert (eggert@twinsun.com). + + * inp.c, util.c, patch.c: Don't bother checking for stat() > 0. + +Mon Jul 6 13:01:52 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * version.c (version): Don't print the RCS stuff, since we're + not updating it regularly. + + * patch.c (get_some_switches): Make the usage message more accurate. + + * patchlevel.h: PATCHLEVEL 12u7. + + * Makefile.SH (dist): New target. + Makedist: File removed. + + * inp.c (plan_a): Check whether the user can write to the + file, not whether anyone can write to the file. + +Sat Jul 4 00:06:58 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * inp.c (plan_a): Try to check out read-only files from RCS or SCCS. + + * util.c (move_file): If backing up by linking fails, try copying. + From cek@sdc.boeing.com (Conrad Kimball). + + * patch.c (get_some_switches): Eliminate -E option; always + remove empty output files. + + * util.c (fetchname): Only undo slash removal for relative + paths if -p was not given. + + * Makefile.sh: Add mostlyclean target. + +Fri Jul 3 23:48:14 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu) + + * util.c (fetchname): Accept whitespace between `Index:' and filename. + Also plug a small memory leak for diffs against /dev/null. + From eggert@twinsun.com (Paul Eggert). + + * common.h: Don't define TRUE and FALSE if already defined. + From phk@data.fls.dk (Poul-Henning Kamp). + +Wed Apr 29 10:19:33 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu) + + * backupfile.c (get_version): Exit if given a bad backup type. + +Fri Mar 27 09:57:14 1992 Karl Berry (karl at hayley) + + * common.h (S_ISDIR, S_ISREG): define these. + * inp.c (plan_a): use S_ISREG, not S_IFREG. + * util.c (fetchname): use S_ISDIR, not S_IFDIR. + +Mon Mar 16 14:10:42 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu) + + * patchlevel.h: PATCHLEVEL 12u6. + +Sat Mar 14 13:13:29 1992 David J. MacKenzie (djm at frob.eng.umd.edu) + + * Configure, config.h.SH: Check for directory header and unistd.h. + + * patch.c (main): If -E was given and output file is empty after + patching, remove it. + (get_some_switches): Recognize -E option. + + * patch.c (copy_till): Make garbled output an error, not a warning + that doesn't change the exit status. + + * common.h: Protect against system declarations of malloc and realloc. + + * Makedist: Add backupfile.[ch]. + + * Configure: Look for C library where NeXT and SVR4 put it. + Look in /usr/ucb after /bin and /usr/bin for utilities, + and look in /usr/ccs/bin, to make SVR4 happier. + Recognize m68k predefine. + + * util.c (fetchname): Test of stat return value was backward. + From csss@scheme.cs.ubc.ca. + + * version.c (version): Exit with status 0, not 1. + + * Makefile.SH: Add backupfile.[cho]. + * patch.c (main): Initialize backup file generation. + (get_some_switches): Add -V option. + * common.h, util,c, patch.c: Replace origext with simple_backup_suffix. + * util.c (move_file): Use find_backup_file_name. + +Tue Dec 3 11:27:16 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu) + + * patchlevel.h: PATCHLEVEL 12u5. + + * Makefile.SH: Change clean, distclean, and realclean targets a + little so they agree with the GNU coding standards. + Add Makefile to addedbyconf, so distclean removes it. + + * Configure: Recognize Domain/OS C library in /lib/libc. + From mmuegel@mot.com (Michael S. Muegel). + + * pch.c: Fixes from Wayne Davison: + Patch now accepts no-context context diffs that are + specified with an assumed one line hunk (e.g. "*** 10 ****"). + Fixed a bug in both context and unified diff processing that would + put a zero-context hunk in the wrong place (one line too soon). + Fixed a minor problem with p_max in unified diffs where it would + set p_max to hunkmax unnecessarily (the only adverse effect was to + not supply empty lines at eof by assuming they were truncated). + +Tue Jul 2 03:25:51 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu) + + * Configure: Check for signal declaration in + /usr/include/sys/signal.h as well as /usr/include/signal.h. + + * Configure, common.h, config.h.SH: Comment out the sprintf + declaration and tests to determine its return value type. It + conflicts with ANSI C systems' prototypes in stdio.h and the + return value of sprintf is never used anyway -- it's always cast + to void. + +Thu Jun 27 13:05:32 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu) + + * patchlevel.h: PATCHLEVEL 12u4. + +Thu Feb 21 15:18:14 1991 David J. MacKenzie (djm at geech.ai.mit.edu) + + * pch.c (another_hunk): Fix off by 1 error. From + iverson@xstor.com (Tim Iverson). + +Sun Jan 20 20:18:58 1991 David J. MacKenzie (djm at geech.ai.mit.edu) + + * Makefile.SH (all): Don't make a dummy `all' file. + + * patchlevel.h: PATCHLEVEL 12u3. + + * patch.c (nextarg): New function. + (get_some_switches): Use it, to prevent dereferencing a null + pointer if an option that takes an arg is not given one (is last + on the command line). From Paul Eggert. + + * pch.c (another_hunk): Fix from Wayne Davison to recognize + single-line hunks in unified diffs (with a single line number + instead of a range). + + * inp.c (rev_in_string): Don't use `s' before defining it. From + Wayne Davison. + +Mon Jan 7 06:25:11 1991 David J. MacKenzie (djm at geech.ai.mit.edu) + + * patchlevel.h: PATCHLEVEL 12u2. + + * pch.c (intuit_diff_type): Recognize `+++' in diff headers, for + unified diff format. From unidiff patch 1. + +Mon Dec 3 00:14:25 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * patch.c (get_some_switches): Make the usage message more + informative. + +Sun Dec 2 23:20:18 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * Configure: When checking for C preprocessor, look for 'abc.*xyz' + instead of 'abc.xyz', so ANSI C preprocessors work. + + * Apply fix for -D from ksb@mentor.cc.purdue.edu (Kevin Braunsdorf). + + * Apply unidiff patches from davison@dri.com (Wayne Davison). + +Wed Mar 7 23:47:25 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * pch.c: Call malformed instead of goto malformed + (just allows easier debugging). + +Tue Jan 23 21:27:00 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * common.h (TMP*NAME): Make these char *, not char []. + patch.c (main): Use TMPDIR (if present) to set TMP*NAME. + common.h: Declare getenv. + +Sun Dec 17 17:29:48 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * patch.c (reverse_flag_specified): New variable. + (get_some_switches, reinitialize_almost_everything): Use it. + +Local Variables: +mode: indented-text +left-margin: 8 +version-control: never +end: diff --git a/xc/util/patch/MANIFEST b/xc/util/patch/MANIFEST new file mode 100644 index 000000000..05fc9417c --- /dev/null +++ b/xc/util/patch/MANIFEST @@ -0,0 +1,27 @@ +After all the patch kits are run you should have the following files: + +Filename Kit Description +-------- --- ----------- +Configure 1 A shell script that installs everything system dependent. +EXTERN.h 4 Toggle .h files to look foreign. +INTERN.h 4 Toggle .h files to look domestic. +MANIFEST 2 This list of files. +Makefile.SH 2 The makefile. +README 1 Installation instructions. +backupfile.c 4 Make Emacs style backup file names. +backupfile.h 4 Declarations to make Emacs style backup file names. +common.h 3 Common definitions. +config.H 4 Sample config.h, in case Configure won't run. +config.h.SH 3 Produces config.h. +inp.c 3 Input file abstract data type routines. +inp.h 3 Public defs for above. +malloc.c 1 An optional malloc package. +patch.c 3 The patch program. +patch.man 2 Manual page for patch. +patchlevel.h 4 The patch level of the patch program. +pch.c 2 Patch abstract data type routines. +pch.h 3 Public defs for above. +util.c 3 Utility routines. +util.h 3 Public defs for above. +version.c 1 Version number routine. +version.h 4 Public defs for above. diff --git a/xc/util/patch/README b/xc/util/patch/README new file mode 100644 index 000000000..c8bd0e9c4 --- /dev/null +++ b/xc/util/patch/README @@ -0,0 +1,98 @@ +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 + +You may copy the patch kit in whole or in part as long as you don't try to +make money off it, or pretend that you wrote it. +-------------------------------------------------------------------------- + +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/xc/util/patch/backupfile.c b/xc/util/patch/backupfile.c new file mode 100644 index 000000000..41632a6e2 --- /dev/null +++ b/xc/util/patch/backupfile.c @@ -0,0 +1,338 @@ +/* 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 . + Some algorithms adapted from GNU Emacs. */ + +#include +#include +#include +#include "backupfile.h" +#include "config.h" +char *index (); +char *rindex (); +char *malloc (); + +#ifdef DIRENT +#include +#ifdef direct +#undef direct +#endif +#define direct dirent +#define NLENGTH(direct) (strlen((direct)->d_name)) +#else /* !DIRENT */ +#define NLENGTH(direct) ((direct)->d_namlen) +#ifdef USG +#ifdef SYSNDIR +#include +#else /* !SYSNDIR */ +#include +#endif /* !SYSNDIR */ +#else /* !USG */ +#ifdef SYSDIR +#include +#endif /* SYSDIR */ +#endif /* !USG */ +#endif /* !DIRENT */ + +#ifndef isascii +#define ISDIGIT(c) (isdigit ((unsigned char) (c))) +#else +#define ISDIGIT(c) (isascii (c) && isdigit (c)) +#endif + +#if defined (HAVE_UNISTD_H) +#include +#endif + +#if defined (_POSIX_VERSION) +/* POSIX does not require that the d_ino field be present, and some + systems do not provide it. */ +#define REAL_DIR_ENTRY(dp) 1 +#else +#define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0) +#endif + +/* 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 = "~"; + +char *basename (); +char *dirname (); +static char *concat (); +char *find_backup_file_name (); +static char *make_version_name (); +static int max_backup_version (); +static int version_number (); + +/* Return NAME with any leading path stripped off. */ + +char * +basename (name) + char *name; +{ + char *base; + + base = rindex (name, '/'); + return base ? base + 1 : name; +} + +#ifndef NODIR +/* 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 (file) + char *file; +{ + char *dir; + char *base_versions; + int highest_backup; + + if (backup_type == simple) + return concat (file, simple_backup_suffix); + base_versions = concat (basename (file), ".~"); + if (base_versions == 0) + return 0; + dir = dirname (file); + if (dir == 0) + { + free (base_versions); + return 0; + } + highest_backup = max_backup_version (base_versions, dir); + free (base_versions); + free (dir); + 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 (file, dir) + char *file, *dir; +{ + DIR *dirp; + struct direct *dp; + int highest_version; + int this_version; + int file_name_length; + + dirp = opendir (dir); + if (!dirp) + return 0; + + highest_version = 0; + file_name_length = strlen (file); + + while ((dp = readdir (dirp)) != 0) + { + if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) <= 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 (file, version) + char *file; + int version; +{ + char *backup_name; + + backup_name = malloc (strlen (file) + 16); + if (backup_name == 0) + return 0; + sprintf (backup_name, "%s.~%d~", file, version); + 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 (base, backup, base_length) + char *base; + char *backup; + int base_length; +{ + int version; + 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 (str1, str2) + char *str1, *str2; +{ + char *newstr; + char str1_length = strlen (str1); + + newstr = malloc (str1_length + strlen (str2) + 1); + if (newstr == 0) + return 0; + strcpy (newstr, str1); + strcpy (newstr + str1_length, str2); + return newstr; +} + +/* Return the leading directories part of PATH, + allocated with malloc. If out of memory, return 0. + Assumes that trailing slashes have already been + removed. */ + +char * +dirname (path) + char *path; +{ + char *newpath; + char *slash; + int length; /* Length of result, not including NUL. */ + + slash = rindex (path, '/'); + if (slash == 0) + { + /* File is in the current directory. */ + path = "."; + length = 1; + } + else + { + /* Remove any trailing slashes from result. */ + while (slash > path && *slash == '/') + --slash; + + length = slash - path + 1; + } + newpath = malloc (length + 1); + if (newpath == 0) + return 0; + strncpy (newpath, path, length); + newpath[length] = 0; + return newpath; +} + +/* 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). */ + +int +argmatch (arg, optlist) + char *arg; + char **optlist; +{ + int i; /* Temporary index in OPTLIST. */ + int 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. */ + +void +invalid_arg (kind, value, problem) + char *kind; + 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 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 (version) + char *version; +{ + int i; + + if (version == 0 || *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 (1); +} +#endif /* NODIR */ diff --git a/xc/util/patch/backupfile.h b/xc/util/patch/backupfile.h new file mode 100644 index 000000000..43240a130 --- /dev/null +++ b/xc/util/patch/backupfile.h @@ -0,0 +1,37 @@ +/* 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; + +#ifdef __STDC__ +char *find_backup_file_name (char *file); +enum backup_type get_version (char *version); +#else +char *find_backup_file_name (); +enum backup_type get_version (); +#endif diff --git a/xc/util/patch/config.H b/xc/util/patch/config.H new file mode 100644 index 000000000..93cdf0327 --- /dev/null +++ b/xc/util/patch/config.H @@ -0,0 +1,33 @@ +/* config.h + * This file was produced by running the Configure script. + * Feel free to modify any of this as the need arises. + */ + + +#/*undef EUNICE /* no file linking? */ +#/*undef VMS + +#/*undef index strchr /* cultural */ +#/*undef rindex strrchr /* differences? */ + +#/*undef void int /* is void to be avoided? */ + +/* How many register declarations are paid attention to? */ + +#define Reg1 register +#define Reg2 register +#define Reg3 register +#define Reg4 register +#define Reg5 register +#define Reg6 register +#define Reg7 +#define Reg8 +#define Reg9 +#define Reg10 +#define Reg11 +#define Reg12 +#define Reg13 +#define Reg14 +#define Reg15 +#define Reg16 + diff --git a/xc/util/patch/config.h.SH b/xc/util/patch/config.h.SH new file mode 100644 index 000000000..e34562fcc --- /dev/null +++ b/xc/util/patch/config.h.SH @@ -0,0 +1,146 @@ +case $CONFIG in +'') + if test ! -f config.sh; then + ln ../config.sh . || \ + ln ../../config.sh . || \ + ln ../../../config.sh . || \ + (echo "Can't find config.sh."; exit 1) + echo "Using config.sh from above..." + fi + . ./config.sh + ;; +esac +echo "Extracting config.h (with variable substitutions)" +cat <config.h +/* config.h + * This file was produced by running the config.h.SH script, which + * gets its values from config.sh, which is generally produced by + * running Configure. + * + * Feel free to modify any of this as the need arises. Note, however, + * that running config.h.SH again will wipe out any changes you've made. + * For a more permanent change edit config.sh and rerun config.h.SH. + */ + + +/* EUNICE: + * This symbol, if defined, indicates that the program is being compiled + * under the EUNICE package under VMS. The program will need to handle + * things like files that don't go away the first time you unlink them, + * due to version numbering. It will also need to compensate for lack + * of a respectable link() command. + */ +/* VMS: + * This symbol, if defined, indicates that the program is running under + * VMS. It is currently only set in conjunction with the EUNICE symbol. + */ +#$d_eunice EUNICE /**/ +#$d_eunice VMS /**/ + +/* CPPSTDIN: + * This symbol contains the first part of the string which will invoke + * the C preprocessor on the standard input and produce to standard + * output. Typical value of "cc -E" or "/lib/cpp". + */ +/* CPPMINUS: + * This symbol contains the second part of the string which will invoke + * the C preprocessor on the standard input and produce to standard + * output. This symbol will have the value "-" if CPPSTDIN needs a minus + * to specify standard input, otherwise the value is "". + */ +#define CPPSTDIN "$cppstdin" +#define CPPMINUS "$cppminus" + +/* CHARSPRINTF: + * This symbol is defined if this system declares "char *sprintf()" in + * stdio.h. The trend seems to be to declare it as "int sprintf()". It + * is up to the package author to declare sprintf correctly based on the + * symbol. + */ +/* #$d_charsprf CHARSPRINTF /**/ + +/* FLEXFILENAMES: + * This symbol, if defined, indicates that the system supports filenames + * longer than 14 characters. + */ +#$d_flexfnam FLEXFILENAMES /**/ + +/* index: + * This preprocessor symbol is defined, along with rindex, if the system + * uses the strchr and strrchr routines instead. + */ +/* rindex: + * This preprocessor symbol is defined, along with index, if the system + * uses the strchr and strrchr routines instead. + */ +#$d_index index strchr /* cultural */ +#$d_index rindex strrchr /* differences? */ + +/* VOIDSIG: + * This symbol is defined if this system declares "void (*signal())()" in + * signal.h. The old way was to declare it as "int (*signal())()". It + * is up to the package author to declare things correctly based on the + * symbol. + */ +#$d_voidsig VOIDSIG /**/ + +/* DIRHEADER: + * This definition indicates which directory library header to use. + */ +$d_dirheader + +/* HAVE_UNISTD_H: + * This is defined if the system has unistd.h. + */ +#$d_unistd HAVE_UNISTD_H /**/ + +/* Reg1: + * This symbol, along with Reg2, Reg3, etc. is either the word "register" + * or null, depending on whether the C compiler pays attention to this + * many register declarations. The intent is that you don't have to + * order your register declarations in the order of importance, so you + * can freely declare register variables in sub-blocks of code and as + * function parameters. Do not use Reg more than once per routine. + */ + +#define Reg1 $reg1 /**/ +#define Reg2 $reg2 /**/ +#define Reg3 $reg3 /**/ +#define Reg4 $reg4 /**/ +#define Reg5 $reg5 /**/ +#define Reg6 $reg6 /**/ +#define Reg7 $reg7 /**/ +#define Reg8 $reg8 /**/ +#define Reg9 $reg9 /**/ +#define Reg10 $reg10 /**/ +#define Reg11 $reg11 /**/ +#define Reg12 $reg12 /**/ +#define Reg13 $reg13 /**/ +#define Reg14 $reg14 /**/ +#define Reg15 $reg15 /**/ +#define Reg16 $reg16 /**/ + +/* VOIDFLAGS: + * This symbol indicates how much support of the void type is given by this + * compiler. What various bits mean: + * + * 1 = supports declaration of void + * 2 = supports arrays of pointers to functions returning void + * 4 = supports comparisons between pointers to void functions and + * addresses of void functions + * + * The package designer should define VOIDUSED to indicate the requirements + * of the package. This can be done either by #defining VOIDUSED before + * including config.h, or by defining defvoidused in Myinit.U. If the + * level of void support necessary is not present, defines void to int. + */ +#ifndef VOIDUSED +#define VOIDUSED $defvoidused +#endif +#define VOIDFLAGS $voidflags +#if (VOIDFLAGS & VOIDUSED) != VOIDUSED +#$define void int /* is void to be avoided? */ +#$define M_VOID /* Xenix strikes again */ +#endif + +!GROK!THIS! diff --git a/xc/util/patch/malloc.c b/xc/util/patch/malloc.c new file mode 100644 index 000000000..3145bd434 --- /dev/null +++ b/xc/util/patch/malloc.c @@ -0,0 +1,467 @@ +/* + * @(#)nmalloc.c 1 (Caltech) 2/21/82 + * + * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs + * + * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD. + * + * This is a very fast storage allocator. It allocates blocks of a small + * number of different sizes, and keeps free lists of each size. Blocks + * that don't exactly fit are passed up to the next larger size. In this + * implementation, the available sizes are (2^n)-4 (or -16) bytes long. + * This is designed for use in a program that uses vast quantities of + * memory, but bombs when it runs out. To make it a little better, it + * warns the user when he starts to get near the end. + * + * June 84, ACT: modified rcheck code to check the range given to malloc, + * rather than the range determined by the 2-power used. + * + * Jan 85, RMS: calls malloc_warning to issue warning on nearly full. + * No longer Emacs-specific; can serve as all-purpose malloc for GNU. + * You should call malloc_init to reinitialize after loading dumped Emacs. + * Call malloc_stats to get info on memory stats if MSTATS turned on. + * realloc knows how to return same block given, just changing its size, + * if the power of 2 is correct. + */ + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+3). The + * smallest allocatable block is 8 bytes. The overhead information will + * go in the first int of the block, and the returned pointer will point + * to the second. + * +#ifdef MSTATS + * nmalloc[i] is the difference between the number of mallocs and frees + * for a given block size. +#endif /* MSTATS */ + */ + +#define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ +#define ISFREE ((char) 0x54) /* magic byte that implies free block */ + /* this is for error checking only */ + +extern char etext; + +/* end of the program; can be changed by calling init_malloc */ +static char *endofpure = &etext; + +#ifdef MSTATS +static int nmalloc[30]; +static int nmal, nfre; +#endif /* MSTATS */ + +/* If range checking is not turned on, all we have is a flag indicating + whether memory is allocated, an index in nextf[], and a size field; to + realloc() memory we copy either size bytes or 1<<(index+3) bytes depending + on whether the former can hold the exact size (given the value of + 'index'). If range checking is on, we always need to know how much space + is allocated, so the 'size' field is never used. */ + +struct mhead { + char mh_alloc; /* ISALLOC or ISFREE */ + char mh_index; /* index in nextf[] */ +/* Remainder are valid only when block is allocated */ + unsigned short mh_size; /* size, if < 0x10000 */ +#ifdef rcheck + unsigned mh_nbytes; /* number of bytes allocated */ + int mh_magic4; /* should be == MAGIC4 */ +#endif /* rcheck */ + }; + +/* Access free-list pointer of a block. + It is stored at block + 4. + This is not a field in the mhead structure + because we want sizeof (struct mhead) + to describe the overhead for when the block is in use, + and we do not want the free-list pointer to count in that. */ + +#define CHAIN(a) \ + (*(struct mhead **) (sizeof (char *) + (char *) (a))) + +#ifdef rcheck + +/* To implement range checking, we write magic values in at the beginning and + end of each allocated block, and make sure they are undisturbed whenever a + free or a realloc occurs. */ +/* Written in each of the 4 bytes following the block's real space */ +#define MAGIC1 0x55 +/* Written in the 4 bytes before the block's real space */ +#define MAGIC4 0x55555555 +#define ASSERT(p) if (!(p)) botch("p"); else +static +botch(s) + char *s; +{ + + printf("assertion botched: %s\n", s); + abort(); +} +#define EXTRA 4 /* 4 bytes extra for MAGIC1s */ +#else +#define ASSERT(p) +#define EXTRA 0 +#endif /* rcheck */ + +/* nextf[i] is free list of blocks of size 2**(i + 3) */ + +static struct mhead *nextf[30]; + +#ifdef M_WARN +/* Number of bytes of writable memory we can expect to be able to get */ +static int lim_data; +/* Level number of warnings already issued. + 0 -- no warnings issued. + 1 -- 75% warning already issued. + 2 -- 85% warning already issued. +*/ +static int warnlevel; +#endif /* M_WARN */ + +/* nonzero once initial bunch of free blocks made */ +static int gotpool; + +/* Cause reinitialization based on job parameters; + also declare where the end of pure storage is. */ +malloc_init (end) + char *end; { + endofpure = end; +#ifdef M_WARN + lim_data = 0; + warnlevel = 0; +#endif /* M_WARN */ + } + +static +morecore (nu) /* ask system for more memory */ + register int nu; { /* size index to get more of */ + char *sbrk (); + register char *cp; + register int nblks; + register int siz; + +#ifdef M_WARN +#ifndef BSD42 +#ifdef USG + extern long ulimit (); + if (lim_data == 0) /* find out how much we can get */ + lim_data = ulimit (3, 0) - TEXT_START; +#else /*HMS: was endif */ + if (lim_data == 0) /* find out how much we can get */ + lim_data = vlimit (LIM_DATA, -1); +#endif /* USG */ /HMS:* was not here */ +#else + if (lim_data == 0) { + struct rlimit XXrlimit; + + getrlimit (RLIMIT_DATA, &XXrlimit); + lim_data = XXrlimit.rlim_cur;} /* soft limit */ +#endif /* BSD42 */ +#endif /* M_WARN */ + + /* On initial startup, get two blocks of each size up to 1k bytes */ + if (!gotpool) + getpool (), getpool (), gotpool = 1; + + /* Find current end of memory and issue warning if getting near max */ + + cp = sbrk (0); + siz = cp - endofpure; +#ifdef M_WARN + switch (warnlevel) { + case 0: + if (siz > (lim_data / 4) * 3) { + warnlevel++; + malloc_warning ("Warning: past 75% of memory limit");} + break; + case 1: + if (siz > (lim_data / 20) * 17) { + warnlevel++; + malloc_warning ("Warning: past 85% of memory limit");} + break; + case 2: + if (siz > (lim_data / 20) * 19) { + warnlevel++; + malloc_warning ("Warning: past 95% of memory limit");} + break;} +#endif /* M_WARN */ + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); + + /* Take at least 2k, and figure out how many blocks of the desired size we're about to get */ + nblks = 1; + if ((siz = nu) < 8) + nblks = 1 << ((siz = 8) - nu); + + if ((cp = sbrk (1 << (siz + 3))) == (char *) -1) + return; /* no more room! */ + if ((int) cp & 7) { /* shouldn't happen, but just in case */ + cp = (char *) (((int) cp + 8) & ~7); + nblks--;} + + /* save new header and link the nblks blocks together */ + nextf[nu] = (struct mhead *) cp; + siz = 1 << (nu + 3); + while (1) { + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + if (--nblks <= 0) break; + CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz); + cp += siz;} +/* CHAIN ((struct mhead *) cp) = 0; /* since sbrk() returns cleared core, this is already set */ + } + +static +getpool () { + register int nu; + register char *cp = sbrk (0); + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); + + /* Get 2k of storage */ + + cp = sbrk (04000); + if (cp == (char *) -1) + return; + + /* Divide it into an initial 8-word block + plus one block of size 2**nu for nu = 3 ... 10. */ + + CHAIN (cp) = nextf[0]; + nextf[0] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = 0; + cp += 8; + + for (nu = 0; nu < 7; nu++) { + CHAIN (cp) = nextf[nu]; + nextf[nu] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + cp += 8 << nu;}} + +char * +malloc (n) /* get a block */ + unsigned n; { + register struct mhead *p; + register unsigned int nbytes; + register int nunits = 0; + + /* Figure out how many bytes are required, rounding up to the nearest + multiple of 4, then figure out which nextf[] area to use */ + nbytes = (n + sizeof *p + EXTRA + 3) & ~3; + { + register unsigned int shiftr = (nbytes - 1) >> 2; + + while (shiftr >>= 1) + nunits++; + } + + /* If there are no blocks of the appropriate size, go get some */ + /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */ + if (nextf[nunits] == 0) + morecore (nunits); + + /* Get one block off the list, and set the new list head */ + if ((p = nextf[nunits]) == 0) + return 0; + nextf[nunits] = CHAIN (p); + + /* Check for free block clobbered */ + /* If not for this check, we would gobble a clobbered free chain ptr */ + /* and bomb out on the NEXT allocate of this size block */ + if (p -> mh_alloc != ISFREE || p -> mh_index != nunits) +#ifdef rcheck + botch ("block on free list clobbered"); +#else + abort (); +#endif /* rcheck */ + + /* Fill in the info, and if range checking, set up the magic numbers */ + p -> mh_alloc = ISALLOC; +#ifdef rcheck + p -> mh_nbytes = n; + p -> mh_magic4 = MAGIC4; + { + register char *m = (char *) (p + 1) + n; + + *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1; + } +#else + p -> mh_size = n; +#endif /* rcheck */ +#ifdef MSTATS + nmalloc[nunits]++; + nmal++; +#endif /* MSTATS */ + return (char *) (p + 1);} + +free (mem) + char *mem; { + register struct mhead *p; + { + register char *ap = mem; + + ASSERT (ap != 0); + p = (struct mhead *) ap - 1; + ASSERT (p -> mh_alloc == ISALLOC); +#ifdef rcheck + ASSERT (p -> mh_magic4 == MAGIC4); + ap += p -> mh_nbytes; + ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); + ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); +#endif /* rcheck */ + } + { + register int nunits = p -> mh_index; + + ASSERT (nunits <= 29); + p -> mh_alloc = ISFREE; + CHAIN (p) = nextf[nunits]; + nextf[nunits] = p; +#ifdef MSTATS + nmalloc[nunits]--; + nfre++; +#endif /* MSTATS */ + } + } + +char * +realloc (mem, n) + char *mem; + register unsigned n; { + register struct mhead *p; + register unsigned int tocopy; + register int nbytes; + register int nunits; + + if ((p = (struct mhead *) mem) == 0) + return malloc (n); + p--; + nunits = p -> mh_index; + ASSERT (p -> mh_alloc == ISALLOC); +#ifdef rcheck + ASSERT (p -> mh_magic4 == MAGIC4); + { + register char *m = mem + (tocopy = p -> mh_nbytes); + ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); + ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); + } +#else + if (p -> mh_index >= 13) + tocopy = (1 << (p -> mh_index + 3)) - sizeof *p; + else + tocopy = p -> mh_size; +#endif /* rcheck */ + + /* See if desired size rounds to same power of 2 as actual size. */ + nbytes = (n + sizeof *p + EXTRA + 7) & ~7; + + /* If ok, use the same block, just marking its size as changed. */ + if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) { +#ifdef rcheck + register char *m = mem + tocopy; + *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; + p-> mh_nbytes = n; + m = mem + n; + *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; +#else + p -> mh_size = n; +#endif /* rcheck */ + return mem;} + + if (n < tocopy) + tocopy = n; + { + register char *new; + void bcopy(); /*HMS: here? */ + + if ((new = malloc (n)) == 0) + return 0; + bcopy (mem, new, tocopy); + free (mem); + return new; + } + } + +#ifdef MSTATS +/* Return statistics describing allocation of blocks of size 2**n. */ + +struct mstats_value { + int blocksize; + int nfree; + int nused; + }; + +struct mstats_value +malloc_stats (size) + int size; { + struct mstats_value v; + register int i; + register struct mhead *p; + + v.nfree = 0; + + if (size < 0 || size >= 30) { + v.blocksize = 0; + v.nused = 0; + return v;} + + v.blocksize = 1 << (size + 3); + v.nused = nmalloc[size]; + + for (p = nextf[size]; p; p = CHAIN (p)) + v.nfree++; + + return v;} +#endif + +/* how much space is available? */ + +unsigned freespace() { + register int i, j; + register struct mhead *p; + register unsigned space = 0; + int local; /* address only is used */ + + space = (char *)&local - sbrk(0); /* stack space */ + + for (i = 0; i < 30; i++) { + for (j = 0, p = nextf[i]; p; p = CHAIN (p), j++) ; + space += j * (1 << (i + 3));} + + return(space);} + +/* How big is this cell? */ + +unsigned mc_size(cp) + char *cp;{ + register struct mhead *p; + + if ((p = (struct mhead *) cp) == 0) { + /*HMS? */ + } + p--; +#ifdef rcheck + return p -> mh_nbytes; +#else + return (1 << (p -> mh_index + 3)) - sizeof *p; +/**/ +/* if (p -> mh_index >= 13) +/* return (1 << (p -> mh_index + 3)) - sizeof *p; +/* else +/* return p -> mh_size; +/**/ +#endif /* rcheck */ + } + +/*HMS: Really should use memcpy, if available... */ + +void bcopy(source, dest, len) + register char *source, *dest; + register len; { + register i; + + for (i = 0; i < len; i++) + *dest++ = *source++;} diff --git a/xc/util/patch/util.c b/xc/util/patch/util.c new file mode 100644 index 000000000..e33f21ddb --- /dev/null +++ b/xc/util/patch/util.c @@ -0,0 +1,450 @@ +#include "EXTERN.h" +#include "common.h" +#include "INTERN.h" +#include "util.h" +#include "backupfile.h" + +void my_exit(); + +static char * +private_strerror (errnum) + int errnum; +{ + extern char *sys_errlist[]; + extern int sys_nerr; + + if (errnum > 0 && errnum <= sys_nerr) + return sys_errlist[errnum]; + return "Unknown system error"; +} +#define strerror private_strerror + +/* Rename a file, copying it if necessary. */ + +int +move_file(from,to) +char *from, *to; +{ + char bakname[512]; + Reg1 char *s; + Reg2 int i; + Reg3 int fromfd; + + /* to stdout? */ + + if (strEQ(to, "-")) { +#ifdef DEBUGGING + if (debug & 4) + say2("Moving %s to stdout.\n", from); +#endif + fromfd = open(from, 0); + if (fromfd < 0) + pfatal2("internal error, can't reopen %s", from); + while ((i=read(fromfd, buf, sizeof buf)) > 0) + if (write(1, buf, i) != 1) + pfatal1("write failed"); + Close(fromfd); + return 0; + } + + if (origprae) { + Strcpy(bakname, origprae); + Strcat(bakname, to); + } else { +#ifndef NODIR + char *backupname = find_backup_file_name(to); + if (backupname == (char *) 0) + fatal1("out of memory\n"); + Strcpy(bakname, backupname); + free(backupname); +#else /* NODIR */ + Strcpy(bakname, to); + Strcat(bakname, simple_backup_suffix); +#endif /* NODIR */ + } + + if (stat(to, &filestat) == 0) { /* output file exists */ + dev_t to_device = filestat.st_dev; + ino_t to_inode = filestat.st_ino; + char *simplename = bakname; + + for (s=bakname; *s; s++) { + if (*s == '/') + simplename = s+1; + } + /* 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 && + to_device == filestat.st_dev && to_inode == filestat.st_ino) { + /* Skip initial non-lowercase chars. */ + for (s=simplename; *s && !islower(*s); s++) ; + if (*s) + *s = toupper(*s); + else + Strcpy(simplename, simplename+1); + } + while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */ +#ifdef DEBUGGING + if (debug & 4) + say3("Moving %s to %s.\n", to, bakname); +#endif + if (link(to, bakname) < 0) { + /* Maybe `to' is a symlink into a different file system. + Copying replaces the symlink with a file; using rename + would be better. */ + Reg4 int tofd; + Reg5 int bakfd; + + bakfd = creat(bakname, 0666); + if (bakfd < 0) { + say4("Can't backup %s, output is in %s: %s\n", to, from, + strerror(errno)); + return -1; + } + tofd = open(to, 0); + if (tofd < 0) + pfatal2("internal error, can't open %s", to); + while ((i=read(tofd, buf, sizeof buf)) > 0) + if (write(bakfd, buf, i) != i) + pfatal1("write failed"); + Close(tofd); + Close(bakfd); + } + while (unlink(to) >= 0) ; + } +#ifdef DEBUGGING + if (debug & 4) + say3("Moving %s to %s.\n", from, to); +#endif + if (link(from, to) < 0) { /* different file system? */ + Reg4 int tofd; + + tofd = creat(to, 0666); + if (tofd < 0) { + say4("Can't create %s, output is in %s: %s\n", + to, from, strerror(errno)); + return -1; + } + fromfd = open(from, 0); + if (fromfd < 0) + pfatal2("internal error, can't reopen %s", from); + while ((i=read(fromfd, buf, sizeof buf)) > 0) + if (write(tofd, buf, i) != i) + pfatal1("write failed"); + Close(fromfd); + Close(tofd); + } + Unlink(from); + return 0; +} + +/* Copy a file. */ + +void +copy_file(from,to) +char *from, *to; +{ + Reg3 int tofd; + Reg2 int fromfd; + Reg1 int i; + + tofd = creat(to, 0666); + if (tofd < 0) + pfatal2("can't create %s", to); + fromfd = open(from, 0); + if (fromfd < 0) + pfatal2("internal error, can't reopen %s", from); + while ((i=read(fromfd, buf, sizeof buf)) > 0) + if (write(tofd, buf, i) != i) + pfatal2("write to %s failed", to); + Close(fromfd); + Close(tofd); +} + +/* Allocate a unique area for a string. */ + +char * +savestr(s) +Reg1 char *s; +{ + Reg3 char *rv; + Reg2 char *t; + + if (!s) + s = "Oops"; + t = s; + while (*t++); + rv = malloc((MEM) (t - s)); + if (rv == Nullch) { + if (using_plan_a) + out_of_mem = TRUE; + else + fatal1("out of memory\n"); + } + else { + t = rv; + while (*t++ = *s++); + } + return rv; +} + +#if defined(lint) && defined(CANVARARG) + +/*VARARGS ARGSUSED*/ +say(pat) char *pat; { ; } +/*VARARGS ARGSUSED*/ +fatal(pat) char *pat; { ; } +/*VARARGS ARGSUSED*/ +pfatal(pat) char *pat; { ; } +/*VARARGS ARGSUSED*/ +ask(pat) char *pat; { ; } + +#else + +/* Vanilla terminal output (buffered). */ + +void +say(pat,arg1,arg2,arg3) +char *pat; +long arg1,arg2,arg3; +{ + fprintf(stderr, pat, arg1, arg2, arg3); + Fflush(stderr); +} + +/* Terminal output, pun intended. */ + +void /* very void */ +fatal(pat,arg1,arg2,arg3) +char *pat; +long arg1,arg2,arg3; +{ + fprintf(stderr, "patch: **** "); + fprintf(stderr, pat, arg1, arg2, arg3); + my_exit(1); +} + +/* Say something from patch, something from the system, then silence . . . */ + +void /* very void */ +pfatal(pat,arg1,arg2,arg3) +char *pat; +long arg1,arg2,arg3; +{ + int errnum = errno; + + fprintf(stderr, "patch: **** "); + fprintf(stderr, pat, arg1, arg2, arg3); + fprintf(stderr, ": %s\n", strerror(errnum)); + my_exit(1); +} + +/* Get a response from the user, somehow or other. */ + +void +ask(pat,arg1,arg2,arg3) +char *pat; +long arg1,arg2,arg3; +{ + int ttyfd; + int r; + bool tty2 = isatty(2); + + Sprintf(buf, pat, arg1, arg2, arg3); + Fflush(stderr); + write(2, buf, strlen(buf)); + if (tty2) { /* might be redirected to a file */ + r = read(2, buf, sizeof buf); + } + else if (isatty(1)) { /* this may be new file output */ + Fflush(stdout); + write(1, buf, strlen(buf)); + r = read(1, buf, sizeof buf); + } + else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) { + /* might be deleted or unwriteable */ + write(ttyfd, buf, strlen(buf)); + r = read(ttyfd, buf, sizeof buf); + Close(ttyfd); + } + else if (isatty(0)) { /* this is probably patch input */ + Fflush(stdin); + write(0, buf, strlen(buf)); + r = read(0, buf, sizeof buf); + } + else { /* no terminal at all--default it */ + buf[0] = '\n'; + r = 1; + } + if (r <= 0) + buf[0] = 0; + else + buf[r] = '\0'; + if (!tty2) + say1(buf); +} +#endif /* lint */ + +/* How to handle certain events when not in a critical region. */ + +void +set_signals(reset) +int reset; +{ +#ifndef lint +#ifdef VOIDSIG + static void (*hupval)(),(*intval)(); +#else + static int (*hupval)(),(*intval)(); +#endif + + if (!reset) { + hupval = signal(SIGHUP, SIG_IGN); + if (hupval != SIG_IGN) +#ifdef VOIDSIG + hupval = my_exit; +#else + hupval = (int(*)())my_exit; +#endif + intval = signal(SIGINT, SIG_IGN); + if (intval != SIG_IGN) +#ifdef VOIDSIG + intval = my_exit; +#else + intval = (int(*)())my_exit; +#endif + } + Signal(SIGHUP, hupval); + Signal(SIGINT, intval); +#endif +} + +/* How to handle certain events when in a critical region. */ + +void +ignore_signals() +{ +#ifndef lint + Signal(SIGHUP, SIG_IGN); + Signal(SIGINT, SIG_IGN); +#endif +} + +/* Make sure we'll have the directories to create a file. + If `striplast' is TRUE, ignore the last element of `filename'. */ + +void +makedirs(filename,striplast) +Reg1 char *filename; +bool striplast; +{ + char tmpbuf[256]; + Reg2 char *s = tmpbuf; + char *dirv[20]; /* Point to the NULs between elements. */ + Reg3 int i; + Reg4 int dirvp = 0; /* Number of finished entries in dirv. */ + + /* Copy `filename' into `tmpbuf' with a NUL instead of a slash + between the directories. */ + while (*filename) { + if (*filename == '/') { + filename++; + dirv[dirvp++] = s; + *s++ = '\0'; + } + else { + *s++ = *filename++; + } + } + *s = '\0'; + dirv[dirvp] = s; + if (striplast) + dirvp--; + if (dirvp < 0) + return; + + strcpy(buf, "mkdir"); + s = buf; + for (i=0; i<=dirvp; i++) { + struct stat sbuf; + + if (stat(tmpbuf, &sbuf) && errno == ENOENT) { + while (*s) s++; + *s++ = ' '; + strcpy(s, tmpbuf); + } + *dirv[i] = '/'; + } + if (s != buf) + system(buf); +} + +/* Make filenames more reasonable. */ + +char * +fetchname(at,strip_leading,assume_exists) +char *at; +int strip_leading; +int assume_exists; +{ + char *fullname; + char *name; + Reg1 char *t; + char tmpbuf[200]; + int sleading = strip_leading; + + if (!at) + return Nullch; + while (isspace(*at)) + at++; +#ifdef DEBUGGING + if (debug & 128) + say4("fetchname %s %d %d\n",at,strip_leading,assume_exists); +#endif + if (strnEQ(at, "/dev/null", 9)) /* so files can be created by diffing */ + return Nullch; /* against /dev/null. */ + name = fullname = t = savestr(at); + + /* Strip off up to `sleading' leading slashes and null terminate. */ + for (; *t && !isspace(*t); t++) + if (*t == '/') + 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); + + if (stat(name, &filestat) && !assume_exists) { + char *filebase = basename(name); + int pathlen = filebase - name; + + /* Put any leading path into `tmpbuf'. */ + strncpy(tmpbuf, name, pathlen); + +#define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0) + if ( try("RCS/%s%s", filebase, RCSSUFFIX) + || try("RCS/%s" , filebase, 0) + || try( "%s%s", filebase, RCSSUFFIX) + || try("SCCS/%s%s", SCCSPREFIX, filebase) + || try( "%s%s", SCCSPREFIX, filebase)) + return name; + free(name); + name = Nullch; + } + + return name; +} -- cgit v1.2.3