Larry Wall's patch v2.0-11 (2 of 3)

egray at fthood.UUCP egray at fthood.UUCP
Wed Jun 8 02:43:00 AEST 1988


This is part 2 of 3 to Larry Wall's patch 2.0-11

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!ihnp4!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

-------------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	config.h.SH
#	inp.c
#	inp.h
#	malloc.c
#	patch.c
#	util.h
#	version.c
#	version.h
# This archive created: Tue Jun  7 11:32:44 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'config.h.SH'" '(4619 characters)'
if test -f 'config.h.SH'
then
	echo shar: "will not over-write existing file 'config.h.SH'"
else
sed 's/^X//' << \SHAR_EOF > 'config.h.SH'
Xcase $CONFIG in
X'')
X    if test ! -f config.sh; then
X	ln ../config.sh . || \
X	ln ../../config.sh . || \
X	ln ../../../config.sh . || \
X	(echo "Can't find config.sh."; exit 1)
X	echo "Using config.sh from above..."
X    fi
X    . ./config.sh
X    ;;
Xesac
Xecho "Extracting config.h (with variable substitutions)"
Xcat <<!GROK!THIS! >config.h
X/* config.h
X * This file was produced by running the config.h.SH script, which
X * gets its values from config.sh, which is generally produced by
X * running Configure.
X *
X * Feel free to modify any of this as the need arises.  Note, however,
X * that running config.h.SH again will wipe out any changes you've made.
X * For a more permanent change edit config.sh and rerun config.h.SH.
X */
X
X
X/* EUNICE:
X *	This symbol, if defined, indicates that the program is being compiled
X *	under the EUNICE package under VMS.  The program will need to handle
X *	things like files that don't go away the first time you unlink them,
X *	due to version numbering.  It will also need to compensate for lack
X *	of a respectable link() command.
X */
X/* VMS:
X *	This symbol, if defined, indicates that the program is running under
X *	VMS.  It is currently only set in conjunction with the EUNICE symbol.
X */
X#$d_eunice	EUNICE		/**/
X#$d_eunice	VMS		/**/
X
X/* CPPSTDIN:
X *	This symbol contains the first part of the string which will invoke
X *	the C preprocessor on the standard input and produce to standard
X *	output.	 Typical value of "cc -E" or "/lib/cpp".
X */
X/* CPPMINUS:
X *	This symbol contains the second part of the string which will invoke
X *	the C preprocessor on the standard input and produce to standard
X *	output.  This symbol will have the value "-" if CPPSTDIN needs a minus
X *	to specify standard input, otherwise the value is "".
X */
X#define CPPSTDIN "$cppstdin"
X#define CPPMINUS "$cppminus"
X
X/* CHARSPRINTF:
X *	This symbol is defined if this system declares "char *sprintf()" in
X *	stdio.h.  The trend seems to be to declare it as "int sprintf()".  It
X *	is up to the package author to declare sprintf correctly based on the
X *	symbol.
X */
X#$d_charsprf	CHARSPRINTF 	/**/
X
X/* FLEXFILENAMES:
X *	This symbol, if defined, indicates that the system supports filenames
X *	longer than 14 characters.
X */
X#$d_flexfnam	FLEXFILENAMES		/**/
X
X/* index:
X *	This preprocessor symbol is defined, along with rindex, if the system
X *	uses the strchr and strrchr routines instead.
X */
X/* rindex:
X *	This preprocessor symbol is defined, along with index, if the system
X *	uses the strchr and strrchr routines instead.
X */
X#$d_index	index strchr	/* cultural */
X#$d_index	rindex strrchr	/*  differences? */
X
X/* VOIDSIG:
X *	This symbol is defined if this system declares "void (*signal())()" in
X *	signal.h.  The old way was to declare it as "int (*signal())()".  It
X *	is up to the package author to declare things correctly based on the
X *	symbol.
X */
X#$d_voidsig	VOIDSIG 	/**/
X
X/* Reg1:
X *	This symbol, along with Reg2, Reg3, etc. is either the word "register"
X *	or null, depending on whether the C compiler pays attention to this
X *	many register declarations.  The intent is that you don't have to
X *	order your register declarations in the order of importance, so you
X *	can freely declare register variables in sub-blocks of code and as
X *	function parameters.  Do not use Reg<n> more than once per routine.
X */
X
X#define Reg1 $reg1		/**/
X#define Reg2 $reg2		/**/
X#define Reg3 $reg3		/**/
X#define Reg4 $reg4		/**/
X#define Reg5 $reg5		/**/
X#define Reg6 $reg6		/**/
X#define Reg7 $reg7		/**/
X#define Reg8 $reg8		/**/
X#define Reg9 $reg9		/**/
X#define Reg10 $reg10		/**/
X#define Reg11 $reg11		/**/
X#define Reg12 $reg12		/**/
X#define Reg13 $reg13		/**/
X#define Reg14 $reg14		/**/
X#define Reg15 $reg15		/**/
X#define Reg16 $reg16		/**/
X
X/* VOIDFLAGS:
X *	This symbol indicates how much support of the void type is given by this
X *	compiler.  What various bits mean:
X *
X *	    1 = supports declaration of void
X *	    2 = supports arrays of pointers to functions returning void
X *	    4 = supports comparisons between pointers to void functions and
X *		    addresses of void functions
X *
X *	The package designer should define VOIDUSED to indicate the requirements
X *	of the package.  This can be done either by #defining VOIDUSED before
X *	including config.h, or by defining defvoidused in Myinit.U.  If the
X *	level of void support necessary is not present, defines void to int.
X */
X#ifndef VOIDUSED
X#define VOIDUSED $defvoidused
X#endif
X#define VOIDFLAGS $voidflags
X#if (VOIDFLAGS & VOIDUSED) != VOIDUSED
X#$define void int		/* is void to be avoided? */
X#$define M_VOID		/* Xenix strikes again */
X#endif
X
X!GROK!THIS!
SHAR_EOF
if test 4619 -ne "`wc -c < 'config.h.SH'`"
then
	echo shar: "error transmitting 'config.h.SH'" '(should have been 4619 characters)'
fi
fi
echo shar: "extracting 'inp.c'" '(8134 characters)'
if test -f 'inp.c'
then
	echo shar: "will not over-write existing file 'inp.c'"
else
sed 's/^X//' << \SHAR_EOF > 'inp.c'
X/* $Header: inp.c,v 2.0.1.1 88/06/03 15:06:13 lwall Locked $
X *
X * $Log:	inp.c,v $
X * Revision 2.0.1.1  88/06/03  15:06:13  lwall
X * patch10: made a little smarter about sccs files
X * 
X * Revision 2.0  86/09/17  15:37:02  lwall
X * Baseline for netwide release.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "pch.h"
X#include "INTERN.h"
X#include "inp.h"
X
X/* Input-file-with-indexable-lines abstract type */
X
Xstatic long i_size;			/* size of the input file */
Xstatic char *i_womp;			/* plan a buffer for entire file */
Xstatic char **i_ptr;			/* pointers to lines in i_womp */
X
Xstatic int tifd = -1;			/* plan b virtual string array */
Xstatic char *tibuf[2];			/* plan b buffers */
Xstatic LINENUM tiline[2] = {-1, -1};	/* 1st line in each buffer */
Xstatic LINENUM lines_per_buf;		/* how many lines per buffer */
Xstatic int tireclen;			/* length of records in tmp file */
X
X/* New patch--prepare to edit another file. */
X
Xvoid
Xre_input()
X{
X    if (using_plan_a) {
X	i_size = 0;
X#ifndef lint
X	if (i_ptr != Null(char**))
X	    free((char *)i_ptr);
X#endif
X	if (i_womp != Nullch)
X	    free(i_womp);
X	i_womp = Nullch;
X	i_ptr = Null(char **);
X    }
X    else {
X	using_plan_a = TRUE;		/* maybe the next one is smaller */
X	Close(tifd);
X	tifd = -1;
X	free(tibuf[0]);
X	free(tibuf[1]);
X	tibuf[0] = tibuf[1] = Nullch;
X	tiline[0] = tiline[1] = -1;
X	tireclen = 0;
X    }
X}
X
X/* Constuct the line index, somehow or other. */
X
Xvoid
Xscan_input(filename)
Xchar *filename;
X{
X    if (!plan_a(filename))
X	plan_b(filename);
X    if (verbose) {
X	say3("Patching file %s using Plan %s...\n", filename,
X	  (using_plan_a ? "A" : "B") );
X    }
X}
X
X/* Try keeping everything in memory. */
X
Xbool
Xplan_a(filename)
Xchar *filename;
X{
X    int ifd;
X    Reg1 char *s;
X    Reg2 LINENUM iline;
X
X    if (ok_to_create_file && stat(filename, &filestat) < 0) {
X	if (verbose)
X	    say2("(Creating file %s...)\n",filename);
X	makedirs(filename, TRUE);
X	close(creat(filename, 0666));
X    }
X    if (stat(filename, &filestat) < 0) {
X	Sprintf(buf, "RCS/%s%s", filename, RCSSUFFIX);
X	if (stat(buf, &filestat) >= 0 || stat(buf+4, &filestat) >= 0) {
X	    Sprintf(buf, CHECKOUT, filename);
X	    if (verbose)
X		say2("Can't find %s--attempting to check it out from RCS.\n",
X		    filename);
X	    if (system(buf) || stat(filename, &filestat))
X		fatal2("Can't check out %s.\n", filename);
X	}
X	else {
X	    Sprintf(buf+20, "SCCS/%s%s", SCCSPREFIX, filename);
X	    if (stat(s=buf+20, &filestat) >= 0 ||
X	      stat(s=buf+25, &filestat) >= 0) {
X		Sprintf(buf, GET, s);
X		if (verbose)
X		    say2("Can't find %s--attempting to get it from SCCS.\n",
X			filename);
X		if (system(buf) || stat(filename, &filestat))
X		    fatal2("Can't get %s.\n", filename);
X	    }
X	    else
X		fatal2("Can't find %s.\n", filename);
X	}
X    }
X    filemode = filestat.st_mode;
X    if ((filemode & S_IFMT) & ~S_IFREG)
X	fatal2("%s is not a normal file--can't patch.\n", filename);
X    i_size = filestat.st_size;
X    if (out_of_mem) {
X	set_hunkmax();		/* make sure dynamic arrays are allocated */
X	out_of_mem = FALSE;
X	return FALSE;			/* force plan b because plan a bombed */
X    }
X#ifdef lint
X    i_womp = Nullch;
X#else
X    i_womp = malloc((MEM)(i_size+2));	/* lint says this may alloc less than */
X					/* i_size, but that's okay, I think. */
X#endif
X    if (i_womp == Nullch)
X	return FALSE;
X    if ((ifd = open(filename, 0)) < 0)
X	fatal2("Can't open file %s\n", filename);
X#ifndef lint
X    if (read(ifd, i_womp, (int)i_size) != i_size) {
X	Close(ifd);	/* probably means i_size > 15 or 16 bits worth */
X	free(i_womp);	/* at this point it doesn't matter if i_womp was */
X	return FALSE;	/*   undersized. */
X    }
X#endif
X    Close(ifd);
X    if (i_size && i_womp[i_size-1] != '\n')
X	i_womp[i_size++] = '\n';
X    i_womp[i_size] = '\0';
X
X    /* count the lines in the buffer so we know how many pointers we need */
X
X    iline = 0;
X    for (s=i_womp; *s; s++) {
X	if (*s == '\n')
X	    iline++;
X    }
X#ifdef lint
X    i_ptr = Null(char**);
X#else
X    i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
X#endif
X    if (i_ptr == Null(char **)) {	/* shucks, it was a near thing */
X	free((char *)i_womp);
X	return FALSE;
X    }
X    
X    /* now scan the buffer and build pointer array */
X
X    iline = 1;
X    i_ptr[iline] = i_womp;
X    for (s=i_womp; *s; s++) {
X	if (*s == '\n')
X	    i_ptr[++iline] = s+1;	/* these are NOT null terminated */
X    }
X    input_lines = iline - 1;
X
X    /* now check for revision, if any */
X
X    if (revision != Nullch) { 
X	if (!rev_in_string(i_womp)) {
X	    if (force) {
X		if (verbose)
X		    say2(
X"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
X			revision);
X	    }
X	    else {
X		ask2(
X"This file doesn't appear to be the %s version--patch anyway? [n] ",
X		    revision);
X	    if (*buf != 'y')
X		fatal1("Aborted.\n");
X	    }
X	}
X	else if (verbose)
X	    say2("Good.  This file appears to be the %s version.\n",
X		revision);
X    }
X    return TRUE;			/* plan a will work */
X}
X
X/* Keep (virtually) nothing in memory. */
X
Xvoid
Xplan_b(filename)
Xchar *filename;
X{
X    Reg3 FILE *ifp;
X    Reg1 int i = 0;
X    Reg2 int maxlen = 1;
X    Reg4 bool found_revision = (revision == Nullch);
X
X    using_plan_a = FALSE;
X    if ((ifp = fopen(filename, "r")) == Nullfp)
X	fatal2("Can't open file %s\n", filename);
X    if ((tifd = creat(TMPINNAME, 0666)) < 0)
X	fatal2("Can't open file %s\n", TMPINNAME);
X    while (fgets(buf, sizeof buf, ifp) != Nullch) {
X	if (revision != Nullch && !found_revision && rev_in_string(buf))
X	    found_revision = TRUE;
X	if ((i = strlen(buf)) > maxlen)
X	    maxlen = i;			/* find longest line */
X    }
X    if (revision != Nullch) {
X	if (!found_revision) {
X	    if (force) {
X		if (verbose)
X		    say2(
X"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
X			revision);
X	    }
X	    else {
X		ask2(
X"This file doesn't appear to be the %s version--patch anyway? [n] ",
X		    revision);
X		if (*buf != 'y')
X		    fatal1("Aborted.\n");
X	    }
X	}
X	else if (verbose)
X	    say2("Good.  This file appears to be the %s version.\n",
X		revision);
X    }
X    Fseek(ifp, 0L, 0);		/* rewind file */
X    lines_per_buf = BUFFERSIZE / maxlen;
X    tireclen = maxlen;
X    tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
X    tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
X    if (tibuf[1] == Nullch)
X	fatal1("Can't seem to get enough memory.\n");
X    for (i=1; ; i++) {
X	if (! (i % lines_per_buf))	/* new block */
X	    if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
X		fatal1("patch: can't write temp file.\n");
X	if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
X	  == Nullch) {
X	    input_lines = i - 1;
X	    if (i % lines_per_buf)
X		if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
X		    fatal1("patch: can't write temp file.\n");
X	    break;
X	}
X    }
X    Fclose(ifp);
X    Close(tifd);
X    if ((tifd = open(TMPINNAME, 0)) < 0) {
X	fatal2("Can't reopen file %s\n", TMPINNAME);
X    }
X}
X
X/* Fetch a line from the input file, \n terminated, not necessarily \0. */
X
Xchar *
Xifetch(line,whichbuf)
XReg1 LINENUM line;
Xint whichbuf;				/* ignored when file in memory */
X{
X    if (line < 1 || line > input_lines)
X	return "";
X    if (using_plan_a)
X	return i_ptr[line];
X    else {
X	LINENUM offline = line % lines_per_buf;
X	LINENUM baseline = line - offline;
X
X	if (tiline[0] == baseline)
X	    whichbuf = 0;
X	else if (tiline[1] == baseline)
X	    whichbuf = 1;
X	else {
X	    tiline[whichbuf] = baseline;
X#ifndef lint		/* complains of long accuracy */
X	    Lseek(tifd, (long)baseline / lines_per_buf * BUFFERSIZE, 0);
X#endif
X	    if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
X		fatal2("Error reading tmp file %s.\n", TMPINNAME);
X	}
X	return tibuf[whichbuf] + (tireclen*offline);
X    }
X}
X
X/* True if the string argument contains the revision number we want. */
X
Xbool
Xrev_in_string(string)
Xchar *string;
X{
X    Reg1 char *s;
X    Reg2 int patlen;
X
X    if (revision == Nullch)
X	return TRUE;
X    patlen = strlen(revision);
X    if (strnEQ(string,revision,patlen) && isspace(s[patlen]))
X	return TRUE;
X    for (s = string; *s; s++) {
X	if (isspace(*s) && strnEQ(s+1, revision, patlen) && 
X		isspace(s[patlen+1] )) {
X	    return TRUE;
X	}
X    }
X    return FALSE;
X}
X
SHAR_EOF
if test 8134 -ne "`wc -c < 'inp.c'`"
then
	echo shar: "error transmitting 'inp.c'" '(should have been 8134 characters)'
fi
fi
echo shar: "extracting 'inp.h'" '(473 characters)'
if test -f 'inp.h'
then
	echo shar: "will not over-write existing file 'inp.h'"
else
sed 's/^X//' << \SHAR_EOF > 'inp.h'
X/* $Header: inp.h,v 2.0 86/09/17 15:37:25 lwall Exp $
X *
X * $Log:	inp.h,v $
X * Revision 2.0  86/09/17  15:37:25  lwall
X * Baseline for netwide release.
X * 
X */
X
XEXT LINENUM input_lines INIT(0);	/* how long is input file in lines */
XEXT LINENUM last_frozen_line INIT(0);	/* how many input lines have been */
X					/* irretractibly output */
X
Xbool rev_in_string();
Xvoid scan_input();
Xbool plan_a();			/* returns false if insufficient memory */
Xvoid plan_b();
Xchar *ifetch();
X
SHAR_EOF
if test 473 -ne "`wc -c < 'inp.h'`"
then
	echo shar: "error transmitting 'inp.h'" '(should have been 473 characters)'
fi
fi
echo shar: "extracting 'malloc.c'" '(12262 characters)'
if test -f 'malloc.c'
then
	echo shar: "will not over-write existing file 'malloc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'malloc.c'
X/*
X * @(#)nmalloc.c 1 (Caltech) 2/21/82
X *
X *	U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs
X *
X *	Nov 1983, Mike at BRL, Added support for 4.1C/4.2 BSD.
X *
X * This is a very fast storage allocator.  It allocates blocks of a small 
X * number of different sizes, and keeps free lists of each size.  Blocks
X * that don't exactly fit are passed up to the next larger size.  In this 
X * implementation, the available sizes are (2^n)-4 (or -16) bytes long.
X * This is designed for use in a program that uses vast quantities of
X * memory, but bombs when it runs out.  To make it a little better, it
X * warns the user when he starts to get near the end.
X *
X * June 84, ACT: modified rcheck code to check the range given to malloc,
X * rather than the range determined by the 2-power used.
X *
X * Jan 85, RMS: calls malloc_warning to issue warning on nearly full.
X * No longer Emacs-specific; can serve as all-purpose malloc for GNU.
X * You should call malloc_init to reinitialize after loading dumped Emacs.
X * Call malloc_stats to get info on memory stats if MSTATS turned on.
X * realloc knows how to return same block given, just changing its size,
X * if the power of 2 is correct.
X */
X
X/*
X * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
X * smallest allocatable block is 8 bytes.  The overhead information will
X * go in the first int of the block, and the returned pointer will point
X * to the second.
X *
X#ifdef MSTATS
X * nmalloc[i] is the difference between the number of mallocs and frees
X * for a given block size.
X#endif /* MSTATS */
X */
X
X#define ISALLOC ((char) 0xf7)	/* magic byte that implies allocation */
X#define ISFREE ((char) 0x54)	/* magic byte that implies free block */
X				/* this is for error checking only */
X
Xextern char etext;
X
X/* end of the program; can be changed by calling init_malloc */
Xstatic char *endofpure = &etext;
X
X#ifdef MSTATS
Xstatic int nmalloc[30];
Xstatic int nmal, nfre;
X#endif /* MSTATS */
X
X/* If range checking is not turned on, all we have is a flag indicating
X   whether memory is allocated, an index in nextf[], and a size field; to
X   realloc() memory we copy either size bytes or 1<<(index+3) bytes depending
X   on whether the former can hold the exact size (given the value of
X   'index').  If range checking is on, we always need to know how much space
X   is allocated, so the 'size' field is never used. */
X
Xstruct mhead {
X	char     mh_alloc;	/* ISALLOC or ISFREE */
X	char     mh_index;	/* index in nextf[] */
X/* Remainder are valid only when block is allocated */
X	unsigned short mh_size;	/* size, if < 0x10000 */
X#ifdef rcheck
X	unsigned mh_nbytes;	/* number of bytes allocated */
X	int      mh_magic4;	/* should be == MAGIC4 */
X#endif /* rcheck */
X	};
X
X/* Access free-list pointer of a block.
X  It is stored at block + 4.
X  This is not a field in the mhead structure
X  because we want sizeof (struct mhead)
X  to describe the overhead for when the block is in use,
X  and we do not want the free-list pointer to count in that.  */
X
X#define CHAIN(a) \
X  (*(struct mhead **) (sizeof (char *) + (char *) (a)))
X
X#ifdef rcheck
X
X/* To implement range checking, we write magic values in at the beginning and
X   end of each allocated block, and make sure they are undisturbed whenever a
X   free or a realloc occurs. */
X/* Written in each of the 4 bytes following the block's real space */
X#define MAGIC1 0x55
X/* Written in the 4 bytes before the block's real space */
X#define MAGIC4 0x55555555
X#define ASSERT(p) if (!(p)) botch("p"); else
Xstatic
Xbotch(s)
X	char *s;
X{
X
X	printf("assertion botched: %s\n", s);
X	abort();
X}
X#define EXTRA  4		/* 4 bytes extra for MAGIC1s */
X#else
X#define ASSERT(p)
X#define EXTRA  0
X#endif /* rcheck */
X
X/* nextf[i] is free list of blocks of size 2**(i + 3)  */
X
Xstatic struct mhead *nextf[30];
X
X#ifdef	M_WARN
X/* Number of bytes of writable memory we can expect to be able to get */
Xstatic int  lim_data;
X/* Level number of warnings already issued.
X  0 -- no warnings issued.
X  1 -- 75% warning already issued.
X  2 -- 85% warning already issued.
X*/
Xstatic int  warnlevel;
X#endif /* M_WARN */
X
X/* nonzero once initial bunch of free blocks made */
Xstatic int gotpool;
X
X/* Cause reinitialization based on job parameters;
X  also declare where the end of pure storage is. */
Xmalloc_init (end)
X    char *end; {
X	endofpure = end;
X#ifdef	M_WARN
X	lim_data = 0;
X	warnlevel = 0;
X#endif /* M_WARN */
X	}
X
Xstatic
Xmorecore (nu)			/* ask system for more memory */
X    register int nu; {		/* size index to get more of  */
X	char   *sbrk ();
X	register char  *cp;
X	register int    nblks;
X	register int    siz;
X
X#ifdef	M_WARN
X#ifndef BSD42
X#ifdef USG
X	extern long ulimit ();
X	if (lim_data == 0)		/* find out how much we can get */
X	    lim_data = ulimit (3, 0) - TEXT_START;
X#else	/*HMS: was endif */
X	if (lim_data == 0)		/* find out how much we can get */
X	    lim_data = vlimit (LIM_DATA, -1);
X#endif /* USG */	/HMS:* was not here */
X#else
X	if (lim_data == 0) {
X		struct rlimit   XXrlimit;
X
X		getrlimit (RLIMIT_DATA, &XXrlimit);
X		lim_data = XXrlimit.rlim_cur;}	/* soft limit */
X#endif /* BSD42 */
X#endif /* M_WARN */
X
X	/* On initial startup, get two blocks of each size up to 1k bytes */
X	if (!gotpool)
X	    getpool (), getpool (), gotpool = 1;
X
X	/* Find current end of memory and issue warning if getting near max */
X
X	cp = sbrk (0);
X	siz = cp - endofpure;
X#ifdef	M_WARN
X	switch (warnlevel) {
X	    case 0: 
X		if (siz > (lim_data / 4) * 3) {
X			warnlevel++;
X			malloc_warning ("Warning: past 75% of memory limit");}
X		break;
X	    case 1: 
X		if (siz > (lim_data / 20) * 17) {
X			warnlevel++;
X			malloc_warning ("Warning: past 85% of memory limit");}
X		break;
X	    case 2: 
X		if (siz > (lim_data / 20) * 19) {
X			warnlevel++;
X			malloc_warning ("Warning: past 95% of memory limit");}
X		break;}
X#endif /* M_WARN */
X
X	if ((int) cp & 0x3ff)	/* land on 1K boundaries */
X	    sbrk (1024 - ((int) cp & 0x3ff));
X
X	/* Take at least 2k, and figure out how many blocks of the desired size we're about to get */
X	nblks = 1;
X	if ((siz = nu) < 8)
X	    nblks = 1 << ((siz = 8) - nu);
X
X	if ((cp = sbrk (1 << (siz + 3))) == (char *) -1)
X	    return;			/* no more room! */
X	if ((int) cp & 7) {		/* shouldn't happen, but just in case */
X		cp = (char *) (((int) cp + 8) & ~7);
X		nblks--;}
X
X	/* save new header and link the nblks blocks together */
X	nextf[nu] = (struct mhead *) cp;
X	siz = 1 << (nu + 3);
X	while (1) {
X		((struct mhead *) cp) -> mh_alloc = ISFREE;
X		((struct mhead *) cp) -> mh_index = nu;
X		if (--nblks <= 0) break;
X		CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz);
X		cp += siz;}
X/*	CHAIN ((struct mhead *) cp) = 0;	/* since sbrk() returns cleared core, this is already set */
X	}
X
Xstatic
Xgetpool () {
X	register int nu;
X	register char *cp = sbrk (0);
X
X	if ((int) cp & 0x3ff)	/* land on 1K boundaries */
X	    sbrk (1024 - ((int) cp & 0x3ff));
X
X	/* Get 2k of storage */
X
X	cp = sbrk (04000);
X	if (cp == (char *) -1)
X	    return;
X
X	/* Divide it into an initial 8-word block
X	plus one block of size 2**nu for nu = 3 ... 10.  */
X
X	CHAIN (cp) = nextf[0];
X	nextf[0] = (struct mhead *) cp;
X	((struct mhead *) cp) -> mh_alloc = ISFREE;
X	((struct mhead *) cp) -> mh_index = 0;
X	cp += 8;
X
X	for (nu = 0; nu < 7; nu++) {
X		CHAIN (cp) = nextf[nu];
X		nextf[nu] = (struct mhead *) cp;
X		((struct mhead *) cp) -> mh_alloc = ISFREE;
X		((struct mhead *) cp) -> mh_index = nu;
X		cp += 8 << nu;}}
X
Xchar *
Xmalloc (n)		/* get a block */
X    unsigned n; {
X	register struct  mhead *p;
X	register unsigned int  nbytes;
X	register int    nunits = 0;
X
X	/* Figure out how many bytes are required, rounding up to the nearest
X	multiple of 4, then figure out which nextf[] area to use */
X	nbytes = (n + sizeof *p + EXTRA + 3) & ~3;
X		{
X		register unsigned int   shiftr = (nbytes - 1) >> 2;
X
X		while (shiftr >>= 1)
X		    nunits++;
X		}
X
X	/* If there are no blocks of the appropriate size, go get some */
X	/* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */
X	if (nextf[nunits] == 0)
X	    morecore (nunits);
X
X	/* Get one block off the list, and set the new list head */
X	if ((p = nextf[nunits]) == 0)
X	    return 0;
X	nextf[nunits] = CHAIN (p);
X
X	/* Check for free block clobbered */
X	/* If not for this check, we would gobble a clobbered free chain ptr */
X	/* and bomb out on the NEXT allocate of this size block */
X	if (p -> mh_alloc != ISFREE || p -> mh_index != nunits)
X#ifdef rcheck
X	    botch ("block on free list clobbered");
X#else
X	    abort ();
X#endif /* rcheck */
X
X	/* Fill in the info, and if range checking, set up the magic numbers */
X	p -> mh_alloc = ISALLOC;
X#ifdef rcheck
X	p -> mh_nbytes = n;
X	p -> mh_magic4 = MAGIC4;
X		{
X		register char  *m = (char *) (p + 1) + n;
X
X		*m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1;
X		}
X#else
X	p -> mh_size = n;
X#endif /* rcheck */
X#ifdef MSTATS
X	nmalloc[nunits]++;
X	nmal++;
X#endif /* MSTATS */
X	return (char *) (p + 1);}
X
Xfree (mem)
X    char *mem; {
X	register struct mhead *p;
X		{
X		register char *ap = mem;
X
X		ASSERT (ap != 0);
X		p = (struct mhead *) ap - 1;
X		ASSERT (p -> mh_alloc == ISALLOC);
X#ifdef rcheck
X		ASSERT (p -> mh_magic4 == MAGIC4);
X		ap += p -> mh_nbytes;
X		ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1);
X		ASSERT (*ap++ == MAGIC1); ASSERT (*ap   == MAGIC1);
X#endif /* rcheck */
X		}
X		{
X		register int nunits = p -> mh_index;
X
X		ASSERT (nunits <= 29);
X		p -> mh_alloc = ISFREE;
X		CHAIN (p) = nextf[nunits];
X		nextf[nunits] = p;
X#ifdef MSTATS
X		nmalloc[nunits]--;
X		nfre++;
X#endif /* MSTATS */
X		}
X	}
X
Xchar *
Xrealloc (mem, n)
X    char *mem;
X    register unsigned n; {
X	register struct mhead *p;
X	register unsigned int tocopy;
X	register int nbytes;
X	register int nunits;
X
X	if ((p = (struct mhead *) mem) == 0)
X	    return malloc (n);
X	p--;
X	nunits = p -> mh_index;
X	ASSERT (p -> mh_alloc == ISALLOC);
X#ifdef rcheck
X	ASSERT (p -> mh_magic4 == MAGIC4);
X		{
X		register char *m = mem + (tocopy = p -> mh_nbytes);
X		ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1);
X		ASSERT (*m++ == MAGIC1); ASSERT (*m   == MAGIC1);
X		}
X#else
X	if (p -> mh_index >= 13)
X	    tocopy = (1 << (p -> mh_index + 3)) - sizeof *p;
X	else
X	    tocopy = p -> mh_size;
X#endif /* rcheck */
X
X	/* See if desired size rounds to same power of 2 as actual size. */
X	nbytes = (n + sizeof *p + EXTRA + 7) & ~7;
X
X	/* If ok, use the same block, just marking its size as changed.  */
X	if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) {
X#ifdef rcheck
X		register char *m = mem + tocopy;
X		*m++ = 0;  *m++ = 0;  *m++ = 0;  *m++ = 0;
X		p-> mh_nbytes = n;
X		m = mem + n;
X		*m++ = MAGIC1;  *m++ = MAGIC1;  *m++ = MAGIC1;  *m++ = MAGIC1;
X#else
X		p -> mh_size = n;
X#endif /* rcheck */
X		return mem;}
X
X	if (n < tocopy)
X	    tocopy = n;
X		{
X		register char *new;
X		void bcopy();	/*HMS: here? */
X
X		if ((new = malloc (n)) == 0)
X		    return 0;
X		bcopy (mem, new, tocopy);
X		free (mem);
X		return new;
X		}
X	}
X
X#ifdef MSTATS
X/* Return statistics describing allocation of blocks of size 2**n. */
X
Xstruct mstats_value {
X	int blocksize;
X	int nfree;
X	int nused;
X	};
X
Xstruct mstats_value
Xmalloc_stats (size)
X    int size; {
X	struct mstats_value v;
X	register int i;
X	register struct mhead *p;
X
X	v.nfree = 0;
X
X	if (size < 0 || size >= 30) {
X		v.blocksize = 0;
X		v.nused = 0;
X		return v;}
X
X	v.blocksize = 1 << (size + 3);
X	v.nused = nmalloc[size];
X
X	for (p = nextf[size]; p; p = CHAIN (p))
X	    v.nfree++;
X
X	return v;}
X#endif
X
X/* how much space is available? */
X
Xunsigned freespace() {
X  	register int i, j;
X  	register struct mhead *p;
X  	register unsigned space = 0;
X	int local;	/* address only is used */
X
X	space = (char *)&local - sbrk(0);	/* stack space */
X
X  	for (i = 0; i < 30; i++) {
X  		for (j = 0, p = nextf[i]; p; p = CHAIN (p), j++) ;
X  		space += j * (1 << (i + 3));}
X
X	return(space);}
X
X/* How big is this cell? */
X
Xunsigned mc_size(cp)
X    char *cp;{
X	register struct mhead *p;
X
X	if ((p = (struct mhead *) cp) == 0) {
X		/*HMS? */
X		}
X	p--;
X#ifdef rcheck
X	return p -> mh_nbytes;
X#else
X	return (1 << (p -> mh_index + 3)) - sizeof *p;
X/**/
X/*	if (p -> mh_index >= 13)
X/*	    return (1 << (p -> mh_index + 3)) - sizeof *p;
X/*	else
X/*	    return p -> mh_size;
X/**/
X#endif /* rcheck */
X	}
X
X/*HMS: Really should use memcpy, if available... */
X
Xvoid bcopy(source, dest, len)
X    register char *source, *dest;
X    register len; {
X	register i;
X	
X	for (i = 0; i < len; i++)
X	    *dest++ = *source++;}
SHAR_EOF
if test 12262 -ne "`wc -c < 'malloc.c'`"
then
	echo shar: "error transmitting 'malloc.c'" '(should have been 12262 characters)'
fi
fi
echo shar: "extracting 'patch.c'" '(18908 characters)'
if test -f 'patch.c'
then
	echo shar: "will not over-write existing file 'patch.c'"
else
sed 's/^X//' << \SHAR_EOF > 'patch.c'
Xchar rcsid[] =
X	"$Header: patch.c,v 2.0.1.5 88/06/03 15:09:37 lwall Locked $";
X
X/* patch - a program to apply diffs to original files
X *
X * Copyright 1986, Larry Wall
X *
X * This program may be copied as long as you don't try to make any
X * money off of it, or pretend that you wrote it.
X *
X * $Log:	patch.c,v $
X * Revision 2.0.1.5  88/06/03  15:09:37  lwall
X * patch10: exit code improved.
X * patch10: better support for non-flexfilenames.
X * 
X * Revision 2.0.1.4  87/02/16  14:00:04  lwall
X * Short replacement caused spurious "Out of sync" message.
X * 
X * Revision 2.0.1.3  87/01/30  22:45:50  lwall
X * Improved diagnostic on sync error.
X * Moved do_ed_script() to pch.c.
X * 
X * Revision 2.0.1.2  86/11/21  09:39:15  lwall
X * Fuzz factor caused offset of installed lines.
X * 
X * Revision 2.0.1.1  86/10/29  13:10:22  lwall
X * Backwards search could terminate prematurely.
X * 
X * Revision 2.0  86/09/17  15:37:32  lwall
X * Baseline for netwide release.
X * 
X * Revision 1.5  86/08/01  20:53:24  lwall
X * Changed some %d's to %ld's.
X * Linted.
X * 
X * Revision 1.4  86/08/01  19:17:29  lwall
X * Fixes for machines that can't vararg.
X * Added fuzz factor.
X * Generalized -p.
X * General cleanup.
X * 
X * 85/08/15 van%ucbmonet at berkeley
X * Changes for 4.3bsd diff -c.
X *
X * Revision 1.3  85/03/26  15:07:43  lwall
X * Frozen.
X * 
X * Revision 1.2.1.9  85/03/12  17:03:35  lwall
X * Changed pfp->_file to fileno(pfp).
X * 
X * Revision 1.2.1.8  85/03/12  16:30:43  lwall
X * Check i_ptr and i_womp to make sure they aren't null before freeing.
X * Also allow ed output to be suppressed.
X * 
X * Revision 1.2.1.7  85/03/12  15:56:13  lwall
X * Added -p option from jromine at uci-750a.
X * 
X * Revision 1.2.1.6  85/03/12  12:12:51  lwall
X * Now checks for normalness of file to patch.
X * 
X * Revision 1.2.1.5  85/03/12  11:52:12  lwall
X * Added -D (#ifdef) option from joe at fluke.
X * 
X * Revision 1.2.1.4  84/12/06  11:14:15  lwall
X * Made smarter about SCCS subdirectories.
X * 
X * Revision 1.2.1.3  84/12/05  11:18:43  lwall
X * Added -l switch to do loose string comparison.
X * 
X * Revision 1.2.1.2  84/12/04  09:47:13  lwall
X * Failed hunk count not reset on multiple patch file.
X * 
X * Revision 1.2.1.1  84/12/04  09:42:37  lwall
X * Branch for sdcrdcf changes.
X * 
X * Revision 1.2  84/11/29  13:29:51  lwall
X * Linted.  Identifiers uniqified.  Fixed i_ptr malloc() bug.  Fixed
X * multiple calls to mktemp().  Will now work on machines that can only
X * read 32767 chars.  Added -R option for diffs with new and old swapped.
X * Various cosmetic changes.
X * 
X * Revision 1.1  84/11/09  17:03:58  lwall
X * Initial revision
X * 
X */
X
X#include "INTERN.h"
X#include "common.h"
X#include "EXTERN.h"
X#include "version.h"
X#include "util.h"
X#include "pch.h"
X#include "inp.h"
X
X/* procedures */
X
Xvoid reinitialize_almost_everything();
Xvoid get_some_switches();
XLINENUM locate_hunk();
Xvoid abort_hunk();
Xvoid apply_hunk();
Xvoid init_output();
Xvoid init_reject();
Xvoid copy_till();
Xvoid spew_output();
Xvoid dump_line();
Xbool patch_match();
Xbool similar();
Xvoid re_input();
Xvoid my_exit();
X
X/* Apply a set of diffs as appropriate. */
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X    LINENUM where;
X    LINENUM newwhere;
X    LINENUM fuzz;
X    LINENUM mymaxfuzz;
X    int hunk = 0;
X    int failed = 0;
X    int failtotal = 0;
X    int i;
X
X    setbuf(stderr, serrbuf);
X    for (i = 0; i<MAXFILEC; i++)
X	filearg[i] = Nullch;
X    Mktemp(TMPOUTNAME);
X    Mktemp(TMPINNAME);
X    Mktemp(TMPREJNAME);
X    Mktemp(TMPPATNAME);
X
X    /* parse switches */
X    Argc = argc;
X    Argv = argv;
X    get_some_switches();
X    
X    /* make sure we clean up /tmp in case of disaster */
X    set_signals(0);
X
X    for (
X	open_patch_file(filearg[1]);
X	there_is_another_patch();
X	reinitialize_almost_everything()
X    ) {					/* for each patch in patch file */
X
X	if (outname == Nullch)
X	    outname = savestr(filearg[0]);
X    
X	/* initialize the patched file */
X	if (!skip_rest_of_patch)
X	    init_output(TMPOUTNAME);
X    
X	/* for ed script just up and do it and exit */
X	if (diff_type == ED_DIFF) {
X	    do_ed_script();
X	    continue;
X	}
X    
X	/* initialize reject file */
X	init_reject(TMPREJNAME);
X    
X	/* find out where all the lines are */
X	if (!skip_rest_of_patch)
X	    scan_input(filearg[0]);
X    
X	/* from here on, open no standard i/o files, because malloc */
X	/* might misfire and we can't catch it easily */
X    
X	/* apply each hunk of patch */
X	hunk = 0;
X	failed = 0;
X	out_of_mem = FALSE;
X	while (another_hunk()) {
X	    hunk++;
X	    fuzz = Nulline;
X	    mymaxfuzz = pch_context();
X	    if (maxfuzz < mymaxfuzz)
X		mymaxfuzz = maxfuzz;
X	    if (!skip_rest_of_patch) {
X		do {
X		    where = locate_hunk(fuzz);
X		    if (hunk == 1 && where == Nulline && !force) {
X						/* dwim for reversed patch? */
X			if (!pch_swap()) {
X			    if (fuzz == Nulline)
X				say1(
X"Not enough memory to try swapped hunk!  Assuming unswapped.\n");
X			    continue;
X			}
X			reverse = !reverse;
X			where = locate_hunk(fuzz);  /* try again */
X			if (where == Nulline) {	    /* didn't find it swapped */
X			    if (!pch_swap())         /* put it back to normal */
X				fatal1("Lost hunk on alloc error!\n");
X			    reverse = !reverse;
X			}
X			else if (noreverse) {
X			    if (!pch_swap())         /* put it back to normal */
X				fatal1("Lost hunk on alloc error!\n");
X			    reverse = !reverse;
X			    say1(
X"Ignoring previously applied (or reversed) patch.\n");
X			    skip_rest_of_patch = TRUE;
X			}
X			else {
X			    ask3(
X"%seversed (or previously applied) patch detected!  %s -R? [y] ",
X				reverse ? "R" : "Unr",
X				reverse ? "Assume" : "Ignore");
X			    if (*buf == 'n') {
X				ask1("Apply anyway? [n] ");
X				if (*buf != 'y')
X				    skip_rest_of_patch = TRUE;
X				where = Nulline;
X				reverse = !reverse;
X				if (!pch_swap())  /* put it back to normal */
X				    fatal1("Lost hunk on alloc error!\n");
X			    }
X			}
X		    }
X		} while (!skip_rest_of_patch && where == Nulline &&
X		    ++fuzz <= mymaxfuzz);
X
X		if (skip_rest_of_patch) {		/* just got decided */
X		    Fclose(ofp);
X		    ofp = Nullfp;
X		}
X	    }
X
X	    newwhere = pch_newfirst() + last_offset;
X	    if (skip_rest_of_patch) {
X		abort_hunk();
X		failed++;
X		if (verbose)
X		    say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
X	    }
X	    else if (where == Nulline) {
X		abort_hunk();
X		failed++;
X		if (verbose)
X		    say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
X	    }
X	    else {
X		apply_hunk(where);
X		if (verbose) {
X		    say3("Hunk #%d succeeded at %ld", hunk, newwhere);
X		    if (fuzz)
X			say2(" with fuzz %ld", fuzz);
X		    if (last_offset)
X			say3(" (offset %ld line%s)",
X			    last_offset, last_offset==1L?"":"s");
X		    say1(".\n");
X		}
X	    }
X	}
X
X	if (out_of_mem && using_plan_a) {
X	    Argc = Argc_last;
X	    Argv = Argv_last;
X	    say1("\n\nRan out of memory using Plan A--trying again...\n\n");
X	    continue;
X	}
X    
X	assert(hunk);
X    
X	/* finish spewing out the new file */
X	if (!skip_rest_of_patch)
X	    spew_output();
X	
X	/* and put the output where desired */
X	ignore_signals();
X	if (!skip_rest_of_patch) {
X	    if (move_file(TMPOUTNAME, outname) < 0) {
X		toutkeep = TRUE;
X		chmod(TMPOUTNAME, filemode);
X	    }
X	    else
X		chmod(outname, filemode);
X	}
X	Fclose(rejfp);
X	rejfp = Nullfp;
X	if (failed) {
X	    failtotal += failed;
X	    if (!*rejname) {
X		Strcpy(rejname, outname);
X#ifndef FLEXFILENAMES
X		{
X		    char *s = rindex(rejname,'/');
X
X		    if (!s)
X			s = rejname;
X		    if (strlen(s) > 13)
X			if (s[12] == '.')	/* try to preserve difference */
X			    s[12] = s[13];	/* between .h, .c, .y, etc. */
X			s[13] = '\0';
X		}
X#endif
X		Strcat(rejname, REJEXT);
X	    }
X	    if (skip_rest_of_patch) {
X		say4("%d out of %d hunks ignored--saving rejects to %s\n",
X		    failed, hunk, rejname);
X	    }
X	    else {
X		say4("%d out of %d hunks failed--saving rejects to %s\n",
X		    failed, hunk, rejname);
X	    }
X	    if (move_file(TMPREJNAME, rejname) < 0)
X		trejkeep = TRUE;
X	}
X	set_signals(1);
X    }
X    my_exit(failtotal);
X}
X
X/* Prepare to find the next patch to do in the patch file. */
X
Xvoid
Xreinitialize_almost_everything()
X{
X    re_patch();
X    re_input();
X
X    input_lines = 0;
X    last_frozen_line = 0;
X
X    filec = 0;
X    if (filearg[0] != Nullch && !out_of_mem) {
X	free(filearg[0]);
X	filearg[0] = Nullch;
X    }
X
X    if (outname != Nullch) {
X	free(outname);
X	outname = Nullch;
X    }
X
X    last_offset = 0;
X
X    diff_type = 0;
X
X    if (revision != Nullch) {
X	free(revision);
X	revision = Nullch;
X    }
X
X    reverse = FALSE;
X    skip_rest_of_patch = FALSE;
X
X    get_some_switches();
X
X    if (filec >= 2)
X	fatal1("You may not change to a different patch file.\n");
X}
X
X/* Process switches and filenames up to next '+' or end of list. */
X
Xvoid
Xget_some_switches()
X{
X    Reg1 char *s;
X
X    rejname[0] = '\0';
X    Argc_last = Argc;
X    Argv_last = Argv;
X    if (!Argc)
X	return;
X    for (Argc--,Argv++; Argc; Argc--,Argv++) {
X	s = Argv[0];
X	if (strEQ(s, "+")) {
X	    return;			/* + will be skipped by for loop */
X	}
X	if (*s != '-' || !s[1]) {
X	    if (filec == MAXFILEC)
X		fatal1("Too many file arguments.\n");
X	    filearg[filec++] = savestr(s);
X	}
X	else {
X	    switch (*++s) {
X	    case 'b':
X		origext = savestr(Argv[1]);
X		Argc--,Argv++;
X		break;
X	    case 'B':
X		origprae = savestr(Argv[1]);
X		Argc--,Argv++;
X		break;
X	    case 'c':
X		diff_type = CONTEXT_DIFF;
X		break;
X	    case 'd':
X		if (!*++s) {
X		    Argc--,Argv++;
X		    s = Argv[0];
X		}
X		if (chdir(s) < 0)
X		    fatal2("Can't cd to %s.\n", s);
X		break;
X	    case 'D':
X	    	do_defines = TRUE;
X		if (!*++s) {
X		    Argc--,Argv++;
X		    s = Argv[0];
X		}
X		if (!isalpha(*s))
X		    fatal1("Argument to -D not an identifier.\n");
X		Sprintf(if_defined, "#ifdef %s\n", s);
X		Sprintf(not_defined, "#ifndef %s\n", s);
X		Sprintf(end_defined, "#endif /* %s */\n", s);
X		break;
X	    case 'e':
X		diff_type = ED_DIFF;
X		break;
X	    case 'f':
X		force = TRUE;
X		break;
X	    case 'F':
X		if (*++s == '=')
X		    s++;
X		maxfuzz = atoi(s);
X		break;
X	    case 'l':
X		canonicalize = TRUE;
X		break;
X	    case 'n':
X		diff_type = NORMAL_DIFF;
X		break;
X	    case 'N':
X		noreverse = TRUE;
X		break;
X	    case 'o':
X		outname = savestr(Argv[1]);
X		Argc--,Argv++;
X		break;
X	    case 'p':
X		if (*++s == '=')
X		    s++;
X		strippath = atoi(s);
X		break;
X	    case 'r':
X		Strcpy(rejname, Argv[1]);
X		Argc--,Argv++;
X		break;
X	    case 'R':
X		reverse = TRUE;
X		break;
X	    case 's':
X		verbose = FALSE;
X		break;
X	    case 'S':
X		skip_rest_of_patch = TRUE;
X		break;
X	    case 'v':
X		version();
X		break;
X#ifdef DEBUGGING
X	    case 'x':
X		debug = atoi(s+1);
X		break;
X#endif
X	    default:
X		fatal2("Unrecognized switch: %s\n", Argv[0]);
X	    }
X	}
X    }
X}
X
X/* Attempt to find the right place to apply this hunk of patch. */
X
XLINENUM
Xlocate_hunk(fuzz)
XLINENUM fuzz;
X{
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				- pat_lines + 1; 
X    Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
X				+ pch_context();
X
X    if (!pat_lines)			/* null range matches always */
X	return first_guess;
X    if (max_neg_offset >= first_guess)	/* do not try lines < 0 */
X	max_neg_offset = first_guess - 1;
X    if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
X	return first_guess;
X    for (offset = 1; ; offset++) {
X	Reg5 bool check_after = (offset <= max_pos_offset);
X	Reg6 bool check_before = (offset <= max_neg_offset);
X
X	if (check_after && patch_match(first_guess, offset, fuzz)) {
X#ifdef DEBUGGING
X	    if (debug & 1)
X		say3("Offset changing from %ld to %ld\n", last_offset, offset);
X#endif
X	    last_offset = offset;
X	    return first_guess+offset;
X	}
X	else if (check_before && patch_match(first_guess, -offset, fuzz)) {
X#ifdef DEBUGGING
X	    if (debug & 1)
X		say3("Offset changing from %ld to %ld\n", last_offset, -offset);
X#endif
X	    last_offset = -offset;
X	    return first_guess-offset;
X	}
X	else if (!check_before && !check_after)
X	    return Nulline;
X    }
X}
X
X/* We did not find the pattern, dump out the hunk so they can handle it. */
X
Xvoid
Xabort_hunk()
X{
X    Reg1 LINENUM i;
X    Reg2 LINENUM pat_end = pch_end();
X    /* add in last_offset to guess the same as the previous successful hunk */
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++) {
X	switch (pch_char(i)) {
X	case '*':
X	    if (oldlast < oldfirst)
X		fprintf(rejfp, "*** 0%s\n", stars);
X	    else if (oldlast == oldfirst)
X		fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
X	    else
X		fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
X	    break;
X	case '=':
X	    if (newlast < newfirst)
X		fprintf(rejfp, "--- 0%s\n", minuses);
X	    else if (newlast == newfirst)
X		fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
X	    else
X		fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
X	    break;
X	case '\n':
X	    fprintf(rejfp, "%s", pfetch(i));
X	    break;
X	case ' ': case '-': case '+': case '!':
X	    fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
X	    break;
X	default:
X	    say1("Fatal internal error in abort_hunk().\n"); 
X	    abort();
X	}
X    }
X}
X
X/* We found where to apply it (we hope), so do it. */
X
Xvoid
Xapply_hunk(where)
XLINENUM where;
X{
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) == '=' || pch_char(new) == '\n')
X	new++;
X    
X    while (old <= lastline) {
X	if (pch_char(old) == '-') {
X	    copy_till(where + old - 1);
X	    if (R_do_defines) {
X		if (def_state == OUTSIDE) {
X		    fputs(not_defined, ofp);
X		    def_state = IN_IFNDEF;
X		}
X		else if (def_state == IN_IFDEF) {
X		    fputs(else_defined, ofp);
X		    def_state = IN_ELSE;
X		}
X		fputs(pfetch(old), ofp);
X	    }
X	    last_frozen_line++;
X	    old++;
X	}
X	else if (new > pat_end)
X	    break;
X	else if (pch_char(new) == '+') {
X	    copy_till(where + old - 1);
X	    if (R_do_defines) {
X		if (def_state == IN_IFNDEF) {
X		    fputs(else_defined, ofp);
X		    def_state = IN_ELSE;
X		}
X		else if (def_state == OUTSIDE) {
X		    fputs(if_defined, ofp);
X		    def_state = IN_IFDEF;
X		}
X	    }
X	    fputs(pfetch(new), ofp);
X	    new++;
X	}
X	else {
X	    if (pch_char(new) != pch_char(old)) {
X		say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
X		    pch_hunk_beg() + old,
X		    pch_hunk_beg() + new);
X#ifdef DEBUGGING
X		say3("oldchar = '%c', newchar = '%c'\n",
X		    pch_char(old), pch_char(new));
X#endif
X		my_exit(1);
X	    }
X	    if (pch_char(new) == '!') {
X		copy_till(where + old - 1);
X		if (R_do_defines) {
X		   fputs(not_defined, ofp);
X		   def_state = IN_IFNDEF;
X		}
X		while (pch_char(old) == '!') {
X		    if (R_do_defines) {
X			fputs(pfetch(old), ofp);
X		    }
X		    last_frozen_line++;
X		    old++;
X		}
X		if (R_do_defines) {
X		    fputs(else_defined, ofp);
X		    def_state = IN_ELSE;
X		}
X		while (pch_char(new) == '!') {
X		    fputs(pfetch(new), ofp);
X		    new++;
X		}
X		if (R_do_defines) {
X		    fputs(end_defined, ofp);
X		    def_state = OUTSIDE;
X		}
X	    }
X	    else {
X		assert(pch_char(new) == ' ');
X		old++;
X		new++;
X	    }
X	}
X    }
X    if (new <= pat_end && pch_char(new) == '+') {
X	copy_till(where + old - 1);
X	if (R_do_defines) {
X	    if (def_state == OUTSIDE) {
X	    	fputs(if_defined, ofp);
X		def_state = IN_IFDEF;
X	    }
X	    else if (def_state == IN_IFNDEF) {
X		fputs(else_defined, ofp);
X		def_state = IN_ELSE;
X	    }
X	}
X	while (new <= pat_end && pch_char(new) == '+') {
X	    fputs(pfetch(new), ofp);
X	    new++;
X	}
X    }
X    if (R_do_defines && def_state != OUTSIDE) {
X	fputs(end_defined, ofp);
X    }
X}
X
X/* Open the new file. */
X
Xvoid
Xinit_output(name)
Xchar *name;
X{
X    ofp = fopen(name, "w");
X    if (ofp == Nullfp)
X	fatal2("patch: can't create %s.\n", name);
X}
X
X/* Open a file to put hunks we can't locate. */
X
Xvoid
Xinit_reject(name)
Xchar *name;
X{
X    rejfp = fopen(name, "w");
X    if (rejfp == Nullfp)
X	fatal2("patch: can't create %s.\n", name);
X}
X
X/* Copy input file to output, up to wherever hunk is to be applied. */
X
Xvoid
Xcopy_till(lastline)
XReg1 LINENUM lastline;
X{
X    Reg2 LINENUM R_last_frozen_line = last_frozen_line;
X
X    if (R_last_frozen_line > lastline)
X	say1("patch: misordered hunks! output will be garbled.\n");
X    while (R_last_frozen_line < lastline) {
X	dump_line(++R_last_frozen_line);
X    }
X    last_frozen_line = R_last_frozen_line;
X}
X
X/* Finish copying the input file to the output file. */
X
Xvoid
Xspew_output()
X{
X#ifdef DEBUGGING
X    if (debug & 256)
X	say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
X#endif
X    if (input_lines)
X	copy_till(input_lines);		/* dump remainder of file */
X    Fclose(ofp);
X    ofp = Nullfp;
X}
X
X/* Copy one line from input to output. */
X
Xvoid
Xdump_line(line)
XLINENUM line;
X{
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}
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{
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++) {
X	if (canonicalize) {
X	    if (!similar(ifetch(iline, (offset >= 0)),
X			 pfetch(pline),
X			 pch_line_len(pline) ))
X		return FALSE;
X	}
X	else if (strnNE(ifetch(iline, (offset >= 0)),
X		   pfetch(pline),
X		   pch_line_len(pline) ))
X	    return FALSE;
X    }
X    return TRUE;
X}
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{
X    while (len) {
X	if (isspace(*b)) {		/* whitespace (or \n) to match? */
X	    if (!isspace(*a))		/* no corresponding whitespace? */
X		return FALSE;
X	    while (len && isspace(*b) && *b != '\n')
X		b++,len--;		/* skip pattern whitespace */
X	    while (isspace(*a) && *a != '\n')
X		a++;			/* skip target whitespace */
X	    if (*a == '\n' || *b == '\n')
X		return (*a == *b);	/* should end in sync */
X	}
X	else if (*a++ != *b++)		/* match non-whitespace chars */
X	    return FALSE;
X	else
X	    len--;			/* probably not necessary */
X    }
X    return TRUE;			/* actually, this is not reached */
X					/* since there is always a \n */
X}
X
X/* Exit with cleanup. */
X
Xvoid
Xmy_exit(status)
Xint status;
X{
X    Unlink(TMPINNAME);
X    if (!toutkeep) {
X	Unlink(TMPOUTNAME);
X    }
X    if (!trejkeep) {
X	Unlink(TMPREJNAME);
X    }
X    Unlink(TMPPATNAME);
X    exit(status);
X}
SHAR_EOF
if test 18908 -ne "`wc -c < 'patch.c'`"
then
	echo shar: "error transmitting 'patch.c'" '(should have been 18908 characters)'
fi
fi
echo shar: "extracting 'util.h'" '(1972 characters)'
if test -f 'util.h'
then
	echo shar: "will not over-write existing file 'util.h'"
else
sed 's/^X//' << \SHAR_EOF > 'util.h'
X/* $Header: util.h,v 2.0 86/09/17 15:40:06 lwall Exp $
X *
X * $Log:	util.h,v $
X * Revision 2.0  86/09/17  15:40:06  lwall
X * Baseline for netwide release.
X * 
X */
X
X/* and for those machine that can't handle a variable argument list */
X
X#ifdef CANVARARG
X
X#define say1 say
X#define say2 say
X#define say3 say
X#define say4 say
X#define ask1 ask
X#define ask2 ask
X#define ask3 ask
X#define ask4 ask
X#define fatal1 fatal
X#define fatal2 fatal
X#define fatal3 fatal
X#define fatal4 fatal
X
X#else /* hope they allow multi-line macro actual arguments */
X
X#ifdef lint
X
X#define say1(a) say(a, 0, 0, 0)
X#define say2(a,b) say(a, (b)==(b), 0, 0)
X#define say3(a,b,c) say(a, (b)==(b), (c)==(c), 0)
X#define say4(a,b,c,d) say(a, (b)==(b), (c)==(c), (d)==(d))
X#define ask1(a) ask(a, 0, 0, 0)
X#define ask2(a,b) ask(a, (b)==(b), 0, 0)
X#define ask3(a,b,c) ask(a, (b)==(b), (c)==(c), 0)
X#define ask4(a,b,c,d) ask(a, (b)==(b), (c)==(c), (d)==(d))
X#define fatal1(a) fatal(a, 0, 0, 0)
X#define fatal2(a,b) fatal(a, (b)==(b), 0, 0)
X#define fatal3(a,b,c) fatal(a, (b)==(b), (c)==(c), 0)
X#define fatal4(a,b,c,d) fatal(a, (b)==(b), (c)==(c), (d)==(d))
X
X#else /* lint */
X    /* if this doesn't work, try defining CANVARARG above */
X#define say1(a) say(a, Nullch, Nullch, Nullch)
X#define say2(a,b) say(a, b, Nullch, Nullch)
X#define say3(a,b,c) say(a, b, c, Nullch)
X#define say4 say
X#define ask1(a) ask(a, Nullch, Nullch, Nullch)
X#define ask2(a,b) ask(a, b, Nullch, Nullch)
X#define ask3(a,b,c) ask(a, b, c, Nullch)
X#define ask4 ask
X#define fatal1(a) fatal(a, Nullch, Nullch, Nullch)
X#define fatal2(a,b) fatal(a, b, Nullch, Nullch)
X#define fatal3(a,b,c) fatal(a, b, c, Nullch)
X#define fatal4 fatal
X
X#endif /* lint */
X
X/* if neither of the above work, join all multi-line macro calls. */
X#endif
X
XEXT char serrbuf[BUFSIZ];		/* buffer for stderr */
X
Xchar *fetchname();
Xint move_file();
Xvoid copy_file();
Xvoid say();
Xvoid fatal();
Xvoid ask();
Xchar *savestr();
Xvoid set_signals();
Xvoid ignore_signals();
Xvoid makedirs();
SHAR_EOF
if test 1972 -ne "`wc -c < 'util.h'`"
then
	echo shar: "error transmitting 'util.h'" '(should have been 1972 characters)'
fi
fi
echo shar: "extracting 'version.c'" '(489 characters)'
if test -f 'version.c'
then
	echo shar: "will not over-write existing file 'version.c'"
else
sed 's/^X//' << \SHAR_EOF > 'version.c'
X/* $Header: version.c,v 2.0 86/09/17 15:40:11 lwall Exp $
X *
X * $Log:	version.c,v $
X * Revision 2.0  86/09/17  15:40:11  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 "patchlevel.h"
X#include "version.h"
X
X/* Print out the version number and die. */
X
Xvoid
Xversion()
X{
X    extern char rcsid[];
X
X#ifdef lint
X    rcsid[0] = rcsid[0];
X#else
X    fatal3("%s\nPatch level: %d\n", rcsid, PATCHLEVEL);
X#endif
X}
SHAR_EOF
if test 489 -ne "`wc -c < 'version.c'`"
then
	echo shar: "error transmitting 'version.c'" '(should have been 489 characters)'
fi
fi
echo shar: "extracting 'version.h'" '(185 characters)'
if test -f 'version.h'
then
	echo shar: "will not over-write existing file 'version.h'"
else
sed 's/^X//' << \SHAR_EOF > 'version.h'
X/* $Header: version.h,v 2.0 86/09/17 15:40:14 lwall Exp $
X *
X * $Log:	version.h,v $
X * Revision 2.0  86/09/17  15:40:14  lwall
X * Baseline for netwide release.
X * 
X */
X
Xvoid version();
SHAR_EOF
if test 185 -ne "`wc -c < 'version.h'`"
then
	echo shar: "error transmitting 'version.h'" '(should have been 185 characters)'
fi
fi
exit 0
#	End of shell archive



More information about the Unix-pc.sources mailing list