-+-+-+-+-+-+-+-+ START OF PART 3 -+-+-+-+-+-+-+-+
X`09`09cp = &clist`5Bklist`5Bi`5D`5D;
X`09`09printf("%2d %2d", i, klist`5Bi`5D);
X`09`09if (cp >= &clist`5B0`5D && cp < &clist`5Bclength`5D)
X`09`09`09printf(" (%2d %2d -> %2d)\n", cp->a, cp->b, cp->link);
X`09`09else if (klist`5Bi`5D == -1)
X`09`09`09printf(" End of chain\n");
X`09`09else
X`09`09`09printf(" illegal klist element\n");
X`09`7D
X`09for (i = 0; i <= kmax; i++) `7B
X`09`09count = -1;
X`09`09for (cp = (CANDIDATE *) klist`5Bi`5D; cp > &clist`5B0`5D;
X`09`09`09 cp = (CANDIDATE *) & cp->link) `7B
X`09`09`09if (++count >= 6) `7B
X`09`09`09`09printf("\n    ");
X`09`09`09`09count = 0;
X`09`09`09`7D
X`09`09`09printf(" (%2d: %2d,%2d -> %d)",
X`09`09`09`09   cp - clist, cp->a, cp->b, cp->link);
X`09`09`7D
X`09`09printf("\n");
X`09`7D
X`09printf("*\n");
X`7D
X#endif`09/* DEBUG */
X
X
X
X#ifdef  TIMING
X
X/*
X * Dump time buffer
X */
X
Xptime(why)
X`09char           *why;
X`7B
X`09long            ttemp;
X
X`09ttemp = time(NULL);
X`09printf("%ld seconds for %s\n",
X`09`09   ttemp - sectiontime, why);
X`09sectiontime = ttemp;
X`7D
X#endif`09/* TIMING */
X
X
X/*
X * TRUE if strings are identical
X */
X
Xint
Xstreq(s1, s2)
X`09register char  *s1;
X`09register char  *s2;
X`7B
X`09while (*s1++ == *s2) `7B
X`09`09if (*s2++ == EOS)
X`09`09`09return (TRUE);
X`09`7D
X`09return (FALSE);
X`7D
X
X
X/*
X * Error message before retiring.
X */
X
X/* VARARGS */
Xerror(format, args)
X`09char           *format;
X`7B
X`09fprintf(stderr, format, &args);
X`09putc('\n', stderr);
X`09_error();
X`7D
X
X
X_error()
X`7B
X`09exit(1);
X`7D
X
X
X/*
X * Like fput() except that it puts a newline at the end of the line.
X */
X
Xfputss(s, iop)
X`09register char  *s;
X`09register FILE  *iop;
X`7B
X`09fputs(s, iop);
X`09putc('\n', iop);
X`7D
X
X
X/*
X * Fgetss() is like fgets() except that the terminating newline
X * is removed.`20
X */
X
Xchar           *
Xfgetss(s, n, iop)
X`09char           *s;
X`09register FILE  *iop;
X`7B
X`09register char  *cs;
X
X`09if (fgets(s, n, iop) == NULL)
X`09`09return ((char *) NULL);
X`09cs = s + strlen(s) - 1;
X`09if (*cs == '\n')
X`09`09*cs = '\0';
X`09return (s);
X`7D
$ CALL UNPACK [.SRC]DIFF.C;1 21876700
$ create 'f'
X/* $Header: EXTERN.h,v 2.0 86/09/17 15:35:37 lwall Exp $
X *
X * $Log:`09EXTERN.h,v $
X * Revision 2.0  86/09/17  15:35:37  lwall
X * Baseline for netwide release.
X *`20
X */
X
X#undef EXT
X#define EXT extern
X
X#undef INIT
X#define INIT(x)
X
X#undef DOINIT
$ CALL UNPACK [.SRC]EXTERN.H;1 572608833
$ create 'f'
X/*
X * @(#)includes.h 1.8 89/04/01`09`09Jamie Hanrahan (simpact!jeh)
X *
X * Version simpact-1.8, for DECUS uucp (VMS portion). `20
X * All changes and additions from previous versions (see below) are in
X * the public domain.`20
X *
X * Derived from:
X *`20
X * includes.h 1.7 87/09/29`09Copyright 1987 Free Software Foundation, Inc.
X *
X * Copying and use of this program are controlled by the terms of the
X * GNU Emacs General Public License.
X *
X * Include files for various supported systems:
X * Note that NAMESIZE should be the max length of a file name, including
X * all its directories, drive specifiers, extensions, and the like.
X * E.g. on a Unix with 14-char file names, NAMESIZE is several hundred
X * characters, since the 14-char names can be nested.
X */
X
X#include ctype
X#include descrip
X#include dvidef
X#include errno
X#include file
X#include iodef
X#include math
X#include setjmp
X#include signal
X#include ssdef
X#include stat
X#include stdlib`20
X#include stdio
X#include string
X#include time
X
X#define NAMESIZE 255
X#define UUXQT_DOORBELL "UUCP_UUXQT_DOORBELL"
X#define UUCICO_REQMB "UUCP_REQUESTS"
X#define`09UUX_QUEUE "UUCP_BATCH_QUEUE"
X#define`09UUX_FILE "UUCP_BIN:UUXQT_BATCH.COM"
X#define DEBUG_LOG_FILE "vmsnet_log:uucico_dbg"
X#define`09UUX_LOG "UUCP_LOG:UUXQT.LOG"
X#define`09SYSLOCK_TEMPLATE "UUCP_SYS_%s"
X#define STATUS_LNT "LNM$SYSTEM_TABLE"
X#define STATUS_TEMPLATE "UUCP_STATUS_%s"
X#define MAXLOCK 32
X#define LOGLEN 255
X#define SEQSIZE 4
X#define CONTROL_FILE         "uucp_cfg:control."`20
X#define`09LOGCLOSE`09/* Logfile must be closed; VMS locks it when open */
X#define EXEDIR  "uucp_bin:"`09/* uuxqt executables live here (not used) */
X#define NULL_DEVICE "NL:"
X#define fork vfork`09`09/* (not used) */
X#define STATUS int`09`09/* (not used) */
X#define postmaster "UUCP_POSTMASTER"
X#define EXIT_OK 1`09`09/* image exit code */
X#define EXIT_ERR 0x10000000`09/* image exit code */
X#define ENABLE 1`09`09/* for $SETAST (and maybe others) */
X#define DISABLE 0
X#define`09time_t`09unsigned`09/* (not used) */
X#define remove delete`09/* Remove a file */
X#define qsort pqsort`09/* Our own version (not used) */
X
X#define FOPEN_W_MODE "w"`09/* mode to open files being received */
X#define FOPEN_R_MODE "r"`09/*  or sent */
X
X#define SS_FAILED(status) (((status)&1) == 0)
X#define initdsc(d) d.dsc$b_class = DSC$K_CLASS_S, d.dsc$b_dtype = DSC$K_DTYP
VE_T
X#define fillindsc(d, s) d.dsc$w_length=strlen(s), d.dsc$a_pointer=(s)
X#define init_itmlst3(e,i,l,c,a,r) \
X`09(e`5Bi`5D.len=(l),\
X`09e`5Bi`5D.code=(c),\
X`09e`5Bi`5D.address=(a),\
X`09e`5Bi`5D.retlen=(r))
X
$ CALL UNPACK [.SRC]INCLUDES.H;1 1900750121
$ create 'f'
X/* $Header: inp.c,v 2.0 86/09/17 15:37:02 lwall Exp $
X *
X * $Log:`09inp.c,v $
X * Revision 2.0  86/09/17  15:37:02  lwall
X * Baseline for netwide release.
X *`20
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;`09`09`09/* size of the input file */
Xstatic char *i_womp;`09`09`09/* plan a buffer for entire file */
Xstatic char **i_ptr;`09`09`09/* pointers to lines in i_womp */
X
Xstatic int tifd = -1;`09`09`09/* plan b virtual string array */
Xstatic char *tibuf`5B2`5D;`09`09`09/* plan b buffers */
Xstatic LINENUM tiline`5B2`5D = `7B-1, -1`7D;`09/* 1st line in each buffer */
Xstatic LINENUM lines_per_buf;`09`09/* how many lines per buffer */
Xstatic int tireclen;`09`09`09/* length of records in tmp file */
X
X/* New patch--prepare to edit another file. */
X
Xvoid
Xre_input()
X`7B
X    if (using_plan_a) `7B
X`09i_size = 0;
X#ifndef lint
X`09if (i_ptr != Null(char**))
X`09    free((char *)i_ptr);
X#endif
X`09if (i_womp != Nullch)
X`09    free(i_womp);
X`09i_womp = Nullch;
X`09i_ptr = Null(char **);
X    `7D
X    else `7B
X`09using_plan_a = TRUE;`09`09/* maybe the next one is smaller */
X`09Close(tifd);
X`09tifd = -1;
X`09free(tibuf`5B0`5D);
X`09free(tibuf`5B1`5D);
X`09tibuf`5B0`5D = tibuf`5B1`5D = Nullch;
X`09tiline`5B0`5D = tiline`5B1`5D = -1;
X`09tireclen = 0;
X    `7D
X`7D
X
X/* Constuct the line index, somehow or other. */
X
Xvoid
Xscan_input(filename)
Xchar *filename;
X`7B
X    if (!plan_a(filename))
X`09plan_b(filename);
X    if (verbose) `7B
X`09say3("Patching file %s using Plan %s...\n", filename,
X`09  (using_plan_a ? "A" : "B") );
X    `7D
X`7D
X
X/* Try keeping everything in memory. */
X
Xbool
Xplan_a(filename)
Xchar *filename;
X`7B
X    int ifd;
X    Reg1 char *s;
X    Reg2 LINENUM iline;
X
X    if (ok_to_create_file && stat(filename, &filestat) < 0) `7B
X`09if (verbose)
X`09    say2("(Creating file %s...)\n",filename);
X`09makedirs(filename, TRUE);
X`09close(creat(filename, 0666));
X    `7D
X    if (stat(filename, &filestat) < 0) `7B
X`09Sprintf(buf, "RCS/%s%s", filename, RCSSUFFIX);
X`09if (stat(buf, &filestat) >= 0 `7C`7C stat(buf+4, &filestat) >= 0) `7B
X`09    Sprintf(buf, CHECKOUT, filename);
X`09    if (verbose)
X`09`09say2("Can't find %s--attempting to check it out from RCS.\n",
X`09`09    filename);
X`09    if (system(buf) `7C`7C stat(filename, &filestat))
X`09`09fatal2("Can't check out %s.\n", filename);
X`09`7D
X`09else `7B
X`09    Sprintf(buf, "SCCS/%s%s", SCCSPREFIX, filename);
X`09    if (stat(buf, &filestat) >= 0 `7C`7C stat(buf+5, &filestat) >= 0) `7B
X`09`09Sprintf(buf, GET, filename);
X`09`09if (verbose)
X`09`09    say2("Can't find %s--attempting to get it from SCCS.\n",
X`09`09`09filename);
X`09`09if (system(buf) `7C`7C stat(filename, &filestat))
X`09`09    fatal2("Can't get %s.\n", filename);
X`09    `7D
X`09    else
X`09`09fatal2("Can't find %s.\n", filename);
X`09`7D
X    `7D
X    filemode = filestat.st_mode;
X    if ((filemode & S_IFMT) & `7ES_IFREG)
X`09fatal2("%s is not a normal file--can't patch.\n", filename);
X    i_size = filestat.st_size;
X    if (out_of_mem) `7B
X`09set_hunkmax();`09`09/* make sure dynamic arrays are allocated */
X`09out_of_mem = FALSE;
X`09return FALSE;`09`09`09/* force plan b because plan a bombed */
X    `7D
X#ifdef lint
X    i_womp = Nullch;
X#else
X    i_womp = malloc((MEM)(i_size+2));`09/* lint says this may alloc less tha
Vn */
X`09`09`09`09`09/* i_size, but that's okay, I think. */
X#endif
X    if (i_womp == Nullch)
X`09return FALSE;
X    if ((ifd = open(filename, 0
X#ifdef VMS
X`09`09`09`09,"mbc=64", "mbf=2"
X#endif
X`09`09`09`09)) < 0)
X`09fatal2("Can't open file %s\n", filename);
X#ifndef lint
X#ifdef VMS
X    `7B
X    int ind = 0, count;
X
X    while (ind < i_size) `7B
X`09if (0 >= (count = read(ifd, &i_womp`5Bind`5D, (int)(i_size-ind))))
X`09    break;
X`09ind += count;`09
X    `7D
X    i_size = ind;
X    `7D
X#else
X    if (read(ifd, i_womp, (int)i_size) != i_size) `7B
X`09Close(ifd);`09/* probably means i_size > 15 or 16 bits worth */
X`09free(i_womp);`09/* at this point it doesn't matter if i_womp was */
X`09return FALSE;`09/*   undersized. */
X    `7D
X#endif
X#endif
X    Close(ifd);
X    if (i_size && i_womp`5Bi_size-1`5D != '\n')
X`09i_womp`5Bi_size++`5D = '\n';
X    i_womp`5Bi_size`5D = '\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++) `7B
X`09if (*s == '\n')
X`09    iline++;
X    `7D
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 **)) `7B`09/* shucks, it was a near thing */
X`09free((char *)i_womp);
X`09return FALSE;
X    `7D
X   `20
X    /* now scan the buffer and build pointer array */
X
X    iline = 1;
X    i_ptr`5Biline`5D = i_womp;
X    for (s=i_womp; *s; s++) `7B
X`09if (*s == '\n')
X`09    i_ptr`5B++iline`5D = s+1;`09/* these are NOT null terminated */
X    `7D
X    input_lines = iline - 1;
X
X    /* now check for revision, if any */
X
X    if (revision != Nullch) `7B`20
X`09if (!rev_in_string(i_womp)) `7B
X`09    if (force) `7B
X`09`09if (verbose)
X`09`09    say2("\
XWarning: this file doesn't appear to be the %s version--patching anyway.\n",
X`09`09`09revision);
X`09    `7D
X`09    else `7B
X`09`09ask2("\
XThis file doesn't appear to be the %s version--patch anyway? `5Bn`5D ",
X`09`09    revision);
X`09    if (*buf != 'y')
X`09`09fatal1("Aborted.\n");
X`09    `7D
X`09`7D
X`09else if (verbose)
X`09    say2("Good.  This file appears to be the %s version.\n",
X`09`09revision);
X    `7D
X    return TRUE;`09`09`09/* plan a will work */
X`7D
X
X/* Keep (virtually) nothing in memory. */
X
Xvoid
Xplan_b(filename)
Xchar *filename;
X`7B
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`09fatal2("Can't open file %s\n", filename);
X    if ((tifd = creat(TMPINNAME, 0666)) < 0)
X`09fatal2("Can't open file %s\n", TMPINNAME);
X    while (fgets(buf, sizeof buf, ifp) != Nullch) `7B
X`09if (revision != Nullch && !found_revision && rev_in_string(buf))
X`09    found_revision = TRUE;
X`09if ((i = strlen(buf)) > maxlen)
X`09    maxlen = i;`09`09`09/* find longest line */
X    `7D
X    if (revision != Nullch) `7B
X`09if (!found_revision) `7B
X`09    if (force) `7B
X`09`09if (verbose)
X`09`09    say2("\
XWarning: this file doesn't appear to be the %s version--patching anyway.\n",
X`09`09`09revision);
X`09    `7D
X`09    else `7B
X`09`09ask2("\
XThis file doesn't appear to be the %s version--patch anyway? `5Bn`5D ",
X`09`09    revision);
X`09`09if (*buf != 'y')
X`09`09    fatal1("Aborted.\n");
X`09    `7D
X`09`7D
X`09else if (verbose)
X`09    say2("Good.  This file appears to be the %s version.\n",
X`09`09revision);
X    `7D
X    Fseek(ifp, 0L, 0);`09`09/* rewind file */
X    lines_per_buf = BUFFERSIZE / maxlen;
X    tireclen = maxlen;
X    tibuf`5B0`5D = malloc((MEM)(BUFFERSIZE + 1));
X    tibuf`5B1`5D = malloc((MEM)(BUFFERSIZE + 1));
X    if (tibuf`5B1`5D == Nullch)
X`09fatal1("Can't seem to get enough memory.\n");
X    for (i=1; ; i++) `7B
X`09if (! (i % lines_per_buf))`09/* new block */
X`09    if (write(tifd, tibuf`5B0`5D, BUFFERSIZE) < BUFFERSIZE)
X`09`09fatal1("patch: can't write temp file.\n");
X`09if (fgets(tibuf`5B0`5D + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
X`09  == Nullch) `7B
X`09    input_lines = i - 1;
X`09    if (i % lines_per_buf)
X`09`09if (write(tifd, tibuf`5B0`5D, BUFFERSIZE) < BUFFERSIZE)
X`09`09    fatal1("patch: can't write temp file.\n");
X`09    break;
X`09`7D
X    `7D
X    Fclose(ifp);
X    Close(tifd);
X    if ((tifd = open(TMPINNAME, 0)) < 0) `7B
X`09fatal2("Can't reopen file %s\n", TMPINNAME);
X    `7D
X`7D
X
X/* Fetch a line from the input file, \n terminated, not necessarily \0. */
X
Xchar *
Xifetch(line,whichbuf)
XReg1 LINENUM line;
Xint whichbuf;`09`09`09`09/* ignored when file in memory */
X`7B
X    if (line < 1 `7C`7C line > input_lines)
X`09return "";
X    if (using_plan_a)
X`09return i_ptr`5Bline`5D;
X    else `7B
X`09LINENUM offline = line % lines_per_buf;
X`09LINENUM baseline = line - offline;
X
X`09if (tiline`5B0`5D == baseline)
X`09    whichbuf = 0;
X`09else if (tiline`5B1`5D == baseline)
X`09    whichbuf = 1;
X`09else `7B
X`09    tiline`5Bwhichbuf`5D = baseline;
X#ifndef lint`09`09/* complains of long accuracy */
X`09    Lseek(tifd, (long)baseline / lines_per_buf * BUFFERSIZE, 0);
X#endif
X`09    if (read(tifd, tibuf`5Bwhichbuf`5D, BUFFERSIZE) < 0)
X`09`09fatal2("Error reading tmp file %s.\n", TMPINNAME);
X`09`7D
X`09return tibuf`5Bwhichbuf`5D + (tireclen*offline);
X    `7D
X`7D
X
X/* True if the string argument contains the revision number we want. */
X
Xbool
Xrev_in_string(string)
Xchar *string;
X`7B
X    Reg1 char *s;
X    Reg2 int patlen;
X
X    if (revision == Nullch)
X`09return TRUE;
X    patlen = strlen(revision);
X    for (s = string; *s; s++) `7B
X`09if (isspace(*s) && strnEQ(s+1, revision, patlen) &&`20
X`09`09isspace(s`5Bpatlen+1`5D )) `7B
X`09    return TRUE;
X`09`7D
X    `7D
X    return FALSE;
X`7D
X
$ CALL UNPACK [.SRC]INP.C;1 1092797036
$ create 'f'
X/* $Header: inp.h,v 2.0 86/09/17 15:37:25 lwall Exp $
X *
X * $Log:`09inp.h,v $
X * Revision 2.0  86/09/17  15:37:25  lwall
X * Baseline for netwide release.
X *`20
X */
X
XEXT LINENUM input_lines INIT(0);`09/* how long is input file in lines */
XEXT LINENUM last_frozen_line INIT(0);`09/* how many input lines have been */
X`09`09`09`09`09/* irretractibly output */
X
Xbool rev_in_string();
Xvoid scan_input();
Xbool plan_a();`09`09`09/* returns false if insufficient memory */
Xvoid plan_b();
Xchar *ifetch();
X
$ CALL UNPACK [.SRC]INP.H;1 1192057672
$ create 'f'
X/* $Header: INTERN.h,v 2.0 86/09/17 15:35:58 lwall Exp $
X *
X * $Log:`09INTERN.h,v $
X * Revision 2.0  86/09/17  15:35:58  lwall
X * Baseline for netwide release.
X *`20
X */
X
X#undef EXT
X#define EXT
X
X#undef INIT
X#define INIT(x) = x
X
X#define DOINIT
$ CALL UNPACK [.SRC]INTERN.H;1 696126206
$ create 'f'
Xchar rcsid`5B`5D =
X`09"$Header: patch.c,v 2.0.1.4 87/02/16 14:00:04 lwall Exp $";
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:`09patch.c,v $
X * Revision 2.0.1.4  87/02/16  14:00:04  lwall
X * Short replacement caused spurious "Out of sync" message.
X *`20
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 *`20
X * Revision 2.0.1.2  86/11/21  09:39:15  lwall
X * Fuzz factor caused offset of installed lines.
X *`20
X * Revision 2.0.1.1  86/10/29  13:10:22  lwall
X * Backwards search could terminate prematurely.
X *`20
X * Revision 2.0  86/09/17  15:37:32  lwall
X * Baseline for netwide release.
X *`20
X * Revision 1.5  86/08/01  20:53:24  lwall
X * Changed some %d's to %ld's.
X * Linted.
X *`20
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 *`20
X * 85/08/15 van%ucbmonet@berkeley
X * Changes for 4.3bsd diff -c.
X *
X * Revision 1.3  85/03/26  15:07:43  lwall
X * Frozen.
X *`20
X * Revision 1.2.1.9  85/03/12  17:03:35  lwall
X * Changed pfp->_file to fileno(pfp).
X *`20
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 *`20
X * Revision 1.2.1.7  85/03/12  15:56:13  lwall
X * Added -p option from jromine@uci-750a.
X *`20
X * Revision 1.2.1.6  85/03/12  12:12:51  lwall
X * Now checks for normalness of file to patch.
X *`20
X * Revision 1.2.1.5  85/03/12  11:52:12  lwall
X * Added -D (#ifdef) option from joe@fluke.
X *`20
X * Revision 1.2.1.4  84/12/06  11:14:15  lwall
X * Made smarter about SCCS subdirectories.
X *`20
X * Revision 1.2.1.3  84/12/05  11:18:43  lwall
X * Added -l switch to do loose string comparison.
X *`20
X * Revision 1.2.1.2  84/12/04  09:47:13  lwall
X * Failed hunk count not reset on multiple patch file.
X *`20
X * Revision 1.2.1.1  84/12/04  09:42:37  lwall
X * Branch for sdcrdcf changes.
X *`20
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 *`20
X * Revision 1.1  84/11/09  17:03:58  lwall
X * Initial revision
X *`20
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`7B
X    LINENUM where;
X    LINENUM newwhere;
X    LINENUM fuzz;
X    LINENUM mymaxfuzz;
X    int hunk = 0;
X    int failed = 0;
X    int i;
X
X#ifdef VMS
X    getredirection(&argc, &argv);
X#endif
X    setbuf(stderr, serrbuf);
X    for (i = 0; i<MAXFILEC; i++)
X`09filearg`5Bi`5D = 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   `20
X    /* make sure we clean up /tmp in case of disaster */
X    set_signals();
X
X    for (
X`09open_patch_file(filearg`5B1`5D);
X`09there_is_another_patch();
X`09reinitialize_almost_everything()
X    ) `7B`09`09`09`09`09/* for each patch in patch file */
X
X`09if (outname == Nullch)
X`09    outname = savestr(filearg`5B0`5D);
X   `20
X`09/* initialize the patched file */
X`09if (!skip_rest_of_patch)
X`09    init_output(TMPOUTNAME);
X   `20
X`09/* for ed script just up and do it and exit */
X`09if (diff_type == ED_DIFF) `7B
X`09    do_ed_script();
X`09    continue;
X`09`7D
X   `20
X`09/* initialize reject file */
X`09init_reject(TMPREJNAME);
X   `20
X`09/* find out where all the lines are */
X`09if (!skip_rest_of_patch)
X`09    scan_input(filearg`5B0`5D);
X   `20
X`09/* from here on, open no standard i/o files, because malloc */
X`09/* might misfire and we can't catch it easily */
X   `20
X`09/* apply each hunk of patch */
X`09hunk = 0;
X`09failed = 0;
X`09out_of_mem = FALSE;
X`09while (another_hunk()) `7B
X`09    hunk++;
X`09    fuzz = Nulline;
X`09    mymaxfuzz = pch_context();
X`09    if (maxfuzz < mymaxfuzz)
X`09`09mymaxfuzz = maxfuzz;
X`09    if (!skip_rest_of_patch) `7B
X`09`09do `7B
X`09`09    where = locate_hunk(fuzz);
X`09`09    if (hunk == 1 && where == Nulline && !force) `7B
X`09`09`09`09`09`09/* dwim for reversed patch? */
X`09`09`09if (!pch_swap()) `7B
X`09`09`09    if (fuzz == Nulline)
X`09`09`09`09say1("\
XNot enough memory to try swapped hunk!  Assuming unswapped.\n");
X`09`09`09    continue;
X`09`09`09`7D
X`09`09`09reverse = !reverse;
X`09`09`09where = locate_hunk(fuzz);  /* try again */
X`09`09`09if (where == Nulline) `7B`09    /* didn't find it swapped */
X`09`09`09    if (!pch_swap())         /* put it back to normal */
X`09`09`09`09fatal1("Lost hunk on alloc error!\n");
X`09`09`09    reverse = !reverse;
X`09`09`09`7D
X`09`09`09else if (noreverse) `7B
X`09`09`09    if (!pch_swap())         /* put it back to normal */
X`09`09`09`09fatal1("Lost hunk on alloc error!\n");
X`09`09`09    reverse = !reverse;
X`09`09`09    say1("\
XIgnoring previously applied (or reversed) patch.\n");
X`09`09`09    skip_rest_of_patch = TRUE;
X`09`09`09`7D
X`09`09`09else `7B
X`09`09`09    ask3("\
X%seversed (or previously applied) patch detected!  %s -R? `5By`5D ",
X`09`09`09`09reverse ? "R" : "Unr",
X`09`09`09`09reverse ? "Assume" : "Ignore");
X`09`09`09    if (*buf == 'n') `7B
X`09`09`09`09ask1("Apply anyway? `5Bn`5D ");
X`09`09`09`09if (*buf != 'y')
X`09`09`09`09    skip_rest_of_patch = TRUE;
X`09`09`09`09where = Nulline;
X`09`09`09`09reverse = !reverse;
X`09`09`09`09if (!pch_swap())  /* put it back to normal */
X`09`09`09`09    fatal1("Lost hunk on alloc error!\n");
X`09`09`09    `7D
X`09`09`09`7D
X`09`09    `7D
X`09`09`7D while (!skip_rest_of_patch && where == Nulline &&
X`09`09    ++fuzz <= mymaxfuzz);
X
X`09`09if (skip_rest_of_patch) `7B`09`09/* just got decided */
X`09`09    Fclose(ofp);
X`09`09    ofp = Nullfp;
X`09`09`7D
X`09    `7D
X
X`09    newwhere = pch_newfirst() + last_offset;
X`09    if (skip_rest_of_patch) `7B
X`09`09abort_hunk();
X`09`09failed++;
X`09`09if (verbose)
X`09`09    say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
X`09    `7D
X`09    else if (where == Nulline) `7B
X`09`09abort_hunk();
X`09`09failed++;
X`09`09if (verbose)
X`09`09    say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
X`09    `7D
X`09    else `7B
X`09`09apply_hunk(where);
X`09`09if (verbose) `7B
X`09`09    say3("Hunk #%d succeeded at %ld", hunk, newwhere);
X`09`09    if (fuzz)
X`09`09`09say2(" with fuzz %ld", fuzz);
X`09`09    if (last_offset)
X`09`09`09say3(" (offset %ld line%s)",
X`09`09`09    last_offset, last_offset==1L?"":"s");
X`09`09    say1(".\n");
X`09`09`7D
X`09    `7D
X`09`7D
X
X`09if (out_of_mem && using_plan_a) `7B
X`09    Argc = Argc_last;
X`09    Argv = Argv_last;
X`09    say1("\n\nRan out of memory using Plan A--trying again...\n\n");
X`09    continue;
X`09`7D
X   `20
X`09assert(hunk);
X   `20
X`09/* finish spewing out the new file */
X`09if (!skip_rest_of_patch)
X`09    spew_output();
X`09
X`09/* and put the output where desired */
X`09ignore_signals();
X`09if (!skip_rest_of_patch) `7B
X`09    if (move_file(TMPOUTNAME, outname) < 0) `7B
X`09`09toutkeep = TRUE;
X`09`09chmod(TMPOUTNAME, filemode);
X`09    `7D
X`09    else
X`09`09chmod(outname, filemode);
X`09`7D
X`09Fclose(rejfp);
X`09rejfp = Nullfp;
X`09if (failed) `7B
X`09    if (!*rejname) `7B
X`09`09Strcpy(rejname, outname);
X#ifdef VMS
X`09`09Strcat(rejname, "_rej");
X#else
X`09`09Strcat(rejname, ".rej");
X#endif
X`09    `7D
X`09    if (skip_rest_of_patch) `7B
X`09`09say4("%d out of %d hunks ignored--saving rejects to %s\n",
X`09`09    failed, hunk, rejname);
X`09    `7D
X`09    else `7B
X`09`09say4("%d out of %d hunks failed--saving rejects to %s\n",
X`09`09    failed, hunk, rejname);
X`09    `7D
X`09    if (move_file(TMPREJNAME, rejname) < 0)
X`09`09trejkeep = TRUE;
X`09`7D
X`09set_signals();
X    `7D
X    my_exit(0);
X`7D
X
X/* Prepare to find the next patch to do in the patch file. */
X
Xvoid
Xreinitialize_almost_everything()
X`7B
X    re_patch();
X    re_input();
X
X    input_lines = 0;
X    last_frozen_line = 0;
X
X    filec = 0;
X    if (filearg`5B0`5D != Nullch && !out_of_mem) `7B
X`09free(filearg`5B0`5D);
X`09filearg`5B0`5D = Nullch;
X    `7D
X
X    if (outname != Nullch) `7B
X`09free(outname);
X`09outname = Nullch;
X    `7D
X
X    last_offset = 0;
X
X    diff_type = 0;
X
X    if (revision != Nullch) `7B
X`09free(revision);
X`09revision = Nullch;
X    `7D
X
X    reverse = FALSE;
X    skip_rest_of_patch = FALSE;
X
X    get_some_switches();
X
X    if (filec >= 2)
X`09fatal1("You may not change to a different patch file.\n");
X`7D
X
X/* Process switches and filenames up to next '+' or end of list. */
X
Xvoid
Xget_some_switches()
X`7B
X    Reg1 char *s;
X
X    rejname`5B0`5D = '\0';
X    Argc_last = Argc;
X    Argv_last = Argv;
X    if (!Argc)
X`09return;
X    for (Argc--,Argv++; Argc; Argc--,Argv++) `7B
X`09s = Argv`5B0`5D;
X`09if (strEQ(s, "+")) `7B
X`09    return;`09`09`09/* + will be skipped by for loop */
X`09`7D
X#ifdef VMS
X`09if (*s == '<')`09`09`09/* Parse '<filename' syntax */
X`09    filearg`5B1`5D = savestr(s + 1);
X`09if ((*s != '-' && *s != '<') `7C`7C !s`5B1`5D) `7B
X#else
X`09if (*s != '-' `7C`7C !s`5B1`5D) `7B
X#endif
X`09    if (filec == MAXFILEC)
X`09`09fatal1("Too many file arguments.\n");
X`09    filearg`5Bfilec++`5D = savestr(s);
X`09`7D
X#ifdef VMS
X`09if ((*s == '-') && s`5B1`5D) `7B
X#else
X`09else `7B
X#endif
X`09    switch (*++s) `7B
X`09    case 'b':
X`09`09origext = savestr(Argv`5B1`5D);
X`09`09Argc--,Argv++;
X`09`09break;
X`09    case 'c':
X`09`09diff_type = CONTEXT_DIFF;
X`09`09break;
X`09    case 'd':
X`09`09if (!*++s) `7B
X`09`09    Argc--,Argv++;
X`09`09    s = Argv`5B0`5D;
X`09`09`7D
X`09`09if (chdir(s) < 0)
X`09`09    fatal2("Can't cd to %s.\n", s);
X`09`09break;
X`09    case 'D':
X`09    `09do_defines = TRUE;
X`09`09if (!*++s) `7B
X`09`09    Argc--,Argv++;
X`09`09    s = Argv`5B0`5D;
X`09`09`7D
X`09`09Sprintf(if_defined, "#ifdef %s\n", s);
X`09`09Sprintf(not_defined, "#ifndef %s\n", s);
X`09`09Sprintf(end_defined, "#endif /* %s */\n", s);
X`09`09break;
X`09    case 'e':
X`09`09diff_type = ED_DIFF;
X`09`09break;
X`09    case 'f':
X`09`09force = TRUE;
X`09`09break;
X`09    case 'F':
X`09`09if (*++s == '=')
X`09`09    s++;
X`09`09maxfuzz = atoi(s);
X`09`09break;
X`09    case 'l':
X`09`09canonicalize = TRUE;
X`09`09break;
X`09    case 'n':
X`09`09diff_type = NORMAL_DIFF;
X`09`09break;
X`09    case 'N':
X`09`09noreverse = TRUE;
X`09`09break;
X`09    case 'o':
X`09`09outname = savestr(Argv`5B1`5D);
X`09`09Argc--,Argv++;
X`09`09break;
X`09    case 'p':
X#ifdef VMS
X            case 'P':
X#endif
X`09`09if (*++s == '=')
X`09`09    s++;
X`09`09strippath = atoi(s);
X`09`09break;
X`09    case 'r':
X`09`09Strcpy(rejname, Argv`5B1`5D);
X`09`09Argc--,Argv++;
X`09`09break;
X`09    case 'R':
X`09`09reverse = TRUE;
X`09`09break;
X`09    case 's':
X`09`09verbose = FALSE;
X`09`09break;
X`09    case 'S':
X`09`09skip_rest_of_patch = TRUE;
X`09`09break;
X`09    case 'v':
X`09`09version();
X`09`09break;
X#ifdef DEBUGGING
X`09    case 'x':
X`09`09debug = atoi(s+1);
X`09`09break;
X#endif
X`09    default:
X`09`09fatal2("Unrecognized switch: %s\n", Argv`5B0`5D);
X`09    `7D
X`09`7D
X    `7D
X`7D
X
X/* Attempt to find the right place to apply this hunk of patch. */
X
XLINENUM
Xlocate_hunk(fuzz)
XLINENUM fuzz;
X`7B
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`09`09`09`09- pat_lines + 1;`20
X    Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
X`09`09`09`09+ pch_context();
X
X    if (!pat_lines)`09`09`09/* null range matches always */
X`09return first_guess;
X    if (max_neg_offset >= first_guess)`09/* do not try lines < 0 */
X`09max_neg_offset = first_guess - 1;
X    if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz
V))
X`09return first_guess;
X    for (offset = 1; ; offset++) `7B
X`09Reg5 bool check_after = (offset <= max_pos_offset);
X`09Reg6 bool check_before = (offset <= max_neg_offset);
X
X`09if (check_after && patch_match(first_guess, offset, fuzz)) `7B
X#ifdef DEBUGGING
X`09    if (debug & 1)
X`09`09say3("Offset changing from %ld to %ld\n", last_offset, offset);
X#endif
X`09    last_offset = offset;
X`09    return first_guess+offset;
X`09`7D
X`09else if (check_before && patch_match(first_guess, -offset, fuzz)) `7B
X#ifdef DEBUGGING
X`09    if (debug & 1)
X`09`09say3("Offset changing from %ld to %ld\n", last_offset, -offset);
X#endif
X`09    last_offset = -offset;
X`09    return first_guess-offset;
X`09`7D
X`09else if (!check_before && !check_after)
X`09    return Nulline;
X    `7D
X`7D
X
X/* We did not find the pattern, dump out the hunk so they can handle it. */
X
Xvoid
Xabort_hunk()
X`7B
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
V */
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++) `7B
X`09switch (pch_char(i)) `7B
X`09case '*':
X`09    if (oldlast < oldfirst)
X`09`09fprintf(rejfp, "*** 0%s\n", stars);
X`09    else if (oldlast == oldfirst)
X`09`09fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
X`09    else
X`09`09fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
X`09    break;
X`09case '=':
X`09    if (newlast < newfirst)
X`09`09fprintf(rejfp, "--- 0%s\n", minuses);
X`09    else if (newlast == newfirst)
X`09`09fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
X`09    else
X`09`09fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
X`09    break;
X`09case '\n':
X`09    fprintf(rejfp, "%s", pfetch(i));
X`09    break;
X`09case ' ': case '-': case '+': case '!':
X`09    fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
X`09    break;
X`09default:
X`09    say1("Fatal internal error in abort_hunk().\n");`20
X`09    abort();
X`09`7D
X    `7D
X`7D
X
X/* We found where to apply it (we hope), so do it. */
X
Xvoid
Xapply_hunk(where)
XLINENUM where;
X`7B
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) == '=' `7C`7C pch_char(new) == '\n')
X`09new++;
X   `20
X    while (old <= lastline) `7B
X`09if (pch_char(old) == '-') `7B
X`09    copy_till(where + old - 1);
X`09    if (R_do_defines) `7B
X`09`09if (def_state == OUTSIDE) `7B
X`09`09    fputs(not_defined, ofp);
X`09`09    def_state = IN_IFNDEF;
X`09`09`7D
X`09`09else if (def_state == IN_IFDEF) `7B
X`09`09    fputs(else_defined, ofp);
X`09`09    def_state = IN_ELSE;
X`09`09`7D
X`09`09fputs(pfetch(old), ofp);
X`09    `7D
X`09    last_frozen_line++;
X`09    old++;
X`09`7D
X`09else if (new > pat_end)
X`09    break;
X`09else if (pch_char(new) == '+') `7B
X`09    copy_till(where + old - 1);
X`09    if (R_do_defines) `7B
X`09`09if (def_state == IN_IFNDEF) `7B
X`09`09    fputs(else_defined, ofp);
X`09`09    def_state = IN_ELSE;
X`09`09`7D
X`09`09else if (def_state == OUTSIDE) `7B
X`09`09    fputs(if_defined, ofp);
X`09`09    def_state = IN_IFDEF;
X`09`09`7D
X`09    `7D
X`09    fputs(pfetch(new), ofp);
X`09    new++;
X`09`7D
X`09else `7B
X`09    if (pch_char(new) != pch_char(old)) `7B
X`09`09say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers,
V maybe?\n",
X`09`09    pch_hunk_beg() + old,
X`09`09    pch_hunk_beg() + new);
X#ifdef DEBUGGING
X`09`09say3("oldchar = '%c', newchar = '%c'\n",
X`09`09    pch_char(old), pch_char(new));
X#endif
X`09`09my_exit(1);
X`09    `7D
X`09    if (pch_char(new) == '!') `7B
X`09`09copy_till(where + old - 1);
X`09`09if (R_do_defines) `7B
X`09`09   fputs(not_defined, ofp);
X`09`09   def_state = IN_IFNDEF;
X`09`09`7D
X`09`09while (pch_char(old) == '!') `7B
X`09`09    if (R_do_defines) `7B
X`09`09`09fputs(pfetch(old), ofp);
X`09`09    `7D
X`09`09    last_frozen_line++;
X`09`09    old++;
X`09`09`7D
X`09`09if (R_do_defines) `7B
X`09`09    fputs(else_defined, ofp);
X`09`09    def_state = IN_ELSE;
X`09`09`7D
X`09`09while (pch_char(new) == '!') `7B
X`09`09    fputs(pfetch(new), ofp);
X`09`09    new++;
X`09`09`7D
X`09`09if (R_do_defines) `7B
X`09`09    fputs(end_defined, ofp);
X`09`09    def_state = OUTSIDE;
X`09`09`7D
X`09    `7D
X`09    else `7B
X`09`09assert(pch_char(new) == ' ');
X`09`09old++;
X`09`09new++;
X`09    `7D
X`09`7D
X    `7D
X    if (new <= pat_end && pch_char(new) == '+') `7B
X`09copy_till(where + old - 1);
X`09if (R_do_defines) `7B
X`09    if (def_state == OUTSIDE) `7B
X`09    `09fputs(if_defined, ofp);
X`09`09def_state = IN_IFDEF;
X`09    `7D
X`09    else if (def_state == IN_IFNDEF) `7B
X`09`09fputs(else_defined, ofp);
X`09`09def_state = IN_ELSE;
X`09    `7D
X`09`7D
X`09while (new <= pat_end && pch_char(new) == '+') `7B
X`09    fputs(pfetch(new), ofp);
X`09    new++;
X`09`7D
X    `7D
X    if (R_do_defines && def_state != OUTSIDE) `7B
X`09fputs(end_defined, ofp);
X    `7D
X`7D
X
X/* Open the new file. */
X
Xvoid
Xinit_output(name)
Xchar *name;
X`7B
X    ofp = fopen(name, "w");
X    if (ofp == Nullfp)
X`09fatal2("patch: can't create %s.\n", name);
X`7D
X
X/* Open a file to put hunks we can't locate. */
X
Xvoid
Xinit_reject(name)
Xchar *name;
X`7B
X    rejfp = fopen(name, "w");
X    if (rejfp == Nullfp)
X`09fatal2("patch: can't create %s.\n", name);
X`7D
X
X/* Copy input file to output, up to wherever hunk is to be applied. */
X
Xvoid
Xcopy_till(lastline)
XReg1 LINENUM lastline;
X`7B
X    Reg2 LINENUM R_last_frozen_line = last_frozen_line;
X
X    if (R_last_frozen_line > lastline)
X`09say1("patch: misordered hunks! output will be garbled.\n");
X    while (R_last_frozen_line < lastline) `7B
X`09dump_line(++R_last_frozen_line);
X    `7D
X    last_frozen_line = R_last_frozen_line;
X`7D
X
X/* Finish copying the input file to the output file. */
X
Xvoid
Xspew_output()
X`7B
X#ifdef DEBUGGING
X    if (debug & 256)
X`09say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
X#endif
X    if (input_lines)
X`09copy_till(input_lines);`09`09/* dump remainder of file */
X    Fclose(ofp);
X    ofp = Nullfp;
X`7D
X
X/* Copy one line from input to output. */
X
Xvoid
Xdump_line(line)
XLINENUM line;
X`7B
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`7D
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`7B
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++) `7B
X`09if (canonicalize) `7B
X`09    if (!similar(ifetch(iline, (offset >= 0)),
X`09`09`09 pfetch(pline),
X`09`09`09 pch_line_len(pline) ))
X`09`09return FALSE;
X`09`7D
X`09else if (strnNE(ifetch(iline, (offset >= 0)),
X`09`09   pfetch(pline),
X`09`09   pch_line_len(pline) ))
X`09    return FALSE;
X    `7D
X    return TRUE;
X`7D
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`7B
X    while (len) `7B
X`09if (isspace(*b)) `7B`09`09/* whitespace (or \n) to match? */
X`09    if (!isspace(*a))`09`09/* no corresponding whitespace? */
X`09`09return FALSE;
X`09    while (len && isspace(*b) && *b != '\n')
X`09`09b++,len--;`09`09/* skip pattern whitespace */
X`09    while (isspace(*a) && *a != '\n')
X`09`09a++;`09`09`09/* skip target whitespace */
X`09    if (*a == '\n' `7C`7C *b == '\n')
X`09`09return (*a == *b);`09/* should end in sync */
X`09`7D
X`09else if (*a++ != *b++)`09`09/* match non-whitespace chars */
X`09    return FALSE;
X`09else
X`09    len--;`09`09`09/* probably not necessary */
X    `7D
X    return TRUE;`09`09`09/* actually, this is not reached */
X`09`09`09`09`09/* since there is always a \n */
X`7D
X
X/* Exit with cleanup. */
X
Xvoid
Xmy_exit(status)
Xint status;
X`7B
X    while (unlink(TMPINNAME) >= 0);
X    if (!toutkeep) `7B
X`09while (unlink(TMPOUTNAME) >= 0);
X    `7D
X    if (!trejkeep) `7B
X`09while (unlink(TMPREJNAME) >= 0);
X    `7D
X    while (unlink(TMPPATNAME) >= 0);
X    exit(status);
X`7D
$ CALL UNPACK [.SRC]PATCH.C;1 728881360
$ create 'f'
X#define PATCHLEVEL 9
$ CALL UNPACK [.SRC]PATCHLEVEL.H;1 1781615383
$ create 'f'
X/* $Header: pch.c,v 2.0.1.6 87/06/04 16:18:13 lwall Exp $
X *
X * $Log:`09pch.c,v $
X * Revision 2.0.1.6  87/06/04  16:18:13  lwall
X * pch_swap didn't swap p_bfake and p_efake.
X *`20
X * Revision 2.0.1.5  87/01/30  22:47:42  lwall
X * Improved responses to mangled patches.
X *`20
X * Revision 2.0.1.4  87/01/05  16:59:53  lwall
X * New-style context diffs caused double call to free().
X *`20
X * Revision 2.0.1.3  86/11/14  10:08:33  lwall
X * Fixed problem where a long pattern wouldn't grow the hunk.
X * Also restored p_input_line when backtracking so error messages are right.
X *`20
X * Revision 2.0.1.2  86/11/03  17:49:52  lwall
X * New-style delete triggers spurious assertion error.
X *`20
X * Revision 2.0.1.1  86/10/29  15:52:08  lwall
X * Could falsely report new-style context diff.
X *`20
X * Revision 2.0  86/09/17  15:39:37  lwall
X * Baseline for netwide release.
X *`20
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;`09`09`09/* size of the patch file */
Xstatic LINENUM p_first;`09`09`09/* 1st line number */
Xstatic LINENUM p_newfirst;`09`09/* 1st line number of replacement */
Xstatic LINENUM p_ptrn_lines;`09`09/* # lines in pattern */
Xstatic LINENUM p_repl_lines;`09`09/* # lines in replacement text */
Xstatic LINENUM p_end = -1;`09`09/* last line in hunk */
Xstatic LINENUM p_max;`09`09`09/* max allowed value of p_end */
Xstatic LINENUM p_context = 3;`09`09/* # of context lines */
Xstatic LINENUM p_input_line = 0;`09/* current line # from patch file */
Xstatic char **p_line = Null(char**);`09/* the text of the hunk */
Xstatic short *p_len = Null(short*);`09/* length of each line */
Xstatic char *p_char = Nullch;`09`09/* +, -, and ! */
Xstatic int hunkmax = INITHUNKMAX;`09/* size of above arrays to begin with */
Xstatic int p_indent;`09`09`09/* indent to patch */
Xstatic LINENUM p_base;`09`09`09/* where to intuit this time */
Xstatic LINENUM p_bline;`09`09`09/* line # of p_base */
Xstatic LINENUM p_start;`09`09`09/* where intuit found a patch */
Xstatic LINENUM p_sline;`09`09`09/* and the line number for it */
Xstatic LINENUM p_hunk_beg;`09`09/* line number of current hunk */
Xstatic LINENUM p_efake = -1;`09`09/* end of faked up lines--don't free */
Xstatic LINENUM p_bfake = -1;`09`09/* beg of faked up lines */
X
X/* Prepare to look for the next patch in the patch file. */
X
Xvoid
Xre_patch()
X`7B
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`7D
X
X/* Open the patch file at the beginning of time. */
X
Xvoid
Xopen_patch_file(filename)
Xchar *filename;
X`7B
X    if (filename == Nullch `7C`7C !*filename `7C`7C strEQ(filename, "-")) `7
VB
X`09pfp = fopen(TMPPATNAME, "w");
X`09if (pfp == Nullfp)
X`09    fatal2("patch: can't create %s.\n", TMPPATNAME);
X`09while (fgets(buf, sizeof buf, stdin) != Nullch)
X`09    fputs(buf, pfp);
X`09Fclose(pfp);
X`09filename = TMPPATNAME;
X    `7D
X    pfp = fopen(filename, "r");
X    if (pfp == Nullfp)
X`09fatal2("patch file %s not found\n", filename);
X    Fstat(fileno(pfp), &filestat);
X    p_filesize = filestat.st_size;
X    next_intuit_at(0L,1L);`09`09`09/* start at the beginning */
X    set_hunkmax();
X`7D
X
X/* Make sure our dynamically realloced tables are malloced to begin with. */
X
Xvoid
Xset_hunkmax()
X`7B
X#ifndef lint
X    if (p_line == Null(char**))
X`09p_line = (char**) malloc((MEM)hunkmax * sizeof(char *));
X    if (p_len == Null(short*))
X`09p_len  = (short*) malloc((MEM)hunkmax * sizeof(short));
X#endif
X    if (p_char == Nullch)
X`09p_char = (char*)  malloc((MEM)hunkmax * sizeof(char));
X`7D
X
X/* Enlarge the arrays containing the current hunk of patch. */
X
Xvoid
Xgrow_hunkmax()
X`7B
X    hunkmax *= 2;
X    /*`20
X     * Note that on most systems, only the p_line array ever gets fresh memo
Vry
X     * since p_len can move into p_line's old space, and p_char can move int
Vo
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 != Null
Vch);
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`09return;
X    if (!using_plan_a)
X`09fatal1("patch: out of memory (grow_hunkmax)\n");
X    out_of_mem = TRUE;`09`09/* whatever is null will be allocated again */
X`09`09`09`09/* from within plan_a(), of all places */
X`7D
X
X/* True if the remainder of the patch file contains a diff of some sort. */
X
Xbool
Xthere_is_another_patch()
X`7B
X    if (p_base != 0L && p_base >= p_filesize) `7B
X`09if (verbose)
X`09    say1("done\n");
X`09return FALSE;
X    `7D
X    if (verbose)
X`09say1("Hmm...");
X    diff_type = intuit_diff_type();
X    if (!diff_type) `7B
X`09if (p_base != 0L) `7B
X`09    if (verbose)
X`09`09say1("  Ignoring the trailing garbage.\ndone\n");
X`09`7D
X`09else
X`09    say1("  I can't seem to find a patch in there anywhere.\n");
X`09return FALSE;
X    `7D
X    if (verbose)
X`09say3("  %sooks like %s to me...\n",
X`09    (p_base == 0L ? "L" : "The next patch l"),
X`09    diff_type == CONTEXT_DIFF ? "a context diff" :
X`09    diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
X`09    diff_type == NORMAL_DIFF ? "a normal diff" :
X`09    "an ed script" );
X    if (p_indent && verbose)
X`09say3("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s");
X    skip_to(p_start,p_sline);
X    while (filearg`5B0`5D == Nullch) `7B
X`09if (force) `7B
X`09    say1("No file to patch.  Skipping...\n");
X`09    filearg`5B0`5D = savestr(bestguess);
X`09    return TRUE;
X`09`7D
X`09ask1("File to patch: ");
X`09if (*buf != '\n') `7B
X`09    if (bestguess)
X`09`09free(bestguess);
X`09    bestguess = savestr(buf);
X`09    filearg`5B0`5D = fetchname(buf, 0, FALSE);
X`09`7D
X`09if (filearg`5B0`5D == Nullch) `7B
X`09    ask1("No file found--skip this patch? `5Bn`5D ");
X`09    if (*buf != 'y') `7B
X`09`09continue;
X`09    `7D
X`09    if (verbose)
X`09`09say1("Skipping patch...\n");
X`09    filearg`5B0`5D = fetchname(bestguess, 0, TRUE);
X`09    skip_rest_of_patch = TRUE;
X`09    return TRUE;
X`09`7D
X    `7D
X    return TRUE;
X`7D
X
X/* Determine what kind of diff is in the remaining part of the patch file. *
V/
X
Xint
Xintuit_diff_type()
X`7B
X    Reg4 long this_line = 0;
X    Reg5 long previous_line;
X    Reg6 long first_command_line = -1;
X    long fcl_line;
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`5B0`5D == Nullch);
X
X    ok_to_create_file = FALSE;
X    Fseek(pfp, p_base, 0);
X    p_input_line = p_bline - 1;
X    for (;;) `7B
X`09previous_line = this_line;
X`09last_line_was_command = this_is_a_command;
X`09stars_last_line = stars_this_line;
X`09this_line = ftell(pfp);
X`09indent = 0;
X`09p_input_line++;
X`09if (fgets(buf, sizeof buf, pfp) == Nullch) `7B
X`09    if (first_command_line >= 0L) `7B
X`09`09`09`09`09/* nothing but deletes!? */
X`09`09p_start = first_command_line;
X`09`09p_sline = fcl_line;
X`09`09retval = ED_DIFF;
X`09`09goto scan_exit;
X`09    `7D
X`09    else `7B
X`09`09p_start = this_line;
X`09`09p_sline = p_input_line;
X`09`09retval = 0;
X`09`09goto scan_exit;
X`09    `7D
X`09`7D
X`09for (s = buf; *s == ' ' `7C`7C *s == '\t'; s++) `7B
X`09    if (*s == '\t')
X`09`09indent += 8 - (indent % 8);
X`09    else
X`09`09indent++;
X`09`7D
X`09for (t=s; isdigit(*t) `7C`7C *t == ','; t++) ;`20
X`09this_is_a_command = (isdigit(*s) &&
X`09  (*t == 'd' `7C`7C *t == 'c' `7C`7C *t == 'a') );
X`09if (first_command_line < 0L && this_is_a_command) `7B`20
X`09    first_command_line = this_line;
X`09    fcl_line = p_input_line;
X`09    p_indent = indent;`09`09/* assume this for now */
X`09`7D
X`09if (!stars_last_line && strnEQ(s, "*** ", 4))
X`09    oldtmp = savestr(s+4);
X`09else if (strnEQ(s, "--- ", 4))
X`09    newtmp = savestr(s+4);
X`09else if (strnEQ(s, "Index:", 6))
X`09    indtmp = savestr(s+6);
X`09else if (strnEQ(s, "Prereq:", 7)) `7B
X`09    for (t=s+7; isspace(*t); t++) ;
X`09    revision = savestr(t);
X`09    for (t=revision; *t && !isspace(*t); t++) ;
X`09    *t = '\0';
X`09    if (!*revision) `7B
X`09`09free(revision);
X`09`09revision = Nullch;
X`09    `7D
X`09`7D
X`09if ((!diff_type `7C`7C diff_type == ED_DIFF) &&
X`09  first_command_line >= 0L &&
X`09  strEQ(s, ".\n") ) `7B
X`09    p_indent = indent;
X`09    p_start = first_command_line;
X`09    p_sline = fcl_line;
X`09    retval = ED_DIFF;
X`09    goto scan_exit;
X`09`7D
X`09stars_this_line = strnEQ(s, "********", 8);
X`09if ((!diff_type `7C`7C diff_type == CONTEXT_DIFF) && stars_last_line &&
X`09`09 strnEQ(s, "*** ", 4)) `7B
X`09    if (!atol(s+4))
X`09`09ok_to_create_file = TRUE;
X`09    /* if this is a new context diff the character just before */
X`09    /* the newline is a '*'. */
X`09    while (*s != '\n')
X`09`09s++;
X`09    p_indent = indent;
+-+-+-+-+-+-+-+-  END  OF PART 3 +-+-+-+-+-+-+-+-
