844 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			844 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
char rcsid[] =
 | 
						|
	"$Header$";
 | 
						|
 | 
						|
/* patch - a program to apply diffs to original files
 | 
						|
 *
 | 
						|
 * Copyright 1986, Larry Wall
 | 
						|
 *
 | 
						|
 * This program may be copied as long as you don't try to make any
 | 
						|
 * money off of it, or pretend that you wrote it.
 | 
						|
 *
 | 
						|
 * $Log$
 | 
						|
 * Revision 1.1  2005/04/21 14:55:10  beng
 | 
						|
 * Initial revision
 | 
						|
 *
 | 
						|
 * Revision 1.1.1.1  2005/04/20 13:33:19  beng
 | 
						|
 * Initial import of minix 2.0.4
 | 
						|
 *
 | 
						|
 * Revision 2.0.1.6  88/06/22  20:46:39  lwall
 | 
						|
 * patch12: rindex() wasn't declared
 | 
						|
 * 
 | 
						|
 * Revision 2.0.1.5  88/06/03  15:09:37  lwall
 | 
						|
 * patch10: exit code improved.
 | 
						|
 * patch10: better support for non-flexfilenames.
 | 
						|
 * 
 | 
						|
 * Revision 2.0.1.4  87/02/16  14:00:04  lwall
 | 
						|
 * Short replacement caused spurious "Out of sync" message.
 | 
						|
 * 
 | 
						|
 * Revision 2.0.1.3  87/01/30  22:45:50  lwall
 | 
						|
 * Improved diagnostic on sync error.
 | 
						|
 * Moved do_ed_script() to pch.c.
 | 
						|
 * 
 | 
						|
 * Revision 2.0.1.2  86/11/21  09:39:15  lwall
 | 
						|
 * Fuzz factor caused offset of installed lines.
 | 
						|
 * 
 | 
						|
 * Revision 2.0.1.1  86/10/29  13:10:22  lwall
 | 
						|
 * Backwards search could terminate prematurely.
 | 
						|
 * 
 | 
						|
 * Revision 2.0  86/09/17  15:37:32  lwall
 | 
						|
 * Baseline for netwide release.
 | 
						|
 * 
 | 
						|
 * Revision 1.5  86/08/01  20:53:24  lwall
 | 
						|
 * Changed some %d's to %ld's.
 | 
						|
 * Linted.
 | 
						|
 * 
 | 
						|
 * Revision 1.4  86/08/01  19:17:29  lwall
 | 
						|
 * Fixes for machines that can't vararg.
 | 
						|
 * Added fuzz factor.
 | 
						|
 * Generalized -p.
 | 
						|
 * General cleanup.
 | 
						|
 * 
 | 
						|
 * 85/08/15 van%ucbmonet@berkeley
 | 
						|
 * Changes for 4.3bsd diff -c.
 | 
						|
 *
 | 
						|
 * Revision 1.3  85/03/26  15:07:43  lwall
 | 
						|
 * Frozen.
 | 
						|
 * 
 | 
						|
 * Revision 1.2.1.9  85/03/12  17:03:35  lwall
 | 
						|
 * Changed pfp->_file to fileno(pfp).
 | 
						|
 * 
 | 
						|
 * Revision 1.2.1.8  85/03/12  16:30:43  lwall
 | 
						|
 * Check i_ptr and i_womp to make sure they aren't null before freeing.
 | 
						|
 * Also allow ed output to be suppressed.
 | 
						|
 * 
 | 
						|
 * Revision 1.2.1.7  85/03/12  15:56:13  lwall
 | 
						|
 * Added -p option from jromine@uci-750a.
 | 
						|
 * 
 | 
						|
 * Revision 1.2.1.6  85/03/12  12:12:51  lwall
 | 
						|
 * Now checks for normalness of file to patch.
 | 
						|
 * 
 | 
						|
 * Revision 1.2.1.5  85/03/12  11:52:12  lwall
 | 
						|
 * Added -D (#ifdef) option from joe@fluke.
 | 
						|
 * 
 | 
						|
 * Revision 1.2.1.4  84/12/06  11:14:15  lwall
 | 
						|
 * Made smarter about SCCS subdirectories.
 | 
						|
 * 
 | 
						|
 * Revision 1.2.1.3  84/12/05  11:18:43  lwall
 | 
						|
 * Added -l switch to do loose string comparison.
 | 
						|
 * 
 | 
						|
 * Revision 1.2.1.2  84/12/04  09:47:13  lwall
 | 
						|
 * Failed hunk count not reset on multiple patch file.
 | 
						|
 * 
 | 
						|
 * Revision 1.2.1.1  84/12/04  09:42:37  lwall
 | 
						|
 * Branch for sdcrdcf changes.
 | 
						|
 * 
 | 
						|
 * Revision 1.2  84/11/29  13:29:51  lwall
 | 
						|
 * Linted.  Identifiers uniqified.  Fixed i_ptr malloc() bug.  Fixed
 | 
						|
 * multiple calls to mktemp().  Will now work on machines that can only
 | 
						|
 * read 32767 chars.  Added -R option for diffs with new and old swapped.
 | 
						|
 * Various cosmetic changes.
 | 
						|
 * 
 | 
						|
 * Revision 1.1  84/11/09  17:03:58  lwall
 | 
						|
 * Initial revision
 | 
						|
 * 
 | 
						|
 */
 | 
						|
/*
 | 
						|
 * 1992-01-15
 | 
						|
 * Modified by Saeko & Kouichi Hirabayashi to fit small memory (64K+64K)
 | 
						|
 * system by adding "#if[n]def SMALL" parts.
 | 
						|
 */
 | 
						|
 | 
						|
#include "INTERN.h"
 | 
						|
#include "common.h"
 | 
						|
#include "EXTERN.h"
 | 
						|
#include "version.h"
 | 
						|
#include "util.h"
 | 
						|
#include "pch.h"
 | 
						|
#include "inp.h"
 | 
						|
 | 
						|
/* procedures */
 | 
						|
 | 
						|
_PROTOTYPE(int main , (int argc , char **argv ));
 | 
						|
_PROTOTYPE(void reinitialize_almost_everything , (void));
 | 
						|
_PROTOTYPE(void get_some_switches , (void));
 | 
						|
_PROTOTYPE(LINENUM locate_hunk , (LINENUM fuzz ));
 | 
						|
_PROTOTYPE(void abort_hunk , (void));
 | 
						|
_PROTOTYPE(void apply_hunk , (LINENUM where ));
 | 
						|
_PROTOTYPE(void init_output , (char *name ));
 | 
						|
_PROTOTYPE(void init_reject , (char *name ));
 | 
						|
_PROTOTYPE(void copy_till , (Reg1 LINENUM lastline ));
 | 
						|
_PROTOTYPE(void spew_output , (void));
 | 
						|
_PROTOTYPE(void dump_line , (LINENUM line ));
 | 
						|
_PROTOTYPE(bool patch_match , (LINENUM base , LINENUM offset , LINENUM fuzz ));
 | 
						|
_PROTOTYPE(bool similar , (Reg1 char *a , Reg2 char *b , Reg3 int len ));
 | 
						|
 | 
						|
/* Apply a set of diffs as appropriate. */
 | 
						|
 | 
						|
int main(argc,argv)
 | 
						|
int argc;
 | 
						|
char **argv;
 | 
						|
{
 | 
						|
    LINENUM where;
 | 
						|
    LINENUM newwhere;
 | 
						|
    LINENUM fuzz;
 | 
						|
    LINENUM mymaxfuzz;
 | 
						|
    int hunk = 0;
 | 
						|
    int failed = 0;
 | 
						|
    int failtotal = 0;
 | 
						|
    int i;
 | 
						|
 | 
						|
    setbuf(stderr, serrbuf);
 | 
						|
    for (i = 0; i<MAXFILEC; i++)
 | 
						|
	filearg[i] = Nullch;
 | 
						|
    Mktemp(TMPOUTNAME);
 | 
						|
    Mktemp(TMPINNAME);
 | 
						|
    Mktemp(TMPREJNAME);
 | 
						|
    Mktemp(TMPPATNAME);
 | 
						|
#ifdef SMALL
 | 
						|
    Mktemp(TMPSTRNAME);
 | 
						|
#endif
 | 
						|
 | 
						|
    /* parse switches */
 | 
						|
    Argc = argc;
 | 
						|
    Argv = argv;
 | 
						|
    get_some_switches();
 | 
						|
    
 | 
						|
    /* make sure we clean up /tmp in case of disaster */
 | 
						|
    set_signals(0);
 | 
						|
 | 
						|
    for (
 | 
						|
	open_patch_file(filearg[1]);
 | 
						|
	there_is_another_patch();
 | 
						|
	reinitialize_almost_everything()
 | 
						|
    ) {					/* for each patch in patch file */
 | 
						|
 | 
						|
	if (outname == Nullch)
 | 
						|
	    outname = savestr(filearg[0]);
 | 
						|
    
 | 
						|
	/* initialize the patched file */
 | 
						|
	if (!skip_rest_of_patch)
 | 
						|
	    init_output(TMPOUTNAME);
 | 
						|
    
 | 
						|
	/* for ed script just up and do it and exit */
 | 
						|
	if (diff_type == ED_DIFF) {
 | 
						|
	    do_ed_script();
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
    
 | 
						|
	/* initialize reject file */
 | 
						|
	init_reject(TMPREJNAME);
 | 
						|
    
 | 
						|
	/* find out where all the lines are */
 | 
						|
	if (!skip_rest_of_patch)
 | 
						|
	    scan_input(filearg[0]);
 | 
						|
    
 | 
						|
	/* from here on, open no standard i/o files, because malloc */
 | 
						|
	/* might misfire and we can't catch it easily */
 | 
						|
    
 | 
						|
	/* apply each hunk of patch */
 | 
						|
	hunk = 0;
 | 
						|
	failed = 0;
 | 
						|
	out_of_mem = FALSE;
 | 
						|
	while (another_hunk()) {
 | 
						|
	    hunk++;
 | 
						|
	    fuzz = Nulline;
 | 
						|
	    mymaxfuzz = pch_context();
 | 
						|
	    if (maxfuzz < mymaxfuzz)
 | 
						|
		mymaxfuzz = maxfuzz;
 | 
						|
	    if (!skip_rest_of_patch) {
 | 
						|
		do {
 | 
						|
		    where = locate_hunk(fuzz);
 | 
						|
		    if (hunk == 1 && where == Nulline && !force) {
 | 
						|
						/* dwim for reversed patch? */
 | 
						|
			if (!pch_swap()) {
 | 
						|
			    if (fuzz == Nulline)
 | 
						|
				say1(
 | 
						|
"Not enough memory to try swapped hunk!  Assuming unswapped.\n");
 | 
						|
			    continue;
 | 
						|
			}
 | 
						|
			reverse = !reverse;
 | 
						|
			where = locate_hunk(fuzz);  /* try again */
 | 
						|
			if (where == Nulline) {	    /* didn't find it swapped */
 | 
						|
			    if (!pch_swap())         /* put it back to normal */
 | 
						|
				fatal1("Lost hunk on alloc error!\n");
 | 
						|
			    reverse = !reverse;
 | 
						|
			}
 | 
						|
			else if (noreverse) {
 | 
						|
			    if (!pch_swap())         /* put it back to normal */
 | 
						|
				fatal1("Lost hunk on alloc error!\n");
 | 
						|
			    reverse = !reverse;
 | 
						|
			    say1(
 | 
						|
"Ignoring previously applied (or reversed) patch.\n");
 | 
						|
			    skip_rest_of_patch = TRUE;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
			    ask3(
 | 
						|
"%seversed (or previously applied) patch detected!  %s -R? [y] ",
 | 
						|
				reverse ? "R" : "Unr",
 | 
						|
				reverse ? "Assume" : "Ignore");
 | 
						|
			    if (*buf == 'n') {
 | 
						|
				ask1("Apply anyway? [n] ");
 | 
						|
				if (*buf != 'y')
 | 
						|
				    skip_rest_of_patch = TRUE;
 | 
						|
				where = Nulline;
 | 
						|
				reverse = !reverse;
 | 
						|
				if (!pch_swap())  /* put it back to normal */
 | 
						|
				    fatal1("Lost hunk on alloc error!\n");
 | 
						|
			    }
 | 
						|
			}
 | 
						|
		    }
 | 
						|
		} while (!skip_rest_of_patch && where == Nulline &&
 | 
						|
		    ++fuzz <= mymaxfuzz);
 | 
						|
 | 
						|
		if (skip_rest_of_patch) {		/* just got decided */
 | 
						|
		    Fclose(ofp);
 | 
						|
		    ofp = Nullfp;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	    newwhere = pch_newfirst() + last_offset;
 | 
						|
	    if (skip_rest_of_patch) {
 | 
						|
		abort_hunk();
 | 
						|
		failed++;
 | 
						|
		if (verbose)
 | 
						|
		    say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
 | 
						|
	    }
 | 
						|
	    else if (where == Nulline) {
 | 
						|
		abort_hunk();
 | 
						|
		failed++;
 | 
						|
		if (verbose)
 | 
						|
		    say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		apply_hunk(where);
 | 
						|
		if (verbose) {
 | 
						|
		    say3("Hunk #%d succeeded at %ld", hunk, newwhere);
 | 
						|
		    if (fuzz)
 | 
						|
			say2(" with fuzz %ld", fuzz);
 | 
						|
		    if (last_offset)
 | 
						|
			say3(" (offset %ld line%s)",
 | 
						|
			    last_offset, last_offset==1L?"":"s");
 | 
						|
		    say1(".\n");
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
	if (out_of_mem && using_plan_a) {
 | 
						|
	    Argc = Argc_last;
 | 
						|
	    Argv = Argv_last;
 | 
						|
	    say1("\n\nRan out of memory using Plan A--trying again...\n\n");
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
    
 | 
						|
	assert(hunk);
 | 
						|
    
 | 
						|
	/* finish spewing out the new file */
 | 
						|
	if (!skip_rest_of_patch)
 | 
						|
	    spew_output();
 | 
						|
	
 | 
						|
	/* and put the output where desired */
 | 
						|
	ignore_signals();
 | 
						|
	if (!skip_rest_of_patch) {
 | 
						|
	    if (move_file(TMPOUTNAME, outname) < 0) {
 | 
						|
		toutkeep = TRUE;
 | 
						|
		chmod(TMPOUTNAME, filemode);
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		chmod(outname, filemode);
 | 
						|
	}
 | 
						|
	Fclose(rejfp);
 | 
						|
	rejfp = Nullfp;
 | 
						|
	if (failed) {
 | 
						|
	    failtotal += failed;
 | 
						|
	    if (!*rejname) {
 | 
						|
		Strcpy(rejname, outname);
 | 
						|
#ifndef FLEXFILENAMES
 | 
						|
		{
 | 
						|
		    char *s = rindex(rejname,'/');
 | 
						|
 | 
						|
		    if (!s)
 | 
						|
			s = rejname;
 | 
						|
		    if (strlen(s) > 13)
 | 
						|
			if (s[12] == '.')	/* try to preserve difference */
 | 
						|
			    s[12] = s[13];	/* between .h, .c, .y, etc. */
 | 
						|
			s[13] = '\0';
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		Strcat(rejname, REJEXT);
 | 
						|
	    }
 | 
						|
	    if (skip_rest_of_patch) {
 | 
						|
		say4("%d out of %d hunks ignored--saving rejects to %s\n",
 | 
						|
		    failed, hunk, rejname);
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		say4("%d out of %d hunks failed--saving rejects to %s\n",
 | 
						|
		    failed, hunk, rejname);
 | 
						|
	    }
 | 
						|
	    if (move_file(TMPREJNAME, rejname) < 0)
 | 
						|
		trejkeep = TRUE;
 | 
						|
	}
 | 
						|
	set_signals(1);
 | 
						|
    }
 | 
						|
#ifdef SMALL
 | 
						|
    if (sfp != Nullfp)
 | 
						|
	Fclose(sfp);
 | 
						|
#endif
 | 
						|
    my_exit(failtotal);
 | 
						|
}
 | 
						|
 | 
						|
/* Prepare to find the next patch to do in the patch file. */
 | 
						|
 | 
						|
void
 | 
						|
reinitialize_almost_everything()
 | 
						|
{
 | 
						|
    re_patch();
 | 
						|
    re_input();
 | 
						|
 | 
						|
    input_lines = 0;
 | 
						|
    last_frozen_line = 0;
 | 
						|
 | 
						|
    filec = 0;
 | 
						|
    if (filearg[0] != Nullch && !out_of_mem) {
 | 
						|
	free(filearg[0]);
 | 
						|
	filearg[0] = Nullch;
 | 
						|
    }
 | 
						|
 | 
						|
    if (outname != Nullch) {
 | 
						|
	free(outname);
 | 
						|
	outname = Nullch;
 | 
						|
    }
 | 
						|
 | 
						|
    last_offset = 0;
 | 
						|
 | 
						|
    diff_type = 0;
 | 
						|
 | 
						|
    if (revision != Nullch) {
 | 
						|
	free(revision);
 | 
						|
	revision = Nullch;
 | 
						|
    }
 | 
						|
 | 
						|
    reverse = FALSE;
 | 
						|
    skip_rest_of_patch = FALSE;
 | 
						|
 | 
						|
    get_some_switches();
 | 
						|
 | 
						|
    if (filec >= 2)
 | 
						|
	fatal1("You may not change to a different patch file.\n");
 | 
						|
}
 | 
						|
 | 
						|
/* Process switches and filenames up to next '+' or end of list. */
 | 
						|
 | 
						|
void
 | 
						|
get_some_switches()
 | 
						|
{
 | 
						|
    Reg1 char *s;
 | 
						|
 | 
						|
    rejname[0] = '\0';
 | 
						|
    Argc_last = Argc;
 | 
						|
    Argv_last = Argv;
 | 
						|
    if (!Argc)
 | 
						|
	return;
 | 
						|
    for (Argc--,Argv++; Argc; Argc--,Argv++) {
 | 
						|
	s = Argv[0];
 | 
						|
	if (strEQ(s, "+")) {
 | 
						|
	    return;			/* + will be skipped by for loop */
 | 
						|
	}
 | 
						|
	if (*s != '-' || !s[1]) {
 | 
						|
	    if (filec == MAXFILEC)
 | 
						|
		fatal1("Too many file arguments.\n");
 | 
						|
	    filearg[filec++] = savestr(s);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    switch (*++s) {
 | 
						|
	    case 'b':
 | 
						|
		origext = savestr(Argv[1]);
 | 
						|
		Argc--,Argv++;
 | 
						|
		break;
 | 
						|
	    case 'B':
 | 
						|
		origprae = savestr(Argv[1]);
 | 
						|
		Argc--,Argv++;
 | 
						|
		break;
 | 
						|
	    case 'c':
 | 
						|
		diff_type = CONTEXT_DIFF;
 | 
						|
		break;
 | 
						|
	    case 'd':
 | 
						|
		if (!*++s) {
 | 
						|
		    Argc--,Argv++;
 | 
						|
		    s = Argv[0];
 | 
						|
		}
 | 
						|
		if (chdir(s) < 0)
 | 
						|
		    fatal2("Can't cd to %s.\n", s);
 | 
						|
		break;
 | 
						|
	    case 'D':
 | 
						|
	    	do_defines = TRUE;
 | 
						|
		if (!*++s) {
 | 
						|
		    Argc--,Argv++;
 | 
						|
		    s = Argv[0];
 | 
						|
		}
 | 
						|
		if (!isalpha(*s))
 | 
						|
		    fatal1("Argument to -D not an identifier.\n");
 | 
						|
		Sprintf(if_defined, "#ifdef %s\n", s);
 | 
						|
		Sprintf(not_defined, "#ifndef %s\n", s);
 | 
						|
		Sprintf(end_defined, "#endif /* %s */\n", s);
 | 
						|
		break;
 | 
						|
	    case 'e':
 | 
						|
		diff_type = ED_DIFF;
 | 
						|
		break;
 | 
						|
	    case 'f':
 | 
						|
		force = TRUE;
 | 
						|
		break;
 | 
						|
	    case 'F':
 | 
						|
		if (*++s == '=')
 | 
						|
		    s++;
 | 
						|
		maxfuzz = atoi(s);
 | 
						|
		break;
 | 
						|
	    case 'l':
 | 
						|
		canonicalize = TRUE;
 | 
						|
		break;
 | 
						|
	    case 'n':
 | 
						|
		diff_type = NORMAL_DIFF;
 | 
						|
		break;
 | 
						|
	    case 'N':
 | 
						|
		noreverse = TRUE;
 | 
						|
		break;
 | 
						|
	    case 'o':
 | 
						|
		outname = savestr(Argv[1]);
 | 
						|
		Argc--,Argv++;
 | 
						|
		break;
 | 
						|
	    case 'p':
 | 
						|
		if (*++s == '=')
 | 
						|
		    s++;
 | 
						|
		strippath = atoi(s);
 | 
						|
		break;
 | 
						|
	    case 'r':
 | 
						|
		Strcpy(rejname, Argv[1]);
 | 
						|
		Argc--,Argv++;
 | 
						|
		break;
 | 
						|
	    case 'R':
 | 
						|
		reverse = TRUE;
 | 
						|
		break;
 | 
						|
	    case 's':
 | 
						|
		verbose = FALSE;
 | 
						|
		break;
 | 
						|
	    case 'S':
 | 
						|
		skip_rest_of_patch = TRUE;
 | 
						|
		break;
 | 
						|
	    case 'v':
 | 
						|
		version();
 | 
						|
		break;
 | 
						|
#ifdef DEBUGGING
 | 
						|
	    case 'x':
 | 
						|
		debug = atoi(s+1);
 | 
						|
		break;
 | 
						|
#endif
 | 
						|
	    default:
 | 
						|
		fatal2("Unrecognized switch: %s\n", Argv[0]);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Attempt to find the right place to apply this hunk of patch. */
 | 
						|
 | 
						|
LINENUM
 | 
						|
locate_hunk(fuzz)
 | 
						|
LINENUM fuzz;
 | 
						|
{
 | 
						|
    Reg1 LINENUM first_guess = pch_first() + last_offset;
 | 
						|
    Reg2 LINENUM offset;
 | 
						|
    LINENUM pat_lines = pch_ptrn_lines();
 | 
						|
    Reg3 LINENUM max_pos_offset = input_lines - first_guess
 | 
						|
				- pat_lines + 1; 
 | 
						|
    Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
 | 
						|
				+ pch_context();
 | 
						|
 | 
						|
    if (!pat_lines)			/* null range matches always */
 | 
						|
	return first_guess;
 | 
						|
    if (max_neg_offset >= first_guess)	/* do not try lines < 0 */
 | 
						|
	max_neg_offset = first_guess - 1;
 | 
						|
    if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
 | 
						|
	return first_guess;
 | 
						|
    for (offset = 1; ; offset++) {
 | 
						|
	Reg5 bool check_after = (offset <= max_pos_offset);
 | 
						|
	Reg6 bool check_before = (offset <= max_neg_offset);
 | 
						|
 | 
						|
	if (check_after && patch_match(first_guess, offset, fuzz)) {
 | 
						|
#ifdef DEBUGGING
 | 
						|
	    if (debug & 1)
 | 
						|
		say3("Offset changing from %ld to %ld\n", last_offset, offset);
 | 
						|
#endif
 | 
						|
	    last_offset = offset;
 | 
						|
	    return first_guess+offset;
 | 
						|
	}
 | 
						|
	else if (check_before && patch_match(first_guess, -offset, fuzz)) {
 | 
						|
#ifdef DEBUGGING
 | 
						|
	    if (debug & 1)
 | 
						|
		say3("Offset changing from %ld to %ld\n", last_offset, -offset);
 | 
						|
#endif
 | 
						|
	    last_offset = -offset;
 | 
						|
	    return first_guess-offset;
 | 
						|
	}
 | 
						|
	else if (!check_before && !check_after)
 | 
						|
	    return Nulline;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* We did not find the pattern, dump out the hunk so they can handle it. */
 | 
						|
 | 
						|
void
 | 
						|
abort_hunk()
 | 
						|
{
 | 
						|
    Reg1 LINENUM i;
 | 
						|
    Reg2 LINENUM pat_end = pch_end();
 | 
						|
    /* add in last_offset to guess the same as the previous successful hunk */
 | 
						|
    LINENUM oldfirst = pch_first() + last_offset;
 | 
						|
    LINENUM newfirst = pch_newfirst() + last_offset;
 | 
						|
    LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
 | 
						|
    LINENUM newlast = newfirst + pch_repl_lines() - 1;
 | 
						|
    char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : "");
 | 
						|
    char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----");
 | 
						|
 | 
						|
    fprintf(rejfp, "***************\n");
 | 
						|
    for (i=0; i<=pat_end; i++) {
 | 
						|
	switch (pch_char(i)) {
 | 
						|
	case '*':
 | 
						|
	    if (oldlast < oldfirst)
 | 
						|
		fprintf(rejfp, "*** 0%s\n", stars);
 | 
						|
	    else if (oldlast == oldfirst)
 | 
						|
		fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
 | 
						|
	    else
 | 
						|
		fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
 | 
						|
	    break;
 | 
						|
	case '=':
 | 
						|
	    if (newlast < newfirst)
 | 
						|
		fprintf(rejfp, "--- 0%s\n", minuses);
 | 
						|
	    else if (newlast == newfirst)
 | 
						|
		fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
 | 
						|
	    else
 | 
						|
		fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
 | 
						|
	    break;
 | 
						|
	case '\n':
 | 
						|
	    fprintf(rejfp, "%s", pfetch(i));
 | 
						|
	    break;
 | 
						|
	case ' ': case '-': case '+': case '!':
 | 
						|
	    fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    say1("Fatal internal error in abort_hunk().\n"); 
 | 
						|
	    abort();
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* We found where to apply it (we hope), so do it. */
 | 
						|
 | 
						|
void
 | 
						|
apply_hunk(where)
 | 
						|
LINENUM where;
 | 
						|
{
 | 
						|
    Reg1 LINENUM old = 1;
 | 
						|
    Reg2 LINENUM lastline = pch_ptrn_lines();
 | 
						|
    Reg3 LINENUM new = lastline+1;
 | 
						|
#define OUTSIDE 0
 | 
						|
#define IN_IFNDEF 1
 | 
						|
#define IN_IFDEF 2
 | 
						|
#define IN_ELSE 3
 | 
						|
    Reg4 int def_state = OUTSIDE;
 | 
						|
    Reg5 bool R_do_defines = do_defines;
 | 
						|
    Reg6 LINENUM pat_end = pch_end();
 | 
						|
 | 
						|
    where--;
 | 
						|
    while (pch_char(new) == '=' || pch_char(new) == '\n')
 | 
						|
	new++;
 | 
						|
    
 | 
						|
    while (old <= lastline) {
 | 
						|
	if (pch_char(old) == '-') {
 | 
						|
	    copy_till(where + old - 1);
 | 
						|
	    if (R_do_defines) {
 | 
						|
		if (def_state == OUTSIDE) {
 | 
						|
		    fputs(not_defined, ofp);
 | 
						|
		    def_state = IN_IFNDEF;
 | 
						|
		}
 | 
						|
		else if (def_state == IN_IFDEF) {
 | 
						|
		    fputs(else_defined, ofp);
 | 
						|
		    def_state = IN_ELSE;
 | 
						|
		}
 | 
						|
		fputs(pfetch(old), ofp);
 | 
						|
	    }
 | 
						|
	    last_frozen_line++;
 | 
						|
	    old++;
 | 
						|
	}
 | 
						|
	else if (new > pat_end)
 | 
						|
	    break;
 | 
						|
	else if (pch_char(new) == '+') {
 | 
						|
	    copy_till(where + old - 1);
 | 
						|
	    if (R_do_defines) {
 | 
						|
		if (def_state == IN_IFNDEF) {
 | 
						|
		    fputs(else_defined, ofp);
 | 
						|
		    def_state = IN_ELSE;
 | 
						|
		}
 | 
						|
		else if (def_state == OUTSIDE) {
 | 
						|
		    fputs(if_defined, ofp);
 | 
						|
		    def_state = IN_IFDEF;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    fputs(pfetch(new), ofp);
 | 
						|
	    new++;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
	    if (pch_char(new) != pch_char(old)) {
 | 
						|
		say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
 | 
						|
		    pch_hunk_beg() + old,
 | 
						|
		    pch_hunk_beg() + new);
 | 
						|
#ifdef DEBUGGING
 | 
						|
		say3("oldchar = '%c', newchar = '%c'\n",
 | 
						|
		    pch_char(old), pch_char(new));
 | 
						|
#endif
 | 
						|
		my_exit(1);
 | 
						|
	    }
 | 
						|
	    if (pch_char(new) == '!') {
 | 
						|
		copy_till(where + old - 1);
 | 
						|
		if (R_do_defines) {
 | 
						|
		   fputs(not_defined, ofp);
 | 
						|
		   def_state = IN_IFNDEF;
 | 
						|
		}
 | 
						|
		while (pch_char(old) == '!') {
 | 
						|
		    if (R_do_defines) {
 | 
						|
			fputs(pfetch(old), ofp);
 | 
						|
		    }
 | 
						|
		    last_frozen_line++;
 | 
						|
		    old++;
 | 
						|
		}
 | 
						|
		if (R_do_defines) {
 | 
						|
		    fputs(else_defined, ofp);
 | 
						|
		    def_state = IN_ELSE;
 | 
						|
		}
 | 
						|
		while (pch_char(new) == '!') {
 | 
						|
		    fputs(pfetch(new), ofp);
 | 
						|
		    new++;
 | 
						|
		}
 | 
						|
		if (R_do_defines) {
 | 
						|
		    fputs(end_defined, ofp);
 | 
						|
		    def_state = OUTSIDE;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		assert(pch_char(new) == ' ');
 | 
						|
		old++;
 | 
						|
		new++;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (new <= pat_end && pch_char(new) == '+') {
 | 
						|
	copy_till(where + old - 1);
 | 
						|
	if (R_do_defines) {
 | 
						|
	    if (def_state == OUTSIDE) {
 | 
						|
	    	fputs(if_defined, ofp);
 | 
						|
		def_state = IN_IFDEF;
 | 
						|
	    }
 | 
						|
	    else if (def_state == IN_IFNDEF) {
 | 
						|
		fputs(else_defined, ofp);
 | 
						|
		def_state = IN_ELSE;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	while (new <= pat_end && pch_char(new) == '+') {
 | 
						|
	    fputs(pfetch(new), ofp);
 | 
						|
	    new++;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (R_do_defines && def_state != OUTSIDE) {
 | 
						|
	fputs(end_defined, ofp);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Open the new file. */
 | 
						|
 | 
						|
void
 | 
						|
init_output(name)
 | 
						|
char *name;
 | 
						|
{
 | 
						|
    ofp = fopen(name, "w");
 | 
						|
    if (ofp == Nullfp)
 | 
						|
	fatal2("patch: can't create %s.\n", name);
 | 
						|
}
 | 
						|
 | 
						|
/* Open a file to put hunks we can't locate. */
 | 
						|
 | 
						|
void
 | 
						|
init_reject(name)
 | 
						|
char *name;
 | 
						|
{
 | 
						|
    rejfp = fopen(name, "w");
 | 
						|
    if (rejfp == Nullfp)
 | 
						|
	fatal2("patch: can't create %s.\n", name);
 | 
						|
}
 | 
						|
 | 
						|
/* Copy input file to output, up to wherever hunk is to be applied. */
 | 
						|
 | 
						|
void
 | 
						|
copy_till(lastline)
 | 
						|
Reg1 LINENUM lastline;
 | 
						|
{
 | 
						|
    Reg2 LINENUM R_last_frozen_line = last_frozen_line;
 | 
						|
 | 
						|
    if (R_last_frozen_line > lastline)
 | 
						|
	say1("patch: misordered hunks! output will be garbled.\n");
 | 
						|
    while (R_last_frozen_line < lastline) {
 | 
						|
	dump_line(++R_last_frozen_line);
 | 
						|
    }
 | 
						|
    last_frozen_line = R_last_frozen_line;
 | 
						|
}
 | 
						|
 | 
						|
/* Finish copying the input file to the output file. */
 | 
						|
 | 
						|
void
 | 
						|
spew_output()
 | 
						|
{
 | 
						|
#ifdef DEBUGGING
 | 
						|
    if (debug & 256)
 | 
						|
	say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
 | 
						|
#endif
 | 
						|
    if (input_lines)
 | 
						|
	copy_till(input_lines);		/* dump remainder of file */
 | 
						|
    Fclose(ofp);
 | 
						|
    ofp = Nullfp;
 | 
						|
}
 | 
						|
 | 
						|
/* Copy one line from input to output. */
 | 
						|
 | 
						|
void
 | 
						|
dump_line(line)
 | 
						|
LINENUM line;
 | 
						|
{
 | 
						|
    Reg1 char *s;
 | 
						|
    Reg2 char R_newline = '\n';
 | 
						|
 | 
						|
    /* Note: string is not null terminated. */
 | 
						|
    for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
 | 
						|
}
 | 
						|
 | 
						|
/* Does the patch pattern match at line base+offset? */
 | 
						|
 | 
						|
bool
 | 
						|
patch_match(base, offset, fuzz)
 | 
						|
LINENUM base;
 | 
						|
LINENUM offset;
 | 
						|
LINENUM fuzz;
 | 
						|
{
 | 
						|
    Reg1 LINENUM pline = 1 + fuzz;
 | 
						|
    Reg2 LINENUM iline;
 | 
						|
    Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
 | 
						|
 | 
						|
    for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
 | 
						|
	if (canonicalize) {
 | 
						|
	    if (!similar(ifetch(iline, (offset >= 0)),
 | 
						|
			 pfetch(pline),
 | 
						|
			 pch_line_len(pline) ))
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
	else if (strnNE(ifetch(iline, (offset >= 0)),
 | 
						|
		   pfetch(pline),
 | 
						|
		   pch_line_len(pline) ))
 | 
						|
	    return FALSE;
 | 
						|
    }
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/* Do two lines match with canonicalized white space? */
 | 
						|
 | 
						|
bool
 | 
						|
similar(a,b,len)
 | 
						|
Reg1 char *a;
 | 
						|
Reg2 char *b;
 | 
						|
Reg3 int len;
 | 
						|
{
 | 
						|
    while (len) {
 | 
						|
	if (isspace(*b)) {		/* whitespace (or \n) to match? */
 | 
						|
	    if (!isspace(*a))		/* no corresponding whitespace? */
 | 
						|
		return FALSE;
 | 
						|
	    while (len && isspace(*b) && *b != '\n')
 | 
						|
		b++,len--;		/* skip pattern whitespace */
 | 
						|
	    while (isspace(*a) && *a != '\n')
 | 
						|
		a++;			/* skip target whitespace */
 | 
						|
	    if (*a == '\n' || *b == '\n')
 | 
						|
		return (*a == *b);	/* should end in sync */
 | 
						|
	}
 | 
						|
	else if (*a++ != *b++)		/* match non-whitespace chars */
 | 
						|
	    return FALSE;
 | 
						|
	else
 | 
						|
	    len--;			/* probably not necessary */
 | 
						|
    }
 | 
						|
    return TRUE;			/* actually, this is not reached */
 | 
						|
					/* since there is always a \n */
 | 
						|
}
 | 
						|
 | 
						|
/* Exit with cleanup. */
 | 
						|
 | 
						|
void
 | 
						|
my_exit(status)
 | 
						|
int status;
 | 
						|
{
 | 
						|
    Unlink(TMPINNAME);
 | 
						|
    if (!toutkeep) {
 | 
						|
	Unlink(TMPOUTNAME);
 | 
						|
    }
 | 
						|
    if (!trejkeep) {
 | 
						|
	Unlink(TMPREJNAME);
 | 
						|
    }
 | 
						|
    Unlink(TMPPATNAME);
 | 
						|
#ifdef SMALL
 | 
						|
    Unlink(TMPSTRNAME);
 | 
						|
#endif
 | 
						|
    exit(status);
 | 
						|
}
 |