124294Smckusick #ifndef lint 2*33496Sbostic static char sccsid[] = "@(#)patch.c 5.9 (Berkeley) 02/18/88"; 324294Smckusick #endif not lint 424294Smckusick 5*33496Sbostic char rcsid[] = 6*33496Sbostic "$Header: patch.c,v 2.0.1.4 87/02/16 14:00:04 lwall Exp $"; 7*33496Sbostic 824294Smckusick /* patch - a program to apply diffs to original files 924294Smckusick * 10*33496Sbostic * Copyright 1986, Larry Wall 1124294Smckusick * 1224294Smckusick * This program may be copied as long as you don't try to make any 1324294Smckusick * money off of it, or pretend that you wrote it. 1424294Smckusick * 1524294Smckusick * $Log: patch.c,v $ 16*33496Sbostic * Revision 2.0.1.4 87/02/16 14:00:04 lwall 17*33496Sbostic * Short replacement caused spurious "Out of sync" message. 18*33496Sbostic * 19*33496Sbostic * Revision 2.0.1.3 87/01/30 22:45:50 lwall 20*33496Sbostic * Improved diagnostic on sync error. 21*33496Sbostic * Moved do_ed_script() to pch.c. 22*33496Sbostic * 23*33496Sbostic * Revision 2.0.1.2 86/11/21 09:39:15 lwall 24*33496Sbostic * Fuzz factor caused offset of installed lines. 25*33496Sbostic * 26*33496Sbostic * Revision 2.0.1.1 86/10/29 13:10:22 lwall 27*33496Sbostic * Backwards search could terminate prematurely. 28*33496Sbostic * 29*33496Sbostic * Revision 2.0 86/09/17 15:37:32 lwall 30*33496Sbostic * Baseline for netwide release. 31*33496Sbostic * 32*33496Sbostic * Revision 1.5 86/08/01 20:53:24 lwall 33*33496Sbostic * Changed some %d's to %ld's. 34*33496Sbostic * Linted. 35*33496Sbostic * 36*33496Sbostic * Revision 1.4 86/08/01 19:17:29 lwall 37*33496Sbostic * Fixes for machines that can't vararg. 38*33496Sbostic * Added fuzz factor. 39*33496Sbostic * Generalized -p. 40*33496Sbostic * General cleanup. 41*33496Sbostic * 4224295Smckusick * 85/08/15 van%ucbmonet@berkeley 4324295Smckusick * Changes for 4.3bsd diff -c. 4424295Smckusick * 4524294Smckusick * Revision 1.3 85/03/26 15:07:43 lwall 4624294Smckusick * Frozen. 4724294Smckusick * 4824294Smckusick * Revision 1.2.1.9 85/03/12 17:03:35 lwall 4924294Smckusick * Changed pfp->_file to fileno(pfp). 5024294Smckusick * 5124294Smckusick * Revision 1.2.1.8 85/03/12 16:30:43 lwall 5224294Smckusick * Check i_ptr and i_womp to make sure they aren't null before freeing. 5324294Smckusick * Also allow ed output to be suppressed. 5424294Smckusick * 5524294Smckusick * Revision 1.2.1.7 85/03/12 15:56:13 lwall 5624294Smckusick * Added -p option from jromine@uci-750a. 5724294Smckusick * 5824294Smckusick * Revision 1.2.1.6 85/03/12 12:12:51 lwall 5924294Smckusick * Now checks for normalness of file to patch. 6024294Smckusick * 6124294Smckusick * Revision 1.2.1.5 85/03/12 11:52:12 lwall 6224294Smckusick * Added -D (#ifdef) option from joe@fluke. 6324294Smckusick * 6424294Smckusick * Revision 1.2.1.4 84/12/06 11:14:15 lwall 6524294Smckusick * Made smarter about SCCS subdirectories. 6624294Smckusick * 6724294Smckusick * Revision 1.2.1.3 84/12/05 11:18:43 lwall 6824294Smckusick * Added -l switch to do loose string comparison. 6924294Smckusick * 7024294Smckusick * Revision 1.2.1.2 84/12/04 09:47:13 lwall 7124294Smckusick * Failed hunk count not reset on multiple patch file. 7224294Smckusick * 7324294Smckusick * Revision 1.2.1.1 84/12/04 09:42:37 lwall 7424294Smckusick * Branch for sdcrdcf changes. 7524294Smckusick * 7624294Smckusick * Revision 1.2 84/11/29 13:29:51 lwall 7724294Smckusick * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed 7824294Smckusick * multiple calls to mktemp(). Will now work on machines that can only 7924294Smckusick * read 32767 chars. Added -R option for diffs with new and old swapped. 8024294Smckusick * Various cosmetic changes. 8124294Smckusick * 8224294Smckusick * Revision 1.1 84/11/09 17:03:58 lwall 8324294Smckusick * Initial revision 8424294Smckusick * 8524294Smckusick */ 8624294Smckusick 87*33496Sbostic #include "INTERN.h" 88*33496Sbostic #include "common.h" 89*33496Sbostic #include "EXTERN.h" 90*33496Sbostic #include "version.h" 91*33496Sbostic #include "util.h" 92*33496Sbostic #include "pch.h" 93*33496Sbostic #include "inp.h" 9424294Smckusick 9524294Smckusick /* procedures */ 9624294Smckusick 97*33496Sbostic void reinitialize_almost_everything(); 98*33496Sbostic void get_some_switches(); 9924294Smckusick LINENUM locate_hunk(); 100*33496Sbostic void abort_hunk(); 101*33496Sbostic void apply_hunk(); 102*33496Sbostic void init_output(); 103*33496Sbostic void init_reject(); 104*33496Sbostic void copy_till(); 105*33496Sbostic void spew_output(); 106*33496Sbostic void dump_line(); 10724294Smckusick bool patch_match(); 10824294Smckusick bool similar(); 109*33496Sbostic void re_input(); 110*33496Sbostic void my_exit(); 11124294Smckusick 112*33496Sbostic /* Apply a set of diffs as appropriate. */ 11324294Smckusick 11424294Smckusick main(argc,argv) 11524294Smckusick int argc; 11624294Smckusick char **argv; 11724294Smckusick { 11824294Smckusick LINENUM where; 119*33496Sbostic LINENUM newwhere; 120*33496Sbostic LINENUM fuzz; 121*33496Sbostic LINENUM mymaxfuzz; 12224294Smckusick int hunk = 0; 12324294Smckusick int failed = 0; 12424294Smckusick int i; 12524294Smckusick 126*33496Sbostic setbuf(stderr, serrbuf); 12724294Smckusick for (i = 0; i<MAXFILEC; i++) 12824294Smckusick filearg[i] = Nullch; 12924294Smckusick Mktemp(TMPOUTNAME); 13024294Smckusick Mktemp(TMPINNAME); 13124294Smckusick Mktemp(TMPREJNAME); 13224294Smckusick Mktemp(TMPPATNAME); 13324294Smckusick 13424294Smckusick /* parse switches */ 13524294Smckusick Argc = argc; 13624294Smckusick Argv = argv; 13724294Smckusick get_some_switches(); 13824294Smckusick 13924294Smckusick /* make sure we clean up /tmp in case of disaster */ 14024294Smckusick set_signals(); 14124294Smckusick 14224294Smckusick for ( 14324294Smckusick open_patch_file(filearg[1]); 14424294Smckusick there_is_another_patch(); 14524294Smckusick reinitialize_almost_everything() 14624294Smckusick ) { /* for each patch in patch file */ 14724294Smckusick 14824294Smckusick if (outname == Nullch) 14924294Smckusick outname = savestr(filearg[0]); 15024294Smckusick 15124294Smckusick /* initialize the patched file */ 152*33496Sbostic if (!skip_rest_of_patch) 153*33496Sbostic init_output(TMPOUTNAME); 15424294Smckusick 15524294Smckusick /* for ed script just up and do it and exit */ 15624294Smckusick if (diff_type == ED_DIFF) { 15724294Smckusick do_ed_script(); 15824294Smckusick continue; 15924294Smckusick } 16024294Smckusick 16124294Smckusick /* initialize reject file */ 16224294Smckusick init_reject(TMPREJNAME); 16324294Smckusick 16424294Smckusick /* find out where all the lines are */ 165*33496Sbostic if (!skip_rest_of_patch) 166*33496Sbostic scan_input(filearg[0]); 16724294Smckusick 16824294Smckusick /* from here on, open no standard i/o files, because malloc */ 169*33496Sbostic /* might misfire and we can't catch it easily */ 17024294Smckusick 17124294Smckusick /* apply each hunk of patch */ 17224294Smckusick hunk = 0; 17324294Smckusick failed = 0; 174*33496Sbostic out_of_mem = FALSE; 17524294Smckusick while (another_hunk()) { 17624294Smckusick hunk++; 177*33496Sbostic fuzz = Nulline; 178*33496Sbostic mymaxfuzz = pch_context(); 179*33496Sbostic if (maxfuzz < mymaxfuzz) 180*33496Sbostic mymaxfuzz = maxfuzz; 181*33496Sbostic if (!skip_rest_of_patch) { 182*33496Sbostic do { 183*33496Sbostic where = locate_hunk(fuzz); 184*33496Sbostic if (hunk == 1 && where == Nulline && !force) { 185*33496Sbostic /* dwim for reversed patch? */ 186*33496Sbostic if (!pch_swap()) { 187*33496Sbostic if (fuzz == Nulline) 188*33496Sbostic say1("\ 189*33496Sbostic Not enough memory to try swapped hunk! Assuming unswapped.\n"); 190*33496Sbostic continue; 191*33496Sbostic } 192*33496Sbostic reverse = !reverse; 193*33496Sbostic where = locate_hunk(fuzz); /* try again */ 194*33496Sbostic if (where == Nulline) { /* didn't find it swapped */ 195*33496Sbostic if (!pch_swap()) /* put it back to normal */ 196*33496Sbostic fatal1("Lost hunk on alloc error!\n"); 197*33496Sbostic reverse = !reverse; 198*33496Sbostic } 199*33496Sbostic else if (noreverse) { 200*33496Sbostic if (!pch_swap()) /* put it back to normal */ 201*33496Sbostic fatal1("Lost hunk on alloc error!\n"); 202*33496Sbostic reverse = !reverse; 203*33496Sbostic say1("\ 204*33496Sbostic Ignoring previously applied (or reversed) patch.\n"); 205*33496Sbostic skip_rest_of_patch = TRUE; 206*33496Sbostic } 207*33496Sbostic else { 208*33496Sbostic ask3("\ 209*33496Sbostic %seversed (or previously applied) patch detected! %s -R? [y] ", 210*33496Sbostic reverse ? "R" : "Unr", 211*33496Sbostic reverse ? "Assume" : "Ignore"); 212*33496Sbostic if (*buf == 'n') { 213*33496Sbostic ask1("Apply anyway? [n] "); 214*33496Sbostic if (*buf != 'y') 215*33496Sbostic skip_rest_of_patch = TRUE; 216*33496Sbostic where = Nulline; 217*33496Sbostic reverse = !reverse; 218*33496Sbostic if (!pch_swap()) /* put it back to normal */ 219*33496Sbostic fatal1("Lost hunk on alloc error!\n"); 220*33496Sbostic } 221*33496Sbostic } 222*33496Sbostic } 223*33496Sbostic } while (!skip_rest_of_patch && where == Nulline && 224*33496Sbostic ++fuzz <= mymaxfuzz); 225*33496Sbostic 226*33496Sbostic if (skip_rest_of_patch) { /* just got decided */ 227*33496Sbostic Fclose(ofp); 228*33496Sbostic ofp = Nullfp; 22924294Smckusick } 23024294Smckusick } 231*33496Sbostic 232*33496Sbostic newwhere = pch_newfirst() + last_offset; 233*33496Sbostic if (skip_rest_of_patch) { 23424294Smckusick abort_hunk(); 23524294Smckusick failed++; 23624294Smckusick if (verbose) 237*33496Sbostic say3("Hunk #%d ignored at %ld.\n", hunk, newwhere); 23824294Smckusick } 239*33496Sbostic else if (where == Nulline) { 240*33496Sbostic abort_hunk(); 241*33496Sbostic failed++; 242*33496Sbostic if (verbose) 243*33496Sbostic say3("Hunk #%d failed at %ld.\n", hunk, newwhere); 244*33496Sbostic } 24524294Smckusick else { 24624294Smckusick apply_hunk(where); 247*33496Sbostic if (verbose) { 248*33496Sbostic say3("Hunk #%d succeeded at %ld", hunk, newwhere); 249*33496Sbostic if (fuzz) 250*33496Sbostic say2(" with fuzz %ld", fuzz); 25124294Smckusick if (last_offset) 252*33496Sbostic say3(" (offset %ld line%s)", 253*33496Sbostic last_offset, last_offset==1L?"":"s"); 254*33496Sbostic say1(".\n"); 255*33496Sbostic } 25624294Smckusick } 25724294Smckusick } 258*33496Sbostic 259*33496Sbostic if (out_of_mem && using_plan_a) { 260*33496Sbostic Argc = Argc_last; 261*33496Sbostic Argv = Argv_last; 262*33496Sbostic say1("\n\nRan out of memory using Plan A--trying again...\n\n"); 263*33496Sbostic continue; 264*33496Sbostic } 26524294Smckusick 26624294Smckusick assert(hunk); 26724294Smckusick 26824294Smckusick /* finish spewing out the new file */ 269*33496Sbostic if (!skip_rest_of_patch) 270*33496Sbostic spew_output(); 27124294Smckusick 27224294Smckusick /* and put the output where desired */ 27324294Smckusick ignore_signals(); 274*33496Sbostic if (!skip_rest_of_patch) { 275*33496Sbostic if (move_file(TMPOUTNAME, outname) < 0) { 276*33496Sbostic toutkeep = TRUE; 277*33496Sbostic chmod(TMPOUTNAME, filemode); 278*33496Sbostic } 279*33496Sbostic else 280*33496Sbostic chmod(outname, filemode); 281*33496Sbostic } 28224294Smckusick Fclose(rejfp); 28324294Smckusick rejfp = Nullfp; 28424294Smckusick if (failed) { 28524294Smckusick if (!*rejname) { 28624294Smckusick Strcpy(rejname, outname); 28724294Smckusick Strcat(rejname, ".rej"); 28824294Smckusick } 289*33496Sbostic if (skip_rest_of_patch) { 290*33496Sbostic say4("%d out of %d hunks ignored--saving rejects to %s\n", 291*33496Sbostic failed, hunk, rejname); 292*33496Sbostic } 293*33496Sbostic else { 294*33496Sbostic say4("%d out of %d hunks failed--saving rejects to %s\n", 295*33496Sbostic failed, hunk, rejname); 296*33496Sbostic } 297*33496Sbostic if (move_file(TMPREJNAME, rejname) < 0) 298*33496Sbostic trejkeep = TRUE; 29924294Smckusick } 30024294Smckusick set_signals(); 30124294Smckusick } 30224294Smckusick my_exit(0); 30324294Smckusick } 30424294Smckusick 305*33496Sbostic /* Prepare to find the next patch to do in the patch file. */ 306*33496Sbostic 307*33496Sbostic void 30824294Smckusick reinitialize_almost_everything() 30924294Smckusick { 31024294Smckusick re_patch(); 31124294Smckusick re_input(); 31224294Smckusick 31324294Smckusick input_lines = 0; 31424294Smckusick last_frozen_line = 0; 31524294Smckusick 31624294Smckusick filec = 0; 317*33496Sbostic if (filearg[0] != Nullch && !out_of_mem) { 31824294Smckusick free(filearg[0]); 31924294Smckusick filearg[0] = Nullch; 32024294Smckusick } 32124294Smckusick 32224294Smckusick if (outname != Nullch) { 32324294Smckusick free(outname); 32424294Smckusick outname = Nullch; 32524294Smckusick } 32624294Smckusick 32724294Smckusick last_offset = 0; 32824294Smckusick 32924294Smckusick diff_type = 0; 33024294Smckusick 33124294Smckusick if (revision != Nullch) { 33224294Smckusick free(revision); 33324294Smckusick revision = Nullch; 33424294Smckusick } 33524294Smckusick 33624294Smckusick reverse = FALSE; 337*33496Sbostic skip_rest_of_patch = FALSE; 33824294Smckusick 33924294Smckusick get_some_switches(); 34024294Smckusick 34124294Smckusick if (filec >= 2) 342*33496Sbostic fatal1("You may not change to a different patch file.\n"); 34324294Smckusick } 34424294Smckusick 345*33496Sbostic /* Process switches and filenames up to next '+' or end of list. */ 346*33496Sbostic 347*33496Sbostic void 34824294Smckusick get_some_switches() 34924294Smckusick { 350*33496Sbostic Reg1 char *s; 35124294Smckusick 35224294Smckusick rejname[0] = '\0'; 353*33496Sbostic Argc_last = Argc; 354*33496Sbostic Argv_last = Argv; 35524294Smckusick if (!Argc) 35624294Smckusick return; 35724294Smckusick for (Argc--,Argv++; Argc; Argc--,Argv++) { 35824294Smckusick s = Argv[0]; 359*33496Sbostic if (strEQ(s, "+")) { 36024294Smckusick return; /* + will be skipped by for loop */ 36124294Smckusick } 36224294Smckusick if (*s != '-' || !s[1]) { 36324294Smckusick if (filec == MAXFILEC) 364*33496Sbostic fatal1("Too many file arguments.\n"); 36524294Smckusick filearg[filec++] = savestr(s); 36624294Smckusick } 36724294Smckusick else { 36824294Smckusick switch (*++s) { 36924294Smckusick case 'b': 37024294Smckusick origext = savestr(Argv[1]); 37124294Smckusick Argc--,Argv++; 37224294Smckusick break; 37324294Smckusick case 'c': 37424294Smckusick diff_type = CONTEXT_DIFF; 37524294Smckusick break; 37624294Smckusick case 'd': 377*33496Sbostic if (!*++s) { 378*33496Sbostic Argc--,Argv++; 379*33496Sbostic s = Argv[0]; 380*33496Sbostic } 381*33496Sbostic if (chdir(s) < 0) 382*33496Sbostic fatal2("Can't cd to %s.\n", s); 38324294Smckusick break; 38424294Smckusick case 'D': 385*33496Sbostic do_defines = TRUE; 386*33496Sbostic if (!*++s) { 387*33496Sbostic Argc--,Argv++; 388*33496Sbostic s = Argv[0]; 389*33496Sbostic } 390*33496Sbostic Sprintf(if_defined, "#ifdef %s\n", s); 391*33496Sbostic Sprintf(not_defined, "#ifndef %s\n", s); 392*33496Sbostic Sprintf(end_defined, "#endif /* %s */\n", s); 39324294Smckusick break; 39424294Smckusick case 'e': 39524294Smckusick diff_type = ED_DIFF; 39624294Smckusick break; 397*33496Sbostic case 'f': 398*33496Sbostic force = TRUE; 399*33496Sbostic break; 400*33496Sbostic case 'F': 401*33496Sbostic if (*++s == '=') 402*33496Sbostic s++; 403*33496Sbostic maxfuzz = atoi(s); 404*33496Sbostic break; 40524294Smckusick case 'l': 40624294Smckusick canonicalize = TRUE; 40724294Smckusick break; 40824294Smckusick case 'n': 40924294Smckusick diff_type = NORMAL_DIFF; 41024294Smckusick break; 411*33496Sbostic case 'N': 412*33496Sbostic noreverse = TRUE; 413*33496Sbostic break; 41424294Smckusick case 'o': 41524294Smckusick outname = savestr(Argv[1]); 41624294Smckusick Argc--,Argv++; 41724294Smckusick break; 41824294Smckusick case 'p': 419*33496Sbostic if (*++s == '=') 420*33496Sbostic s++; 421*33496Sbostic strippath = atoi(s); 42224294Smckusick break; 42324294Smckusick case 'r': 424*33496Sbostic Strcpy(rejname, Argv[1]); 42524294Smckusick Argc--,Argv++; 42624294Smckusick break; 42724294Smckusick case 'R': 42824294Smckusick reverse = TRUE; 42924294Smckusick break; 43024294Smckusick case 's': 43124294Smckusick verbose = FALSE; 43224294Smckusick break; 433*33496Sbostic case 'S': 434*33496Sbostic skip_rest_of_patch = TRUE; 435*33496Sbostic break; 436*33496Sbostic case 'v': 437*33496Sbostic version(); 438*33496Sbostic break; 43924294Smckusick #ifdef DEBUGGING 44024294Smckusick case 'x': 44124294Smckusick debug = atoi(s+1); 44224294Smckusick break; 44324294Smckusick #endif 44424294Smckusick default: 445*33496Sbostic fatal2("Unrecognized switch: %s\n", Argv[0]); 44624294Smckusick } 44724294Smckusick } 44824294Smckusick } 44924294Smckusick } 45024294Smckusick 451*33496Sbostic /* Attempt to find the right place to apply this hunk of patch. */ 452*33496Sbostic 45324294Smckusick LINENUM 454*33496Sbostic locate_hunk(fuzz) 455*33496Sbostic LINENUM fuzz; 45624294Smckusick { 457*33496Sbostic Reg1 LINENUM first_guess = pch_first() + last_offset; 458*33496Sbostic Reg2 LINENUM offset; 45924294Smckusick LINENUM pat_lines = pch_ptrn_lines(); 460*33496Sbostic Reg3 LINENUM max_pos_offset = input_lines - first_guess 46124294Smckusick - pat_lines + 1; 462*33496Sbostic Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1 463*33496Sbostic + pch_context(); 46424294Smckusick 46524294Smckusick if (!pat_lines) /* null range matches always */ 46624294Smckusick return first_guess; 46724294Smckusick if (max_neg_offset >= first_guess) /* do not try lines < 0 */ 46824294Smckusick max_neg_offset = first_guess - 1; 469*33496Sbostic if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz)) 47024294Smckusick return first_guess; 47124294Smckusick for (offset = 1; ; offset++) { 472*33496Sbostic Reg5 bool check_after = (offset <= max_pos_offset); 473*33496Sbostic Reg6 bool check_before = (offset <= max_neg_offset); 47424294Smckusick 475*33496Sbostic if (check_after && patch_match(first_guess, offset, fuzz)) { 47624294Smckusick #ifdef DEBUGGING 47724294Smckusick if (debug & 1) 478*33496Sbostic say3("Offset changing from %ld to %ld\n", last_offset, offset); 47924294Smckusick #endif 48024294Smckusick last_offset = offset; 48124294Smckusick return first_guess+offset; 48224294Smckusick } 483*33496Sbostic else if (check_before && patch_match(first_guess, -offset, fuzz)) { 48424294Smckusick #ifdef DEBUGGING 48524294Smckusick if (debug & 1) 486*33496Sbostic say3("Offset changing from %ld to %ld\n", last_offset, -offset); 48724294Smckusick #endif 48824294Smckusick last_offset = -offset; 48924294Smckusick return first_guess-offset; 49024294Smckusick } 49124294Smckusick else if (!check_before && !check_after) 492*33496Sbostic return Nulline; 49324294Smckusick } 49424294Smckusick } 49524294Smckusick 496*33496Sbostic /* We did not find the pattern, dump out the hunk so they can handle it. */ 49724294Smckusick 498*33496Sbostic void 49924294Smckusick abort_hunk() 50024294Smckusick { 501*33496Sbostic Reg1 LINENUM i; 502*33496Sbostic Reg2 LINENUM pat_end = pch_end(); 50324294Smckusick /* add in last_offset to guess the same as the previous successful hunk */ 504*33496Sbostic LINENUM oldfirst = pch_first() + last_offset; 505*33496Sbostic LINENUM newfirst = pch_newfirst() + last_offset; 506*33496Sbostic LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1; 507*33496Sbostic LINENUM newlast = newfirst + pch_repl_lines() - 1; 508*33496Sbostic char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : ""); 509*33496Sbostic char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----"); 51024294Smckusick 511*33496Sbostic fprintf(rejfp, "***************\n"); 51224294Smckusick for (i=0; i<=pat_end; i++) { 51324294Smckusick switch (pch_char(i)) { 51424294Smckusick case '*': 515*33496Sbostic if (oldlast < oldfirst) 516*33496Sbostic fprintf(rejfp, "*** 0%s\n", stars); 517*33496Sbostic else if (oldlast == oldfirst) 518*33496Sbostic fprintf(rejfp, "*** %ld%s\n", oldfirst, stars); 51926977Svan else 520*33496Sbostic fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars); 52124294Smckusick break; 52224294Smckusick case '=': 523*33496Sbostic if (newlast < newfirst) 524*33496Sbostic fprintf(rejfp, "--- 0%s\n", minuses); 525*33496Sbostic else if (newlast == newfirst) 526*33496Sbostic fprintf(rejfp, "--- %ld%s\n", newfirst, minuses); 527*33496Sbostic else 528*33496Sbostic fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses); 52924294Smckusick break; 53024294Smckusick case '\n': 531*33496Sbostic fprintf(rejfp, "%s", pfetch(i)); 53224294Smckusick break; 53324294Smckusick case ' ': case '-': case '+': case '!': 534*33496Sbostic fprintf(rejfp, "%c %s", pch_char(i), pfetch(i)); 53524294Smckusick break; 53624294Smckusick default: 537*33496Sbostic say1("Fatal internal error in abort_hunk().\n"); 53824294Smckusick abort(); 53924294Smckusick } 54024294Smckusick } 54124294Smckusick } 54224294Smckusick 543*33496Sbostic /* We found where to apply it (we hope), so do it. */ 54424294Smckusick 545*33496Sbostic void 54624294Smckusick apply_hunk(where) 54724294Smckusick LINENUM where; 54824294Smckusick { 549*33496Sbostic Reg1 LINENUM old = 1; 550*33496Sbostic Reg2 LINENUM lastline = pch_ptrn_lines(); 551*33496Sbostic Reg3 LINENUM new = lastline+1; 552*33496Sbostic #define OUTSIDE 0 553*33496Sbostic #define IN_IFNDEF 1 554*33496Sbostic #define IN_IFDEF 2 555*33496Sbostic #define IN_ELSE 3 556*33496Sbostic Reg4 int def_state = OUTSIDE; 557*33496Sbostic Reg5 bool R_do_defines = do_defines; 558*33496Sbostic Reg6 LINENUM pat_end = pch_end(); 55924294Smckusick 56024294Smckusick where--; 56124294Smckusick while (pch_char(new) == '=' || pch_char(new) == '\n') 56224294Smckusick new++; 56324294Smckusick 56424294Smckusick while (old <= lastline) { 56524294Smckusick if (pch_char(old) == '-') { 56624294Smckusick copy_till(where + old - 1); 567*33496Sbostic if (R_do_defines) { 568*33496Sbostic if (def_state == OUTSIDE) { 56924294Smckusick fputs(not_defined, ofp); 570*33496Sbostic def_state = IN_IFNDEF; 571*33496Sbostic } 572*33496Sbostic else if (def_state == IN_IFDEF) { 57324294Smckusick fputs(else_defined, ofp); 574*33496Sbostic def_state = IN_ELSE; 57524294Smckusick } 57624294Smckusick fputs(pfetch(old), ofp); 57724294Smckusick } 57824294Smckusick last_frozen_line++; 57924294Smckusick old++; 58024294Smckusick } 581*33496Sbostic else if (new > pat_end) 582*33496Sbostic break; 58324294Smckusick else if (pch_char(new) == '+') { 58424294Smckusick copy_till(where + old - 1); 585*33496Sbostic if (R_do_defines) { 586*33496Sbostic if (def_state == IN_IFNDEF) { 58724294Smckusick fputs(else_defined, ofp); 588*33496Sbostic def_state = IN_ELSE; 589*33496Sbostic } 590*33496Sbostic else if (def_state == OUTSIDE) { 59124294Smckusick fputs(if_defined, ofp); 592*33496Sbostic def_state = IN_IFDEF; 59324294Smckusick } 59424294Smckusick } 595*33496Sbostic fputs(pfetch(new), ofp); 59624294Smckusick new++; 59724294Smckusick } 59824294Smckusick else { 59924294Smckusick if (pch_char(new) != pch_char(old)) { 600*33496Sbostic say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n", 601*33496Sbostic pch_hunk_beg() + old, 602*33496Sbostic pch_hunk_beg() + new); 60324294Smckusick #ifdef DEBUGGING 604*33496Sbostic say3("oldchar = '%c', newchar = '%c'\n", 60524294Smckusick pch_char(old), pch_char(new)); 60624294Smckusick #endif 60724294Smckusick my_exit(1); 60824294Smckusick } 60924294Smckusick if (pch_char(new) == '!') { 61024294Smckusick copy_till(where + old - 1); 611*33496Sbostic if (R_do_defines) { 612*33496Sbostic fputs(not_defined, ofp); 613*33496Sbostic def_state = IN_IFNDEF; 61424294Smckusick } 61524294Smckusick while (pch_char(old) == '!') { 616*33496Sbostic if (R_do_defines) { 617*33496Sbostic fputs(pfetch(old), ofp); 61824294Smckusick } 61924294Smckusick last_frozen_line++; 62024294Smckusick old++; 62124294Smckusick } 622*33496Sbostic if (R_do_defines) { 62324294Smckusick fputs(else_defined, ofp); 624*33496Sbostic def_state = IN_ELSE; 62524294Smckusick } 62624294Smckusick while (pch_char(new) == '!') { 627*33496Sbostic fputs(pfetch(new), ofp); 62824294Smckusick new++; 62924294Smckusick } 630*33496Sbostic if (R_do_defines) { 63124294Smckusick fputs(end_defined, ofp); 632*33496Sbostic def_state = OUTSIDE; 63324294Smckusick } 63424294Smckusick } 63524294Smckusick else { 63624294Smckusick assert(pch_char(new) == ' '); 63724294Smckusick old++; 63824294Smckusick new++; 63924294Smckusick } 64024294Smckusick } 64124294Smckusick } 642*33496Sbostic if (new <= pat_end && pch_char(new) == '+') { 64324294Smckusick copy_till(where + old - 1); 644*33496Sbostic if (R_do_defines) { 645*33496Sbostic if (def_state == OUTSIDE) { 64624294Smckusick fputs(if_defined, ofp); 647*33496Sbostic def_state = IN_IFDEF; 648*33496Sbostic } 649*33496Sbostic else if (def_state == IN_IFNDEF) { 65024294Smckusick fputs(else_defined, ofp); 651*33496Sbostic def_state = IN_ELSE; 65224294Smckusick } 65324294Smckusick } 654*33496Sbostic while (new <= pat_end && pch_char(new) == '+') { 655*33496Sbostic fputs(pfetch(new), ofp); 65624294Smckusick new++; 65724294Smckusick } 65824294Smckusick } 659*33496Sbostic if (R_do_defines && def_state != OUTSIDE) { 66024294Smckusick fputs(end_defined, ofp); 66124294Smckusick } 66224294Smckusick } 66324294Smckusick 664*33496Sbostic /* Open the new file. */ 66524294Smckusick 666*33496Sbostic void 66724294Smckusick init_output(name) 66824294Smckusick char *name; 66924294Smckusick { 670*33496Sbostic ofp = fopen(name, "w"); 67124294Smckusick if (ofp == Nullfp) 672*33496Sbostic fatal2("patch: can't create %s.\n", name); 67324294Smckusick } 67424294Smckusick 675*33496Sbostic /* Open a file to put hunks we can't locate. */ 676*33496Sbostic 677*33496Sbostic void 67824294Smckusick init_reject(name) 67924294Smckusick char *name; 68024294Smckusick { 681*33496Sbostic rejfp = fopen(name, "w"); 68224294Smckusick if (rejfp == Nullfp) 683*33496Sbostic fatal2("patch: can't create %s.\n", name); 68424294Smckusick } 68524294Smckusick 686*33496Sbostic /* Copy input file to output, up to wherever hunk is to be applied. */ 687*33496Sbostic 688*33496Sbostic void 689*33496Sbostic copy_till(lastline) 690*33496Sbostic Reg1 LINENUM lastline; 69124294Smckusick { 692*33496Sbostic Reg2 LINENUM R_last_frozen_line = last_frozen_line; 69324294Smckusick 694*33496Sbostic if (R_last_frozen_line > lastline) 695*33496Sbostic say1("patch: misordered hunks! output will be garbled.\n"); 696*33496Sbostic while (R_last_frozen_line < lastline) { 697*33496Sbostic dump_line(++R_last_frozen_line); 69824294Smckusick } 699*33496Sbostic last_frozen_line = R_last_frozen_line; 70024294Smckusick } 70124294Smckusick 702*33496Sbostic /* Finish copying the input file to the output file. */ 70324294Smckusick 704*33496Sbostic void 70524294Smckusick spew_output() 70624294Smckusick { 707*33496Sbostic #ifdef DEBUGGING 708*33496Sbostic if (debug & 256) 709*33496Sbostic say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line); 710*33496Sbostic #endif 711*33496Sbostic if (input_lines) 712*33496Sbostic copy_till(input_lines); /* dump remainder of file */ 71324294Smckusick Fclose(ofp); 71424294Smckusick ofp = Nullfp; 71524294Smckusick } 71624294Smckusick 717*33496Sbostic /* Copy one line from input to output. */ 718*33496Sbostic 719*33496Sbostic void 72024294Smckusick dump_line(line) 72124294Smckusick LINENUM line; 72224294Smckusick { 723*33496Sbostic Reg1 char *s; 724*33496Sbostic Reg2 char R_newline = '\n'; 72524294Smckusick 726*33496Sbostic /* Note: string is not null terminated. */ 727*33496Sbostic for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ; 72824294Smckusick } 72924294Smckusick 730*33496Sbostic /* Does the patch pattern match at line base+offset? */ 73124294Smckusick 73224294Smckusick bool 733*33496Sbostic patch_match(base, offset, fuzz) 73424294Smckusick LINENUM base; 73524294Smckusick LINENUM offset; 736*33496Sbostic LINENUM fuzz; 73724294Smckusick { 738*33496Sbostic Reg1 LINENUM pline = 1 + fuzz; 739*33496Sbostic Reg2 LINENUM iline; 740*33496Sbostic Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz; 74124294Smckusick 742*33496Sbostic for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) { 74324294Smckusick if (canonicalize) { 744*33496Sbostic if (!similar(ifetch(iline, (offset >= 0)), 74524294Smckusick pfetch(pline), 74624294Smckusick pch_line_len(pline) )) 74724294Smckusick return FALSE; 74824294Smckusick } 749*33496Sbostic else if (strnNE(ifetch(iline, (offset >= 0)), 75024294Smckusick pfetch(pline), 75124294Smckusick pch_line_len(pline) )) 75224294Smckusick return FALSE; 75324294Smckusick } 75424294Smckusick return TRUE; 75524294Smckusick } 75624294Smckusick 757*33496Sbostic /* Do two lines match with canonicalized white space? */ 75824294Smckusick 75924294Smckusick bool 76024294Smckusick similar(a,b,len) 761*33496Sbostic Reg1 char *a; 762*33496Sbostic Reg2 char *b; 763*33496Sbostic Reg3 int len; 76424294Smckusick { 76524294Smckusick while (len) { 76624294Smckusick if (isspace(*b)) { /* whitespace (or \n) to match? */ 76724294Smckusick if (!isspace(*a)) /* no corresponding whitespace? */ 76824294Smckusick return FALSE; 76924294Smckusick while (len && isspace(*b) && *b != '\n') 77024294Smckusick b++,len--; /* skip pattern whitespace */ 77124294Smckusick while (isspace(*a) && *a != '\n') 77224294Smckusick a++; /* skip target whitespace */ 77324294Smckusick if (*a == '\n' || *b == '\n') 77424294Smckusick return (*a == *b); /* should end in sync */ 77524294Smckusick } 77624294Smckusick else if (*a++ != *b++) /* match non-whitespace chars */ 77724294Smckusick return FALSE; 77824294Smckusick else 77924294Smckusick len--; /* probably not necessary */ 78024294Smckusick } 78124294Smckusick return TRUE; /* actually, this is not reached */ 78224294Smckusick /* since there is always a \n */ 78324294Smckusick } 78424294Smckusick 785*33496Sbostic /* Exit with cleanup. */ 78624294Smckusick 787*33496Sbostic void 78824294Smckusick my_exit(status) 78924294Smckusick int status; 79024294Smckusick { 79124294Smckusick Unlink(TMPINNAME); 792*33496Sbostic if (!toutkeep) { 793*33496Sbostic Unlink(TMPOUTNAME); 794*33496Sbostic } 795*33496Sbostic if (!trejkeep) { 796*33496Sbostic Unlink(TMPREJNAME); 797*33496Sbostic } 79824294Smckusick Unlink(TMPPATNAME); 79924294Smckusick exit(status); 80024294Smckusick } 801