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