-+-+-+-+-+-+-+-+ 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= 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 '= 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 +-+-+-+-+-+-+-+-