fritz@unocss.UUCP (Tim Russell) (08/27/89)
+-+-+-+ Beginning of part 3 +-+-+-+
X`009filearg[0] = Nullch;
X `125
X
X if (outname != Nullch) `123
X`009free(outname);
X`009outname = Nullch;
X `125
X
X last_offset = 0;
X
X diff_type = 0;
X
X if (revision != Nullch) `123
X`009free(revision);
X`009revision = Nullch;
X `125
X
X reverse = FALSE;
X skip_rest_of_patch = FALSE;
X
X get_some_switches();
X
X if (filec >= 2)
X`009fatal1("You may not change to a different patch file.\n");
X`125
X
X/* Process switches and filenames up to next '+' or end of list. */
X
Xvoid
Xget_some_switches()
X`123
X Reg1 char *s;
X
X rejname[0] = '\0';
X Argc_last = Argc;
X Argv_last = Argv;
X if (!Argc)
X`009return;
X for (Argc--,Argv++; Argc; Argc--,Argv++) `123
X`009s = Argv[0];
X`009if (strEQ(s, "+")) `123
X`009 return;`009`009`009/* + will be skipped by for loop */
X`009`125
X#ifdef VMS
X`009if (*s == '<')`009`009`009/* Parse '<filename' syntax */
X`009 filearg[1] = savestr(s + 1);
X`009if ((*s != '-' && *s != '<') `124`124 !s[1]) `123
X#else
X`009if (*s != '-' `124`124 !s[1]) `123
X#endif
X`009 if (filec == MAXFILEC)
X`009`009fatal1("Too many file arguments.\n");
X`009 filearg[filec++] = savestr(s);
X`009`125
X#ifdef VMS
X`009if ((*s == '-') && s[1]) `123
X#else
X`009else `123
X#endif
X`009 switch (*++s) `123
X`009 case 'b':
X`009`009origext = savestr(Argv[1]);
X`009`009Argc--,Argv++;
X`009`009break;
X`009 case 'c':
X`009`009diff_type = CONTEXT_DIFF;
X`009`009break;
X`009 case 'd':
X`009`009if (!*++s) `123
X`009`009 Argc--,Argv++;
X`009`009 s = Argv[0];
X`009`009`125
X`009`009if (chdir(s) < 0)
X`009`009 fatal2("Can't cd to %s.\n", s);
X`009`009break;
X`009 case 'D':
X`009 `009do_defines = TRUE;
X`009`009if (!*++s) `123
X`009`009 Argc--,Argv++;
X`009`009 s = Argv[0];
X`009`009`125
X`009`009Sprintf(if_defined, "#ifdef %s\n", s);
X`009`009Sprintf(not_defined, "#ifndef %s\n", s);
X`009`009Sprintf(end_defined, "#endif /* %s */\n", s);
X`009`009break;
X`009 case 'e':
X`009`009diff_type = ED_DIFF;
X`009`009break;
X`009 case 'f':
X`009`009force = TRUE;
X`009`009break;
X`009 case 'F':
X`009`009if (*++s == '=')
X`009`009 s++;
X`009`009maxfuzz = atoi(s);
X`009`009break;
X`009 case 'l':
X`009`009canonicalize = TRUE;
X`009`009break;
X`009 case 'n':
X`009`009diff_type = NORMAL_DIFF;
X`009`009break;
X`009 case 'N':
X`009`009noreverse = TRUE;
X`009`009break;
X`009 case 'o':
X`009`009outname = savestr(Argv[1]);
X`009`009Argc--,Argv++;
X`009`009break;
X`009 case 'p':
X#ifdef VMS
X case 'P':
X#endif
X`009`009if (*++s == '=')
X`009`009 s++;
X`009`009strippath = atoi(s);
X`009`009break;
X`009 case 'r':
X`009`009Strcpy(rejname, Argv[1]);
X`009`009Argc--,Argv++;
X`009`009break;
X`009 case 'R':
X`009`009reverse = TRUE;
X`009`009break;
X`009 case 's':
X`009`009verbose = FALSE;
X`009`009break;
X`009 case 'S':
X`009`009skip_rest_of_patch = TRUE;
X`009`009break;
X`009 case 'v':
X`009`009version();
X`009`009break;
X#ifdef DEBUGGING
X`009 case 'x':
X`009`009debug = atoi(s+1);
X`009`009break;
X#endif
X`009 default:
X`009`009fatal2("Unrecognized switch: %s\n", Argv[0]);
X`009 `125
X`009`125
X `125
X`125
X
X/* Attempt to find the right place to apply this hunk of patch. */
X
XLINENUM
Xlocate_hunk(fuzz)
XLINENUM fuzz;
X`123
X Reg1 LINENUM first_guess = pch_first() + last_offset;
X Reg2 LINENUM offset;
X LINENUM pat_lines = pch_ptrn_lines();
X Reg3 LINENUM max_pos_offset = input_lines - first_guess
X`009`009`009`009- pat_lines + 1;`032
X Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
X`009`009`009`009+ pch_context();
X
X if (!pat_lines)`009`009`009/* null range matches always */
X`009return first_guess;
X if (max_neg_offset >= first_guess)`009/* do not try lines < 0 */
X`009max_neg_offset = first_guess - 1;
V if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz)
X)
X`009return first_guess;
X for (offset = 1; ; offset++) `123
X`009Reg5 bool check_after = (offset <= max_pos_offset);
X`009Reg6 bool check_before = (offset <= max_neg_offset);
X
X`009if (check_after && patch_match(first_guess, offset, fuzz)) `123
X#ifdef DEBUGGING
X`009 if (debug & 1)
X`009`009say3("Offset changing from %ld to %ld\n", last_offset, offset);
X#endif
X`009 last_offset = offset;
X`009 return first_guess+offset;
X`009`125
X`009else if (check_before && patch_match(first_guess, -offset, fuzz)) `123
X#ifdef DEBUGGING
X`009 if (debug & 1)
X`009`009say3("Offset changing from %ld to %ld\n", last_offset, -offset);
X#endif
X`009 last_offset = -offset;
X`009 return first_guess-offset;
X`009`125
X`009else if (!check_before && !check_after)
X`009 return Nulline;
X `125
X`125
X
X/* We did not find the pattern, dump out the hunk so they can handle it. */
X
Xvoid
Xabort_hunk()
X`123
X Reg1 LINENUM i;
X Reg2 LINENUM pat_end = pch_end();
V /* add in last_offset to guess the same as the previous successful hunk *
X/
X LINENUM oldfirst = pch_first() + last_offset;
X LINENUM newfirst = pch_newfirst() + last_offset;
X LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
X LINENUM newlast = newfirst + pch_repl_lines() - 1;
X char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : "");
X char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----");
X
X fprintf(rejfp, "***************\n");
X for (i=0; i<=pat_end; i++) `123
X`009switch (pch_char(i)) `123
X`009case '*':
X`009 if (oldlast < oldfirst)
X`009`009fprintf(rejfp, "*** 0%s\n", stars);
X`009 else if (oldlast == oldfirst)
X`009`009fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
X`009 else
X`009`009fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
X`009 break;
X`009case '=':
X`009 if (newlast < newfirst)
X`009`009fprintf(rejfp, "--- 0%s\n", minuses);
X`009 else if (newlast == newfirst)
X`009`009fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
X`009 else
X`009`009fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
X`009 break;
X`009case '\n':
X`009 fprintf(rejfp, "%s", pfetch(i));
X`009 break;
X`009case ' ': case '-': case '+': case '!':
X`009 fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
X`009 break;
X`009default:
X`009 say1("Fatal internal error in abort_hunk().\n");`032
X`009 abort();
X`009`125
X `125
X`125
X
X/* We found where to apply it (we hope), so do it. */
X
Xvoid
Xapply_hunk(where)
XLINENUM where;
X`123
X Reg1 LINENUM old = 1;
X Reg2 LINENUM lastline = pch_ptrn_lines();
X Reg3 LINENUM new = lastline+1;
X#define OUTSIDE 0
X#define IN_IFNDEF 1
X#define IN_IFDEF 2
X#define IN_ELSE 3
X Reg4 int def_state = OUTSIDE;
X Reg5 bool R_do_defines = do_defines;
X Reg6 LINENUM pat_end = pch_end();
X
X where--;
X while (pch_char(new) == '=' `124`124 pch_char(new) == '\n')
X`009new++;
X `032
X while (old <= lastline) `123
X`009if (pch_char(old) == '-') `123
X`009 copy_till(where + old - 1);
X`009 if (R_do_defines) `123
X`009`009if (def_state == OUTSIDE) `123
X`009`009 fputs(not_defined, ofp);
X`009`009 def_state = IN_IFNDEF;
X`009`009`125
X`009`009else if (def_state == IN_IFDEF) `123
X`009`009 fputs(else_defined, ofp);
X`009`009 def_state = IN_ELSE;
X`009`009`125
X`009`009fputs(pfetch(old), ofp);
X`009 `125
X`009 last_frozen_line++;
X`009 old++;
X`009`125
X`009else if (new > pat_end)
X`009 break;
X`009else if (pch_char(new) == '+') `123
X`009 copy_till(where + old - 1);
X`009 if (R_do_defines) `123
X`009`009if (def_state == IN_IFNDEF) `123
X`009`009 fputs(else_defined, ofp);
X`009`009 def_state = IN_ELSE;
X`009`009`125
X`009`009else if (def_state == OUTSIDE) `123
X`009`009 fputs(if_defined, ofp);
X`009`009 def_state = IN_IFDEF;
X`009`009`125
X`009 `125
X`009 fputs(pfetch(new), ofp);
X`009 new++;
X`009`125
X`009else `123
X`009 if (pch_char(new) != pch_char(old)) `123
V`009`009say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers,
X maybe?\n",
X`009`009 pch_hunk_beg() + old,
X`009`009 pch_hunk_beg() + new);
X#ifdef DEBUGGING
X`009`009say3("oldchar = '%c', newchar = '%c'\n",
X`009`009 pch_char(old), pch_char(new));
X#endif
X`009`009my_exit(1);
X`009 `125
X`009 if (pch_char(new) == '!') `123
X`009`009copy_till(where + old - 1);
X`009`009if (R_do_defines) `123
X`009`009 fputs(not_defined, ofp);
X`009`009 def_state = IN_IFNDEF;
X`009`009`125
X`009`009while (pch_char(old) == '!') `123
X`009`009 if (R_do_defines) `123
X`009`009`009fputs(pfetch(old), ofp);
X`009`009 `125
X`009`009 last_frozen_line++;
X`009`009 old++;
X`009`009`125
X`009`009if (R_do_defines) `123
X`009`009 fputs(else_defined, ofp);
X`009`009 def_state = IN_ELSE;
X`009`009`125
X`009`009while (pch_char(new) == '!') `123
X`009`009 fputs(pfetch(new), ofp);
X`009`009 new++;
X`009`009`125
X`009`009if (R_do_defines) `123
X`009`009 fputs(end_defined, ofp);
X`009`009 def_state = OUTSIDE;
X`009`009`125
X`009 `125
X`009 else `123
X`009`009assert(pch_char(new) == ' ');
X`009`009old++;
X`009`009new++;
X`009 `125
X`009`125
X `125
X if (new <= pat_end && pch_char(new) == '+') `123
X`009copy_till(where + old - 1);
X`009if (R_do_defines) `123
X`009 if (def_state == OUTSIDE) `123
X`009 `009fputs(if_defined, ofp);
X`009`009def_state = IN_IFDEF;
X`009 `125
X`009 else if (def_state == IN_IFNDEF) `123
X`009`009fputs(else_defined, ofp);
X`009`009def_state = IN_ELSE;
X`009 `125
X`009`125
X`009while (new <= pat_end && pch_char(new) == '+') `123
X`009 fputs(pfetch(new), ofp);
X`009 new++;
X`009`125
X `125
X if (R_do_defines && def_state != OUTSIDE) `123
X`009fputs(end_defined, ofp);
X `125
X`125
X
X/* Open the new file. */
X
Xvoid
Xinit_output(name)
Xchar *name;
X`123
X ofp = fopen(name, "w");
X if (ofp == Nullfp)
X`009fatal2("patch: can't create %s.\n", name);
X`125
X
X/* Open a file to put hunks we can't locate. */
X
Xvoid
Xinit_reject(name)
Xchar *name;
X`123
X rejfp = fopen(name, "w");
X if (rejfp == Nullfp)
X`009fatal2("patch: can't create %s.\n", name);
X`125
X
X/* Copy input file to output, up to wherever hunk is to be applied. */
X
Xvoid
Xcopy_till(lastline)
XReg1 LINENUM lastline;
X`123
X Reg2 LINENUM R_last_frozen_line = last_frozen_line;
X
X if (R_last_frozen_line > lastline)
X`009say1("patch: misordered hunks! output will be garbled.\n");
X while (R_last_frozen_line < lastline) `123
X`009dump_line(++R_last_frozen_line);
X `125
X last_frozen_line = R_last_frozen_line;
X`125
X
X/* Finish copying the input file to the output file. */
X
Xvoid
Xspew_output()
X`123
X#ifdef DEBUGGING
X if (debug & 256)
X`009say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
X#endif
X if (input_lines)
X`009copy_till(input_lines);`009`009/* dump remainder of file */
X Fclose(ofp);
X ofp = Nullfp;
X`125
X
X/* Copy one line from input to output. */
X
Xvoid
Xdump_line(line)
XLINENUM line;
X`123
X Reg1 char *s;
X Reg2 char R_newline = '\n';
X
X /* Note: string is not null terminated. */
X for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
X`125
X
X/* Does the patch pattern match at line base+offset? */
X
Xbool
Xpatch_match(base, offset, fuzz)
XLINENUM base;
XLINENUM offset;
XLINENUM fuzz;
X`123
X Reg1 LINENUM pline = 1 + fuzz;
X Reg2 LINENUM iline;
X Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
X
X for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) `123
X`009if (canonicalize) `123
X`009 if (!similar(ifetch(iline, (offset >= 0)),
X`009`009`009 pfetch(pline),
X`009`009`009 pch_line_len(pline) ))
X`009`009return FALSE;
X`009`125
X`009else if (strnNE(ifetch(iline, (offset >= 0)),
X`009`009 pfetch(pline),
X`009`009 pch_line_len(pline) ))
X`009 return FALSE;
X `125
X return TRUE;
X`125
X
X/* Do two lines match with canonicalized white space? */
X
Xbool
Xsimilar(a,b,len)
XReg1 char *a;
XReg2 char *b;
XReg3 int len;
X`123
X while (len) `123
X`009if (isspace(*b)) `123`009`009/* whitespace (or \n) to match? */
X`009 if (!isspace(*a))`009`009/* no corresponding whitespace? */
X`009`009return FALSE;
X`009 while (len && isspace(*b) && *b != '\n')
X`009`009b++,len--;`009`009/* skip pattern whitespace */
X`009 while (isspace(*a) && *a != '\n')
X`009`009a++;`009`009`009/* skip target whitespace */
X`009 if (*a == '\n' `124`124 *b == '\n')
X`009`009return (*a == *b);`009/* should end in sync */
X`009`125
X`009else if (*a++ != *b++)`009`009/* match non-whitespace chars */
X`009 return FALSE;
X`009else
X`009 len--;`009`009`009/* probably not necessary */
X `125
X return TRUE;`009`009`009/* actually, this is not reached */
X`009`009`009`009`009/* since there is always a \n */
X`125
X
X/* Exit with cleanup. */
X
Xvoid
Xmy_exit(status)
Xint status;
X`123
X while (unlink(TMPINNAME) >= 0);
X if (!toutkeep) `123
X`009while (unlink(TMPOUTNAME) >= 0);
X `125
X if (!trejkeep) `123
X`009while (unlink(TMPREJNAME) >= 0);
X `125
X while (unlink(TMPPATNAME) >= 0);
X exit(status);
X`125
$ GOSUB UNPACK_FILE
$ FILE_IS = "PATCH.DOC"
$ CHECKSUM_IS = 964225761
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X
X
X
X
XPATCH(1) UNIX Programmer's Manual PATCH(1)
X
X
X
XNAME
X patch - a program for applying a diff file to an original
X
XSYNOPSIS
X patch [options] orig patchfile [+ [options] orig]
X
X but usually just
X
X patch <patchfile
X
XDESCRIPTION
X Patch will take a patch file containing any of the three
X forms of difference listing produced by the diff program and
X apply those differences to an original file, producing a
X patched version. By default, the patched version is put in
X place of the original, with the original file backed up to
X the same name with the extension ".orig", or as specified by
X the -b switch. You may also specify where you want the out-
X put to go with a -o switch. If patchfile is omitted, or is
X a hyphen, the patch will be read from standard input.
X
X Upon startup, patch will attempt to determine the type of
X the diff listing, unless over-ruled by a -c, -e, or -n
X switch. Context diffs and normal diffs are applied by the
X patch program itself, while ed diffs are simply fed to the
X ed editor via a pipe.
X
X Patch will try to skip any leading garbage, apply the diff,
X and then skip any trailing garbage. Thus you could feed an
X article or message containing a diff listing to patch, and
X it should work. If the entire diff is indented by a con-
X sistent amount, this will be taken into account.
X
X With context diffs, and to a lesser extent with normal
X diffs, patch can detect when the line numbers mentioned in
X the patch are incorrect, and will attempt to find the
-+-+-+-+-+ End of part 3 +-+-+-+-+-
--
---------------------------------+--------------------------------------------
Tim Russell, Computer Operator | Internet: russell@zeus.unl.edu
Campus Computing | Bitnet: russell@unoma1
University of Nebraska at Omaha | UUCP: uunet!zeus.unl.edu!russell