+-+-+-+ Beginning of part 7 +-+-+-+ X diff. X V -N causes _`008p_`008a_`008t_`008c_`008h to ignore patches that it thi Xnks are X reversed or already applied. See also -R . X X -o causes the next argument to be interpreted as the out- X put file name. X X -p X sets the pathname strip count, which controls how path- X names found in the patch file are treated, in case the X you keep your files in a different directory than the X person who sent out the patch. The strip count speci- X fies how many slashes are to be stripped from the front X of the pathname. (Any intervening directory names also X go away.) For example, supposing the filename in the X patch file was X X /u/howard/src/blurfl/blurfl.c X X setting -p or -p0 gives the entire pathname unmodified, X -p1 gives X X u/howard/src/blurfl/blurfl.c X X without the leading slash, -p4 gives X X blurfl/blurfl.c X X and not specifying -p at all just gives you "blurfl.c". X Whatever you end up with is looked for either in the X current directory, or the directory specified by the -d X switch. X X -r causes the next argument to be interpreted as the X reject file name. X V -R tells _`008p_`008a_`008t_`008c_`008h that this patch was created wi Xth the old X and new files swapped. (Yes, I'm afraid that does hap- V pen occasionally, human nature being what it is.) _`008P_`008a_`008 Xt_`008c_`008h X will attempt to swap each hunk around before applying X it. Rejects will come out in the swapped format. The X -R switch will not work with ed diff scripts because X there is too little information to reconstruct the X reverse operation. X X X X X4 X X X X X X X PATCH(1) X X X V If the first hunk of a patch fails, _`008p_`008a_`008t_`008c_`008h X will reverse X the hunk to see if it can be applied that way. If it X can, you will be asked if you want to have the -R X switch set. If it can't, the patch will continue to be X applied normally. (Note: this method cannot detect a X reversed patch if it is a normal diff and if the first X command is an append (i.e. it should have been a X delete) since appends always succeed, due to the fact X that a null context will match anywhere. Luckily, most X patches add or change lines rather than delete them, so X most reversed normal diffs will begin with a delete, X which will fail, triggering the heuristic.) X V -s makes _`008p_`008a_`008t_`008c_`008h do its work silently, unless a Xnerror X occurs. X V -S causes _`008p_`008a_`008t_`008c_`008h to ignore this patch from the X patch file, X but continue on looking for the next patch in the file. X Thus X X patch -S + -S + X sets internal debugging flags, and is of interest only X to _`008p_`008a_`008t_`008c_`008h patchers. X XAUTHOR X Larry Wall X XENVIRONMENT X No environment variables are used by _`008p_`008a_`008t_`008c_`008h. X XFILES X /tmp/patch* X XSEE ALSO X diff(1) X XNOTES FOR PATCH SENDERS X There are several things you should bear in mind if you are X going to be sending out patches. First, you can save people X a lot of grief by keeping a patchlevel.h file which is X patched to increment the patch level as the first diff in X the patch file you send out. If you put a Prereq: line in X with the patch, it won't let them apply patches out of order X without some warning. Second, make sure you've specified X the filenames right, either in a context diff header, or X X X X 5 X X X X X X XPATCH(1) X X X X with an Index: line. If you are patching something in a X subdirectory, be sure to tell the patch user to specify a -p X switch as needed. Third, you can create a file by sending X out a diff that compares a null file to the file you want to X create. This will only work if the file you want to create X doesn't exist already in the target directory. Fourth, take X care not to send out reversed patches, since it makes people X wonder whether they already applied the patch. Fifth, while X you may be able to get away with putting 582 diff listings X into one file, it is probably wiser to group related patches X into separate files in case something goes haywire. X XDIAGNOSTICS V Too many to list here, but generally indicative that _`008p_`008a_`008t_ X`008c_`008h X couldn't parse your patch file. X X The message "Hmm..." indicates that there is unprocessed V text in the patch file and that _`008p_`008a_`008t_`008c_`008h is attemp Xting to X intuit whether there is a patch in that text and, if so, X what kind of patch it is. X V _`008P_`008a_`008t_`008c_`008h will exit with a non-zero status if any r Xeject files X were created. When applying a set of patches in a loop it X behooves you to check this exit status so you don't apply a X later patch to a partially patched file. X XCAVEATS V _`008P_`008a_`008t_`008c_`008h cannot tell if the line numbers are off i Xnan ed X script, and can only detect bad line numbers in a normal X diff when it finds a "change" or a "delete" command. A con- X text diff using fuzz factor 3 may have the same problem. X Until a suitable interactive interface is added, you should X probably do a context diff in these cases to see if the X changes made sense. Of course, compiling without errors is X a pretty good indication that the patch worked, but not X always. X V _`008P_`008a_`008t_`008c_`008h usually produces the correct results, eve Xnwhen it has X to do a lot of guessing. However, the results are X guaranteed to be correct only when the patch is applied to X exactly the same version of the file that the patch was gen- X erated from. X XBUGS X Could be smarter about partial matches, excessively deviant X offsets and swapped code, but that would take an extra pass. X X If code has been duplicated (for instance with #ifdef OLD- V CODE ... #else ... #endif), _`008p_`008a_`008t_`008c_`008h is incapable X of patching X both versions, and, if it works at all, will likely patch X the wrong one, and tell you that it succeeded to boot. X X X X X6 X X X X X X X PATCH(1) X X X V If you apply a patch you've already applied, _`008p_`008a_`008t_`008c_`0 X08h will X think it is a reversed patch, and offer to un-apply the X patch. This could be construed as a feature. X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X 7 X X X $ GOSUB UNPACK_FILE $ FILE_IS = "PATCHLEVEL.H" $ CHECKSUM_IS = 1647397705 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X#define PATCHLEVEL 12 $ GOSUB UNPACK_FILE $ FILE_IS = "PCH.C" $ CHECKSUM_IS = 386535234 $ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY X/* $Header: pch.c,v 2.0.1.7 88/06/03 15:13:28 lwall Locked $ X * X * $Log: pch.c,v $ X * Revision 2.0.1.7 88/06/03 15:13:28 lwall X * patch10: Can now find patches in shar scripts. X * patch10: Hunks that swapped and then swapped back could core dump. X * X * Revision 2.0.1.6 87/06/04 16:18:13 lwall X * pch_swap didn't swap p_bfake and p_efake. X * X * Revision 2.0.1.5 87/01/30 22:47:42 lwall X * Improved responses to mangled patches. X * X * Revision 2.0.1.4 87/01/05 16:59:53 lwall X * New-style context diffs caused double call to free(). X * X * Revision 2.0.1.3 86/11/14 10:08:33 lwall X * Fixed problem where a long pattern wouldn't grow the hunk. X * Also restored p_input_line when backtracking so error messages are right. X * X * Revision 2.0.1.2 86/11/03 17:49:52 lwall X * New-style delete triggers spurious assertion error. X * X * Revision 2.0.1.1 86/10/29 15:52:08 lwall X * Could falsely report new-style context diff. X * X * Revision 2.0 86/09/17 15:39:37 lwall X * Baseline for netwide release. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "util.h" X#include "INTERN.h" X#include "pch.h" X X/* Patch (diff listing) abstract type. */ X Xstatic long p_filesize; /* size of the patch file */ Xstatic LINENUM p_first; /* 1st line number */ Xstatic LINENUM p_newfirst; /* 1st line number of replacement */ Xstatic LINENUM p_ptrn_lines; /* # lines in pattern */ Xstatic LINENUM p_repl_lines; /* # lines in replacement text */ Xstatic LINENUM p_end = -1; /* last line in hunk */ Xstatic LINENUM p_max; /* max allowed value of p_end */ Xstatic LINENUM p_context = 3; /* # of context lines */ Xstatic LINENUM p_input_line = 0; /* current line # from patch file */ Xstatic char **p_line = Null(char**); /* the text of the hunk */ Xstatic short *p_len = Null(short*); /* length of each line */ Xstatic char *p_char = Nullch; /* +, -, and ! */ Vstatic int hunkmax = INITHUNKMAX; /* size of above arrays to begin with X */ Xstatic int p_indent; /* indent to patch */ Xstatic LINENUM p_base; /* where to intuit this time */ Xstatic LINENUM p_bline; /* line # of p_base */ Xstatic LINENUM p_start; /* where intuit found a patch */ Xstatic LINENUM p_sline; /* and the line number for it */ Xstatic LINENUM p_hunk_beg; /* line number of current hunk */ Vstatic LINENUM p_efake = -1; /* end of faked up lines--don't free X */ Xstatic LINENUM p_bfake = -1; /* beg of faked up lines */ X X/* Prepare to look for the next patch in the patch file. */ X Xvoid Xre_patch() X`123 X p_first = Nulline; X p_newfirst = Nulline; X p_ptrn_lines = Nulline; X p_repl_lines = Nulline; X p_end = (LINENUM)-1; X p_max = Nulline; X p_indent = 0; X`125 X X/* Open the patch file at the beginning of time. */ X Xvoid Xopen_patch_file(filename) Xchar *filename; X`123 V if (filename == Nullch `124`124 !*filename `124`124 strEQ(filename, "-")) X `123 X pfp = fopen(TMPPATNAME, "w"); X if (pfp == Nullfp) X fatal2("patch: can't create %s.\n", TMPPATNAME); X while (fgets(buf, sizeof buf, stdin) != Nullch) X fputs(buf, pfp); X Fclose(pfp); X filename = TMPPATNAME; X `125 X pfp = fopen(filename, "r"); X if (pfp == Nullfp) X fatal2("patch file %s not found\n", filename); X Fstat(fileno(pfp), &filestat); X p_filesize = filestat.st_size; X next_intuit_at(0L,1L); /* start at the beginning */ X set_hunkmax(); X`125 X X/* Make sure our dynamically realloced tables are malloced to begin with. */ X Xvoid Xset_hunkmax() X`123 X#ifndef lint X if (p_line == Null(char**)) X p_line = (char**) malloc((MEM)hunkmax * sizeof(char *)); X if (p_len == Null(short*)) X p_len = (short*) malloc((MEM)hunkmax * sizeof(short)); X#endif X if (p_char == Nullch) X p_char = (char*) malloc((MEM)hunkmax * sizeof(char)); X`125 X X/* Enlarge the arrays containing the current hunk of patch. */ X Xvoid Xgrow_hunkmax() X`123 X hunkmax *= 2; X /* V * Note that on most systems, only the p_line array ever gets fresh memor Xy X * since p_len can move into p_line's old space, and p_char can move into X * p_len's old space. Not on PDP-11's however. But it doesn't matter. X */ V assert(p_line != Null(char**) && p_len != Null(short*) && p_char != Nullc Xh); X#ifndef lint X p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *)); X p_len = (short*) realloc((char*)p_len, (MEM)hunkmax * sizeof(short)); X p_char = (char*) realloc((char*)p_char, (MEM)hunkmax * sizeof(char)); X#endif X if (p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch) X return; X if (!using_plan_a) X fatal1("patch: out of memory (grow_hunkmax)\n"); V out_of_mem = TRUE; /* whatever is null will be allocated again * X/ X /* from within plan_a(), of all places */ X`125 X X/* True if the remainder of the patch file contains a diff of some sort. */ X Xbool Xthere_is_another_patch() X`123 X if (p_base != 0L && p_base >= p_filesize) `123 X if (verbose) X say1("done\n"); X return FALSE; X `125 X if (verbose) X say1("Hmm..."); X diff_type = intuit_diff_type(); X if (!diff_type) `123 X if (p_base != 0L) `123 X if (verbose) X say1(" Ignoring the trailing garbage.\ndone\n"); X `125 X else X say1(" I can't seem to find a patch in there anywhere.\n"); X return FALSE; X `125 X if (verbose) X say3(" %sooks like %s to me...\n", X (p_base == 0L ? "L" : "The next patch l"), X diff_type == CONTEXT_DIFF ? "a context diff" : X diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : X diff_type == NORMAL_DIFF ? "a normal diff" : X "an ed script" ); X if (p_indent && verbose) V say3("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s X"); X skip_to(p_start,p_sline); X while (filearg[0] == Nullch) `123 X if (force) `123 X say1("No file to patch. Skipping...\n"); X filearg[0] = savestr(bestguess); X return TRUE; X `125 X ask1("File to patch: "); X if (*buf != '\n') `123 X if (bestguess) X free(bestguess); X bestguess = savestr(buf); X filearg[0] = fetchname(buf, 0, FALSE); X `125 X if (filearg[0] == Nullch) `123 X ask1("No file found--skip this patch? [n] "); X if (*buf != 'y') `123 X continue; X `125 X if (verbose) X say1("Skipping patch...\n"); X filearg[0] = fetchname(bestguess, 0, TRUE); X skip_rest_of_patch = TRUE; X return TRUE; X `125 X `125 X return TRUE; X`125 X X/* Determine what kind of diff is in the remaining part of the patch file. */ X Xint Xintuit_diff_type() X`123 -+-+-+-+-+ End of part 7 +-+-+-+-+-