[mod.sources] v07i038: Release 2.0 of patch, Part01/03

sources-request@mirror.UUCP (10/27/86)

Submitted by: sdcrdcf!lwall (Larry Wall)
Mod.sources: Volume 7, Issue 38
Archive-name: patch2/Part01

Here is the official 2.0 release of patch.  It supersedes the 1.5 beta
version posted to net.sources, and the version that comes with 4.3bsd.

Larry Wall
sdcrdcf!lwall

--------------------------CUT HERE---------------------------
#! /bin/sh

# Make a new directory for the patch sources, cd to it, and run kits 1 thru 3 
# through sh.  When all 3 kits have been run, read README.

echo "This is patch kit 1 (of 3).  If kit 1 is complete, the line"
echo '"'"End of kit 1 (of 3)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting pch.c
sed >pch.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: pch.c,v 2.0 86/09/17 15:39:37 lwall Exp $
X *
X * $Log:	pch.c,v $
X * Revision 2.0  86/09/17  15:39:37  lwall
X * Baseline for netwide release.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "INTERN.h"
X#include "pch.h"
X
X/* Patch (diff listing) abstract type. */
X
Xstatic long p_filesize;			/* size of the patch file */
Xstatic LINENUM p_first;			/* 1st line number */
Xstatic LINENUM p_newfirst;		/* 1st line number of replacement */
Xstatic LINENUM p_ptrn_lines;		/* # lines in pattern */
Xstatic LINENUM p_repl_lines;		/* # lines in replacement text */
Xstatic LINENUM p_end = -1;		/* last line in hunk */
Xstatic LINENUM p_max;			/* max allowed value of p_end */
Xstatic LINENUM p_context = 3;		/* # of context lines */
Xstatic LINENUM p_input_line = 0;	/* current line # from patch file */
Xstatic char **p_line = Null(char**);	/* the text of the hunk */
Xstatic short *p_len = Null(short*);	/* length of each line */
Xstatic char *p_char = Nullch;		/* +, -, and ! */
Xstatic int hunkmax = INITHUNKMAX;	/* size of above arrays to begin with */
Xstatic int p_indent;			/* indent to patch */
Xstatic LINENUM p_base;			/* where to intuit this time */
Xstatic LINENUM p_start;			/* where intuit found a patch */
X
X/* Prepare to look for the next patch in the patch file. */
X
Xvoid
Xre_patch()
X{
X    p_first = Nulline;
X    p_newfirst = Nulline;
X    p_ptrn_lines = Nulline;
X    p_repl_lines = Nulline;
X    p_end = (LINENUM)-1;
X    p_max = Nulline;
X    p_indent = 0;
X}
X
X/* Open the patch file at the beginning of time. */
X
Xvoid
Xopen_patch_file(filename)
Xchar *filename;
X{
X    if (filename == Nullch || !*filename || strEQ(filename, "-")) {
X	pfp = fopen(TMPPATNAME, "w");
X	if (pfp == Nullfp)
X	    fatal2("patch: can't create %s.\n", TMPPATNAME);
X	while (fgets(buf, sizeof buf, stdin) != Nullch)
X	    fputs(buf, pfp);
X	Fclose(pfp);
X	filename = TMPPATNAME;
X    }
X    pfp = fopen(filename, "r");
X    if (pfp == Nullfp)
X	fatal2("patch file %s not found\n", filename);
X    Fstat(fileno(pfp), &filestat);
X    p_filesize = filestat.st_size;
X    next_intuit_at(0L);			/* start at the beginning */
X    set_hunkmax();
X}
X
X/* Make sure our dynamically realloced tables are malloced to begin with. */
X
Xvoid
Xset_hunkmax()
X{
X#ifndef lint
X    if (p_line == Null(char**))
X	p_line = (char**) malloc((MEM)hunkmax * sizeof(char *));
X    if (p_len == Null(short*))
X	p_len  = (short*) malloc((MEM)hunkmax * sizeof(short));
X#endif
X    if (p_char == Nullch)
X	p_char = (char*)  malloc((MEM)hunkmax * sizeof(char));
X}
X
X/* Enlarge the arrays containing the current hunk of patch. */
X
Xvoid
Xgrow_hunkmax()
X{
X    hunkmax *= 2;
X    /* 
X     * Note that on most systems, only the p_line array ever gets fresh memory
X     * since p_len can move into p_line's old space, and p_char can move into
X     * p_len's old space.  Not on PDP-11's however.  But it doesn't matter.
X     */
X    assert(p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch);
X#ifndef lint
X    p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *));
X    p_len  = (short*) realloc((char*)p_len,  (MEM)hunkmax * sizeof(short));
X    p_char = (char*)  realloc((char*)p_char, (MEM)hunkmax * sizeof(char));
X#endif
X    if (p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch)
X	return;
X    if (!using_plan_a)
X	fatal1("patch: out of memory (grow_hunkmax)\n");
X    out_of_mem = TRUE;		/* whatever is null will be allocated again */
X				/* from within plan_a(), of all places */
X}
X
X/* True if the remainder of the patch file contains a diff of some sort. */
X
Xbool
Xthere_is_another_patch()
X{
X    if (p_base != 0L && p_base >= p_filesize) {
X	if (verbose)
X	    say1("done\n");
X	return FALSE;
X    }
X    if (verbose)
X	say1("Hmm...");
X    diff_type = intuit_diff_type();
X    if (!diff_type) {
X	if (p_base != 0L) {
X	    if (verbose)
X		say1("  Ignoring the trailing garbage.\ndone\n");
X	}
X	else
X	    say1("  I can't seem to find a patch in there anywhere.\n");
X	return FALSE;
X    }
X    if (verbose)
X	say3("  %sooks like %s to me...\n",
X	    (p_base == 0L ? "L" : "The next patch l"),
X	    diff_type == CONTEXT_DIFF ? "a context diff" :
X	    diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
X	    diff_type == NORMAL_DIFF ? "a normal diff" :
X	    "an ed script" );
X    if (p_indent && verbose)
X	say3("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s");
X    skip_to(p_start);
X    while (filearg[0] == Nullch) {
X	if (force) {
X	    say1("No file to patch.  Skipping...\n");
X	    filearg[0] = savestr(bestguess);
X	    return TRUE;
X	}
X	ask1("File to patch: ");
X	if (*buf != '\n') {
X	    if (bestguess)
X		free(bestguess);
X	    bestguess = savestr(buf);
X	    filearg[0] = fetchname(buf, 0, FALSE);
X	}
X	if (filearg[0] == Nullch) {
X	    ask1("No file found--skip this patch? [n] ");
X	    if (*buf != 'y') {
X		continue;
X	    }
X	    if (verbose)
X		say1("Skipping patch...\n");
X	    filearg[0] = fetchname(bestguess, 0, TRUE);
X	    skip_rest_of_patch = TRUE;
X	    return TRUE;
X	}
X    }
X    return TRUE;
X}
X
X/* Determine what kind of diff is in the remaining part of the patch file. */
X
Xint
Xintuit_diff_type()
X{
X    Reg4 long this_line = 0;
X    Reg5 long previous_line;
X    Reg6 long first_command_line = -1;
X    Reg7 bool last_line_was_command = FALSE;
X    Reg8 bool this_is_a_command = FALSE;
X    Reg9 bool stars_last_line = FALSE;
X    Reg10 bool stars_this_line = FALSE;
X    Reg3 int indent;
X    Reg1 char *s;
X    Reg2 char *t;
X    char *indtmp = Nullch;
X    char *oldtmp = Nullch;
X    char *newtmp = Nullch;
X    char *indname = Nullch;
X    char *oldname = Nullch;
X    char *newname = Nullch;
X    Reg11 int retval;
X    bool no_filearg = (filearg[0] == Nullch);
X
X    ok_to_create_file = FALSE;
X    Fseek(pfp, p_base, 0);
X    for (;;) {
X	previous_line = this_line;
X	last_line_was_command = this_is_a_command;
X	stars_last_line = stars_this_line;
X	this_line = ftell(pfp);
X	indent = 0;
X	if (fgets(buf, sizeof buf, pfp) == Nullch) {
X	    if (first_command_line >= 0L) {
X					/* nothing but deletes!? */
X		p_start = first_command_line;
X		retval = ED_DIFF;
X		goto scan_exit;
X	    }
X	    else {
X		p_start = this_line;
X		retval = 0;
X		goto scan_exit;
X	    }
X	}
X	for (s = buf; *s == ' ' || *s == '\t'; s++) {
X	    if (*s == '\t')
X		indent += 8 - (indent % 8);
X	    else
X		indent++;
X	}
X	for (t=s; isdigit(*t) || *t == ','; t++) ; 
X	this_is_a_command = (isdigit(*s) &&
X	  (*t == 'd' || *t == 'c' || *t == 'a') );
X	if (first_command_line < 0L && this_is_a_command) { 
X	    first_command_line = this_line;
X	    p_indent = indent;		/* assume this for now */
X	}
X	if (!stars_last_line && strnEQ(s, "*** ", 4))
X	    oldtmp = savestr(s+4);
X	else if (strnEQ(s, "--- ", 4))
X	    newtmp = savestr(s+4);
X	else if (strnEQ(s, "Index:", 6))
X	    indtmp = savestr(s+6);
X	else if (strnEQ(s, "Prereq:", 7)) {
X	    for (t=s+7; isspace(*t); t++) ;
X	    revision = savestr(t);
X	    for (t=revision; *t && !isspace(*t); t++) ;
X	    *t = '\0';
X	    if (!*revision) {
X		free(revision);
X		revision = Nullch;
X	    }
X	}
X	if ((!diff_type || diff_type == ED_DIFF) &&
X	  first_command_line >= 0L &&
X	  strEQ(s, ".\n") ) {
X	    p_indent = indent;
X	    p_start = first_command_line;
X	    retval = ED_DIFF;
X	    goto scan_exit;
X	}
X	stars_this_line = strnEQ(s, "********", 8);
X	if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
X		 strnEQ(s, "*** ", 4)) {
X	    if (!atol(s+4))
X		ok_to_create_file = TRUE;
X	    /* if this is a new context diff the character just before */
X	    /* the newline is a '*'. */
X	    while (*s != '\n')
X		s++;
X	    p_indent = indent;
X	    p_start = previous_line;
X	    retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
X	    goto scan_exit;
X	}
X	if ((!diff_type || diff_type == NORMAL_DIFF) && 
X	  last_line_was_command &&
X	  (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {
X	    p_start = previous_line;
X	    p_indent = indent;
X	    retval = NORMAL_DIFF;
X	    goto scan_exit;
X	}
X    }
X  scan_exit:
X    if (no_filearg) {
X	if (indtmp != Nullch)
X	    indname = fetchname(indtmp, strippath, ok_to_create_file);
X	if (oldtmp != Nullch)
X	    oldname = fetchname(oldtmp, strippath, ok_to_create_file);
X	if (newtmp != Nullch)
X	    newname = fetchname(newtmp, strippath, ok_to_create_file);
X	if (oldname && newname) {
X	    if (strlen(oldname) < strlen(newname))
X		filearg[0] = savestr(oldname);
X	    else
X		filearg[0] = savestr(newname);
X	}
X	else if (oldname)
X	    filearg[0] = savestr(oldname);
X	else if (newname)
X	    filearg[0] = savestr(newname);
X	else if (indname)
X	    filearg[0] = savestr(indname);
X    }
X    if (bestguess) {
X	free(bestguess);
X	bestguess = Nullch;
X    }
X    if (filearg[0] != Nullch)
X	bestguess = savestr(filearg[0]);
X    else if (indtmp != Nullch)
X	bestguess = fetchname(indtmp, strippath, TRUE);
X    else {
X	if (oldtmp != Nullch)
X	    oldname = fetchname(oldtmp, strippath, TRUE);
X	if (newtmp != Nullch)
X	    newname = fetchname(newtmp, strippath, TRUE);
X	if (oldname && newname) {
X	    if (strlen(oldname) < strlen(newname))
X		bestguess = savestr(oldname);
X	    else
X		bestguess = savestr(newname);
X	}
X	else if (oldname)
X	    bestguess = savestr(oldname);
X	else if (newname)
X	    bestguess = savestr(newname);
X    }
X    if (indtmp != Nullch)
X	free(indtmp);
X    if (oldtmp != Nullch)
X	free(oldtmp);
X    if (newtmp != Nullch)
X	free(newtmp);
X    if (indname != Nullch)
X	free(indname);
X    if (oldname != Nullch)
X	free(oldname);
X    if (newname != Nullch)
X	free(newname);
X    return retval;
X}
X
X/* Remember where this patch ends so we know where to start up again. */
X
Xvoid
Xnext_intuit_at(file_pos)
Xlong file_pos;
X{
X    p_base = file_pos;
X}
X
X/* Basically a verbose fseek() to the actual diff listing. */
X
Xvoid
Xskip_to(file_pos)
Xlong file_pos;
X{
X    char *ret;
X
X    assert(p_base <= file_pos);
X    if (verbose && p_base < file_pos) {
X	Fseek(pfp, p_base, 0);
X	say1("The text leading up to this was:\n--------------------------\n");
X	while (ftell(pfp) < file_pos) {
X	    ret = fgets(buf, sizeof buf, pfp);
X	    assert(ret != Nullch);
X	    say2("|%s", buf);
X	}
X	say1("--------------------------\n");
X    }
X    else
X	Fseek(pfp, file_pos, 0);
X}
X
X/* True if there is more of the current diff listing to process. */
X
Xbool
Xanother_hunk()
X{
X    Reg1 char *s;
X    Reg8 char *ret;
X    Reg2 int context = 0;
X
X    while (p_end >= 0) {
X	free(p_line[p_end]);		/* Changed from postdecrement */
X	p_end--;			/* by Keenan Ross for BSD2.9  */
X    }
X    assert(p_end == -1);
X
X    p_max = hunkmax;			/* gets reduced when --- found */
X    if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
X	long line_beginning = ftell(pfp);
X					/* file pos of the current line */
X	LINENUM repl_beginning = 0;	/* index of --- line */
X	Reg4 LINENUM fillcnt = 0;	/* #lines of missing ptrn or repl */
X	Reg5 LINENUM fillsrc;		/* index of first line to copy */
X	Reg6 LINENUM filldst;		/* index of first missing line */
X	bool ptrn_spaces_eaten = FALSE;	/* ptrn was slightly misformed */
X	Reg9 bool repl_could_be_missing = TRUE;
X					/* no + or ! lines in this hunk */
X	bool repl_missing = FALSE;	/* we are now backtracking */
X	long repl_backtrack_position = 0;
X					/* file pos of first repl line */
X	Reg7 LINENUM ptrn_copiable = 0;
X					/* # of copiable lines in ptrn */
X
X	ret = pgets(buf, sizeof buf, pfp);
X	if (ret == Nullch || strnNE(buf, "********", 8)) {
X	    next_intuit_at(line_beginning);
X	    return FALSE;
X	}
X	p_context = 100;
X	while (p_end < p_max) {
X	    line_beginning = ftell(pfp);
X	    ret = pgets(buf, sizeof buf, pfp);
X	    if (ret == Nullch) {
X		if (p_max - p_end < 4)
X		    Strcpy(buf, "  \n");  /* assume blank lines got chopped */
X		else {
X		    if (repl_beginning && repl_could_be_missing) {
X			repl_missing = TRUE;
X			goto hunk_done;
X		    }
X		    fatal1("Unexpected end of file in patch.\n");
X		}
X	    }
X	    p_input_line++;
X	    p_char[++p_end] = *buf;
X	    p_line[p_end] = Nullch;
X	    switch (*buf) {
X	    case '*':
X		if (strnEQ(buf, "********", 8)) {
X		    if (repl_beginning && repl_could_be_missing) {
X			repl_missing = TRUE;
X			goto hunk_done;
X		    }
X		    else
X			fatal2("Unexpected end of hunk at line %ld.\n",
X			    p_input_line);
X		}
X		if (p_end != 0) {
X		    if (repl_beginning && repl_could_be_missing) {
X			repl_missing = TRUE;
X			goto hunk_done;
X		    }
X		    fatal3("Unexpected *** at line %ld: %s", p_input_line, buf);
X		}
X		context = 0;
X		p_line[p_end] = savestr(buf);
X		if (out_of_mem) {
X		    p_end--;
X		    return FALSE;
X		}
X		for (s=buf; *s && !isdigit(*s); s++) ;
X		if (!*s)
X		    goto malformed;
X		p_first = (LINENUM) atol(s);
X		while (isdigit(*s)) s++;
X		if (*s == ',') {
X		    for (; *s && !isdigit(*s); s++) ;
X		    if (!*s)
X			goto malformed;
X		    p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
X		}
X		else if (p_first)
X		    p_ptrn_lines = 1;
X		else {
X		    p_ptrn_lines = 0;
X		    p_first = 1;
X		}
X		break;
X	    case '-':
X		if (buf[1] == '-') {
X		    if (p_end != p_ptrn_lines + 1 &&
X			p_end != p_ptrn_lines + 2) {
X			if (p_end == 1) {
X			    /* `old' lines were omitted - set up to fill */
X			    /* them in from 'new' context lines. */
X			    p_end = p_ptrn_lines + 1;
X			    fillsrc = p_end + 1;
X			    filldst = 1;
X			    fillcnt = p_ptrn_lines;
X			}
X			else {
X			    if (repl_beginning && repl_could_be_missing){
X				repl_missing = TRUE;
X				goto hunk_done;
X			    }
X			    fatal3("Unexpected --- at line %ld: %s",
X				p_input_line, buf);
X			}
X		    }
X		    repl_beginning = p_end;
X		    repl_backtrack_position = ftell(pfp);
X		    p_line[p_end] = savestr(buf);
X		    if (out_of_mem) {
X			p_end--;
X			return FALSE;
X		    }
X		    p_char[p_end] = '=';
X		    for (s=buf; *s && !isdigit(*s); s++) ;
X		    if (!*s)
X			goto malformed;
X		    p_newfirst = (LINENUM) atol(s);
X		    while (isdigit(*s)) s++;
X		    if (*s == ',') {
X			for (; *s && !isdigit(*s); s++) ;
X			if (!*s)
X			    goto malformed;
X			p_repl_lines = ((LINENUM)atol(s)) - p_newfirst + 1;
X		    }
X		    else if (p_newfirst)
X			p_repl_lines = 1;
X		    else {
X			p_repl_lines = 0;
X			p_newfirst = 1;
X		    }
X		    p_max = p_repl_lines + p_end;
X		    if (p_max > MAXHUNKSIZE)
X			fatal4("Hunk too large (%ld lines) at line %ld: %s",
X			      p_max, p_input_line, buf);
X		    while (p_max >= hunkmax)
X			grow_hunkmax();
X		    if (p_repl_lines != ptrn_copiable)
X			repl_could_be_missing = FALSE;
X		    break;
X		}
X		goto change_line;
X	    case '+':  case '!':
X		repl_could_be_missing = FALSE;
X	      change_line:
X		if (!isspace(buf[1]) && buf[1] != '>' && buf[1] != '<' &&
X		  repl_beginning && repl_could_be_missing) {
X		    repl_missing = TRUE;
X		    goto hunk_done;
X		}
X		if (context > 0) {
X		    if (context < p_context)
X			p_context = context;
X		    context = -1000;
X		}
X		p_line[p_end] = savestr(buf+2);
X		if (out_of_mem) {
X		    p_end--;
X		    return FALSE;
X		}
X		break;
X	    case '\t': case '\n':	/* assume the 2 spaces got eaten */
X		if (repl_beginning && repl_could_be_missing &&
X		  (!ptrn_spaces_eaten || diff_type == NEW_CONTEXT_DIFF) ) {
X		    repl_missing = TRUE;
X		    goto hunk_done;
X		}
X		p_line[p_end] = savestr(buf);
X		if (out_of_mem) {
X		    p_end--;
X		    return FALSE;
X		}
X		if (p_end != p_ptrn_lines + 1) {
X		    ptrn_spaces_eaten |= (repl_beginning != 0);
X		    context++;
X		    if (!repl_beginning)
X			ptrn_copiable++;
X		    p_char[p_end] = ' ';
X		}
X		break;
X	    case ' ':
X		if (!isspace(buf[1]) &&
X		  repl_beginning && repl_could_be_missing) {
X		    repl_missing = TRUE;
X		    goto hunk_done;
X		}
X		context++;
X		if (!repl_beginning)
X		    ptrn_copiable++;
X		p_line[p_end] = savestr(buf+2);
X		if (out_of_mem) {
X		    p_end--;
X		    return FALSE;
X		}
X		break;
X	    default:
X		if (repl_beginning && repl_could_be_missing) {
X		    repl_missing = TRUE;
X		    goto hunk_done;
X		}
X		goto malformed;
X	    }
X	    /* set up p_len for strncmp() so we don't have to */
X	    /* assume null termination */
X	    if (p_line[p_end])
X		p_len[p_end] = strlen(p_line[p_end]);
X	    else
X		p_len[p_end] = 0;
X	}
X	
X    hunk_done:
X	if (p_end >=0 && !repl_beginning)
X	    fatal2("No --- found in patch at line %ld\n", pch_hunk_beg());
X
X	if (repl_missing) {
X	    
X	    /* reset state back to just after --- */
X	    for (p_end--; p_end > repl_beginning; p_end--)
X		free(p_line[p_end]);
X	    Fseek(pfp, repl_backtrack_position, 0);
X	    
X	    /* redundant 'new' context lines were omitted - set */
X	    /* up to fill them in from the old file context */
X	    fillsrc = 1;
X	    filldst = repl_beginning+1;
X	    fillcnt = p_repl_lines;
X	    p_end = p_max;
X	}
X
X	if (diff_type == CONTEXT_DIFF &&
X	  (fillcnt || ptrn_copiable > 2*p_context) ) {
X	    if (verbose)
X		say1("\
X(Fascinating--this is really a new-style context diff but without the telltale\n\
Xextra asterisks on the *** line that usually indicate the new style...)\n");
X	    diff_type = NEW_CONTEXT_DIFF;
X	}
X	
X	/* if there were omitted context lines, fill them in now */
X	if (fillcnt) {
X	    while (fillcnt-- > 0) {
X		while (p_char[fillsrc] != ' ')
X		    fillsrc++;
X		p_line[filldst] = p_line[fillsrc];
X		p_char[filldst] = p_char[fillsrc];
X		p_len[filldst] = p_len[fillsrc];
X		fillsrc++; filldst++;
X	    }
X	    while (fillsrc <= p_end && p_char[fillsrc] != ' ')
X		fillsrc++;
X#ifdef DEBUGGING
X	    if (debug & 64)
X		printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
X		    fillsrc,filldst,repl_beginning,p_end+1);
X#endif
X	    assert(fillsrc==p_end+1 || fillsrc==repl_beginning);
X	    assert(filldst==p_end+1 || filldst==repl_beginning);
X	}
X    }
X    else {				/* normal diff--fake it up */
X	char hunk_type;
X	Reg3 int i;
X	LINENUM min, max;
X	long line_beginning = ftell(pfp);
X
X	p_context = 0;
X	ret = pgets(buf, sizeof buf, pfp);
X	p_input_line++;
X	if (ret == Nullch || !isdigit(*buf)) {
X	    next_intuit_at(line_beginning);
X	    return FALSE;
X	}
X	p_first = (LINENUM)atol(buf);
X	for (s=buf; isdigit(*s); s++) ;
X	if (*s == ',') {
X	    p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1;
X	    while (isdigit(*s)) s++;
X	}
X	else
X	    p_ptrn_lines = (*s != 'a');
X	hunk_type = *s;
X	if (hunk_type == 'a')
X	    p_first++;			/* do append rather than insert */
X	min = (LINENUM)atol(++s);
X	for (; isdigit(*s); s++) ;
X	if (*s == ',')
X	    max = (LINENUM)atol(++s);
X	else
X	    max = min;
X	if (hunk_type == 'd')
X	    min++;
X	p_end = p_ptrn_lines + 1 + max - min + 1;
X	if (p_end > MAXHUNKSIZE)
X	    fatal4("Hunk too large (%ld lines) at line %ld: %s",
X		  p_end, p_input_line, buf);
X	while (p_end >= hunkmax)
X	    grow_hunkmax();
X	p_newfirst = min;
X	p_repl_lines = max - min + 1;
X	Sprintf(buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1);
X	p_line[0] = savestr(buf);
X	if (out_of_mem) {
X	    p_end = -1;
X	    return FALSE;
X	}
X	p_char[0] = '*';
X	for (i=1; i<=p_ptrn_lines; i++) {
X	    ret = pgets(buf, sizeof buf, pfp);
X	    p_input_line++;
X	    if (ret == Nullch)
X		fatal2("Unexpected end of file in patch at line %ld.\n",
X		  p_input_line);
X	    if (*buf != '<')
X		fatal2("< expected at line %ld of patch.\n", p_input_line);
X	    p_line[i] = savestr(buf+2);
X	    if (out_of_mem) {
X		p_end = i-1;
X		return FALSE;
X	    }
X	    p_len[i] = strlen(p_line[i]);
X	    p_char[i] = '-';
X	}
X	if (hunk_type == 'c') {
X	    ret = pgets(buf, sizeof buf, pfp);
X	    p_input_line++;
X	    if (ret == Nullch)
X		fatal2("Unexpected end of file in patch at line %ld.\n",
X		    p_input_line);
X	    if (*buf != '-')
X		fatal2("--- expected at line %ld of patch.\n", p_input_line);
X	}
X	Sprintf(buf, "--- %ld,%ld\n", min, max);
X	p_line[i] = savestr(buf);
X	if (out_of_mem) {
X	    p_end = i-1;
X	    return FALSE;
X	}
X	p_char[i] = '=';
X	for (i++; i<=p_end; i++) {
X	    ret = pgets(buf, sizeof buf, pfp);
X	    p_input_line++;
X	    if (ret == Nullch)
X		fatal2("Unexpected end of file in patch at line %ld.\n",
X		    p_input_line);
X	    if (*buf != '>')
X		fatal2("> expected at line %ld of patch.\n", p_input_line);
X	    p_line[i] = savestr(buf+2);
X	    if (out_of_mem) {
X		p_end = i-1;
X		return FALSE;
X	    }
X	    p_len[i] = strlen(p_line[i]);
X	    p_char[i] = '+';
X	}
X    }
X    if (reverse)			/* backwards patch? */
X	if (!pch_swap())
X	    say1("Not enough memory to swap next hunk!\n");
X#ifdef DEBUGGING
X    if (debug & 2) {
X	int i;
X	char special;
X
X	for (i=0; i <= p_end; i++) {
X	    if (i == p_ptrn_lines)
X		special = '^';
X	    else
X		special = ' ';
X	    fprintf(stderr, "%3d %c %c %s", i, p_char[i], special, p_line[i]);
X	    Fflush(stderr);
X	}
X    }
X#endif
X    if (p_end+1 < hunkmax)	/* paranoia reigns supreme... */
X	p_char[p_end+1] = '^';  /* add a stopper for apply_hunk */
X    return TRUE;
X
Xmalformed:
X    fatal3("Malformed patch at line %ld: %s", p_input_line, buf);
X		/* about as informative as "Syntax error" in C */
X    return FALSE;	/* for lint */
X}
X
X/* Input a line from the patch file, worrying about indentation. */
X
Xchar *
Xpgets(bf,sz,fp)
Xchar *bf;
Xint sz;
XFILE *fp;
X{
X    char *ret = fgets(bf, sz, fp);
X    Reg1 char *s;
X    Reg2 int indent = 0;
X
X    if (p_indent && ret != Nullch) {
X	for (s=buf; indent < p_indent && (*s == ' ' || *s == '\t'); s++) {
X	    if (*s == '\t')
X		indent += 8 - (indent % 7);
X	    else
X		indent++;
X	}
X	if (buf != s)
X	    Strcpy(buf, s);
X    }
X    return ret;
X}
X
X/* Reverse the old and new portions of the current hunk. */
X
Xbool
Xpch_swap()
X{
X    char **tp_line;		/* the text of the hunk */
X    short *tp_len;		/* length of each line */
X    char *tp_char;		/* +, -, and ! */
X    Reg1 LINENUM i;
X    Reg2 LINENUM n;
X    bool blankline = FALSE;
X    Reg3 char *s;
X
X    i = p_first;
X    p_first = p_newfirst;
X    p_newfirst = i;
X    
X    /* make a scratch copy */
X
X    tp_line = p_line;
X    tp_len = p_len;
X    tp_char = p_char;
X    p_line = Null(char**);	/* force set_hunkmax to allocate again */
X    p_len = Null(short*);
X    p_char = Nullch;
X    set_hunkmax();
X    if (p_line == Null(char**) || p_len == Null(short*) || p_char == Nullch) {
X#ifndef lint
X	if (p_line == Null(char**))
X	    free((char*)p_line);
X	p_line = tp_line;
X	if (p_len == Null(short*))
X	    free((char*)p_len);
X	p_len = tp_len;
X#endif
X	if (p_char == Nullch)
X	    free((char*)p_char);
X	p_char = tp_char;
X	return FALSE;		/* not enough memory to swap hunk! */
X    }
X
X    /* now turn the new into the old */
X
X    i = p_ptrn_lines + 1;
X    if (tp_char[i] == '\n') {		/* account for possible blank line */
X	blankline = TRUE;
X	i++;
X    }
X    for (n=0; i <= p_end; i++,n++) {
X	p_line[n] = tp_line[i];
X	p_char[n] = tp_char[i];
X	if (p_char[n] == '+')
X	    p_char[n] = '-';
X	p_len[n] = tp_len[i];
X    }
X    if (blankline) {
X	i = p_ptrn_lines + 1;
X	p_line[n] = tp_line[i];
X	p_char[n] = tp_char[i];
X	p_len[n] = tp_len[i];
X	n++;
X    }
X    assert(p_char[0] == '=');
X    p_char[0] = '*';
X    for (s=p_line[0]; *s; s++)
X	if (*s == '-')
X	    *s = '*';
X
X    /* now turn the old into the new */
X
X    assert(tp_char[0] == '*');
X    tp_char[0] = '=';
X    for (s=tp_line[0]; *s; s++)
X	if (*s == '*')
X	    *s = '-';
X    for (i=0; n <= p_end; i++,n++) {
X	p_line[n] = tp_line[i];
X	p_char[n] = tp_char[i];
X	if (p_char[n] == '-')
X	    p_char[n] = '+';
X	p_len[n] = tp_len[i];
X    }
X    assert(i == p_ptrn_lines + 1);
X    i = p_ptrn_lines;
X    p_ptrn_lines = p_repl_lines;
X    p_repl_lines = i;
X#ifndef lint
X    if (tp_line == Null(char**))
X	free((char*)tp_line);
X    if (tp_len == Null(short*))
X	free((char*)tp_len);
X#endif
X    if (tp_char == Nullch)
X	free((char*)tp_char);
X    return TRUE;
X}
X
X/* Return the specified line position in the old file of the old context. */
X
XLINENUM
Xpch_first()
X{
X    return p_first;
X}
X
X/* Return the number of lines of old context. */
X
XLINENUM
Xpch_ptrn_lines()
X{
X    return p_ptrn_lines;
X}
X
X/* Return the probable line position in the new file of the first line. */
X
XLINENUM
Xpch_newfirst()
X{
X    return p_newfirst;
X}
X
X/* Return the number of lines in the replacement text including context. */
X
XLINENUM
Xpch_repl_lines()
X{
X    return p_repl_lines;
X}
X
X/* Return the number of lines in the whole hunk. */
X
XLINENUM
Xpch_end()
X{
X    return p_end;
X}
X
X/* Return the number of context lines before the first changed line. */
X
XLINENUM
Xpch_context()
X{
X    return p_context;
X}
X
X/* Return the length of a particular patch line. */
X
Xshort
Xpch_line_len(line)
XLINENUM line;
X{
X    return p_len[line];
X}
X
X/* Return the control character (+, -, *, !, etc) for a patch line. */
X
Xchar
Xpch_char(line)
XLINENUM line;
X{
X    return p_char[line];
X}
X
X/* Return a pointer to a particular patch line. */
X
Xchar *
Xpfetch(line)
XLINENUM line;
X{
X    return p_line[line];
X}
X
X/* Return where in the patch file this hunk began, for error messages. */
X
XLINENUM
Xpch_hunk_beg()
X{
X    return p_input_line - p_end - 1;
X}
X
!STUFFY!FUNK!
echo Extracting Configure
sed >Configure <<'!STUFFY!FUNK!' -e 's/X//'
X#! /bin/sh
X#
X# If these # comments don't work, trim them.  Don't worry about any other
X# shell scripts, Configure will trim # comments from them for you.
X#
X# Note: if you are running ksh, be sure to say "sh Configure".
X#
X# (If you are trying to port this package to a machine without sh, I would
X# suggest you cut out the prototypical config.h from the end of Configure
X# and edit it to reflect your system.  Some packages may include samples
X# of config.h for certain machines, so you might look for one of those.)
X#
X# $Header: Configure,v 2.0 86/09/17 15:32:58 lwall Exp $
X#
X# $Log:	Configure,v $
X# Revision 2.0  86/09/17  15:32:58  lwall
X# Baseline for netwide release.
X# 
X#
X# Yes, you may rip this off to use in other distribution packages.
X#
X# (Note: this Configure script was generated automatically.  Rather than
X# working with this copy of Configure, you may wish to get metaconfig.)
X
Xdefine='define'
Xundef='/*undef'
X
Xd_eunice=''
Xeunicefix=''
Xloclist=''
Xexpr=''
Xsed=''
Xecho=''
Xcat=''
Xrm=''
Xmv=''
Xcp=''
Xtail=''
Xtr=''
Xmkdir=''
Xsort=''
Xuniq=''
Xgrep=''
Xtrylist=''
Xtest=''
Xinews=''
Xegrep=''
Xmore=''
Xpg=''
XMcc=''
Xvi=''
Xmailx=''
XLog=''
XHeader=''
Xbin=''
Xcc=''
Xcontains=''
Xcpp=''
Xd_index=''
Xd_void=''
Xiandd=''
Xlibc=''
Xmansrc=''
Xmanext=''
Xn=''
Xc=''
Xpackage=''
Xregisters=''
Xreg1=''
Xreg2=''
Xreg3=''
Xreg4=''
Xreg5=''
Xreg6=''
Xreg7=''
Xreg8=''
Xreg9=''
Xreg10=''
Xreg11=''
Xreg12=''
Xreg13=''
Xreg14=''
Xreg15=''
Xreg16=''
Xspitshell=''
Xshsharp=''
Xsharpbang=''
Xstartsh=''
XCONFIG=''
X
Xpackage=patch
X
Xecho "Beginning of configuration questions for $package kit."
X: Eunice requires " " instead of "", can you believe it
Xecho " "
X
X: sanity checks
XPATH='.:/bin:/usr/bin:/usr/local/bin:/usr/ucb:/usr/local:/usr/lbin:/etc'
Xexport PATH || (echo "OOPS, this isn't sh.  Desperation time.  I will feed myself to sh."; sh $0; kill $$)
X
Xif test ! -t 0; then
X    echo "Say 'sh Configure', not 'sh <Configure'"
X    exit 1
Xfi
X
X: some greps do not return status, grrr.
Xecho "grimblepritz" >grimble
Xif grep blurfldyick grimble >/dev/null 2>&1 ; then
X    contains=contains
Xelse
X    if grep grimblepritz grimble >/dev/null 2>&1 ; then
X	contains=grep
X    else
X	contains=contains
X    fi
Xfi
Xrm -f grimble
X: the following should work in any shell
Xcase "$contains" in
Xcontains*)
X    echo " "
X    echo "AGH!  Grep doesn't return a status.  Attempting remedial action."
X    cat >contains <<'EOSS'
Xgrep "$1" "$2" >.greptmp && cat .greptmp && test -s .greptmp
XEOSS
Xchmod 755 contains
Xesac
X
X: first determine how to suppress newline on echo command
Xecho "Checking echo to see how to suppress newlines..."
X(echo "hi there\c" ; echo " ") >.echotmp
Xif $contains c .echotmp >/dev/null 2>&1 ; then
X    echo "...using -n."
X    n='-n'
X    c=''
Xelse
X    echo "...using \\\c"
X    echo "c."
X    n=''
X    c='\c'
Xfi
Xecho $n "Type carriage return to continue.  Your cursor should be here-->$c"
Xread ans
Xrm -f .echotmp
X
X: now set up to do reads with possible shell escape
X: if this does not work on your machine, 1,$ s/. myread/read ans/
Xcat <<EOSC >myread
Xans='!'
Xwhile expr "X\$ans" : "X!" >/dev/null; do
X    read ans
X    case "\$ans" in
X    !)
X	sh
X	echo " "
X	echo $n "\$rp $c"
X	;;
X    !*)
X	set \`expr "X\$ans" : "X!\(.*\)\$"\`
X	sh -c "\$*"
X	echo " "
X	echo $n "\$rp $c"
X	;;
X    esac
Xdone
Xrp='Your answer:'
XEOSC
X
X: general instructions
Xcat <<EOH
X 
XThis installation shell script will examine your system and ask you questions
Xto determine how $package and any auxiliary files should be installed.  If you
Xget stuck on a question, you may use a ! shell escape to start a subshell or
Xexecute a command.  Many of the questions will have default answers in
Xsquare brackets--typing carriage return will give you the default.
X
XOn some of the questions which ask for file or directory names you are
Xallowed to use the ~name construct to specify the login directory belonging
Xto "name", even if you don't have a shell which knows about that.  Questions
Xwhere this is allowed will be marked "(~name ok)".
XEOH
Xrp="[Type carriage return to continue]"
Xecho $n "$rp $c"
X. myread
Xcat <<EOH
XMuch effort has been expended to ensure that this shell script will run
Xon any Unix system.  If despite that it blows up on you, your best bet is
Xto edit Configure and run it again.  (Trying to install this package
Xwithout having run Configure may be well nigh impossible.)  Also, let me
X(lwall@sdcrdcf.UUCP) know how I blew it.
X
XThis installation script affects things in two ways: 1) it may do direct
Xvariable substitutions on some of the files included in this kit, and
X2) it builds a config.h file for inclusion in C programs.  You may edit
Xany of these files as the need arises after running this script.
X
XEOH
Xrp="[Type carriage return to continue]"
Xecho $n "$rp $c"
X. myread
X
X: get old answers, if there is a config file out there
Xif test -f config.sh; then
X    echo " "
X    rp="I see a config.sh file.  Did Configure make it on THIS system? [y]"
X    echo $n "$rp $c"
X    . myread
X    case "$ans" in
X    n*) echo "OK, I'll ignore it.";;
X    *)  echo "Fetching default answers from your old config.sh file..."
X        . config.sh
X	;;
X    esac
Xfi
X
X: get list of predefined functions in a handy place
Xecho " "
Xif test -f /lib/libc.a; then
X    echo "Your C library is in /lib/libc.a.  You're normal."
X    libc=/lib/libc.a
Xelse
X    if test -f /usr/lib/libc.a; then
X	echo "Your C library is in /usr/lib/libc.a, of all places."
X	libc=/usr/lib/libc.a
X    else
X	if test -f "$libc"; then
X	    echo "Your C library is in $libc, like you said before."
X	else
X	    cat <<'EOM'
X 
XI can't seem to find your C library.  I've looked for /lib/libc.a and
X/usr/lib/libc.a, but neither of those are there.  What is the full name
XEOM
X	    echo $n "of your C library? $c"
X	    rp='C library full name?'
X	    . myread
X	    libc="$ans"
X	fi
X    fi
Xfi
Xecho " "
Xecho $n "Extracting names from $libc for later perusal...$c"
Xif ar t $libc > libc.list; then
X    echo "done"
Xelse
X    echo " "
X    echo "The archiver doesn't think $libc is a reasonable library."
X    exit 1
Xfi
X
X: make some quick guesses about what we are up against
Xecho " "
Xecho $n "Hmm...  $c"
Xif $contains SIGTSTP /usr/include/signal.h >/dev/null 2>&1 ; then
X    echo "Looks kind of like a BSD system, but we'll see..."
X    echo exit 0 >bsd
X    echo exit 1 >usg
X    echo exit 1 >v7
Xelse
X    if $contains fcntl libc.list >/dev/null 2>&1 ; then
X	echo "Looks kind of like a USG system, but we'll see..."
X	echo exit 1 >bsd
X	echo exit 0 >usg
X	echo exit 1 >v7
X    else
X	echo "Looks kind of like a version 7 system, but we'll see..."
X	echo exit 1 >bsd
X	echo exit 1 >usg
X	echo exit 0 >v7
X    fi
Xfi
Xif $contains vmssystem libc.list >/dev/null 2>&1 ; then
X    cat <<'EOI'
XThere is, however, a strange, musty smell in the air that reminds me of
Xsomething...hmm...yes...I've got it...there's a VMS nearby, or I'm a Blit.
XEOI
X    echo "exit 0" >eunice
X    eunicefix=unixtovms
X    d_eunice="$define"
X: it so happens the Eunice I know will not run shell scripts in Unix format
Xelse
X    echo " "
X    echo "Congratulations.  You aren't running Eunice."
X    eunicefix=':'
X    d_eunice="$undef"
X    echo "exit 1" >eunice
Xfi
Xchmod 755 bsd usg v7 eunice
X$eunicefix bsd usg v7 eunice
X
X: see if sh knows # comments
Xecho " "
Xecho "Checking your sh to see if it knows about # comments..."
Xif sh -c '#' >/dev/null 2>&1 ; then
X    echo "Your sh handles # comments correctly."
X    shsharp=true
X    spitshell=cat
X    echo " "
X    echo "Okay, let's see if #! works on this system..."
X    echo "#!/bin/echo hi" > try
X    $eunicefix try
X    chmod 755 try
X    try > today
X    if test -s today; then
X	echo "It does."
X	sharpbang='#!'
X    else
X	echo "#! /bin/echo hi" > try
X	$eunicefix try
X	chmod 755 try
X	try > today
X	if test -s today; then
X	    echo "It does."
X	    sharpbang='#! '
X	else
X	    echo "It doesn't."
X	    sharpbang=': use '
X	fi
X    fi
Xelse
X    echo "Your sh doesn't grok # comments--I will strip them later on."
X    shsharp=false
X    echo "exec grep -v '^#'" >spitshell
X    chmod 755 spitshell
X    $eunicefix spitshell
X    spitshell=`pwd`/spitshell
X    echo "I presume that if # doesn't work, #! won't work either!"
X    sharpbang=': use '
Xfi
X
X: figure out how to guarantee sh startup
Xecho " "
Xecho "Checking out how to guarantee sh startup..."
Xstartsh=$sharpbang'/bin/sh'
Xecho "Let's see if '$startsh' works..."
Xcat >try <<EOSS
X$startsh
Xset abc
Xtest "$?abc" != 1
XEOSS
X
Xchmod 755 try
X$eunicefix try
Xif try; then
X    echo "Yup, it does."
Xelse
X    echo "Nope.  You may have to fix up the shell scripts to make sure sh runs them."
Xfi
Xrm -f try today
X
X: find out where common programs are
Xecho " "
Xecho "Locating common programs..."
Xpth="/usr/ucb /bin /usr/bin /usr/local /usr/local/bin /usr/lbin /etc /usr/lib"
Xcat <<EOSC >loc
X$startsh
Xthing=\$1
Xshift
Xdflt=\$1
Xshift
Xfor dir in \$*; do
X    case "\$thing" in
X    .)
X	if test -d \$dir/\$thing; then
X	    echo \$dir
X	    exit 0
X	fi
X	;;
X    *)
X	if test -f \$dir/\$thing; then
X	    echo \$dir/\$thing
X	    exit 0
X	fi
X	;;
X    esac
Xdone
Xecho \$dflt
Xexit 1
XEOSC
Xchmod 755 loc
X$eunicefix loc
Xloclist="
Xexpr
Xsed
Xecho
Xcat
Xrm
Xgrep
X"
Xtrylist="
Xtest
XMcc
X"
Xfor file in $loclist; do
X    xxx=`loc $file $file $pth`
X    eval $file=$xxx
X    case "$xxx" in
X    /*)
X	echo $file is in $xxx.
X	;;
X    *)
X	echo "I don't know where $file is.  I hope it's in everyone's PATH."
X	;;
X    esac
Xdone
Xecho " "
Xecho "Don't worry if any of the following aren't found..."
Xans=offhand
Xfor file in $trylist; do
X    xxx=`loc $file $file $pth`
X    eval $file=$xxx
X    case "$xxx" in
X    /*)
X	echo $file is in $xxx.
X	;;
X    *)
X	echo "I don't see $file out there, $ans."
X	ans=either
X	;;
X    esac
Xdone
Xcase "$egrep" in
Xegrep)
X    echo "Substituting grep for egrep."
X    egrep=$grep
X    ;;
Xesac
Xcase "$test" in
Xtest)
X    echo "Hopefully test is built into your sh."
X    ;;
X/bin/test)
X    echo " "
X    echo $n 'Is your "test" built into sh? [n] (OK to guess) '"$c"
X    rp='test built into sh? [n]'
X    . myread
X    case "$ans" in
X    y*) test=test ;;
X    esac
X    ;;
X*)
X    test=test
X    ;;
Xesac
Xcase "$echo" in
Xecho)
X    echo "Hopefully echo is built into your sh."
X    ;;
X/bin/echo)
X    echo " "
X    echo "Checking compatibility between /bin/echo and builtin echo (if any)..."
X    $echo $n "hi there$c" >foo1
X    echo $n "hi there$c" >foo2
X    if cmp foo1 foo2 >/dev/null 2>&1; then
X	echo "They are compatible.  In fact, they may be identical."
X    else
X	echo "They are not compatible--the echo builtin will be used."
X	echo=echo
X    fi
X    $rm -f foo1 foo2
X    ;;
X*)
X    echo=echo
X    ;;
Xesac
X
X: index or strcpy
X$echo " "
Xif $contains index libc.list >/dev/null 2>&1 ; then
X    $echo "Your system appears to use index() and rindex() rather than strchr()"
X    $echo $n "and strrchr().  Is this correct? [y] $c"
X    rp='index() rather than strchr()? [y]'
X    . myread
X    case "$ans" in
X	n*|f*) d_index="$define" ;;
X	*)     d_index="$undef" ;;
X    esac
Xelse
X    $echo "Your system appears to use strchr() and strrchr() rather than index()"
X    $echo $n "and rindex().  Is this correct? [y] $c"
X    rp='strchr() rather than index()? [y]'
X    . myread
X    case "$ans" in
X	n*|f*) d_index="$undef" ;;
X	*)     d_index="$define" ;;
X    esac
Xfi
X
X: check for void type
X$echo " "
X$echo "Checking to see if your C compiler groks the void type..."
X$cat >try.c <<'EOCP'
Xvoid main();
XEOCP
Xif cc -c try.c >/dev/null 2>&1 ; then
X    d_void="$undef"
X    $echo "Yup, it does."
Xelse
X    d_void="$define"
X    $echo "Nope, it doesn't (boo hiss).  I will substitute int."
Xfi
X$rm -f try.*
X
X: see how we invoke the C preprocessor
Xecho " "
Xecho "Checking to see how your C preprocessor is invoked..."
Xcat <<'EOT' >testcpp.c
X#define ABC abc
X#define XYZ xyz
XABC.XYZ
XEOT
Xecho 'Maybe "cc -E" will work...'
Xcc -E testcpp.c >testcpp.out 2>&1
Xif $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
X    echo "Yup, it does."
X    cpp='cc -E'
Xelse
X    echo 'Nope...maybe "cc -P" will work...'
X    cc -P testcpp.c >testcpp.out 2>&1
X    if $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
X	echo "Yup, that does."
X	cpp='cc -P'
X    else
X	echo 'Nixed again...maybe "/lib/cpp" will work...'
X	/lib/cpp testcpp.c >testcpp.out 2>&1
X	if $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
X	    echo "Hooray, it works!  I was beginning to wonder."
X	    cpp='/lib/cpp'
X	else
X	    echo 'Hmm...maybe you already told me...'
X	    case "$cpp" in
X	    '') ;;
X	    *) $cpp testcpp.c >testcpp.out 2>&1;;
X	    esac
X	    if $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
X		echo "Hooray, you did!  I was beginning to wonder."
X	    else
X		echo $n "Nope. I can't find a C preprocessor.  Name one: $c"
X		rp='Name a C preprocessor:'
X		. myread
X		cpp="$ans"
X		$cpp testcpp.c >testcpp.out 2>&1
X		if $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
X		    echo "OK, that will do."
X		else
X		    echo "Sorry, I can't get that to work.  Go find one."
X		    exit 1
X		fi
X	    fi
X	fi
X    fi
Xfi
Xrm -f testcpp.c testcpp.out
X
X: get C preprocessor symbols handy
Xecho " "
Xcat <<'EOT' >Cppsym.c
Xchar *sym[] = {
X#ifdef mc68000
X	"mc68000",
X#endif
X#ifdef sun
X	"sun",
X#endif
X#ifdef gcos
X	"gcos",
X#endif
X#ifdef unix
X	"unix",
X#endif
X#ifdef ibm
X	"ibm",
X#endif
X#ifdef gimpel
X	"gimpel",
X#endif
X#ifdef interdata
X	"interdata",
X#endif
X#ifdef tss
X	"tss",
X#endif
X#ifdef os
X	"os",
X#endif
X#ifdef mert
X	"mert",
X#endif
X#ifdef pyr
X	"pyr",
X#endif
X#ifdef vax
X	"vax",
X#endif
X#ifdef pdp11
X	"pdp11",
X#endif
X#ifdef i8086
X	"i8086",
X#endif
X#ifdef z8000
X	"z8000",
X#endif
X#ifdef 3b2
X	"3b2",
X#endif
X#ifdef 3b5
X	"3b5",
X#endif
X#ifdef 3b20
X	"3b20",
X#endif
X#ifdef 3b200
X	"3b200",
X#endif
X0};
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X    int i;
X
X    for (argc--,argv++; argc; argc--,argv++) {
X	for (i=0; sym[i]; i++) {
X	    if (strcmp(argv[0],sym[i]) == 0)
X		exit(0);
X	}
X    }
X    exit(1);
X}
XEOT
Xecho "Your machine appears to have the following attributes:"
X$cpp Cppsym.c | sed -n -e 's/^	"\(.*\)",$/\1/p'
Xcc Cppsym.c -o Cppsym
Xrm -f Cppsym.c
X
X: see how many register declarations we want to use
Xcase "$registers" in
X'')
X    if Cppsym pdp11 i8086 z8000; then
X	dflt=3
X    else
X	if Cppsym sun mc68000; then
X	    dflt=10
X	else
X	    : if you have any other numbers for me, send them in
X	    dflt=6
X	fi
X    fi
X    ;;
X*)  dflt=$registers ;;
Xesac
Xcat <<EOM
X 
XDifferent C compilers on different machines pay attention to different
Xnumbers of register declarations.  About how many register declarations in
XEOM
X$echo $n "each routine does your C compiler pay attention to? (OK to guess) [$dflt] $c"
Xrp="# register declarations used? [$dflt]"
X. myread
Xcase "$ans" in
X'') ans=$dflt;;
Xesac
Xregisters=$ans
Xreg1=''
Xawk "END { for (i=1; i<=16; i++) printf \"reg%d=''\n\", i}" </dev/null >.foo
X. .foo
Xawk "END { for (i=1; i<=$registers; i++) printf \"reg%d=register\n\", i}" \
X	</dev/null >.foo
X. .foo
Xrm -f .foo
X
X: preserve RCS keywords in files with variable substitution, grrr
XLog='$Log'
XHeader='$Header'
X
X: set up shell script to do ~ expansion
Xcat >filexp <<EOSS
X$startsh
X: expand filename
Xcase "\$1" in
X~/*|~)
X    $echo \$1 | $sed "s|~|\${HOME-\$LOGDIR}|"
X    ;;
X~*)
X    if $test -f /bin/csh; then
X	/bin/csh -f -c "glob \$1"
X	$echo ""
X    else
X	name=\`$expr x\$1 : '..\([^/]*\)'\`
X	dir=\`$sed </etc/passwd -n -e "/^\${name}:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\).*"'\$'"/\1/" -e p -e q -e '}'\`
X	if $test ! -d "\$dir"; then
X	    me=\`basename \$0\`
X	    $echo "\$me: can't locate home directory for: \$name" >&2
X	    exit 1
X	fi
X	case "\$1" in
X	*/*)
X	    $echo \$dir/\`$expr x\$1 : '..[^/]*/\(.*\)'\`
X	    ;;
X	*)
X	    $echo \$dir
X	    ;;
X	esac
X    fi
X    ;;
X*)
X    $echo \$1
X    ;;
Xesac
XEOSS
Xchmod 755 filexp
X$eunicefix filexp
X
X: determine where public executables go
Xcase "$bin" in
X'')
X    dflt=`loc . /bin /usr/local/bin /usr/lbin /usr/local /usr/bin`
X    ;;
X*)  dflt="$bin"
X    ;;
Xesac
Xbin='blurfl/dyick'
Xwhile $test ! -d "$bin" ; do
X    case "$bin" in
X      blurfl*) ;;
X      *) $echo "$bin does not appear to exist." ;;
X    esac
X    $echo " "
X    rp="Where do you want to put the public executables? [$dflt]"
X    $echo $n "$rp $c"
X    . myread
X    bin="$ans"
X    bin=`filexp $bin`
X    case "$bin" in
X      '') bin=$dflt ;;
X    esac
Xdone
X
X: determine where manual pages go
Xcase "$mansrc" in
X'')
X    dflt=`loc . /usr/man/man1 /usr/man/mann /usr/man/local/man1 /usr/man/u_man/man1 /usr/man/man1`
X    ;;
X*)  dflt="$mansrc"
X    ;;
Xesac
Xmansrc='blurfl/dyick'
Xwhile $test ! -d "$mansrc" ; do
X    case "$mansrc" in
X      blurfl*) ;;
X      *) $echo "$mansrc does not appear to exist." ;;
X    esac
X    $echo " "
X    rp="Where do the manual pages (source) go? [$dflt]"
X    $echo $n "$rp $c"
X    . myread
X    mansrc=`filexp "$ans"`
X    case "$mansrc" in
X      '') mansrc=$dflt ;;
X    esac
Xdone
Xcase "$mansrc" in
X*l)
X    manext=l
X    ;;
X*n)
X    manext=n
X    ;;
X*)
X    manext=1
X    ;;
Xesac
X
X: see if we need a special compiler
X$echo " "
Xif usg; then
X    case "$cc" in
X    '')
X	case "$Mcc" in
X	/*) dflt='Mcc'
X	    ;;
X	*)
X	    if $contains '\-M' $mansrc/cc.1 >/dev/null 2>&1 ; then
X		dflt='cc -M'
X	    else
X		dflt='cc'
X	    fi
X	    ;;
X	esac
X	;;
X    *)  dflt="$cc";;
X    esac
X    $cat <<'EOM'
X 
XOn some systems the default C compiler will not resolve multiple global
Xreferences that happen to have the same name.  On some such systems the
X"Mcc" command may be used to force these to be resolved.  On other systems
Xa "cc -M" command is required.  What command will force resolution on
XEOM
X    $echo $n "this system? [$dflt] $c"
X    rp="Command to resolve multiple refs? [$dflt]"
X    . myread
X    cc="$ans"
X    case "$cc" in
X	'') cc="$dflt" ;;
X    esac
Xelse
X    $echo "Not a USG system--assuming cc can resolve multiple definitions."
X    cc=cc
Xfi
X
X: see if we should throw a -i into the Makefile
X$echo " "
Xif Cppsym pdp11 i8086 z8000; then
X    if $contains '\-i' $mansrc/cc.1 >/dev/null 2>&1 ; then
X	rp="Your system appears to have separate I and D space.  Is this true? [y]"
X	$echo $n "$rp $c"
X	. myread
X	case "$ans" in
X	    n*|f*) iandd='' ;;
X	    *)     iandd='-i' ;;
X	esac
X    else
X	$echo "Your system appears to NOT have separate I and D space."
X	$echo $n "Is this correct? [y] $c"
X	rp='No separate I and D.  Correct? [y]'
X	. myread
X	case "$ans" in
X	    n*|f*) iandd='-i' ;;
X	    *)     iandd='' ;;
X	esac
X    fi
Xelse
X    $echo $n "Does your machine have separate I and D space? [n] $c"
X    . myread
X    case "$ans" in
X	y*)    iandd='-i' ;;
X	*)     iandd='' ;;
X    esac
Xfi
X
X$echo " "
X$echo "End of configuration questions."
X$echo " "
X
X: create config.sh file
X$echo " "
X$echo "Creating config.sh..."
X$spitshell <<EOT >config.sh
X$startsh
X# config.sh
X# This file was produced by running the Configure script.
X
Xd_eunice='$d_eunice'
Xeunicefix='$eunicefix'
Xloclist='$loclist'
Xexpr='$expr'
Xsed='$sed'
Xecho='$echo'
Xcat='$cat'
Xrm='$rm'
Xmv='$mv'
Xcp='$cp'
Xtail='$tail'
Xtr='$tr'
Xmkdir='$mkdir'
Xsort='$sort'
Xuniq='$uniq'
Xgrep='$grep'
Xtrylist='$trylist'
Xtest='$test'
Xinews='$inews'
Xegrep='$egrep'
Xmore='$more'
Xpg='$pg'
XMcc='$Mcc'
Xvi='$vi'
Xmailx='$mailx'
XLog='$Log'
XHeader='$Header'
Xbin='$bin'
Xcc='$cc'
Xcontains='$contains'
Xcpp='$cpp'
Xd_index='$d_index'
Xd_void='$d_void'
Xiandd='$iandd'
Xlibc='$libc'
Xmansrc='$mansrc'
Xmanext='$manext'
Xn='$n'
Xc='$c'
Xpackage='$package'
Xregisters='$registers'
Xreg1='$reg1'
Xreg2='$reg2'
Xreg3='$reg3'
Xreg4='$reg4'
Xreg5='$reg5'
Xreg6='$reg6'
Xreg7='$reg7'
Xreg8='$reg8'
Xreg9='$reg9'
Xreg10='$reg10'
Xreg11='$reg11'
Xreg12='$reg12'
Xreg13='$reg13'
Xreg14='$reg14'
Xreg15='$reg15'
Xreg16='$reg16'
Xspitshell='$spitshell'
Xshsharp='$shsharp'
Xsharpbang='$sharpbang'
Xstartsh='$startsh'
XCONFIG=true
XEOT
X 
X: create config.h file
X$echo " "
X$echo "Creating config.h..."
X$cat <<EOT >config.h
X/* config.h
X * This file was produced by running the Configure script.
X * Feel free to modify any of this as the need arises.
X */
X
X
X#$d_eunice	EUNICE		/* no file linking? */
X#$d_eunice	VMS		/* other assorted ickies? */
X
X#$d_index	index strchr	/* cultural */
X#$d_index	rindex strrchr	/*  differences? */
X
X#$d_void	void int	/* is void to be avoided? */
X
X/* How many register declarations are paid attention to? */
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
XEOT
XCONFIG=true
X
Xif $contains '\.SH' MANIFEST >/dev/null 2>&1; then
X    $echo " "
X    $echo "Doing variable substitutions on .SH files..."
X    set `$grep <MANIFEST '\.SH' | awk '{print $1}'`
X    for file in $*; do
X	case "$file" in
X	*/*)
X	    dir=`$expr X$file : 'X\(.*\)/'`
X	    file=`$expr X$file : 'X.*/\(.*\)'`
X	    (cd $dir && . $file)
X	    ;;
X	*)
X	    . $file
X	    ;;
X	esac
X    done
Xfi
X
Xif $contains '^depend:' Makefile >/dev/null 2>&1; then
X    $echo " "
X    $echo 'Now you need to generate make dependencies by running "make depend".'
X    $echo 'You might prefer to run it in background: "make depend > makedepend.out &"'
X    $echo $n "Would you like me to run it for you (it takes quite a while)? [n] $c" 
X    rp="Run make depend now? [n]"
X    . myread
X    case "$ans" in
X    y*) make depend;;
X    esac
Xfi
X
X$rm -f libc.list kit*isdone bsd usg v7 eunice loc Cppsym
X
Xif test -f Makefile; then
X    $echo " "
X    $echo "Now you must run a make."
Xelse
X    $echo "Done."
Xfi
X: end of Configure
!STUFFY!FUNK!
echo Extracting util.h
sed >util.h <<'!STUFFY!FUNK!' -e 's/X//'
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();
!STUFFY!FUNK!
echo Extracting EXTERN.h
sed >EXTERN.h <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: EXTERN.h,v 2.0 86/09/17 15:35:37 lwall Exp $
X *
X * $Log:	EXTERN.h,v $
X * Revision 2.0  86/09/17  15:35:37  lwall
X * Baseline for netwide release.
X * 
X */
X
X#undef EXT
X#define EXT extern
X
X#undef INIT
X#define INIT(x)
X
X#undef DOINIT
!STUFFY!FUNK!
echo ""
echo "End of kit 1 (of 3)"
cat /dev/null >kit1isdone
config=true
for iskit in 1 2 3; do
    if test -f kit${iskit}isdone; then
	echo "You have run kit ${iskit}."
    else
	echo "You still need to run kit ${iskit}."
	config=false
    fi
done
case $config in
    true)
	echo "You have run all your kits.  Please read README and then type Configure."
	chmod 755 Configure
	;;
esac
: I do not append .signature, but someone might mail this.
exit