124294Smckusick #ifndef lint 2*24295Smckusick static char sccsid[] = "@(#)patch.c 5.2 (Berkeley) 08/16/85"; 324294Smckusick #endif not lint 424294Smckusick 524294Smckusick /* patch - a program to apply diffs to original files 624294Smckusick * 724294Smckusick * $Header: patch.c,v 1.3 85/03/26 15:07:43 lwall Exp $ 824294Smckusick * 924294Smckusick * Copyright 1984, Larry Wall 1024294Smckusick * 1124294Smckusick * This program may be copied as long as you don't try to make any 1224294Smckusick * money off of it, or pretend that you wrote it. 1324294Smckusick * 1424294Smckusick * $Log: patch.c,v $ 15*24295Smckusick * 85/08/15 van%ucbmonet@berkeley 16*24295Smckusick * Changes for 4.3bsd diff -c. 17*24295Smckusick * 1824294Smckusick * Revision 1.3 85/03/26 15:07:43 lwall 1924294Smckusick * Frozen. 2024294Smckusick * 2124294Smckusick * Revision 1.2.1.9 85/03/12 17:03:35 lwall 2224294Smckusick * Changed pfp->_file to fileno(pfp). 2324294Smckusick * 2424294Smckusick * Revision 1.2.1.8 85/03/12 16:30:43 lwall 2524294Smckusick * Check i_ptr and i_womp to make sure they aren't null before freeing. 2624294Smckusick * Also allow ed output to be suppressed. 2724294Smckusick * 2824294Smckusick * Revision 1.2.1.7 85/03/12 15:56:13 lwall 2924294Smckusick * Added -p option from jromine@uci-750a. 3024294Smckusick * 3124294Smckusick * Revision 1.2.1.6 85/03/12 12:12:51 lwall 3224294Smckusick * Now checks for normalness of file to patch. 3324294Smckusick * 3424294Smckusick * Revision 1.2.1.5 85/03/12 11:52:12 lwall 3524294Smckusick * Added -D (#ifdef) option from joe@fluke. 3624294Smckusick * 3724294Smckusick * Revision 1.2.1.4 84/12/06 11:14:15 lwall 3824294Smckusick * Made smarter about SCCS subdirectories. 3924294Smckusick * 4024294Smckusick * Revision 1.2.1.3 84/12/05 11:18:43 lwall 4124294Smckusick * Added -l switch to do loose string comparison. 4224294Smckusick * 4324294Smckusick * Revision 1.2.1.2 84/12/04 09:47:13 lwall 4424294Smckusick * Failed hunk count not reset on multiple patch file. 4524294Smckusick * 4624294Smckusick * Revision 1.2.1.1 84/12/04 09:42:37 lwall 4724294Smckusick * Branch for sdcrdcf changes. 4824294Smckusick * 4924294Smckusick * Revision 1.2 84/11/29 13:29:51 lwall 5024294Smckusick * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed 5124294Smckusick * multiple calls to mktemp(). Will now work on machines that can only 5224294Smckusick * read 32767 chars. Added -R option for diffs with new and old swapped. 5324294Smckusick * Various cosmetic changes. 5424294Smckusick * 5524294Smckusick * Revision 1.1 84/11/09 17:03:58 lwall 5624294Smckusick * Initial revision 5724294Smckusick * 5824294Smckusick */ 5924294Smckusick 6024294Smckusick #define DEBUGGING 6124294Smckusick 6224294Smckusick /* shut lint up about the following when return value ignored */ 6324294Smckusick 6424294Smckusick #define Signal (void)signal 6524294Smckusick #define Unlink (void)unlink 6624294Smckusick #define Lseek (void)lseek 6724294Smckusick #define Fseek (void)fseek 6824294Smckusick #define Fstat (void)fstat 6924294Smckusick #define Pclose (void)pclose 7024294Smckusick #define Close (void)close 7124294Smckusick #define Fclose (void)fclose 7224294Smckusick #define Fflush (void)fflush 7324294Smckusick #define Sprintf (void)sprintf 7424294Smckusick #define Mktemp (void)mktemp 7524294Smckusick #define Strcpy (void)strcpy 7624294Smckusick #define Strcat (void)strcat 7724294Smckusick 7824294Smckusick #include <stdio.h> 7924294Smckusick #include <assert.h> 8024294Smckusick #include <sys/types.h> 8124294Smckusick #include <sys/stat.h> 8224294Smckusick #include <ctype.h> 8324294Smckusick #include <signal.h> 8424294Smckusick 8524294Smckusick /* constants */ 8624294Smckusick 8724294Smckusick #define TRUE (1) 8824294Smckusick #define FALSE (0) 8924294Smckusick 9024294Smckusick #define MAXHUNKSIZE 500 9124294Smckusick #define MAXLINELEN 1024 9224294Smckusick #define BUFFERSIZE 1024 9324294Smckusick #define ORIGEXT ".orig" 9424294Smckusick #define SCCSPREFIX "s." 9524294Smckusick #define GET "get -e %s" 9624294Smckusick #define RCSSUFFIX ",v" 9724294Smckusick #define CHECKOUT "co -l %s" 9824294Smckusick 9924294Smckusick /* handy definitions */ 10024294Smckusick 10124294Smckusick #define Null(t) ((t)0) 10224294Smckusick #define Nullch Null(char *) 10324294Smckusick #define Nullfp Null(FILE *) 10424294Smckusick 10524294Smckusick #define Ctl(ch) (ch & 037) 10624294Smckusick 10724294Smckusick #define strNE(s1,s2) (strcmp(s1,s2)) 10824294Smckusick #define strEQ(s1,s2) (!strcmp(s1,s2)) 10924294Smckusick #define strnNE(s1,s2,l) (strncmp(s1,s2,l)) 11024294Smckusick #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l)) 11124294Smckusick 11224294Smckusick /* typedefs */ 11324294Smckusick 11424294Smckusick typedef char bool; 11524294Smckusick typedef long LINENUM; /* must be signed */ 11624294Smckusick typedef unsigned MEM; /* what to feed malloc */ 11724294Smckusick 11824294Smckusick /* globals */ 11924294Smckusick 12024294Smckusick int Argc; /* guess */ 12124294Smckusick char **Argv; 12224294Smckusick 12324294Smckusick struct stat filestat; /* file statistics area */ 12424294Smckusick 12524294Smckusick char serrbuf[BUFSIZ]; /* buffer for stderr */ 12624294Smckusick char buf[MAXLINELEN]; /* general purpose buffer */ 12724294Smckusick FILE *pfp = Nullfp; /* patch file pointer */ 12824294Smckusick FILE *ofp = Nullfp; /* output file pointer */ 12924294Smckusick FILE *rejfp = Nullfp; /* reject file pointer */ 13024294Smckusick 13124294Smckusick LINENUM input_lines = 0; /* how long is input file in lines */ 13224294Smckusick LINENUM last_frozen_line = 0; /* how many input lines have been */ 13324294Smckusick /* irretractibly output */ 13424294Smckusick 13524294Smckusick #define MAXFILEC 2 13624294Smckusick int filec = 0; /* how many file arguments? */ 13724294Smckusick char *filearg[MAXFILEC]; 13824294Smckusick 13924294Smckusick char *outname = Nullch; 14024294Smckusick char rejname[128]; 14124294Smckusick 14224294Smckusick char *origext = Nullch; 14324294Smckusick 14424294Smckusick char TMPOUTNAME[] = "/tmp/patchoXXXXXX"; 14524294Smckusick char TMPINNAME[] = "/tmp/patchiXXXXXX"; /* you might want /usr/tmp here */ 14624294Smckusick char TMPREJNAME[] = "/tmp/patchrXXXXXX"; 14724294Smckusick char TMPPATNAME[] = "/tmp/patchpXXXXXX"; 14824294Smckusick 14924294Smckusick LINENUM last_offset = 0; 15024294Smckusick #ifdef DEBUGGING 15124294Smckusick int debug = 0; 15224294Smckusick #endif 15324294Smckusick bool verbose = TRUE; 15424294Smckusick bool reverse = FALSE; 15524294Smckusick bool usepath = FALSE; 15624294Smckusick bool canonicalize = FALSE; 15724294Smckusick 15824294Smckusick #define CONTEXT_DIFF 1 15924294Smckusick #define NORMAL_DIFF 2 16024294Smckusick #define ED_DIFF 3 161*24295Smckusick #define NEW_CONTEXT_DIFF 4 16224294Smckusick int diff_type = 0; 16324294Smckusick 16424294Smckusick int do_defines = 0; /* patch using ifdef, ifndef, etc. */ 16524294Smckusick char if_defined[128]; /* #ifdef xyzzy */ 16624294Smckusick char not_defined[128]; /* #ifndef xyzzy */ 16724294Smckusick char else_defined[] = "#else\n"; /* #else */ 16824294Smckusick char end_defined[128]; /* #endif xyzzy */ 16924294Smckusick 17024294Smckusick char *revision = Nullch; /* prerequisite revision, if any */ 17124294Smckusick 17224294Smckusick /* procedures */ 17324294Smckusick 17424294Smckusick LINENUM locate_hunk(); 17524294Smckusick bool patch_match(); 17624294Smckusick bool similar(); 17724294Smckusick char *malloc(); 17824294Smckusick char *savestr(); 17924294Smckusick char *strcpy(); 18024294Smckusick char *strcat(); 18124294Smckusick char *sprintf(); /* usually */ 18224294Smckusick int my_exit(); 18324294Smckusick bool rev_in_string(); 18424294Smckusick char *fetchname(); 18524294Smckusick long atol(); 18624294Smckusick long lseek(); 18724294Smckusick char *mktemp(); 18824294Smckusick 18924294Smckusick /* patch type */ 19024294Smckusick 19124294Smckusick bool there_is_another_patch(); 19224294Smckusick bool another_hunk(); 19324294Smckusick char *pfetch(); 19424294Smckusick int pch_line_len(); 19524294Smckusick LINENUM pch_first(); 19624294Smckusick LINENUM pch_ptrn_lines(); 19724294Smckusick LINENUM pch_newfirst(); 19824294Smckusick LINENUM pch_repl_lines(); 19924294Smckusick LINENUM pch_end(); 20024294Smckusick LINENUM pch_context(); 20124294Smckusick LINENUM pch_hunk_beg(); 20224294Smckusick char pch_char(); 20324294Smckusick char *pfetch(); 20424294Smckusick char *pgets(); 20524294Smckusick 20624294Smckusick /* input file type */ 20724294Smckusick 20824294Smckusick char *ifetch(); 20924294Smckusick 21024294Smckusick /* apply a context patch to a named file */ 21124294Smckusick 21224294Smckusick main(argc,argv) 21324294Smckusick int argc; 21424294Smckusick char **argv; 21524294Smckusick { 21624294Smckusick LINENUM where; 21724294Smckusick int hunk = 0; 21824294Smckusick int failed = 0; 21924294Smckusick int i; 22024294Smckusick 22124294Smckusick setbuf(stderr,serrbuf); 22224294Smckusick for (i = 0; i<MAXFILEC; i++) 22324294Smckusick filearg[i] = Nullch; 22424294Smckusick Mktemp(TMPOUTNAME); 22524294Smckusick Mktemp(TMPINNAME); 22624294Smckusick Mktemp(TMPREJNAME); 22724294Smckusick Mktemp(TMPPATNAME); 22824294Smckusick 22924294Smckusick /* parse switches */ 23024294Smckusick Argc = argc; 23124294Smckusick Argv = argv; 23224294Smckusick get_some_switches(); 23324294Smckusick 23424294Smckusick /* make sure we clean up /tmp in case of disaster */ 23524294Smckusick set_signals(); 23624294Smckusick 23724294Smckusick for ( 23824294Smckusick open_patch_file(filearg[1]); 23924294Smckusick there_is_another_patch(); 24024294Smckusick reinitialize_almost_everything() 24124294Smckusick ) { /* for each patch in patch file */ 24224294Smckusick 24324294Smckusick if (outname == Nullch) 24424294Smckusick outname = savestr(filearg[0]); 24524294Smckusick 24624294Smckusick /* initialize the patched file */ 24724294Smckusick init_output(TMPOUTNAME); 24824294Smckusick 24924294Smckusick /* for ed script just up and do it and exit */ 25024294Smckusick if (diff_type == ED_DIFF) { 25124294Smckusick do_ed_script(); 25224294Smckusick continue; 25324294Smckusick } 25424294Smckusick 25524294Smckusick /* initialize reject file */ 25624294Smckusick init_reject(TMPREJNAME); 25724294Smckusick 25824294Smckusick /* find out where all the lines are */ 25924294Smckusick scan_input(filearg[0]); 26024294Smckusick 26124294Smckusick /* from here on, open no standard i/o files, because malloc */ 26224294Smckusick /* might misfire */ 26324294Smckusick 26424294Smckusick /* apply each hunk of patch */ 26524294Smckusick hunk = 0; 26624294Smckusick failed = 0; 26724294Smckusick while (another_hunk()) { 26824294Smckusick hunk++; 26924294Smckusick where = locate_hunk(); 27024294Smckusick if (hunk == 1 && where == Null(LINENUM)) { 27124294Smckusick /* dwim for reversed patch? */ 27224294Smckusick pch_swap(); 27324294Smckusick reverse = !reverse; 27424294Smckusick where = locate_hunk(); /* try again */ 27524294Smckusick if (where == Null(LINENUM)) { 27624294Smckusick pch_swap(); /* no, put it back to normal */ 27724294Smckusick reverse = !reverse; 27824294Smckusick } 27924294Smckusick else { 28024294Smckusick say("%seversed (or previously applied) patch detected! %s -R.\n", 28124294Smckusick reverse ? "R" : "Unr", 28224294Smckusick reverse ? "Assuming" : "Ignoring"); 28324294Smckusick } 28424294Smckusick } 28524294Smckusick if (where == Null(LINENUM)) { 28624294Smckusick abort_hunk(); 28724294Smckusick failed++; 28824294Smckusick if (verbose) 28924294Smckusick say("Hunk #%d failed.\n",hunk); 29024294Smckusick } 29124294Smckusick else { 29224294Smckusick apply_hunk(where); 29324294Smckusick if (verbose) 29424294Smckusick if (last_offset) 29524294Smckusick say("Hunk #%d succeeded (offset %d line%s).\n", 29624294Smckusick hunk,last_offset,last_offset==1?"":"s"); 29724294Smckusick else 29824294Smckusick say("Hunk #%d succeeded.\n", hunk); 29924294Smckusick } 30024294Smckusick } 30124294Smckusick 30224294Smckusick assert(hunk); 30324294Smckusick 30424294Smckusick /* finish spewing out the new file */ 30524294Smckusick spew_output(); 30624294Smckusick 30724294Smckusick /* and put the output where desired */ 30824294Smckusick ignore_signals(); 30924294Smckusick move_file(TMPOUTNAME,outname); 31024294Smckusick Fclose(rejfp); 31124294Smckusick rejfp = Nullfp; 31224294Smckusick if (failed) { 31324294Smckusick if (!*rejname) { 31424294Smckusick Strcpy(rejname, outname); 31524294Smckusick Strcat(rejname, ".rej"); 31624294Smckusick } 31724294Smckusick say("%d out of %d hunks failed--saving rejects to %s\n", 31824294Smckusick failed, hunk, rejname); 31924294Smckusick move_file(TMPREJNAME,rejname); 32024294Smckusick } 32124294Smckusick set_signals(); 32224294Smckusick } 32324294Smckusick my_exit(0); 32424294Smckusick } 32524294Smckusick 32624294Smckusick reinitialize_almost_everything() 32724294Smckusick { 32824294Smckusick re_patch(); 32924294Smckusick re_input(); 33024294Smckusick 33124294Smckusick input_lines = 0; 33224294Smckusick last_frozen_line = 0; 33324294Smckusick 33424294Smckusick filec = 0; 33524294Smckusick if (filearg[0] != Nullch) { 33624294Smckusick free(filearg[0]); 33724294Smckusick filearg[0] = Nullch; 33824294Smckusick } 33924294Smckusick 34024294Smckusick if (outname != Nullch) { 34124294Smckusick free(outname); 34224294Smckusick outname = Nullch; 34324294Smckusick } 34424294Smckusick 34524294Smckusick last_offset = 0; 34624294Smckusick 34724294Smckusick diff_type = 0; 34824294Smckusick 34924294Smckusick if (revision != Nullch) { 35024294Smckusick free(revision); 35124294Smckusick revision = Nullch; 35224294Smckusick } 35324294Smckusick 35424294Smckusick reverse = FALSE; 35524294Smckusick 35624294Smckusick get_some_switches(); 35724294Smckusick 35824294Smckusick if (filec >= 2) 35924294Smckusick fatal("You may not change to a different patch file.\n"); 36024294Smckusick } 36124294Smckusick 36224294Smckusick get_some_switches() 36324294Smckusick { 36424294Smckusick register char *s; 36524294Smckusick 36624294Smckusick rejname[0] = '\0'; 36724294Smckusick if (!Argc) 36824294Smckusick return; 36924294Smckusick for (Argc--,Argv++; Argc; Argc--,Argv++) { 37024294Smckusick s = Argv[0]; 37124294Smckusick if (strEQ(s,"+")) { 37224294Smckusick return; /* + will be skipped by for loop */ 37324294Smckusick } 37424294Smckusick if (*s != '-' || !s[1]) { 37524294Smckusick if (filec == MAXFILEC) 37624294Smckusick fatal("Too many file arguments.\n"); 37724294Smckusick filearg[filec++] = savestr(s); 37824294Smckusick } 37924294Smckusick else { 38024294Smckusick switch (*++s) { 38124294Smckusick case 'b': 38224294Smckusick origext = savestr(Argv[1]); 38324294Smckusick Argc--,Argv++; 38424294Smckusick break; 38524294Smckusick case 'c': 38624294Smckusick diff_type = CONTEXT_DIFF; 38724294Smckusick break; 38824294Smckusick case 'd': 38924294Smckusick if (chdir(Argv[1]) < 0) 39024294Smckusick fatal("Can't cd to %s.\n",Argv[1]); 39124294Smckusick Argc--,Argv++; 39224294Smckusick break; 39324294Smckusick case 'D': 39424294Smckusick do_defines++; 39524294Smckusick Sprintf(if_defined, "#ifdef %s\n", Argv[1]); 39624294Smckusick Sprintf(not_defined, "#ifndef %s\n", Argv[1]); 39724294Smckusick Sprintf(end_defined, "#endif %s\n", Argv[1]); 39824294Smckusick Argc--,Argv++; 39924294Smckusick break; 40024294Smckusick case 'e': 40124294Smckusick diff_type = ED_DIFF; 40224294Smckusick break; 40324294Smckusick case 'l': 40424294Smckusick canonicalize = TRUE; 40524294Smckusick break; 40624294Smckusick case 'n': 40724294Smckusick diff_type = NORMAL_DIFF; 40824294Smckusick break; 40924294Smckusick case 'o': 41024294Smckusick outname = savestr(Argv[1]); 41124294Smckusick Argc--,Argv++; 41224294Smckusick break; 41324294Smckusick case 'p': 41424294Smckusick usepath = TRUE; /* do not strip path names */ 41524294Smckusick break; 41624294Smckusick case 'r': 41724294Smckusick Strcpy(rejname,Argv[1]); 41824294Smckusick Argc--,Argv++; 41924294Smckusick break; 42024294Smckusick case 'R': 42124294Smckusick reverse = TRUE; 42224294Smckusick break; 42324294Smckusick case 's': 42424294Smckusick verbose = FALSE; 42524294Smckusick break; 42624294Smckusick #ifdef DEBUGGING 42724294Smckusick case 'x': 42824294Smckusick debug = atoi(s+1); 42924294Smckusick break; 43024294Smckusick #endif 43124294Smckusick default: 43224294Smckusick fatal("Unrecognized switch: %s\n",Argv[0]); 43324294Smckusick } 43424294Smckusick } 43524294Smckusick } 43624294Smckusick } 43724294Smckusick 43824294Smckusick LINENUM 43924294Smckusick locate_hunk() 44024294Smckusick { 44124294Smckusick register LINENUM first_guess = pch_first() + last_offset; 44224294Smckusick register LINENUM offset; 44324294Smckusick LINENUM pat_lines = pch_ptrn_lines(); 44424294Smckusick register LINENUM max_pos_offset = input_lines - first_guess 44524294Smckusick - pat_lines + 1; 44624294Smckusick register LINENUM max_neg_offset = first_guess - last_frozen_line - 1 44724294Smckusick - pch_context(); 44824294Smckusick 44924294Smckusick if (!pat_lines) /* null range matches always */ 45024294Smckusick return first_guess; 45124294Smckusick if (max_neg_offset >= first_guess) /* do not try lines < 0 */ 45224294Smckusick max_neg_offset = first_guess - 1; 45324294Smckusick if (first_guess <= input_lines && patch_match(first_guess,(LINENUM)0)) 45424294Smckusick return first_guess; 45524294Smckusick for (offset = 1; ; offset++) { 45624294Smckusick bool check_after = (offset <= max_pos_offset); 45724294Smckusick bool check_before = (offset <= max_pos_offset); 45824294Smckusick 45924294Smckusick if (check_after && patch_match(first_guess,offset)) { 46024294Smckusick #ifdef DEBUGGING 46124294Smckusick if (debug & 1) 46224294Smckusick printf("Offset changing from %d to %d\n",last_offset,offset); 46324294Smckusick #endif 46424294Smckusick last_offset = offset; 46524294Smckusick return first_guess+offset; 46624294Smckusick } 46724294Smckusick else if (check_before && patch_match(first_guess,-offset)) { 46824294Smckusick #ifdef DEBUGGING 46924294Smckusick if (debug & 1) 47024294Smckusick printf("Offset changing from %d to %d\n",last_offset,-offset); 47124294Smckusick #endif 47224294Smckusick last_offset = -offset; 47324294Smckusick return first_guess-offset; 47424294Smckusick } 47524294Smckusick else if (!check_before && !check_after) 47624294Smckusick return Null(LINENUM); 47724294Smckusick } 47824294Smckusick } 47924294Smckusick 48024294Smckusick /* we did not find the pattern, dump out the hunk so they can handle it */ 48124294Smckusick 48224294Smckusick abort_hunk() 48324294Smckusick { 48424294Smckusick register LINENUM i; 48524294Smckusick register LINENUM pat_end = pch_end(); 48624294Smckusick /* add in last_offset to guess the same as the previous successful hunk */ 48724294Smckusick int oldfirst = pch_first() + last_offset; 48824294Smckusick int newfirst = pch_newfirst() + last_offset; 48924294Smckusick int oldlast = oldfirst + pch_ptrn_lines() - 1; 49024294Smckusick int newlast = newfirst + pch_repl_lines() - 1; 49124294Smckusick 49224294Smckusick fprintf(rejfp,"***************\n"); 49324294Smckusick for (i=0; i<=pat_end; i++) { 49424294Smckusick switch (pch_char(i)) { 49524294Smckusick case '*': 49624294Smckusick fprintf(rejfp,"*** %d,%d\n", oldfirst, oldlast); 49724294Smckusick break; 49824294Smckusick case '=': 49924294Smckusick fprintf(rejfp,"--- %d,%d -----\n", newfirst, newlast); 50024294Smckusick break; 50124294Smckusick case '\n': 50224294Smckusick fprintf(rejfp,"%s", pfetch(i)); 50324294Smckusick break; 50424294Smckusick case ' ': case '-': case '+': case '!': 50524294Smckusick fprintf(rejfp,"%c %s", pch_char(i), pfetch(i)); 50624294Smckusick break; 50724294Smckusick default: 50824294Smckusick say("Fatal internal error in abort_hunk().\n"); 50924294Smckusick abort(); 51024294Smckusick } 51124294Smckusick } 51224294Smckusick } 51324294Smckusick 51424294Smckusick /* we found where to apply it (we hope), so do it */ 51524294Smckusick 51624294Smckusick apply_hunk(where) 51724294Smckusick LINENUM where; 51824294Smckusick { 51924294Smckusick register LINENUM old = 1; 52024294Smckusick register LINENUM lastline = pch_ptrn_lines(); 52124294Smckusick register LINENUM new = lastline+1; 52224294Smckusick register int def_state = 0; /* -1 = ifndef, 1 = ifdef */ 52324294Smckusick 52424294Smckusick where--; 52524294Smckusick while (pch_char(new) == '=' || pch_char(new) == '\n') 52624294Smckusick new++; 52724294Smckusick 52824294Smckusick while (old <= lastline) { 52924294Smckusick if (pch_char(old) == '-') { 53024294Smckusick copy_till(where + old - 1); 53124294Smckusick if (do_defines) { 53224294Smckusick if (def_state == 0) { 53324294Smckusick fputs(not_defined, ofp); 53424294Smckusick def_state = -1; 53524294Smckusick } else 53624294Smckusick if (def_state == 1) { 53724294Smckusick fputs(else_defined, ofp); 53824294Smckusick def_state = 2; 53924294Smckusick } 54024294Smckusick fputs(pfetch(old), ofp); 54124294Smckusick } 54224294Smckusick last_frozen_line++; 54324294Smckusick old++; 54424294Smckusick } 54524294Smckusick else if (pch_char(new) == '+') { 54624294Smckusick copy_till(where + old - 1); 54724294Smckusick if (do_defines) { 54824294Smckusick if (def_state == -1) { 54924294Smckusick fputs(else_defined, ofp); 55024294Smckusick def_state = 2; 55124294Smckusick } else 55224294Smckusick if (def_state == 0) { 55324294Smckusick fputs(if_defined, ofp); 55424294Smckusick def_state = 1; 55524294Smckusick } 55624294Smckusick } 55724294Smckusick fputs(pfetch(new),ofp); 55824294Smckusick new++; 55924294Smckusick } 56024294Smckusick else { 56124294Smckusick if (pch_char(new) != pch_char(old)) { 56224294Smckusick say("Out-of-sync patch, lines %d,%d\n", 56324294Smckusick pch_hunk_beg() + old - 1, 56424294Smckusick pch_hunk_beg() + new - 1); 56524294Smckusick #ifdef DEBUGGING 56624294Smckusick printf("oldchar = '%c', newchar = '%c'\n", 56724294Smckusick pch_char(old), pch_char(new)); 56824294Smckusick #endif 56924294Smckusick my_exit(1); 57024294Smckusick } 57124294Smckusick if (pch_char(new) == '!') { 57224294Smckusick copy_till(where + old - 1); 57324294Smckusick if (do_defines) { 57424294Smckusick fputs(not_defined,ofp); 57524294Smckusick def_state = -1; 57624294Smckusick } 57724294Smckusick while (pch_char(old) == '!') { 57824294Smckusick if (do_defines) { 57924294Smckusick fputs(pfetch(old),ofp); 58024294Smckusick } 58124294Smckusick last_frozen_line++; 58224294Smckusick old++; 58324294Smckusick } 58424294Smckusick if (do_defines) { 58524294Smckusick fputs(else_defined, ofp); 58624294Smckusick def_state = 2; 58724294Smckusick } 58824294Smckusick while (pch_char(new) == '!') { 58924294Smckusick fputs(pfetch(new),ofp); 59024294Smckusick new++; 59124294Smckusick } 59224294Smckusick if (do_defines) { 59324294Smckusick fputs(end_defined, ofp); 59424294Smckusick def_state = 0; 59524294Smckusick } 59624294Smckusick } 59724294Smckusick else { 59824294Smckusick assert(pch_char(new) == ' '); 59924294Smckusick old++; 60024294Smckusick new++; 60124294Smckusick } 60224294Smckusick } 60324294Smckusick } 60424294Smckusick if (new <= pch_end() && pch_char(new) == '+') { 60524294Smckusick copy_till(where + old - 1); 60624294Smckusick if (do_defines) { 60724294Smckusick if (def_state == 0) { 60824294Smckusick fputs(if_defined, ofp); 60924294Smckusick def_state = 1; 61024294Smckusick } else 61124294Smckusick if (def_state == -1) { 61224294Smckusick fputs(else_defined, ofp); 61324294Smckusick def_state = 2; 61424294Smckusick } 61524294Smckusick } 61624294Smckusick while (new <= pch_end() && pch_char(new) == '+') { 61724294Smckusick fputs(pfetch(new),ofp); 61824294Smckusick new++; 61924294Smckusick } 62024294Smckusick } 62124294Smckusick if (do_defines && def_state) { 62224294Smckusick fputs(end_defined, ofp); 62324294Smckusick } 62424294Smckusick } 62524294Smckusick 62624294Smckusick do_ed_script() 62724294Smckusick { 62824294Smckusick FILE *pipefp, *popen(); 62924294Smckusick bool this_line_is_command = FALSE; 63024294Smckusick register char *t; 63124294Smckusick long beginning_of_this_line; 63224294Smckusick 63324294Smckusick Unlink(TMPOUTNAME); 63424294Smckusick copy_file(filearg[0],TMPOUTNAME); 63524294Smckusick if (verbose) 63624294Smckusick Sprintf(buf,"/bin/ed %s",TMPOUTNAME); 63724294Smckusick else 63824294Smckusick Sprintf(buf,"/bin/ed - %s",TMPOUTNAME); 63924294Smckusick pipefp = popen(buf,"w"); 64024294Smckusick for (;;) { 64124294Smckusick beginning_of_this_line = ftell(pfp); 64224294Smckusick if (pgets(buf,sizeof buf,pfp) == Nullch) { 64324294Smckusick next_intuit_at(beginning_of_this_line); 64424294Smckusick break; 64524294Smckusick } 64624294Smckusick for (t=buf; isdigit(*t) || *t == ','; t++) ; 64724294Smckusick this_line_is_command = (isdigit(*buf) && 64824294Smckusick (*t == 'd' || *t == 'c' || *t == 'a') ); 64924294Smckusick if (this_line_is_command) { 65024294Smckusick fputs(buf,pipefp); 65124294Smckusick if (*t != 'd') { 65224294Smckusick while (pgets(buf,sizeof buf,pfp) != Nullch) { 65324294Smckusick fputs(buf,pipefp); 65424294Smckusick if (strEQ(buf,".\n")) 65524294Smckusick break; 65624294Smckusick } 65724294Smckusick } 65824294Smckusick } 65924294Smckusick else { 66024294Smckusick next_intuit_at(beginning_of_this_line); 66124294Smckusick break; 66224294Smckusick } 66324294Smckusick } 66424294Smckusick fprintf(pipefp,"w\n"); 66524294Smckusick fprintf(pipefp,"q\n"); 66624294Smckusick Fflush(pipefp); 66724294Smckusick Pclose(pipefp); 66824294Smckusick ignore_signals(); 66924294Smckusick move_file(TMPOUTNAME,outname); 67024294Smckusick set_signals(); 67124294Smckusick } 67224294Smckusick 67324294Smckusick init_output(name) 67424294Smckusick char *name; 67524294Smckusick { 67624294Smckusick ofp = fopen(name,"w"); 67724294Smckusick if (ofp == Nullfp) 67824294Smckusick fatal("patch: can't create %s.\n",name); 67924294Smckusick } 68024294Smckusick 68124294Smckusick init_reject(name) 68224294Smckusick char *name; 68324294Smckusick { 68424294Smckusick rejfp = fopen(name,"w"); 68524294Smckusick if (rejfp == Nullfp) 68624294Smckusick fatal("patch: can't create %s.\n",name); 68724294Smckusick } 68824294Smckusick 68924294Smckusick move_file(from,to) 69024294Smckusick char *from, *to; 69124294Smckusick { 69224294Smckusick char bakname[512]; 69324294Smckusick register char *s; 69424294Smckusick int fromfd; 69524294Smckusick register int i; 69624294Smckusick 69724294Smckusick /* to stdout? */ 69824294Smckusick 69924294Smckusick if (strEQ(to,"-")) { 70024294Smckusick #ifdef DEBUGGING 70124294Smckusick if (debug & 4) 70224294Smckusick say("Moving %s to stdout.\n",from); 70324294Smckusick #endif 70424294Smckusick fromfd = open(from,0); 70524294Smckusick if (fromfd < 0) 70624294Smckusick fatal("patch: internal error, can't reopen %s\n",from); 70724294Smckusick while ((i=read(fromfd,buf,sizeof buf)) > 0) 70824294Smckusick if (write(1,buf,i) != 1) 70924294Smckusick fatal("patch: write failed\n"); 71024294Smckusick Close(fromfd); 71124294Smckusick return; 71224294Smckusick } 71324294Smckusick 71424294Smckusick Strcpy(bakname,to); 71524294Smckusick Strcat(bakname,origext?origext:ORIGEXT); 71624294Smckusick if (stat(to,&filestat) >= 0) { /* output file exists */ 71724294Smckusick dev_t to_device = filestat.st_dev; 71824294Smckusick ino_t to_inode = filestat.st_ino; 71924294Smckusick char *simplename = bakname; 72024294Smckusick 72124294Smckusick for (s=bakname; *s; s++) { 72224294Smckusick if (*s == '/') 72324294Smckusick simplename = s+1; 72424294Smckusick } 72524294Smckusick /* find a backup name that is not the same file */ 72624294Smckusick while (stat(bakname,&filestat) >= 0 && 72724294Smckusick to_device == filestat.st_dev && to_inode == filestat.st_ino) { 72824294Smckusick for (s=simplename; *s && !islower(*s); s++) ; 72924294Smckusick if (*s) 73024294Smckusick *s = toupper(*s); 73124294Smckusick else 73224294Smckusick Strcpy(simplename, simplename+1); 73324294Smckusick } 73424294Smckusick while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */ 73524294Smckusick #ifdef DEBUGGING 73624294Smckusick if (debug & 4) 73724294Smckusick say("Moving %s to %s.\n",to,bakname); 73824294Smckusick #endif 73924294Smckusick if (link(to,bakname) < 0) { 74024294Smckusick say("patch: can't backup %s, output is in %s\n", 74124294Smckusick to,from); 74224294Smckusick return; 74324294Smckusick } 74424294Smckusick while (unlink(to) >= 0) ; 74524294Smckusick } 74624294Smckusick #ifdef DEBUGGING 74724294Smckusick if (debug & 4) 74824294Smckusick say("Moving %s to %s.\n",from,to); 74924294Smckusick #endif 75024294Smckusick if (link(from,to) < 0) { /* different file system? */ 75124294Smckusick int tofd; 75224294Smckusick 75324294Smckusick tofd = creat(to,0666); 75424294Smckusick if (tofd < 0) { 75524294Smckusick say("patch: can't create %s, output is in %s.\n", 75624294Smckusick to, from); 75724294Smckusick return; 75824294Smckusick } 75924294Smckusick fromfd = open(from,0); 76024294Smckusick if (fromfd < 0) 76124294Smckusick fatal("patch: internal error, can't reopen %s\n",from); 76224294Smckusick while ((i=read(fromfd,buf,sizeof buf)) > 0) 76324294Smckusick if (write(tofd,buf,i) != i) 76424294Smckusick fatal("patch: write failed\n"); 76524294Smckusick Close(fromfd); 76624294Smckusick Close(tofd); 76724294Smckusick } 76824294Smckusick Unlink(from); 76924294Smckusick } 77024294Smckusick 77124294Smckusick copy_file(from,to) 77224294Smckusick char *from, *to; 77324294Smckusick { 77424294Smckusick int tofd; 77524294Smckusick int fromfd; 77624294Smckusick register int i; 77724294Smckusick 77824294Smckusick tofd = creat(to,0666); 77924294Smckusick if (tofd < 0) 78024294Smckusick fatal("patch: can't create %s.\n", to); 78124294Smckusick fromfd = open(from,0); 78224294Smckusick if (fromfd < 0) 78324294Smckusick fatal("patch: internal error, can't reopen %s\n",from); 78424294Smckusick while ((i=read(fromfd,buf,sizeof buf)) > 0) 78524294Smckusick if (write(tofd,buf,i) != i) 78624294Smckusick fatal("patch: write (%s) failed\n", to); 78724294Smckusick Close(fromfd); 78824294Smckusick Close(tofd); 78924294Smckusick } 79024294Smckusick 79124294Smckusick copy_till(lastline) 79224294Smckusick register LINENUM lastline; 79324294Smckusick { 79424294Smckusick if (last_frozen_line > lastline) 79524294Smckusick say("patch: misordered hunks! output will be garbled.\n"); 79624294Smckusick while (last_frozen_line < lastline) { 79724294Smckusick dump_line(++last_frozen_line); 79824294Smckusick } 79924294Smckusick } 80024294Smckusick 80124294Smckusick spew_output() 80224294Smckusick { 80324294Smckusick copy_till(input_lines); /* dump remainder of file */ 80424294Smckusick Fclose(ofp); 80524294Smckusick ofp = Nullfp; 80624294Smckusick } 80724294Smckusick 80824294Smckusick dump_line(line) 80924294Smckusick LINENUM line; 81024294Smckusick { 81124294Smckusick register char *s; 81224294Smckusick 81324294Smckusick for (s=ifetch(line,0); putc(*s,ofp) != '\n'; s++) ; 81424294Smckusick } 81524294Smckusick 81624294Smckusick /* does the patch pattern match at line base+offset? */ 81724294Smckusick 81824294Smckusick bool 81924294Smckusick patch_match(base,offset) 82024294Smckusick LINENUM base; 82124294Smckusick LINENUM offset; 82224294Smckusick { 82324294Smckusick register LINENUM pline; 82424294Smckusick register LINENUM iline; 82524294Smckusick register LINENUM pat_lines = pch_ptrn_lines(); 82624294Smckusick 82724294Smckusick for (pline = 1, iline=base+offset; pline <= pat_lines; pline++,iline++) { 82824294Smckusick if (canonicalize) { 82924294Smckusick if (!similar(ifetch(iline,(offset >= 0)), 83024294Smckusick pfetch(pline), 83124294Smckusick pch_line_len(pline) )) 83224294Smckusick return FALSE; 83324294Smckusick } 83424294Smckusick else if (strnNE(ifetch(iline,(offset >= 0)), 83524294Smckusick pfetch(pline), 83624294Smckusick pch_line_len(pline) )) 83724294Smckusick return FALSE; 83824294Smckusick } 83924294Smckusick return TRUE; 84024294Smckusick } 84124294Smckusick 84224294Smckusick /* match two lines with canonicalized white space */ 84324294Smckusick 84424294Smckusick bool 84524294Smckusick similar(a,b,len) 84624294Smckusick register char *a, *b; 84724294Smckusick register int len; 84824294Smckusick { 84924294Smckusick while (len) { 85024294Smckusick if (isspace(*b)) { /* whitespace (or \n) to match? */ 85124294Smckusick if (!isspace(*a)) /* no corresponding whitespace? */ 85224294Smckusick return FALSE; 85324294Smckusick while (len && isspace(*b) && *b != '\n') 85424294Smckusick b++,len--; /* skip pattern whitespace */ 85524294Smckusick while (isspace(*a) && *a != '\n') 85624294Smckusick a++; /* skip target whitespace */ 85724294Smckusick if (*a == '\n' || *b == '\n') 85824294Smckusick return (*a == *b); /* should end in sync */ 85924294Smckusick } 86024294Smckusick else if (*a++ != *b++) /* match non-whitespace chars */ 86124294Smckusick return FALSE; 86224294Smckusick else 86324294Smckusick len--; /* probably not necessary */ 86424294Smckusick } 86524294Smckusick return TRUE; /* actually, this is not reached */ 86624294Smckusick /* since there is always a \n */ 86724294Smckusick } 86824294Smckusick 86924294Smckusick /* input file with indexable lines abstract type */ 87024294Smckusick 87124294Smckusick bool using_plan_a = TRUE; 87224294Smckusick static long i_size; /* size of the input file */ 87324294Smckusick static char *i_womp; /* plan a buffer for entire file */ 87424294Smckusick static char **i_ptr; /* pointers to lines in i_womp */ 87524294Smckusick 87624294Smckusick static int tifd = -1; /* plan b virtual string array */ 87724294Smckusick static char *tibuf[2]; /* plan b buffers */ 87824294Smckusick static LINENUM tiline[2] = {-1,-1}; /* 1st line in each buffer */ 87924294Smckusick static LINENUM lines_per_buf; /* how many lines per buffer */ 88024294Smckusick static int tireclen; /* length of records in tmp file */ 88124294Smckusick 88224294Smckusick re_input() 88324294Smckusick { 88424294Smckusick if (using_plan_a) { 88524294Smckusick i_size = 0; 88624294Smckusick /*NOSTRICT*/ 88724294Smckusick if (i_ptr != Null(char**)) 88824294Smckusick free((char *)i_ptr); 88924294Smckusick if (i_womp != Nullch) 89024294Smckusick free(i_womp); 89124294Smckusick i_womp = Nullch; 89224294Smckusick i_ptr = Null(char **); 89324294Smckusick } 89424294Smckusick else { 89524294Smckusick using_plan_a = TRUE; /* maybe the next one is smaller */ 89624294Smckusick Close(tifd); 89724294Smckusick tifd = -1; 89824294Smckusick free(tibuf[0]); 89924294Smckusick free(tibuf[1]); 90024294Smckusick tibuf[0] = tibuf[1] = Nullch; 90124294Smckusick tiline[0] = tiline[1] = -1; 90224294Smckusick tireclen = 0; 90324294Smckusick } 90424294Smckusick } 90524294Smckusick 90624294Smckusick scan_input(filename) 90724294Smckusick char *filename; 90824294Smckusick { 90924294Smckusick bool plan_a(); 91024294Smckusick 91124294Smckusick if (!plan_a(filename)) 91224294Smckusick plan_b(filename); 91324294Smckusick } 91424294Smckusick 91524294Smckusick /* try keeping everything in memory */ 91624294Smckusick 91724294Smckusick bool 91824294Smckusick plan_a(filename) 91924294Smckusick char *filename; 92024294Smckusick { 92124294Smckusick int ifd; 92224294Smckusick register char *s; 92324294Smckusick register LINENUM iline; 92424294Smckusick 92524294Smckusick if (stat(filename,&filestat) < 0) { 92624294Smckusick Sprintf(buf,"RCS/%s%s",filename,RCSSUFFIX); 92724294Smckusick if (stat(buf,&filestat) >= 0 || stat(buf+4,&filestat) >= 0) { 92824294Smckusick Sprintf(buf,CHECKOUT,filename); 92924294Smckusick if (verbose) 93024294Smckusick say("Can't find %s--attempting to check it out from RCS.\n", 93124294Smckusick filename); 93224294Smckusick if (system(buf) || stat(filename,&filestat)) 93324294Smckusick fatal("Can't check out %s.\n",filename); 93424294Smckusick } 93524294Smckusick else { 93624294Smckusick Sprintf(buf,"SCCS/%s%s",SCCSPREFIX,filename); 93724294Smckusick if (stat(buf,&filestat) >= 0 || stat(buf+5,&filestat) >= 0) { 93824294Smckusick Sprintf(buf,GET,filename); 93924294Smckusick if (verbose) 94024294Smckusick say("Can't find %s--attempting to get it from SCCS.\n", 94124294Smckusick filename); 94224294Smckusick if (system(buf) || stat(filename,&filestat)) 94324294Smckusick fatal("Can't get %s.\n",filename); 94424294Smckusick } 94524294Smckusick else 94624294Smckusick fatal("Can't find %s.\n",filename); 94724294Smckusick } 94824294Smckusick } 94924294Smckusick if ((filestat.st_mode & S_IFMT) & ~S_IFREG) 95024294Smckusick fatal("%s is not a normal file--can't patch.\n",filename); 95124294Smckusick i_size = filestat.st_size; 95224294Smckusick /*NOSTRICT*/ 95324294Smckusick i_womp = malloc((MEM)(i_size+2)); 95424294Smckusick if (i_womp == Nullch) 95524294Smckusick return FALSE; 95624294Smckusick if ((ifd = open(filename,0)) < 0) 95724294Smckusick fatal("Can't open file %s\n",filename); 95824294Smckusick /*NOSTRICT*/ 95924294Smckusick if (read(ifd,i_womp,(int)i_size) != i_size) { 96024294Smckusick Close(ifd); 96124294Smckusick free(i_womp); 96224294Smckusick return FALSE; 96324294Smckusick } 96424294Smckusick Close(ifd); 96524294Smckusick if (i_womp[i_size-1] != '\n') 96624294Smckusick i_womp[i_size++] = '\n'; 96724294Smckusick i_womp[i_size] = '\0'; 96824294Smckusick 96924294Smckusick /* count the lines in the buffer so we know how many pointers we need */ 97024294Smckusick 97124294Smckusick iline = 0; 97224294Smckusick for (s=i_womp; *s; s++) { 97324294Smckusick if (*s == '\n') 97424294Smckusick iline++; 97524294Smckusick } 97624294Smckusick /*NOSTRICT*/ 97724294Smckusick i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *))); 97824294Smckusick if (i_ptr == Null(char **)) { /* shucks, it was a near thing */ 97924294Smckusick free((char *)i_womp); 98024294Smckusick return FALSE; 98124294Smckusick } 98224294Smckusick 98324294Smckusick /* now scan the buffer and build pointer array */ 98424294Smckusick 98524294Smckusick iline = 1; 98624294Smckusick i_ptr[iline] = i_womp; 98724294Smckusick for (s=i_womp; *s; s++) { 98824294Smckusick if (*s == '\n') 98924294Smckusick i_ptr[++iline] = s+1; /* these are NOT null terminated */ 99024294Smckusick } 99124294Smckusick input_lines = iline - 1; 99224294Smckusick 99324294Smckusick /* now check for revision, if any */ 99424294Smckusick 99524294Smckusick if (revision != Nullch) { 99624294Smckusick if (!rev_in_string(i_womp)) { 99724294Smckusick ask("This file doesn't appear to be the %s version--patch anyway? [n] ", 99824294Smckusick revision); 99924294Smckusick if (*buf != 'y') 100024294Smckusick fatal("Aborted.\n"); 100124294Smckusick } 100224294Smckusick else if (verbose) 100324294Smckusick say("Good. This file appears to be the %s version.\n", 100424294Smckusick revision); 100524294Smckusick } 100624294Smckusick return TRUE; /* plan a will work */ 100724294Smckusick } 100824294Smckusick 100924294Smckusick /* keep (virtually) nothing in memory */ 101024294Smckusick 101124294Smckusick plan_b(filename) 101224294Smckusick char *filename; 101324294Smckusick { 101424294Smckusick FILE *ifp; 101524294Smckusick register int i = 0; 101624294Smckusick register int maxlen = 1; 101724294Smckusick bool found_revision = (revision == Nullch); 101824294Smckusick 101924294Smckusick using_plan_a = FALSE; 102024294Smckusick if ((ifp = fopen(filename,"r")) == Nullfp) 102124294Smckusick fatal("Can't open file %s\n",filename); 102224294Smckusick if ((tifd = creat(TMPINNAME,0666)) < 0) 102324294Smckusick fatal("Can't open file %s\n",TMPINNAME); 102424294Smckusick while (fgets(buf,sizeof buf, ifp) != Nullch) { 102524294Smckusick if (revision != Nullch && !found_revision && rev_in_string(buf)) 102624294Smckusick found_revision = TRUE; 102724294Smckusick if ((i = strlen(buf)) > maxlen) 102824294Smckusick maxlen = i; /* find longest line */ 102924294Smckusick } 103024294Smckusick if (revision != Nullch) { 103124294Smckusick if (!found_revision) { 103224294Smckusick ask("This file doesn't appear to be the %s version--patch anyway? [n] ", 103324294Smckusick revision); 103424294Smckusick if (*buf != 'y') 103524294Smckusick fatal("Aborted.\n"); 103624294Smckusick } 103724294Smckusick else if (verbose) 103824294Smckusick say("Good. This file appears to be the %s version.\n", 103924294Smckusick revision); 104024294Smckusick } 104124294Smckusick Fseek(ifp,0L,0); /* rewind file */ 104224294Smckusick lines_per_buf = BUFFERSIZE / maxlen; 104324294Smckusick tireclen = maxlen; 104424294Smckusick tibuf[0] = malloc((MEM)(BUFFERSIZE + 1)); 104524294Smckusick tibuf[1] = malloc((MEM)(BUFFERSIZE + 1)); 104624294Smckusick if (tibuf[1] == Nullch) 104724294Smckusick fatal("Can't seem to get enough memory.\n"); 104824294Smckusick for (i=1; ; i++) { 104924294Smckusick if (! (i % lines_per_buf)) /* new block */ 105024294Smckusick if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE) 105124294Smckusick fatal("patch: can't write temp file.\n"); 105224294Smckusick if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp) 105324294Smckusick == Nullch) { 105424294Smckusick input_lines = i - 1; 105524294Smckusick if (i % lines_per_buf) 105624294Smckusick if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE) 105724294Smckusick fatal("patch: can't write temp file.\n"); 105824294Smckusick break; 105924294Smckusick } 106024294Smckusick } 106124294Smckusick Fclose(ifp); 106224294Smckusick Close(tifd); 106324294Smckusick if ((tifd = open(TMPINNAME,0)) < 0) { 106424294Smckusick fatal("Can't reopen file %s\n",TMPINNAME); 106524294Smckusick } 106624294Smckusick } 106724294Smckusick 106824294Smckusick /* fetch a line from the input file, \n terminated, not necessarily \0 */ 106924294Smckusick char * 107024294Smckusick ifetch(line,whichbuf) 107124294Smckusick register LINENUM line; 107224294Smckusick int whichbuf; /* ignored when file in memory */ 107324294Smckusick { 107424294Smckusick if (line < 1 || line > input_lines) 107524294Smckusick return ""; 107624294Smckusick if (using_plan_a) 107724294Smckusick return i_ptr[line]; 107824294Smckusick else { 107924294Smckusick LINENUM offline = line % lines_per_buf; 108024294Smckusick LINENUM baseline = line - offline; 108124294Smckusick 108224294Smckusick if (tiline[0] == baseline) 108324294Smckusick whichbuf = 0; 108424294Smckusick else if (tiline[1] == baseline) 108524294Smckusick whichbuf = 1; 108624294Smckusick else { 108724294Smckusick tiline[whichbuf] = baseline; 108824294Smckusick Lseek(tifd,(long)baseline / lines_per_buf * BUFFERSIZE,0); 108924294Smckusick if (read(tifd,tibuf[whichbuf],BUFFERSIZE) < 0) 109024294Smckusick fatal("Error reading tmp file %s.\n",TMPINNAME); 109124294Smckusick } 109224294Smckusick return tibuf[whichbuf] + (tireclen*offline); 109324294Smckusick } 109424294Smckusick } 109524294Smckusick 109624294Smckusick /* patch abstract type */ 109724294Smckusick 109824294Smckusick static long p_filesize; /* size of the patch file */ 109924294Smckusick static LINENUM p_first; /* 1st line number */ 110024294Smckusick static LINENUM p_newfirst; /* 1st line number of replacement */ 110124294Smckusick static LINENUM p_ptrn_lines; /* # lines in pattern */ 110224294Smckusick static LINENUM p_repl_lines; /* # lines in replacement text */ 110324294Smckusick static LINENUM p_end = -1; /* last line in hunk */ 110424294Smckusick static LINENUM p_max; /* max allowed value of p_end */ 110524294Smckusick static LINENUM p_context = 3; /* # of context lines */ 110624294Smckusick static LINENUM p_input_line = 0; /* current line # from patch file */ 110724294Smckusick static char *p_line[MAXHUNKSIZE]; /* the text of the hunk */ 110824294Smckusick static char p_char[MAXHUNKSIZE]; /* +, -, and ! */ 110924294Smckusick static int p_len[MAXHUNKSIZE]; /* length of each line */ 111024294Smckusick static int p_indent; /* indent to patch */ 111124294Smckusick static long p_base; /* where to intuit this time */ 111224294Smckusick static long p_start; /* where intuit found a patch */ 111324294Smckusick 111424294Smckusick re_patch() 111524294Smckusick { 111624294Smckusick p_first = (LINENUM)0; 111724294Smckusick p_newfirst = (LINENUM)0; 111824294Smckusick p_ptrn_lines = (LINENUM)0; 111924294Smckusick p_repl_lines = (LINENUM)0; 112024294Smckusick p_end = (LINENUM)-1; 112124294Smckusick p_max = (LINENUM)0; 112224294Smckusick p_indent = 0; 112324294Smckusick } 112424294Smckusick 112524294Smckusick open_patch_file(filename) 112624294Smckusick char *filename; 112724294Smckusick { 112824294Smckusick if (filename == Nullch || !*filename || strEQ(filename,"-")) { 112924294Smckusick pfp = fopen(TMPPATNAME,"w"); 113024294Smckusick if (pfp == Nullfp) 113124294Smckusick fatal("patch: can't create %s.\n",TMPPATNAME); 113224294Smckusick while (fgets(buf,sizeof buf,stdin) != NULL) 113324294Smckusick fputs(buf,pfp); 113424294Smckusick Fclose(pfp); 113524294Smckusick filename = TMPPATNAME; 113624294Smckusick } 113724294Smckusick pfp = fopen(filename,"r"); 113824294Smckusick if (pfp == Nullfp) 113924294Smckusick fatal("patch file %s not found\n",filename); 114024294Smckusick Fstat(fileno(pfp), &filestat); 114124294Smckusick p_filesize = filestat.st_size; 114224294Smckusick next_intuit_at(0L); /* start at the beginning */ 114324294Smckusick } 114424294Smckusick 114524294Smckusick bool 114624294Smckusick there_is_another_patch() 114724294Smckusick { 114824294Smckusick bool no_input_file = (filearg[0] == Nullch); 114924294Smckusick 115024294Smckusick if (p_base != 0L && p_base >= p_filesize) { 115124294Smckusick if (verbose) 115224294Smckusick say("done\n"); 115324294Smckusick return FALSE; 115424294Smckusick } 115524294Smckusick if (verbose) 115624294Smckusick say("Hmm..."); 115724294Smckusick diff_type = intuit_diff_type(); 115824294Smckusick if (!diff_type) { 115924294Smckusick if (p_base != 0L) { 116024294Smckusick if (verbose) 116124294Smckusick say(" Ignoring the trailing garbage.\ndone\n"); 116224294Smckusick } 116324294Smckusick else 116424294Smckusick say(" I can't seem to find a patch in there anywhere.\n"); 116524294Smckusick return FALSE; 116624294Smckusick } 116724294Smckusick if (verbose) 116824294Smckusick say(" %sooks like %s to me...\n", 116924294Smckusick (p_base == 0L ? "L" : "The next patch l"), 117024294Smckusick diff_type == CONTEXT_DIFF ? "a context diff" : 1171*24295Smckusick diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : 117224294Smckusick diff_type == NORMAL_DIFF ? "a normal diff" : 117324294Smckusick "an ed script" ); 117424294Smckusick if (p_indent && verbose) 117524294Smckusick say("(Patch is indented %d space%s.)\n",p_indent,p_indent==1?"":"s"); 117624294Smckusick skip_to(p_start); 117724294Smckusick if (no_input_file) { 117824294Smckusick if (filearg[0] == Nullch) { 117924294Smckusick ask("File to patch: "); 118024294Smckusick filearg[0] = fetchname(buf); 118124294Smckusick } 118224294Smckusick else if (verbose) { 118324294Smckusick say("Patching file %s...\n",filearg[0]); 118424294Smckusick } 118524294Smckusick } 118624294Smckusick return TRUE; 118724294Smckusick } 118824294Smckusick 118924294Smckusick intuit_diff_type() 119024294Smckusick { 119124294Smckusick long this_line = 0; 119224294Smckusick long previous_line; 119324294Smckusick long first_command_line = -1; 119424294Smckusick bool last_line_was_command = FALSE; 119524294Smckusick bool this_line_is_command = FALSE; 1196*24295Smckusick bool last_line_was_stars = FALSE; 1197*24295Smckusick bool this_line_is_stars = FALSE; 119824294Smckusick register int indent; 119924294Smckusick register char *s, *t; 120024294Smckusick char *oldname = Nullch; 120124294Smckusick char *newname = Nullch; 120224294Smckusick bool no_filearg = (filearg[0] == Nullch); 120324294Smckusick 120424294Smckusick Fseek(pfp,p_base,0); 120524294Smckusick for (;;) { 120624294Smckusick previous_line = this_line; 120724294Smckusick last_line_was_command = this_line_is_command; 1208*24295Smckusick last_line_was_stars = this_line_is_stars; 120924294Smckusick this_line = ftell(pfp); 121024294Smckusick indent = 0; 121124294Smckusick if (fgets(buf,sizeof buf,pfp) == Nullch) { 121224294Smckusick if (first_command_line >= 0L) { 121324294Smckusick /* nothing but deletes!? */ 121424294Smckusick p_start = first_command_line; 121524294Smckusick return ED_DIFF; 121624294Smckusick } 121724294Smckusick else { 121824294Smckusick p_start = this_line; 121924294Smckusick return 0; 122024294Smckusick } 122124294Smckusick } 122224294Smckusick for (s = buf; *s == ' ' || *s == '\t'; s++) { 122324294Smckusick if (*s == '\t') 122424294Smckusick indent += 8 - (indent % 8); 122524294Smckusick else 122624294Smckusick indent++; 122724294Smckusick } 122824294Smckusick for (t=s; isdigit(*t) || *t == ','; t++) ; 122924294Smckusick this_line_is_command = (isdigit(*s) && 123024294Smckusick (*t == 'd' || *t == 'c' || *t == 'a') ); 123124294Smckusick if (first_command_line < 0L && this_line_is_command) { 123224294Smckusick first_command_line = this_line; 123324294Smckusick p_indent = indent; /* assume this for now */ 123424294Smckusick } 123524294Smckusick if (strnEQ(s,"*** ",4)) 123624294Smckusick oldname = fetchname(s+4); 123724294Smckusick else if (strnEQ(s,"--- ",4)) { 123824294Smckusick newname = fetchname(s+4); 123924294Smckusick if (no_filearg) { 124024294Smckusick if (oldname && newname) { 124124294Smckusick if (strlen(oldname) < strlen(newname)) 124224294Smckusick filearg[0] = oldname; 124324294Smckusick else 124424294Smckusick filearg[0] = newname; 124524294Smckusick } 124624294Smckusick else if (oldname) 124724294Smckusick filearg[0] = oldname; 124824294Smckusick else if (newname) 124924294Smckusick filearg[0] = newname; 125024294Smckusick } 125124294Smckusick } 125224294Smckusick else if (strnEQ(s,"Index:",6)) { 125324294Smckusick if (no_filearg) 125424294Smckusick filearg[0] = fetchname(s+6); 125524294Smckusick /* this filearg might get limboed */ 125624294Smckusick } 125724294Smckusick else if (strnEQ(s,"Prereq:",7)) { 125824294Smckusick for (t=s+7; isspace(*t); t++) ; 125924294Smckusick revision = savestr(t); 126024294Smckusick for (t=revision; *t && !isspace(*t); t++) ; 126124294Smckusick *t = '\0'; 126224294Smckusick if (!*revision) { 126324294Smckusick free(revision); 126424294Smckusick revision = Nullch; 126524294Smckusick } 126624294Smckusick } 126724294Smckusick if ((!diff_type || diff_type == ED_DIFF) && 126824294Smckusick first_command_line >= 0L && 126924294Smckusick strEQ(s,".\n") ) { 127024294Smckusick p_indent = indent; 127124294Smckusick p_start = first_command_line; 127224294Smckusick return ED_DIFF; 127324294Smckusick } 1274*24295Smckusick this_line_is_stars = strnEQ(s,"********",8); 1275*24295Smckusick if ((!diff_type || diff_type == CONTEXT_DIFF) && last_line_was_stars && 1276*24295Smckusick strnEQ(s,"*** ",4)) { 1277*24295Smckusick /* if this is a new context diff the character just before */ 1278*24295Smckusick /* the newline is a '*'. */ 1279*24295Smckusick while (*s != '\n') 1280*24295Smckusick s++; 128124294Smckusick p_indent = indent; 1282*24295Smckusick p_start = previous_line; 1283*24295Smckusick return (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); 128424294Smckusick } 128524294Smckusick if ((!diff_type || diff_type == NORMAL_DIFF) && 128624294Smckusick last_line_was_command && 128724294Smckusick (strnEQ(s,"< ",2) || strnEQ(s,"> ",2)) ) { 128824294Smckusick p_start = previous_line; 128924294Smckusick p_indent = indent; 129024294Smckusick return NORMAL_DIFF; 129124294Smckusick } 129224294Smckusick } 129324294Smckusick } 129424294Smckusick 129524294Smckusick char * 129624294Smckusick fetchname(at) 129724294Smckusick char *at; 129824294Smckusick { 129924294Smckusick char *s = savestr(at); 130024294Smckusick char *name; 130124294Smckusick register char *t; 130224294Smckusick char tmpbuf[200]; 130324294Smckusick 130424294Smckusick for (t=s; isspace(*t); t++) ; 130524294Smckusick name = t; 130624294Smckusick for (; *t && !isspace(*t); t++) 130724294Smckusick if (!usepath) 130824294Smckusick if (*t == '/') 130924294Smckusick name = t+1; 131024294Smckusick *t = '\0'; 131124294Smckusick name = savestr(name); 131224294Smckusick Sprintf(tmpbuf,"RCS/%s",name); 131324294Smckusick free(s); 131424294Smckusick if (stat(name,&filestat) < 0) { 131524294Smckusick Strcat(tmpbuf,RCSSUFFIX); 131624294Smckusick if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+4,&filestat) < 0) { 131724294Smckusick Sprintf(tmpbuf,"SCCS/%s%s",SCCSPREFIX,name); 131824294Smckusick if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+5,&filestat) < 0) { 131924294Smckusick free(name); 132024294Smckusick name = Nullch; 132124294Smckusick } 132224294Smckusick } 132324294Smckusick } 132424294Smckusick return name; 132524294Smckusick } 132624294Smckusick 132724294Smckusick next_intuit_at(file_pos) 132824294Smckusick long file_pos; 132924294Smckusick { 133024294Smckusick p_base = file_pos; 133124294Smckusick } 133224294Smckusick 133324294Smckusick skip_to(file_pos) 133424294Smckusick long file_pos; 133524294Smckusick { 133624294Smckusick char *ret; 133724294Smckusick 133824294Smckusick assert(p_base <= file_pos); 133924294Smckusick if (verbose && p_base < file_pos) { 134024294Smckusick Fseek(pfp,p_base,0); 134124294Smckusick say("The text leading up to this was:\n--------------------------\n"); 134224294Smckusick while (ftell(pfp) < file_pos) { 134324294Smckusick ret = fgets(buf,sizeof buf,pfp); 134424294Smckusick assert(ret != Nullch); 134524294Smckusick say("|%s",buf); 134624294Smckusick } 134724294Smckusick say("--------------------------\n"); 134824294Smckusick } 134924294Smckusick else 135024294Smckusick Fseek(pfp,file_pos,0); 135124294Smckusick } 135224294Smckusick 135324294Smckusick bool 135424294Smckusick another_hunk() 135524294Smckusick { 135624294Smckusick register char *s; 135724294Smckusick char *ret; 1358*24295Smckusick register int context = 0; 135924294Smckusick 136024294Smckusick while (p_end >= 0) { 136124294Smckusick free(p_line[p_end--]); 136224294Smckusick } 136324294Smckusick assert(p_end == -1); 136424294Smckusick 136524294Smckusick p_max = MAXHUNKSIZE; /* gets reduced when --- found */ 136624294Smckusick if (diff_type == CONTEXT_DIFF) { 136724294Smckusick long line_beginning = ftell(pfp); 136824294Smckusick LINENUM repl_beginning = 0; 136924294Smckusick 137024294Smckusick ret = pgets(buf,sizeof buf, pfp); 137124294Smckusick if (ret == Nullch || strnNE(buf,"********",8)) { 137224294Smckusick next_intuit_at(line_beginning); 137324294Smckusick return FALSE; 137424294Smckusick } 137524294Smckusick p_context = 100; 137624294Smckusick while (p_end < p_max) { 137724294Smckusick ret = pgets(buf,sizeof buf, pfp); 137824294Smckusick if (ret == Nullch) { 137924294Smckusick if (p_max - p_end < 4) 138024294Smckusick Strcpy(buf," \n"); /* assume blank lines got chopped */ 138124294Smckusick else 138224294Smckusick fatal("Unexpected end of file in patch.\n"); 138324294Smckusick } 138424294Smckusick p_input_line++; 138524294Smckusick if (strnEQ(buf,"********",8)) 138624294Smckusick fatal("Unexpected end of hunk at line %d.\n", 138724294Smckusick p_input_line); 138824294Smckusick p_char[++p_end] = *buf; 138924294Smckusick switch (*buf) { 139024294Smckusick case '*': 139124294Smckusick if (p_end != 0) 139224294Smckusick fatal("Unexpected *** at line %d: %s", p_input_line, buf); 139324294Smckusick context = 0; 139424294Smckusick p_line[p_end] = savestr(buf); 139524294Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 139624294Smckusick p_first = (LINENUM) atol(s); 139724294Smckusick while (isdigit(*s)) s++; 139824294Smckusick for (; *s && !isdigit(*s); s++) ; 139924294Smckusick p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; 140024294Smckusick break; 140124294Smckusick case '-': 140224294Smckusick if (buf[1] == '-') { 140324294Smckusick if (p_end != p_ptrn_lines + 1 && 140424294Smckusick p_end != p_ptrn_lines + 2) 140524294Smckusick fatal("Unexpected --- at line %d: %s", 140624294Smckusick p_input_line,buf); 140724294Smckusick repl_beginning = p_end; 140824294Smckusick context = 0; 140924294Smckusick p_line[p_end] = savestr(buf); 141024294Smckusick p_char[p_end] = '='; 141124294Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 141224294Smckusick p_newfirst = (LINENUM) atol(s); 141324294Smckusick while (isdigit(*s)) s++; 141424294Smckusick for (; *s && !isdigit(*s); s++) ; 141524294Smckusick p_max = ((LINENUM)atol(s)) - p_newfirst + 1 + p_end; 141624294Smckusick break; 141724294Smckusick } 141824294Smckusick /* FALL THROUGH */ 141924294Smckusick case '+': case '!': 142024294Smckusick if (context > 0) { 142124294Smckusick if (context < p_context) 142224294Smckusick p_context = context; 142324294Smckusick context = -100; 142424294Smckusick } 142524294Smckusick p_line[p_end] = savestr(buf+2); 142624294Smckusick break; 142724294Smckusick case '\t': case '\n': /* assume the 2 spaces got eaten */ 142824294Smckusick p_line[p_end] = savestr(buf); 142924294Smckusick if (p_end != p_ptrn_lines + 1) { 143024294Smckusick context++; 143124294Smckusick p_char[p_end] = ' '; 143224294Smckusick } 143324294Smckusick break; 143424294Smckusick case ' ': 143524294Smckusick context++; 143624294Smckusick p_line[p_end] = savestr(buf+2); 143724294Smckusick break; 143824294Smckusick default: 143924294Smckusick fatal("Malformed patch at line %d: %s",p_input_line,buf); 144024294Smckusick } 144124294Smckusick p_len[p_end] = strlen(p_line[p_end]); 144224294Smckusick /* for strncmp() so we do not have */ 144324294Smckusick /* to assume null termination */ 144424294Smckusick } 144524294Smckusick if (p_end >=0 && !p_ptrn_lines) 144624294Smckusick fatal("No --- found in patch at line %d\n", pch_hunk_beg()); 144724294Smckusick p_repl_lines = p_end - repl_beginning; 144824294Smckusick } 1449*24295Smckusick else if (diff_type == NEW_CONTEXT_DIFF) { 1450*24295Smckusick long line_beginning = ftell(pfp); 1451*24295Smckusick LINENUM repl_beginning = 0; 1452*24295Smckusick LINENUM fillcnt = 0; 1453*24295Smckusick LINENUM fillsrc; 1454*24295Smckusick LINENUM filldst; 1455*24295Smckusick 1456*24295Smckusick ret = pgets(buf,sizeof buf, pfp); 1457*24295Smckusick if (ret == Nullch || strnNE(buf,"********",8)) { 1458*24295Smckusick next_intuit_at(line_beginning); 1459*24295Smckusick return FALSE; 1460*24295Smckusick } 1461*24295Smckusick p_context = 0; 1462*24295Smckusick while (p_end < p_max) { 1463*24295Smckusick ret = pgets(buf,sizeof buf, pfp); 1464*24295Smckusick if (ret == Nullch) { 1465*24295Smckusick if (p_max - p_end < 4) 1466*24295Smckusick Strcpy(buf," \n"); /* assume blank lines got chopped */ 1467*24295Smckusick else 1468*24295Smckusick fatal("Unexpected end of file in patch.\n"); 1469*24295Smckusick } 1470*24295Smckusick p_input_line++; 1471*24295Smckusick p_char[++p_end] = *buf; 1472*24295Smckusick switch (*buf) { 1473*24295Smckusick case '*': 1474*24295Smckusick if (strnEQ(buf,"********",8)) { 1475*24295Smckusick if (p_end != repl_beginning + 1) 1476*24295Smckusick fatal("Unexpected end of hunk at line %d.\n", 1477*24295Smckusick p_input_line); 1478*24295Smckusick /* redundant 'new' context lines were omitted - set up */ 1479*24295Smckusick /* to fill them in from the the old file's context */ 1480*24295Smckusick fillsrc = 1; 1481*24295Smckusick filldst = p_end; 1482*24295Smckusick fillcnt = p_max - p_end; 1483*24295Smckusick p_end = p_max; 1484*24295Smckusick break; 1485*24295Smckusick } 1486*24295Smckusick if (p_end != 0) 1487*24295Smckusick fatal("Unexpected *** at line %d: %s", p_input_line, buf); 1488*24295Smckusick context = 0; 1489*24295Smckusick p_line[p_end] = savestr(buf); 1490*24295Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 1491*24295Smckusick p_first = (LINENUM) atol(s); 1492*24295Smckusick while (isdigit(*s)) s++; 1493*24295Smckusick for (; *s && !isdigit(*s); s++) ; 1494*24295Smckusick p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; 1495*24295Smckusick break; 1496*24295Smckusick case '-': 1497*24295Smckusick if (buf[1] == '-') { 1498*24295Smckusick if (p_end != p_ptrn_lines + 1) { 1499*24295Smckusick if (p_end == 1) { 1500*24295Smckusick /* `old' lines were omitted - set up to fill them */ 1501*24295Smckusick /* in from 'new' context lines. */ 1502*24295Smckusick p_end = p_ptrn_lines + 1; 1503*24295Smckusick fillsrc = p_end + 1; 1504*24295Smckusick filldst = 1; 1505*24295Smckusick fillcnt = p_ptrn_lines; 1506*24295Smckusick } else 1507*24295Smckusick fatal("Unexpected --- at line %d: %s", 1508*24295Smckusick p_input_line,buf); 1509*24295Smckusick } 1510*24295Smckusick repl_beginning = p_end; 1511*24295Smckusick p_line[p_end] = savestr(buf); 1512*24295Smckusick p_char[p_end] = '='; 1513*24295Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 1514*24295Smckusick p_newfirst = (LINENUM) atol(s); 1515*24295Smckusick while (isdigit(*s)) s++; 1516*24295Smckusick for (; *s && !isdigit(*s); s++) ; 1517*24295Smckusick p_max = ((LINENUM)atol(s)) - p_newfirst + 1 + p_end; 1518*24295Smckusick break; 1519*24295Smckusick } 1520*24295Smckusick /* FALL THROUGH */ 1521*24295Smckusick case '+': case '!': 1522*24295Smckusick if (context > 0 && p_context == 0) { 1523*24295Smckusick p_context = context; 1524*24295Smckusick } 1525*24295Smckusick p_line[p_end] = savestr(buf+2); 1526*24295Smckusick break; 1527*24295Smckusick case '\t': case '\n': /* assume the 2 spaces got eaten */ 1528*24295Smckusick p_line[p_end] = savestr(buf); 1529*24295Smckusick if (p_end != p_ptrn_lines + 1) { 1530*24295Smckusick context++; 1531*24295Smckusick p_char[p_end] = ' '; 1532*24295Smckusick } 1533*24295Smckusick break; 1534*24295Smckusick case ' ': 1535*24295Smckusick context++; 1536*24295Smckusick p_line[p_end] = savestr(buf+2); 1537*24295Smckusick break; 1538*24295Smckusick default: 1539*24295Smckusick fatal("Malformed patch at line %d: %s",p_input_line,buf); 1540*24295Smckusick } 1541*24295Smckusick p_len[p_end] = strlen(p_line[p_end]); 1542*24295Smckusick /* for strncmp() so we do not have */ 1543*24295Smckusick /* to assume null termination */ 1544*24295Smckusick } 1545*24295Smckusick if (p_end >=0 && !p_ptrn_lines) 1546*24295Smckusick fatal("No --- found in patch at line %d\n", pch_hunk_beg()); 1547*24295Smckusick 1548*24295Smckusick /* if there were omitted context lines, fill them in */ 1549*24295Smckusick if (fillcnt) { 1550*24295Smckusick while (fillcnt-- > 0) { 1551*24295Smckusick while (p_char[fillsrc] != ' ') 1552*24295Smckusick fillsrc++; 1553*24295Smckusick p_line[filldst] = p_line[fillsrc]; 1554*24295Smckusick p_char[filldst] = p_char[fillsrc]; 1555*24295Smckusick p_len[filldst] = p_len[fillsrc]; 1556*24295Smckusick fillsrc++; filldst++; 1557*24295Smckusick } 1558*24295Smckusick assert(fillsrc==p_end+1 || fillsrc==repl_beginning); 1559*24295Smckusick assert(filldst==p_end+1 || filldst==repl_beginning); 1560*24295Smckusick } 1561*24295Smckusick p_repl_lines = p_end - repl_beginning; 1562*24295Smckusick } 156324294Smckusick else { /* normal diff--fake it up */ 156424294Smckusick char hunk_type; 156524294Smckusick register int i; 156624294Smckusick LINENUM min, max; 156724294Smckusick long line_beginning = ftell(pfp); 156824294Smckusick 156924294Smckusick p_context = 0; 157024294Smckusick ret = pgets(buf,sizeof buf, pfp); 157124294Smckusick p_input_line++; 157224294Smckusick if (ret == Nullch || !isdigit(*buf)) { 157324294Smckusick next_intuit_at(line_beginning); 157424294Smckusick return FALSE; 157524294Smckusick } 157624294Smckusick p_first = (LINENUM)atol(buf); 157724294Smckusick for (s=buf; isdigit(*s); s++) ; 157824294Smckusick if (*s == ',') { 157924294Smckusick p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1; 158024294Smckusick while (isdigit(*s)) s++; 158124294Smckusick } 158224294Smckusick else 158324294Smckusick p_ptrn_lines = (*s != 'a'); 158424294Smckusick hunk_type = *s; 158524294Smckusick if (hunk_type == 'a') 158624294Smckusick p_first++; /* do append rather than insert */ 158724294Smckusick min = (LINENUM)atol(++s); 158824294Smckusick for (; isdigit(*s); s++) ; 158924294Smckusick if (*s == ',') 159024294Smckusick max = (LINENUM)atol(++s); 159124294Smckusick else 159224294Smckusick max = min; 159324294Smckusick if (hunk_type == 'd') 159424294Smckusick min++; 159524294Smckusick p_end = p_ptrn_lines + 1 + max - min + 1; 159624294Smckusick p_newfirst = min; 159724294Smckusick p_repl_lines = max - min + 1; 159824294Smckusick Sprintf(buf,"*** %d,%d\n", p_first, p_first + p_ptrn_lines - 1); 159924294Smckusick p_line[0] = savestr(buf); 160024294Smckusick p_char[0] = '*'; 160124294Smckusick for (i=1; i<=p_ptrn_lines; i++) { 160224294Smckusick ret = pgets(buf,sizeof buf, pfp); 160324294Smckusick p_input_line++; 160424294Smckusick if (ret == Nullch) 160524294Smckusick fatal("Unexpected end of file in patch at line %d.\n", 160624294Smckusick p_input_line); 160724294Smckusick if (*buf != '<') 160824294Smckusick fatal("< expected at line %d of patch.\n", p_input_line); 160924294Smckusick p_line[i] = savestr(buf+2); 161024294Smckusick p_len[i] = strlen(p_line[i]); 161124294Smckusick p_char[i] = '-'; 161224294Smckusick } 161324294Smckusick if (hunk_type == 'c') { 161424294Smckusick ret = pgets(buf,sizeof buf, pfp); 161524294Smckusick p_input_line++; 161624294Smckusick if (ret == Nullch) 161724294Smckusick fatal("Unexpected end of file in patch at line %d.\n", 161824294Smckusick p_input_line); 161924294Smckusick if (*buf != '-') 162024294Smckusick fatal("--- expected at line %d of patch.\n", p_input_line); 162124294Smckusick } 162224294Smckusick Sprintf(buf,"--- %d,%d\n",min,max); 162324294Smckusick p_line[i] = savestr(buf); 162424294Smckusick p_char[i] = '='; 162524294Smckusick for (i++; i<=p_end; i++) { 162624294Smckusick ret = pgets(buf,sizeof buf, pfp); 162724294Smckusick p_input_line++; 162824294Smckusick if (ret == Nullch) 162924294Smckusick fatal("Unexpected end of file in patch at line %d.\n", 163024294Smckusick p_input_line); 163124294Smckusick if (*buf != '>') 163224294Smckusick fatal("> expected at line %d of patch.\n", p_input_line); 163324294Smckusick p_line[i] = savestr(buf+2); 163424294Smckusick p_len[i] = strlen(p_line[i]); 163524294Smckusick p_char[i] = '+'; 163624294Smckusick } 163724294Smckusick } 163824294Smckusick if (reverse) /* backwards patch? */ 163924294Smckusick pch_swap(); 164024294Smckusick #ifdef DEBUGGING 164124294Smckusick if (debug & 2) { 164224294Smckusick int i; 164324294Smckusick char special; 164424294Smckusick 164524294Smckusick for (i=0; i <= p_end; i++) { 164624294Smckusick if (i == p_ptrn_lines) 164724294Smckusick special = '^'; 164824294Smckusick else 164924294Smckusick special = ' '; 165024294Smckusick printf("%3d %c %c %s",i,p_char[i],special,p_line[i]); 165124294Smckusick } 165224294Smckusick } 165324294Smckusick #endif 165424294Smckusick return TRUE; 165524294Smckusick } 165624294Smckusick 165724294Smckusick char * 165824294Smckusick pgets(bf,sz,fp) 165924294Smckusick char *bf; 166024294Smckusick int sz; 166124294Smckusick FILE *fp; 166224294Smckusick { 166324294Smckusick char *ret = fgets(bf,sz,fp); 166424294Smckusick register char *s; 166524294Smckusick register int indent = 0; 166624294Smckusick 166724294Smckusick if (p_indent && ret != Nullch) { 166824294Smckusick for (s=buf; indent < p_indent && (*s == ' ' || *s == '\t'); s++) { 166924294Smckusick if (*s == '\t') 167024294Smckusick indent += 8 - (indent % 7); 167124294Smckusick else 167224294Smckusick indent++; 167324294Smckusick } 167424294Smckusick if (buf != s) 167524294Smckusick Strcpy(buf,s); 167624294Smckusick } 167724294Smckusick return ret; 167824294Smckusick } 167924294Smckusick 168024294Smckusick pch_swap() 168124294Smckusick { 168224294Smckusick char *tp_line[MAXHUNKSIZE]; /* the text of the hunk */ 168324294Smckusick char tp_char[MAXHUNKSIZE]; /* +, -, and ! */ 168424294Smckusick int tp_len[MAXHUNKSIZE]; /* length of each line */ 168524294Smckusick register LINENUM i, n; 168624294Smckusick bool blankline = FALSE; 168724294Smckusick register char *s; 168824294Smckusick 168924294Smckusick i = p_first; 169024294Smckusick p_first = p_newfirst; 169124294Smckusick p_newfirst = i; 169224294Smckusick 169324294Smckusick /* make a scratch copy */ 169424294Smckusick 169524294Smckusick for (i=0; i<=p_end; i++) { 169624294Smckusick tp_line[i] = p_line[i]; 169724294Smckusick tp_char[i] = p_char[i]; 169824294Smckusick tp_len[i] = p_len[i]; 169924294Smckusick } 170024294Smckusick 170124294Smckusick /* now turn the new into the old */ 170224294Smckusick 170324294Smckusick i = p_ptrn_lines + 1; 170424294Smckusick if (tp_char[i] == '\n') { /* account for possible blank line */ 170524294Smckusick blankline = TRUE; 170624294Smckusick i++; 170724294Smckusick } 170824294Smckusick for (n=0; i <= p_end; i++,n++) { 170924294Smckusick p_line[n] = tp_line[i]; 171024294Smckusick p_char[n] = tp_char[i]; 171124294Smckusick if (p_char[n] == '+') 171224294Smckusick p_char[n] = '-'; 171324294Smckusick p_len[n] = tp_len[i]; 171424294Smckusick } 171524294Smckusick if (blankline) { 171624294Smckusick i = p_ptrn_lines + 1; 171724294Smckusick p_line[n] = tp_line[i]; 171824294Smckusick p_char[n] = tp_char[i]; 171924294Smckusick p_len[n] = tp_len[i]; 172024294Smckusick n++; 172124294Smckusick } 172224294Smckusick assert(p_char[0] == '='); 172324294Smckusick p_char[0] = '*'; 172424294Smckusick for (s=p_line[0]; *s; s++) 172524294Smckusick if (*s == '-') 172624294Smckusick *s = '*'; 172724294Smckusick 172824294Smckusick /* now turn the old into the new */ 172924294Smckusick 173024294Smckusick assert(tp_char[0] == '*'); 173124294Smckusick tp_char[0] = '='; 173224294Smckusick for (s=tp_line[0]; *s; s++) 173324294Smckusick if (*s == '*') 173424294Smckusick *s = '-'; 173524294Smckusick for (i=0; n <= p_end; i++,n++) { 173624294Smckusick p_line[n] = tp_line[i]; 173724294Smckusick p_char[n] = tp_char[i]; 173824294Smckusick if (p_char[n] == '-') 173924294Smckusick p_char[n] = '+'; 174024294Smckusick p_len[n] = tp_len[i]; 174124294Smckusick } 174224294Smckusick assert(i == p_ptrn_lines + 1); 174324294Smckusick i = p_ptrn_lines; 174424294Smckusick p_ptrn_lines = p_repl_lines; 174524294Smckusick p_repl_lines = i; 174624294Smckusick } 174724294Smckusick 174824294Smckusick LINENUM 174924294Smckusick pch_first() 175024294Smckusick { 175124294Smckusick return p_first; 175224294Smckusick } 175324294Smckusick 175424294Smckusick LINENUM 175524294Smckusick pch_ptrn_lines() 175624294Smckusick { 175724294Smckusick return p_ptrn_lines; 175824294Smckusick } 175924294Smckusick 176024294Smckusick LINENUM 176124294Smckusick pch_newfirst() 176224294Smckusick { 176324294Smckusick return p_newfirst; 176424294Smckusick } 176524294Smckusick 176624294Smckusick LINENUM 176724294Smckusick pch_repl_lines() 176824294Smckusick { 176924294Smckusick return p_repl_lines; 177024294Smckusick } 177124294Smckusick 177224294Smckusick LINENUM 177324294Smckusick pch_end() 177424294Smckusick { 177524294Smckusick return p_end; 177624294Smckusick } 177724294Smckusick 177824294Smckusick LINENUM 177924294Smckusick pch_context() 178024294Smckusick { 178124294Smckusick return p_context; 178224294Smckusick } 178324294Smckusick 178424294Smckusick pch_line_len(line) 178524294Smckusick LINENUM line; 178624294Smckusick { 178724294Smckusick return p_len[line]; 178824294Smckusick } 178924294Smckusick 179024294Smckusick char 179124294Smckusick pch_char(line) 179224294Smckusick LINENUM line; 179324294Smckusick { 179424294Smckusick return p_char[line]; 179524294Smckusick } 179624294Smckusick 179724294Smckusick char * 179824294Smckusick pfetch(line) 179924294Smckusick LINENUM line; 180024294Smckusick { 180124294Smckusick return p_line[line]; 180224294Smckusick } 180324294Smckusick 180424294Smckusick LINENUM 180524294Smckusick pch_hunk_beg() 180624294Smckusick { 180724294Smckusick return p_input_line - p_end - 1; 180824294Smckusick } 180924294Smckusick 181024294Smckusick char * 181124294Smckusick savestr(s) 181224294Smckusick register char *s; 181324294Smckusick { 181424294Smckusick register char *rv, 181524294Smckusick *t; 181624294Smckusick 181724294Smckusick t = s; 181824294Smckusick while (*t++); 181924294Smckusick rv = malloc((MEM) (t - s)); 182024294Smckusick if (rv == NULL) 182124294Smckusick fatal ("patch: out of memory (savestr)\n"); 182224294Smckusick t = rv; 182324294Smckusick while (*t++ = *s++); 182424294Smckusick return rv; 182524294Smckusick } 182624294Smckusick 182724294Smckusick my_exit(status) 182824294Smckusick int status; 182924294Smckusick { 183024294Smckusick Unlink(TMPINNAME); 183124294Smckusick Unlink(TMPOUTNAME); 183224294Smckusick Unlink(TMPREJNAME); 183324294Smckusick Unlink(TMPPATNAME); 183424294Smckusick exit(status); 183524294Smckusick } 183624294Smckusick 183724294Smckusick #ifdef lint 183824294Smckusick 183924294Smckusick /*VARARGS ARGSUSED*/ 184024294Smckusick say(pat) char *pat; { ; } 184124294Smckusick /*VARARGS ARGSUSED*/ 184224294Smckusick fatal(pat) char *pat; { ; } 184324294Smckusick /*VARARGS ARGSUSED*/ 184424294Smckusick ask(pat) char *pat; { ; } 184524294Smckusick 184624294Smckusick #else lint 184724294Smckusick 184824294Smckusick say(pat,arg1,arg2,arg3) 184924294Smckusick char *pat; 185024294Smckusick int arg1,arg2,arg3; 185124294Smckusick { 185224294Smckusick fprintf(stderr,pat,arg1,arg2,arg3); 185324294Smckusick Fflush(stderr); 185424294Smckusick } 185524294Smckusick 185624294Smckusick fatal(pat,arg1,arg2,arg3) 185724294Smckusick char *pat; 185824294Smckusick int arg1,arg2,arg3; 185924294Smckusick { 186024294Smckusick say(pat,arg1,arg2,arg3); 186124294Smckusick my_exit(1); 186224294Smckusick } 186324294Smckusick 186424294Smckusick ask(pat,arg1,arg2,arg3) 186524294Smckusick char *pat; 186624294Smckusick int arg1,arg2,arg3; 186724294Smckusick { 186824294Smckusick int ttyfd = open("/dev/tty",2); 186924294Smckusick int r; 187024294Smckusick 187124294Smckusick say(pat,arg1,arg2,arg3); 187224294Smckusick if (ttyfd >= 0) { 187324294Smckusick r = read(ttyfd, buf, sizeof buf); 187424294Smckusick Close(ttyfd); 187524294Smckusick } 187624294Smckusick else 187724294Smckusick r = read(2, buf, sizeof buf); 187824294Smckusick if (r <= 0) 187924294Smckusick buf[0] = 0; 188024294Smckusick } 188124294Smckusick #endif lint 188224294Smckusick 188324294Smckusick bool 188424294Smckusick rev_in_string(string) 188524294Smckusick char *string; 188624294Smckusick { 188724294Smckusick register char *s; 188824294Smckusick register int patlen; 188924294Smckusick 189024294Smckusick if (revision == Nullch) 189124294Smckusick return TRUE; 189224294Smckusick patlen = strlen(revision); 189324294Smckusick for (s = string; *s; s++) { 189424294Smckusick if (isspace(*s) && strnEQ(s+1,revision,patlen) && 189524294Smckusick isspace(s[patlen+1] )) { 189624294Smckusick return TRUE; 189724294Smckusick } 189824294Smckusick } 189924294Smckusick return FALSE; 190024294Smckusick } 190124294Smckusick 190224294Smckusick set_signals() 190324294Smckusick { 190424294Smckusick /*NOSTRICT*/ 190524294Smckusick if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 190624294Smckusick Signal(SIGHUP, my_exit); 190724294Smckusick /*NOSTRICT*/ 190824294Smckusick if (signal(SIGINT, SIG_IGN) != SIG_IGN) 190924294Smckusick Signal(SIGINT, my_exit); 191024294Smckusick } 191124294Smckusick 191224294Smckusick ignore_signals() 191324294Smckusick { 191424294Smckusick /*NOSTRICT*/ 191524294Smckusick Signal(SIGHUP, SIG_IGN); 191624294Smckusick /*NOSTRICT*/ 191724294Smckusick Signal(SIGINT, SIG_IGN); 191824294Smckusick } 1919