1*24294Smckusick #ifndef lint 2*24294Smckusick static char sccsid[] = "@(#)patch.c 5.1 (Berkeley) 08/16/85"; 3*24294Smckusick #endif not lint 4*24294Smckusick 5*24294Smckusick /* patch - a program to apply diffs to original files 6*24294Smckusick * 7*24294Smckusick * $Header: patch.c,v 1.3 85/03/26 15:07:43 lwall Exp $ 8*24294Smckusick * 9*24294Smckusick * Copyright 1984, Larry Wall 10*24294Smckusick * 11*24294Smckusick * This program may be copied as long as you don't try to make any 12*24294Smckusick * money off of it, or pretend that you wrote it. 13*24294Smckusick * 14*24294Smckusick * $Log: patch.c,v $ 15*24294Smckusick * Revision 1.3 85/03/26 15:07:43 lwall 16*24294Smckusick * Frozen. 17*24294Smckusick * 18*24294Smckusick * Revision 1.2.1.9 85/03/12 17:03:35 lwall 19*24294Smckusick * Changed pfp->_file to fileno(pfp). 20*24294Smckusick * 21*24294Smckusick * Revision 1.2.1.8 85/03/12 16:30:43 lwall 22*24294Smckusick * Check i_ptr and i_womp to make sure they aren't null before freeing. 23*24294Smckusick * Also allow ed output to be suppressed. 24*24294Smckusick * 25*24294Smckusick * Revision 1.2.1.7 85/03/12 15:56:13 lwall 26*24294Smckusick * Added -p option from jromine@uci-750a. 27*24294Smckusick * 28*24294Smckusick * Revision 1.2.1.6 85/03/12 12:12:51 lwall 29*24294Smckusick * Now checks for normalness of file to patch. 30*24294Smckusick * 31*24294Smckusick * Revision 1.2.1.5 85/03/12 11:52:12 lwall 32*24294Smckusick * Added -D (#ifdef) option from joe@fluke. 33*24294Smckusick * 34*24294Smckusick * Revision 1.2.1.4 84/12/06 11:14:15 lwall 35*24294Smckusick * Made smarter about SCCS subdirectories. 36*24294Smckusick * 37*24294Smckusick * Revision 1.2.1.3 84/12/05 11:18:43 lwall 38*24294Smckusick * Added -l switch to do loose string comparison. 39*24294Smckusick * 40*24294Smckusick * Revision 1.2.1.2 84/12/04 09:47:13 lwall 41*24294Smckusick * Failed hunk count not reset on multiple patch file. 42*24294Smckusick * 43*24294Smckusick * Revision 1.2.1.1 84/12/04 09:42:37 lwall 44*24294Smckusick * Branch for sdcrdcf changes. 45*24294Smckusick * 46*24294Smckusick * Revision 1.2 84/11/29 13:29:51 lwall 47*24294Smckusick * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed 48*24294Smckusick * multiple calls to mktemp(). Will now work on machines that can only 49*24294Smckusick * read 32767 chars. Added -R option for diffs with new and old swapped. 50*24294Smckusick * Various cosmetic changes. 51*24294Smckusick * 52*24294Smckusick * Revision 1.1 84/11/09 17:03:58 lwall 53*24294Smckusick * Initial revision 54*24294Smckusick * 55*24294Smckusick */ 56*24294Smckusick 57*24294Smckusick #define DEBUGGING 58*24294Smckusick 59*24294Smckusick /* shut lint up about the following when return value ignored */ 60*24294Smckusick 61*24294Smckusick #define Signal (void)signal 62*24294Smckusick #define Unlink (void)unlink 63*24294Smckusick #define Lseek (void)lseek 64*24294Smckusick #define Fseek (void)fseek 65*24294Smckusick #define Fstat (void)fstat 66*24294Smckusick #define Pclose (void)pclose 67*24294Smckusick #define Close (void)close 68*24294Smckusick #define Fclose (void)fclose 69*24294Smckusick #define Fflush (void)fflush 70*24294Smckusick #define Sprintf (void)sprintf 71*24294Smckusick #define Mktemp (void)mktemp 72*24294Smckusick #define Strcpy (void)strcpy 73*24294Smckusick #define Strcat (void)strcat 74*24294Smckusick 75*24294Smckusick #include <stdio.h> 76*24294Smckusick #include <assert.h> 77*24294Smckusick #include <sys/types.h> 78*24294Smckusick #include <sys/stat.h> 79*24294Smckusick #include <ctype.h> 80*24294Smckusick #include <signal.h> 81*24294Smckusick 82*24294Smckusick /* constants */ 83*24294Smckusick 84*24294Smckusick #define TRUE (1) 85*24294Smckusick #define FALSE (0) 86*24294Smckusick 87*24294Smckusick #define MAXHUNKSIZE 500 88*24294Smckusick #define MAXLINELEN 1024 89*24294Smckusick #define BUFFERSIZE 1024 90*24294Smckusick #define ORIGEXT ".orig" 91*24294Smckusick #define SCCSPREFIX "s." 92*24294Smckusick #define GET "get -e %s" 93*24294Smckusick #define RCSSUFFIX ",v" 94*24294Smckusick #define CHECKOUT "co -l %s" 95*24294Smckusick 96*24294Smckusick /* handy definitions */ 97*24294Smckusick 98*24294Smckusick #define Null(t) ((t)0) 99*24294Smckusick #define Nullch Null(char *) 100*24294Smckusick #define Nullfp Null(FILE *) 101*24294Smckusick 102*24294Smckusick #define Ctl(ch) (ch & 037) 103*24294Smckusick 104*24294Smckusick #define strNE(s1,s2) (strcmp(s1,s2)) 105*24294Smckusick #define strEQ(s1,s2) (!strcmp(s1,s2)) 106*24294Smckusick #define strnNE(s1,s2,l) (strncmp(s1,s2,l)) 107*24294Smckusick #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l)) 108*24294Smckusick 109*24294Smckusick /* typedefs */ 110*24294Smckusick 111*24294Smckusick typedef char bool; 112*24294Smckusick typedef long LINENUM; /* must be signed */ 113*24294Smckusick typedef unsigned MEM; /* what to feed malloc */ 114*24294Smckusick 115*24294Smckusick /* globals */ 116*24294Smckusick 117*24294Smckusick int Argc; /* guess */ 118*24294Smckusick char **Argv; 119*24294Smckusick 120*24294Smckusick struct stat filestat; /* file statistics area */ 121*24294Smckusick 122*24294Smckusick char serrbuf[BUFSIZ]; /* buffer for stderr */ 123*24294Smckusick char buf[MAXLINELEN]; /* general purpose buffer */ 124*24294Smckusick FILE *pfp = Nullfp; /* patch file pointer */ 125*24294Smckusick FILE *ofp = Nullfp; /* output file pointer */ 126*24294Smckusick FILE *rejfp = Nullfp; /* reject file pointer */ 127*24294Smckusick 128*24294Smckusick LINENUM input_lines = 0; /* how long is input file in lines */ 129*24294Smckusick LINENUM last_frozen_line = 0; /* how many input lines have been */ 130*24294Smckusick /* irretractibly output */ 131*24294Smckusick 132*24294Smckusick #define MAXFILEC 2 133*24294Smckusick int filec = 0; /* how many file arguments? */ 134*24294Smckusick char *filearg[MAXFILEC]; 135*24294Smckusick 136*24294Smckusick char *outname = Nullch; 137*24294Smckusick char rejname[128]; 138*24294Smckusick 139*24294Smckusick char *origext = Nullch; 140*24294Smckusick 141*24294Smckusick char TMPOUTNAME[] = "/tmp/patchoXXXXXX"; 142*24294Smckusick char TMPINNAME[] = "/tmp/patchiXXXXXX"; /* you might want /usr/tmp here */ 143*24294Smckusick char TMPREJNAME[] = "/tmp/patchrXXXXXX"; 144*24294Smckusick char TMPPATNAME[] = "/tmp/patchpXXXXXX"; 145*24294Smckusick 146*24294Smckusick LINENUM last_offset = 0; 147*24294Smckusick #ifdef DEBUGGING 148*24294Smckusick int debug = 0; 149*24294Smckusick #endif 150*24294Smckusick bool verbose = TRUE; 151*24294Smckusick bool reverse = FALSE; 152*24294Smckusick bool usepath = FALSE; 153*24294Smckusick bool canonicalize = FALSE; 154*24294Smckusick 155*24294Smckusick #define CONTEXT_DIFF 1 156*24294Smckusick #define NORMAL_DIFF 2 157*24294Smckusick #define ED_DIFF 3 158*24294Smckusick int diff_type = 0; 159*24294Smckusick 160*24294Smckusick int do_defines = 0; /* patch using ifdef, ifndef, etc. */ 161*24294Smckusick char if_defined[128]; /* #ifdef xyzzy */ 162*24294Smckusick char not_defined[128]; /* #ifndef xyzzy */ 163*24294Smckusick char else_defined[] = "#else\n"; /* #else */ 164*24294Smckusick char end_defined[128]; /* #endif xyzzy */ 165*24294Smckusick 166*24294Smckusick char *revision = Nullch; /* prerequisite revision, if any */ 167*24294Smckusick 168*24294Smckusick /* procedures */ 169*24294Smckusick 170*24294Smckusick LINENUM locate_hunk(); 171*24294Smckusick bool patch_match(); 172*24294Smckusick bool similar(); 173*24294Smckusick char *malloc(); 174*24294Smckusick char *savestr(); 175*24294Smckusick char *strcpy(); 176*24294Smckusick char *strcat(); 177*24294Smckusick char *sprintf(); /* usually */ 178*24294Smckusick int my_exit(); 179*24294Smckusick bool rev_in_string(); 180*24294Smckusick char *fetchname(); 181*24294Smckusick long atol(); 182*24294Smckusick long lseek(); 183*24294Smckusick char *mktemp(); 184*24294Smckusick 185*24294Smckusick /* patch type */ 186*24294Smckusick 187*24294Smckusick bool there_is_another_patch(); 188*24294Smckusick bool another_hunk(); 189*24294Smckusick char *pfetch(); 190*24294Smckusick int pch_line_len(); 191*24294Smckusick LINENUM pch_first(); 192*24294Smckusick LINENUM pch_ptrn_lines(); 193*24294Smckusick LINENUM pch_newfirst(); 194*24294Smckusick LINENUM pch_repl_lines(); 195*24294Smckusick LINENUM pch_end(); 196*24294Smckusick LINENUM pch_context(); 197*24294Smckusick LINENUM pch_hunk_beg(); 198*24294Smckusick char pch_char(); 199*24294Smckusick char *pfetch(); 200*24294Smckusick char *pgets(); 201*24294Smckusick 202*24294Smckusick /* input file type */ 203*24294Smckusick 204*24294Smckusick char *ifetch(); 205*24294Smckusick 206*24294Smckusick /* apply a context patch to a named file */ 207*24294Smckusick 208*24294Smckusick main(argc,argv) 209*24294Smckusick int argc; 210*24294Smckusick char **argv; 211*24294Smckusick { 212*24294Smckusick LINENUM where; 213*24294Smckusick int hunk = 0; 214*24294Smckusick int failed = 0; 215*24294Smckusick int i; 216*24294Smckusick 217*24294Smckusick setbuf(stderr,serrbuf); 218*24294Smckusick for (i = 0; i<MAXFILEC; i++) 219*24294Smckusick filearg[i] = Nullch; 220*24294Smckusick Mktemp(TMPOUTNAME); 221*24294Smckusick Mktemp(TMPINNAME); 222*24294Smckusick Mktemp(TMPREJNAME); 223*24294Smckusick Mktemp(TMPPATNAME); 224*24294Smckusick 225*24294Smckusick /* parse switches */ 226*24294Smckusick Argc = argc; 227*24294Smckusick Argv = argv; 228*24294Smckusick get_some_switches(); 229*24294Smckusick 230*24294Smckusick /* make sure we clean up /tmp in case of disaster */ 231*24294Smckusick set_signals(); 232*24294Smckusick 233*24294Smckusick for ( 234*24294Smckusick open_patch_file(filearg[1]); 235*24294Smckusick there_is_another_patch(); 236*24294Smckusick reinitialize_almost_everything() 237*24294Smckusick ) { /* for each patch in patch file */ 238*24294Smckusick 239*24294Smckusick if (outname == Nullch) 240*24294Smckusick outname = savestr(filearg[0]); 241*24294Smckusick 242*24294Smckusick /* initialize the patched file */ 243*24294Smckusick init_output(TMPOUTNAME); 244*24294Smckusick 245*24294Smckusick /* for ed script just up and do it and exit */ 246*24294Smckusick if (diff_type == ED_DIFF) { 247*24294Smckusick do_ed_script(); 248*24294Smckusick continue; 249*24294Smckusick } 250*24294Smckusick 251*24294Smckusick /* initialize reject file */ 252*24294Smckusick init_reject(TMPREJNAME); 253*24294Smckusick 254*24294Smckusick /* find out where all the lines are */ 255*24294Smckusick scan_input(filearg[0]); 256*24294Smckusick 257*24294Smckusick /* from here on, open no standard i/o files, because malloc */ 258*24294Smckusick /* might misfire */ 259*24294Smckusick 260*24294Smckusick /* apply each hunk of patch */ 261*24294Smckusick hunk = 0; 262*24294Smckusick failed = 0; 263*24294Smckusick while (another_hunk()) { 264*24294Smckusick hunk++; 265*24294Smckusick where = locate_hunk(); 266*24294Smckusick if (hunk == 1 && where == Null(LINENUM)) { 267*24294Smckusick /* dwim for reversed patch? */ 268*24294Smckusick pch_swap(); 269*24294Smckusick reverse = !reverse; 270*24294Smckusick where = locate_hunk(); /* try again */ 271*24294Smckusick if (where == Null(LINENUM)) { 272*24294Smckusick pch_swap(); /* no, put it back to normal */ 273*24294Smckusick reverse = !reverse; 274*24294Smckusick } 275*24294Smckusick else { 276*24294Smckusick say("%seversed (or previously applied) patch detected! %s -R.\n", 277*24294Smckusick reverse ? "R" : "Unr", 278*24294Smckusick reverse ? "Assuming" : "Ignoring"); 279*24294Smckusick } 280*24294Smckusick } 281*24294Smckusick if (where == Null(LINENUM)) { 282*24294Smckusick abort_hunk(); 283*24294Smckusick failed++; 284*24294Smckusick if (verbose) 285*24294Smckusick say("Hunk #%d failed.\n",hunk); 286*24294Smckusick } 287*24294Smckusick else { 288*24294Smckusick apply_hunk(where); 289*24294Smckusick if (verbose) 290*24294Smckusick if (last_offset) 291*24294Smckusick say("Hunk #%d succeeded (offset %d line%s).\n", 292*24294Smckusick hunk,last_offset,last_offset==1?"":"s"); 293*24294Smckusick else 294*24294Smckusick say("Hunk #%d succeeded.\n", hunk); 295*24294Smckusick } 296*24294Smckusick } 297*24294Smckusick 298*24294Smckusick assert(hunk); 299*24294Smckusick 300*24294Smckusick /* finish spewing out the new file */ 301*24294Smckusick spew_output(); 302*24294Smckusick 303*24294Smckusick /* and put the output where desired */ 304*24294Smckusick ignore_signals(); 305*24294Smckusick move_file(TMPOUTNAME,outname); 306*24294Smckusick Fclose(rejfp); 307*24294Smckusick rejfp = Nullfp; 308*24294Smckusick if (failed) { 309*24294Smckusick if (!*rejname) { 310*24294Smckusick Strcpy(rejname, outname); 311*24294Smckusick Strcat(rejname, ".rej"); 312*24294Smckusick } 313*24294Smckusick say("%d out of %d hunks failed--saving rejects to %s\n", 314*24294Smckusick failed, hunk, rejname); 315*24294Smckusick move_file(TMPREJNAME,rejname); 316*24294Smckusick } 317*24294Smckusick set_signals(); 318*24294Smckusick } 319*24294Smckusick my_exit(0); 320*24294Smckusick } 321*24294Smckusick 322*24294Smckusick reinitialize_almost_everything() 323*24294Smckusick { 324*24294Smckusick re_patch(); 325*24294Smckusick re_input(); 326*24294Smckusick 327*24294Smckusick input_lines = 0; 328*24294Smckusick last_frozen_line = 0; 329*24294Smckusick 330*24294Smckusick filec = 0; 331*24294Smckusick if (filearg[0] != Nullch) { 332*24294Smckusick free(filearg[0]); 333*24294Smckusick filearg[0] = Nullch; 334*24294Smckusick } 335*24294Smckusick 336*24294Smckusick if (outname != Nullch) { 337*24294Smckusick free(outname); 338*24294Smckusick outname = Nullch; 339*24294Smckusick } 340*24294Smckusick 341*24294Smckusick last_offset = 0; 342*24294Smckusick 343*24294Smckusick diff_type = 0; 344*24294Smckusick 345*24294Smckusick if (revision != Nullch) { 346*24294Smckusick free(revision); 347*24294Smckusick revision = Nullch; 348*24294Smckusick } 349*24294Smckusick 350*24294Smckusick reverse = FALSE; 351*24294Smckusick 352*24294Smckusick get_some_switches(); 353*24294Smckusick 354*24294Smckusick if (filec >= 2) 355*24294Smckusick fatal("You may not change to a different patch file.\n"); 356*24294Smckusick } 357*24294Smckusick 358*24294Smckusick get_some_switches() 359*24294Smckusick { 360*24294Smckusick register char *s; 361*24294Smckusick 362*24294Smckusick rejname[0] = '\0'; 363*24294Smckusick if (!Argc) 364*24294Smckusick return; 365*24294Smckusick for (Argc--,Argv++; Argc; Argc--,Argv++) { 366*24294Smckusick s = Argv[0]; 367*24294Smckusick if (strEQ(s,"+")) { 368*24294Smckusick return; /* + will be skipped by for loop */ 369*24294Smckusick } 370*24294Smckusick if (*s != '-' || !s[1]) { 371*24294Smckusick if (filec == MAXFILEC) 372*24294Smckusick fatal("Too many file arguments.\n"); 373*24294Smckusick filearg[filec++] = savestr(s); 374*24294Smckusick } 375*24294Smckusick else { 376*24294Smckusick switch (*++s) { 377*24294Smckusick case 'b': 378*24294Smckusick origext = savestr(Argv[1]); 379*24294Smckusick Argc--,Argv++; 380*24294Smckusick break; 381*24294Smckusick case 'c': 382*24294Smckusick diff_type = CONTEXT_DIFF; 383*24294Smckusick break; 384*24294Smckusick case 'd': 385*24294Smckusick if (chdir(Argv[1]) < 0) 386*24294Smckusick fatal("Can't cd to %s.\n",Argv[1]); 387*24294Smckusick Argc--,Argv++; 388*24294Smckusick break; 389*24294Smckusick case 'D': 390*24294Smckusick do_defines++; 391*24294Smckusick Sprintf(if_defined, "#ifdef %s\n", Argv[1]); 392*24294Smckusick Sprintf(not_defined, "#ifndef %s\n", Argv[1]); 393*24294Smckusick Sprintf(end_defined, "#endif %s\n", Argv[1]); 394*24294Smckusick Argc--,Argv++; 395*24294Smckusick break; 396*24294Smckusick case 'e': 397*24294Smckusick diff_type = ED_DIFF; 398*24294Smckusick break; 399*24294Smckusick case 'l': 400*24294Smckusick canonicalize = TRUE; 401*24294Smckusick break; 402*24294Smckusick case 'n': 403*24294Smckusick diff_type = NORMAL_DIFF; 404*24294Smckusick break; 405*24294Smckusick case 'o': 406*24294Smckusick outname = savestr(Argv[1]); 407*24294Smckusick Argc--,Argv++; 408*24294Smckusick break; 409*24294Smckusick case 'p': 410*24294Smckusick usepath = TRUE; /* do not strip path names */ 411*24294Smckusick break; 412*24294Smckusick case 'r': 413*24294Smckusick Strcpy(rejname,Argv[1]); 414*24294Smckusick Argc--,Argv++; 415*24294Smckusick break; 416*24294Smckusick case 'R': 417*24294Smckusick reverse = TRUE; 418*24294Smckusick break; 419*24294Smckusick case 's': 420*24294Smckusick verbose = FALSE; 421*24294Smckusick break; 422*24294Smckusick #ifdef DEBUGGING 423*24294Smckusick case 'x': 424*24294Smckusick debug = atoi(s+1); 425*24294Smckusick break; 426*24294Smckusick #endif 427*24294Smckusick default: 428*24294Smckusick fatal("Unrecognized switch: %s\n",Argv[0]); 429*24294Smckusick } 430*24294Smckusick } 431*24294Smckusick } 432*24294Smckusick } 433*24294Smckusick 434*24294Smckusick LINENUM 435*24294Smckusick locate_hunk() 436*24294Smckusick { 437*24294Smckusick register LINENUM first_guess = pch_first() + last_offset; 438*24294Smckusick register LINENUM offset; 439*24294Smckusick LINENUM pat_lines = pch_ptrn_lines(); 440*24294Smckusick register LINENUM max_pos_offset = input_lines - first_guess 441*24294Smckusick - pat_lines + 1; 442*24294Smckusick register LINENUM max_neg_offset = first_guess - last_frozen_line - 1 443*24294Smckusick - pch_context(); 444*24294Smckusick 445*24294Smckusick if (!pat_lines) /* null range matches always */ 446*24294Smckusick return first_guess; 447*24294Smckusick if (max_neg_offset >= first_guess) /* do not try lines < 0 */ 448*24294Smckusick max_neg_offset = first_guess - 1; 449*24294Smckusick if (first_guess <= input_lines && patch_match(first_guess,(LINENUM)0)) 450*24294Smckusick return first_guess; 451*24294Smckusick for (offset = 1; ; offset++) { 452*24294Smckusick bool check_after = (offset <= max_pos_offset); 453*24294Smckusick bool check_before = (offset <= max_pos_offset); 454*24294Smckusick 455*24294Smckusick if (check_after && patch_match(first_guess,offset)) { 456*24294Smckusick #ifdef DEBUGGING 457*24294Smckusick if (debug & 1) 458*24294Smckusick printf("Offset changing from %d to %d\n",last_offset,offset); 459*24294Smckusick #endif 460*24294Smckusick last_offset = offset; 461*24294Smckusick return first_guess+offset; 462*24294Smckusick } 463*24294Smckusick else if (check_before && patch_match(first_guess,-offset)) { 464*24294Smckusick #ifdef DEBUGGING 465*24294Smckusick if (debug & 1) 466*24294Smckusick printf("Offset changing from %d to %d\n",last_offset,-offset); 467*24294Smckusick #endif 468*24294Smckusick last_offset = -offset; 469*24294Smckusick return first_guess-offset; 470*24294Smckusick } 471*24294Smckusick else if (!check_before && !check_after) 472*24294Smckusick return Null(LINENUM); 473*24294Smckusick } 474*24294Smckusick } 475*24294Smckusick 476*24294Smckusick /* we did not find the pattern, dump out the hunk so they can handle it */ 477*24294Smckusick 478*24294Smckusick abort_hunk() 479*24294Smckusick { 480*24294Smckusick register LINENUM i; 481*24294Smckusick register LINENUM pat_end = pch_end(); 482*24294Smckusick /* add in last_offset to guess the same as the previous successful hunk */ 483*24294Smckusick int oldfirst = pch_first() + last_offset; 484*24294Smckusick int newfirst = pch_newfirst() + last_offset; 485*24294Smckusick int oldlast = oldfirst + pch_ptrn_lines() - 1; 486*24294Smckusick int newlast = newfirst + pch_repl_lines() - 1; 487*24294Smckusick 488*24294Smckusick fprintf(rejfp,"***************\n"); 489*24294Smckusick for (i=0; i<=pat_end; i++) { 490*24294Smckusick switch (pch_char(i)) { 491*24294Smckusick case '*': 492*24294Smckusick fprintf(rejfp,"*** %d,%d\n", oldfirst, oldlast); 493*24294Smckusick break; 494*24294Smckusick case '=': 495*24294Smckusick fprintf(rejfp,"--- %d,%d -----\n", newfirst, newlast); 496*24294Smckusick break; 497*24294Smckusick case '\n': 498*24294Smckusick fprintf(rejfp,"%s", pfetch(i)); 499*24294Smckusick break; 500*24294Smckusick case ' ': case '-': case '+': case '!': 501*24294Smckusick fprintf(rejfp,"%c %s", pch_char(i), pfetch(i)); 502*24294Smckusick break; 503*24294Smckusick default: 504*24294Smckusick say("Fatal internal error in abort_hunk().\n"); 505*24294Smckusick abort(); 506*24294Smckusick } 507*24294Smckusick } 508*24294Smckusick } 509*24294Smckusick 510*24294Smckusick /* we found where to apply it (we hope), so do it */ 511*24294Smckusick 512*24294Smckusick apply_hunk(where) 513*24294Smckusick LINENUM where; 514*24294Smckusick { 515*24294Smckusick register LINENUM old = 1; 516*24294Smckusick register LINENUM lastline = pch_ptrn_lines(); 517*24294Smckusick register LINENUM new = lastline+1; 518*24294Smckusick register int def_state = 0; /* -1 = ifndef, 1 = ifdef */ 519*24294Smckusick 520*24294Smckusick where--; 521*24294Smckusick while (pch_char(new) == '=' || pch_char(new) == '\n') 522*24294Smckusick new++; 523*24294Smckusick 524*24294Smckusick while (old <= lastline) { 525*24294Smckusick if (pch_char(old) == '-') { 526*24294Smckusick copy_till(where + old - 1); 527*24294Smckusick if (do_defines) { 528*24294Smckusick if (def_state == 0) { 529*24294Smckusick fputs(not_defined, ofp); 530*24294Smckusick def_state = -1; 531*24294Smckusick } else 532*24294Smckusick if (def_state == 1) { 533*24294Smckusick fputs(else_defined, ofp); 534*24294Smckusick def_state = 2; 535*24294Smckusick } 536*24294Smckusick fputs(pfetch(old), ofp); 537*24294Smckusick } 538*24294Smckusick last_frozen_line++; 539*24294Smckusick old++; 540*24294Smckusick } 541*24294Smckusick else if (pch_char(new) == '+') { 542*24294Smckusick copy_till(where + old - 1); 543*24294Smckusick if (do_defines) { 544*24294Smckusick if (def_state == -1) { 545*24294Smckusick fputs(else_defined, ofp); 546*24294Smckusick def_state = 2; 547*24294Smckusick } else 548*24294Smckusick if (def_state == 0) { 549*24294Smckusick fputs(if_defined, ofp); 550*24294Smckusick def_state = 1; 551*24294Smckusick } 552*24294Smckusick } 553*24294Smckusick fputs(pfetch(new),ofp); 554*24294Smckusick new++; 555*24294Smckusick } 556*24294Smckusick else { 557*24294Smckusick if (pch_char(new) != pch_char(old)) { 558*24294Smckusick say("Out-of-sync patch, lines %d,%d\n", 559*24294Smckusick pch_hunk_beg() + old - 1, 560*24294Smckusick pch_hunk_beg() + new - 1); 561*24294Smckusick #ifdef DEBUGGING 562*24294Smckusick printf("oldchar = '%c', newchar = '%c'\n", 563*24294Smckusick pch_char(old), pch_char(new)); 564*24294Smckusick #endif 565*24294Smckusick my_exit(1); 566*24294Smckusick } 567*24294Smckusick if (pch_char(new) == '!') { 568*24294Smckusick copy_till(where + old - 1); 569*24294Smckusick if (do_defines) { 570*24294Smckusick fputs(not_defined,ofp); 571*24294Smckusick def_state = -1; 572*24294Smckusick } 573*24294Smckusick while (pch_char(old) == '!') { 574*24294Smckusick if (do_defines) { 575*24294Smckusick fputs(pfetch(old),ofp); 576*24294Smckusick } 577*24294Smckusick last_frozen_line++; 578*24294Smckusick old++; 579*24294Smckusick } 580*24294Smckusick if (do_defines) { 581*24294Smckusick fputs(else_defined, ofp); 582*24294Smckusick def_state = 2; 583*24294Smckusick } 584*24294Smckusick while (pch_char(new) == '!') { 585*24294Smckusick fputs(pfetch(new),ofp); 586*24294Smckusick new++; 587*24294Smckusick } 588*24294Smckusick if (do_defines) { 589*24294Smckusick fputs(end_defined, ofp); 590*24294Smckusick def_state = 0; 591*24294Smckusick } 592*24294Smckusick } 593*24294Smckusick else { 594*24294Smckusick assert(pch_char(new) == ' '); 595*24294Smckusick old++; 596*24294Smckusick new++; 597*24294Smckusick } 598*24294Smckusick } 599*24294Smckusick } 600*24294Smckusick if (new <= pch_end() && pch_char(new) == '+') { 601*24294Smckusick copy_till(where + old - 1); 602*24294Smckusick if (do_defines) { 603*24294Smckusick if (def_state == 0) { 604*24294Smckusick fputs(if_defined, ofp); 605*24294Smckusick def_state = 1; 606*24294Smckusick } else 607*24294Smckusick if (def_state == -1) { 608*24294Smckusick fputs(else_defined, ofp); 609*24294Smckusick def_state = 2; 610*24294Smckusick } 611*24294Smckusick } 612*24294Smckusick while (new <= pch_end() && pch_char(new) == '+') { 613*24294Smckusick fputs(pfetch(new),ofp); 614*24294Smckusick new++; 615*24294Smckusick } 616*24294Smckusick } 617*24294Smckusick if (do_defines && def_state) { 618*24294Smckusick fputs(end_defined, ofp); 619*24294Smckusick } 620*24294Smckusick } 621*24294Smckusick 622*24294Smckusick do_ed_script() 623*24294Smckusick { 624*24294Smckusick FILE *pipefp, *popen(); 625*24294Smckusick bool this_line_is_command = FALSE; 626*24294Smckusick register char *t; 627*24294Smckusick long beginning_of_this_line; 628*24294Smckusick 629*24294Smckusick Unlink(TMPOUTNAME); 630*24294Smckusick copy_file(filearg[0],TMPOUTNAME); 631*24294Smckusick if (verbose) 632*24294Smckusick Sprintf(buf,"/bin/ed %s",TMPOUTNAME); 633*24294Smckusick else 634*24294Smckusick Sprintf(buf,"/bin/ed - %s",TMPOUTNAME); 635*24294Smckusick pipefp = popen(buf,"w"); 636*24294Smckusick for (;;) { 637*24294Smckusick beginning_of_this_line = ftell(pfp); 638*24294Smckusick if (pgets(buf,sizeof buf,pfp) == Nullch) { 639*24294Smckusick next_intuit_at(beginning_of_this_line); 640*24294Smckusick break; 641*24294Smckusick } 642*24294Smckusick for (t=buf; isdigit(*t) || *t == ','; t++) ; 643*24294Smckusick this_line_is_command = (isdigit(*buf) && 644*24294Smckusick (*t == 'd' || *t == 'c' || *t == 'a') ); 645*24294Smckusick if (this_line_is_command) { 646*24294Smckusick fputs(buf,pipefp); 647*24294Smckusick if (*t != 'd') { 648*24294Smckusick while (pgets(buf,sizeof buf,pfp) != Nullch) { 649*24294Smckusick fputs(buf,pipefp); 650*24294Smckusick if (strEQ(buf,".\n")) 651*24294Smckusick break; 652*24294Smckusick } 653*24294Smckusick } 654*24294Smckusick } 655*24294Smckusick else { 656*24294Smckusick next_intuit_at(beginning_of_this_line); 657*24294Smckusick break; 658*24294Smckusick } 659*24294Smckusick } 660*24294Smckusick fprintf(pipefp,"w\n"); 661*24294Smckusick fprintf(pipefp,"q\n"); 662*24294Smckusick Fflush(pipefp); 663*24294Smckusick Pclose(pipefp); 664*24294Smckusick ignore_signals(); 665*24294Smckusick move_file(TMPOUTNAME,outname); 666*24294Smckusick set_signals(); 667*24294Smckusick } 668*24294Smckusick 669*24294Smckusick init_output(name) 670*24294Smckusick char *name; 671*24294Smckusick { 672*24294Smckusick ofp = fopen(name,"w"); 673*24294Smckusick if (ofp == Nullfp) 674*24294Smckusick fatal("patch: can't create %s.\n",name); 675*24294Smckusick } 676*24294Smckusick 677*24294Smckusick init_reject(name) 678*24294Smckusick char *name; 679*24294Smckusick { 680*24294Smckusick rejfp = fopen(name,"w"); 681*24294Smckusick if (rejfp == Nullfp) 682*24294Smckusick fatal("patch: can't create %s.\n",name); 683*24294Smckusick } 684*24294Smckusick 685*24294Smckusick move_file(from,to) 686*24294Smckusick char *from, *to; 687*24294Smckusick { 688*24294Smckusick char bakname[512]; 689*24294Smckusick register char *s; 690*24294Smckusick int fromfd; 691*24294Smckusick register int i; 692*24294Smckusick 693*24294Smckusick /* to stdout? */ 694*24294Smckusick 695*24294Smckusick if (strEQ(to,"-")) { 696*24294Smckusick #ifdef DEBUGGING 697*24294Smckusick if (debug & 4) 698*24294Smckusick say("Moving %s to stdout.\n",from); 699*24294Smckusick #endif 700*24294Smckusick fromfd = open(from,0); 701*24294Smckusick if (fromfd < 0) 702*24294Smckusick fatal("patch: internal error, can't reopen %s\n",from); 703*24294Smckusick while ((i=read(fromfd,buf,sizeof buf)) > 0) 704*24294Smckusick if (write(1,buf,i) != 1) 705*24294Smckusick fatal("patch: write failed\n"); 706*24294Smckusick Close(fromfd); 707*24294Smckusick return; 708*24294Smckusick } 709*24294Smckusick 710*24294Smckusick Strcpy(bakname,to); 711*24294Smckusick Strcat(bakname,origext?origext:ORIGEXT); 712*24294Smckusick if (stat(to,&filestat) >= 0) { /* output file exists */ 713*24294Smckusick dev_t to_device = filestat.st_dev; 714*24294Smckusick ino_t to_inode = filestat.st_ino; 715*24294Smckusick char *simplename = bakname; 716*24294Smckusick 717*24294Smckusick for (s=bakname; *s; s++) { 718*24294Smckusick if (*s == '/') 719*24294Smckusick simplename = s+1; 720*24294Smckusick } 721*24294Smckusick /* find a backup name that is not the same file */ 722*24294Smckusick while (stat(bakname,&filestat) >= 0 && 723*24294Smckusick to_device == filestat.st_dev && to_inode == filestat.st_ino) { 724*24294Smckusick for (s=simplename; *s && !islower(*s); s++) ; 725*24294Smckusick if (*s) 726*24294Smckusick *s = toupper(*s); 727*24294Smckusick else 728*24294Smckusick Strcpy(simplename, simplename+1); 729*24294Smckusick } 730*24294Smckusick while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */ 731*24294Smckusick #ifdef DEBUGGING 732*24294Smckusick if (debug & 4) 733*24294Smckusick say("Moving %s to %s.\n",to,bakname); 734*24294Smckusick #endif 735*24294Smckusick if (link(to,bakname) < 0) { 736*24294Smckusick say("patch: can't backup %s, output is in %s\n", 737*24294Smckusick to,from); 738*24294Smckusick return; 739*24294Smckusick } 740*24294Smckusick while (unlink(to) >= 0) ; 741*24294Smckusick } 742*24294Smckusick #ifdef DEBUGGING 743*24294Smckusick if (debug & 4) 744*24294Smckusick say("Moving %s to %s.\n",from,to); 745*24294Smckusick #endif 746*24294Smckusick if (link(from,to) < 0) { /* different file system? */ 747*24294Smckusick int tofd; 748*24294Smckusick 749*24294Smckusick tofd = creat(to,0666); 750*24294Smckusick if (tofd < 0) { 751*24294Smckusick say("patch: can't create %s, output is in %s.\n", 752*24294Smckusick to, from); 753*24294Smckusick return; 754*24294Smckusick } 755*24294Smckusick fromfd = open(from,0); 756*24294Smckusick if (fromfd < 0) 757*24294Smckusick fatal("patch: internal error, can't reopen %s\n",from); 758*24294Smckusick while ((i=read(fromfd,buf,sizeof buf)) > 0) 759*24294Smckusick if (write(tofd,buf,i) != i) 760*24294Smckusick fatal("patch: write failed\n"); 761*24294Smckusick Close(fromfd); 762*24294Smckusick Close(tofd); 763*24294Smckusick } 764*24294Smckusick Unlink(from); 765*24294Smckusick } 766*24294Smckusick 767*24294Smckusick copy_file(from,to) 768*24294Smckusick char *from, *to; 769*24294Smckusick { 770*24294Smckusick int tofd; 771*24294Smckusick int fromfd; 772*24294Smckusick register int i; 773*24294Smckusick 774*24294Smckusick tofd = creat(to,0666); 775*24294Smckusick if (tofd < 0) 776*24294Smckusick fatal("patch: can't create %s.\n", to); 777*24294Smckusick fromfd = open(from,0); 778*24294Smckusick if (fromfd < 0) 779*24294Smckusick fatal("patch: internal error, can't reopen %s\n",from); 780*24294Smckusick while ((i=read(fromfd,buf,sizeof buf)) > 0) 781*24294Smckusick if (write(tofd,buf,i) != i) 782*24294Smckusick fatal("patch: write (%s) failed\n", to); 783*24294Smckusick Close(fromfd); 784*24294Smckusick Close(tofd); 785*24294Smckusick } 786*24294Smckusick 787*24294Smckusick copy_till(lastline) 788*24294Smckusick register LINENUM lastline; 789*24294Smckusick { 790*24294Smckusick if (last_frozen_line > lastline) 791*24294Smckusick say("patch: misordered hunks! output will be garbled.\n"); 792*24294Smckusick while (last_frozen_line < lastline) { 793*24294Smckusick dump_line(++last_frozen_line); 794*24294Smckusick } 795*24294Smckusick } 796*24294Smckusick 797*24294Smckusick spew_output() 798*24294Smckusick { 799*24294Smckusick copy_till(input_lines); /* dump remainder of file */ 800*24294Smckusick Fclose(ofp); 801*24294Smckusick ofp = Nullfp; 802*24294Smckusick } 803*24294Smckusick 804*24294Smckusick dump_line(line) 805*24294Smckusick LINENUM line; 806*24294Smckusick { 807*24294Smckusick register char *s; 808*24294Smckusick 809*24294Smckusick for (s=ifetch(line,0); putc(*s,ofp) != '\n'; s++) ; 810*24294Smckusick } 811*24294Smckusick 812*24294Smckusick /* does the patch pattern match at line base+offset? */ 813*24294Smckusick 814*24294Smckusick bool 815*24294Smckusick patch_match(base,offset) 816*24294Smckusick LINENUM base; 817*24294Smckusick LINENUM offset; 818*24294Smckusick { 819*24294Smckusick register LINENUM pline; 820*24294Smckusick register LINENUM iline; 821*24294Smckusick register LINENUM pat_lines = pch_ptrn_lines(); 822*24294Smckusick 823*24294Smckusick for (pline = 1, iline=base+offset; pline <= pat_lines; pline++,iline++) { 824*24294Smckusick if (canonicalize) { 825*24294Smckusick if (!similar(ifetch(iline,(offset >= 0)), 826*24294Smckusick pfetch(pline), 827*24294Smckusick pch_line_len(pline) )) 828*24294Smckusick return FALSE; 829*24294Smckusick } 830*24294Smckusick else if (strnNE(ifetch(iline,(offset >= 0)), 831*24294Smckusick pfetch(pline), 832*24294Smckusick pch_line_len(pline) )) 833*24294Smckusick return FALSE; 834*24294Smckusick } 835*24294Smckusick return TRUE; 836*24294Smckusick } 837*24294Smckusick 838*24294Smckusick /* match two lines with canonicalized white space */ 839*24294Smckusick 840*24294Smckusick bool 841*24294Smckusick similar(a,b,len) 842*24294Smckusick register char *a, *b; 843*24294Smckusick register int len; 844*24294Smckusick { 845*24294Smckusick while (len) { 846*24294Smckusick if (isspace(*b)) { /* whitespace (or \n) to match? */ 847*24294Smckusick if (!isspace(*a)) /* no corresponding whitespace? */ 848*24294Smckusick return FALSE; 849*24294Smckusick while (len && isspace(*b) && *b != '\n') 850*24294Smckusick b++,len--; /* skip pattern whitespace */ 851*24294Smckusick while (isspace(*a) && *a != '\n') 852*24294Smckusick a++; /* skip target whitespace */ 853*24294Smckusick if (*a == '\n' || *b == '\n') 854*24294Smckusick return (*a == *b); /* should end in sync */ 855*24294Smckusick } 856*24294Smckusick else if (*a++ != *b++) /* match non-whitespace chars */ 857*24294Smckusick return FALSE; 858*24294Smckusick else 859*24294Smckusick len--; /* probably not necessary */ 860*24294Smckusick } 861*24294Smckusick return TRUE; /* actually, this is not reached */ 862*24294Smckusick /* since there is always a \n */ 863*24294Smckusick } 864*24294Smckusick 865*24294Smckusick /* input file with indexable lines abstract type */ 866*24294Smckusick 867*24294Smckusick bool using_plan_a = TRUE; 868*24294Smckusick static long i_size; /* size of the input file */ 869*24294Smckusick static char *i_womp; /* plan a buffer for entire file */ 870*24294Smckusick static char **i_ptr; /* pointers to lines in i_womp */ 871*24294Smckusick 872*24294Smckusick static int tifd = -1; /* plan b virtual string array */ 873*24294Smckusick static char *tibuf[2]; /* plan b buffers */ 874*24294Smckusick static LINENUM tiline[2] = {-1,-1}; /* 1st line in each buffer */ 875*24294Smckusick static LINENUM lines_per_buf; /* how many lines per buffer */ 876*24294Smckusick static int tireclen; /* length of records in tmp file */ 877*24294Smckusick 878*24294Smckusick re_input() 879*24294Smckusick { 880*24294Smckusick if (using_plan_a) { 881*24294Smckusick i_size = 0; 882*24294Smckusick /*NOSTRICT*/ 883*24294Smckusick if (i_ptr != Null(char**)) 884*24294Smckusick free((char *)i_ptr); 885*24294Smckusick if (i_womp != Nullch) 886*24294Smckusick free(i_womp); 887*24294Smckusick i_womp = Nullch; 888*24294Smckusick i_ptr = Null(char **); 889*24294Smckusick } 890*24294Smckusick else { 891*24294Smckusick using_plan_a = TRUE; /* maybe the next one is smaller */ 892*24294Smckusick Close(tifd); 893*24294Smckusick tifd = -1; 894*24294Smckusick free(tibuf[0]); 895*24294Smckusick free(tibuf[1]); 896*24294Smckusick tibuf[0] = tibuf[1] = Nullch; 897*24294Smckusick tiline[0] = tiline[1] = -1; 898*24294Smckusick tireclen = 0; 899*24294Smckusick } 900*24294Smckusick } 901*24294Smckusick 902*24294Smckusick scan_input(filename) 903*24294Smckusick char *filename; 904*24294Smckusick { 905*24294Smckusick bool plan_a(); 906*24294Smckusick 907*24294Smckusick if (!plan_a(filename)) 908*24294Smckusick plan_b(filename); 909*24294Smckusick } 910*24294Smckusick 911*24294Smckusick /* try keeping everything in memory */ 912*24294Smckusick 913*24294Smckusick bool 914*24294Smckusick plan_a(filename) 915*24294Smckusick char *filename; 916*24294Smckusick { 917*24294Smckusick int ifd; 918*24294Smckusick register char *s; 919*24294Smckusick register LINENUM iline; 920*24294Smckusick 921*24294Smckusick if (stat(filename,&filestat) < 0) { 922*24294Smckusick Sprintf(buf,"RCS/%s%s",filename,RCSSUFFIX); 923*24294Smckusick if (stat(buf,&filestat) >= 0 || stat(buf+4,&filestat) >= 0) { 924*24294Smckusick Sprintf(buf,CHECKOUT,filename); 925*24294Smckusick if (verbose) 926*24294Smckusick say("Can't find %s--attempting to check it out from RCS.\n", 927*24294Smckusick filename); 928*24294Smckusick if (system(buf) || stat(filename,&filestat)) 929*24294Smckusick fatal("Can't check out %s.\n",filename); 930*24294Smckusick } 931*24294Smckusick else { 932*24294Smckusick Sprintf(buf,"SCCS/%s%s",SCCSPREFIX,filename); 933*24294Smckusick if (stat(buf,&filestat) >= 0 || stat(buf+5,&filestat) >= 0) { 934*24294Smckusick Sprintf(buf,GET,filename); 935*24294Smckusick if (verbose) 936*24294Smckusick say("Can't find %s--attempting to get it from SCCS.\n", 937*24294Smckusick filename); 938*24294Smckusick if (system(buf) || stat(filename,&filestat)) 939*24294Smckusick fatal("Can't get %s.\n",filename); 940*24294Smckusick } 941*24294Smckusick else 942*24294Smckusick fatal("Can't find %s.\n",filename); 943*24294Smckusick } 944*24294Smckusick } 945*24294Smckusick if ((filestat.st_mode & S_IFMT) & ~S_IFREG) 946*24294Smckusick fatal("%s is not a normal file--can't patch.\n",filename); 947*24294Smckusick i_size = filestat.st_size; 948*24294Smckusick /*NOSTRICT*/ 949*24294Smckusick i_womp = malloc((MEM)(i_size+2)); 950*24294Smckusick if (i_womp == Nullch) 951*24294Smckusick return FALSE; 952*24294Smckusick if ((ifd = open(filename,0)) < 0) 953*24294Smckusick fatal("Can't open file %s\n",filename); 954*24294Smckusick /*NOSTRICT*/ 955*24294Smckusick if (read(ifd,i_womp,(int)i_size) != i_size) { 956*24294Smckusick Close(ifd); 957*24294Smckusick free(i_womp); 958*24294Smckusick return FALSE; 959*24294Smckusick } 960*24294Smckusick Close(ifd); 961*24294Smckusick if (i_womp[i_size-1] != '\n') 962*24294Smckusick i_womp[i_size++] = '\n'; 963*24294Smckusick i_womp[i_size] = '\0'; 964*24294Smckusick 965*24294Smckusick /* count the lines in the buffer so we know how many pointers we need */ 966*24294Smckusick 967*24294Smckusick iline = 0; 968*24294Smckusick for (s=i_womp; *s; s++) { 969*24294Smckusick if (*s == '\n') 970*24294Smckusick iline++; 971*24294Smckusick } 972*24294Smckusick /*NOSTRICT*/ 973*24294Smckusick i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *))); 974*24294Smckusick if (i_ptr == Null(char **)) { /* shucks, it was a near thing */ 975*24294Smckusick free((char *)i_womp); 976*24294Smckusick return FALSE; 977*24294Smckusick } 978*24294Smckusick 979*24294Smckusick /* now scan the buffer and build pointer array */ 980*24294Smckusick 981*24294Smckusick iline = 1; 982*24294Smckusick i_ptr[iline] = i_womp; 983*24294Smckusick for (s=i_womp; *s; s++) { 984*24294Smckusick if (*s == '\n') 985*24294Smckusick i_ptr[++iline] = s+1; /* these are NOT null terminated */ 986*24294Smckusick } 987*24294Smckusick input_lines = iline - 1; 988*24294Smckusick 989*24294Smckusick /* now check for revision, if any */ 990*24294Smckusick 991*24294Smckusick if (revision != Nullch) { 992*24294Smckusick if (!rev_in_string(i_womp)) { 993*24294Smckusick ask("This file doesn't appear to be the %s version--patch anyway? [n] ", 994*24294Smckusick revision); 995*24294Smckusick if (*buf != 'y') 996*24294Smckusick fatal("Aborted.\n"); 997*24294Smckusick } 998*24294Smckusick else if (verbose) 999*24294Smckusick say("Good. This file appears to be the %s version.\n", 1000*24294Smckusick revision); 1001*24294Smckusick } 1002*24294Smckusick return TRUE; /* plan a will work */ 1003*24294Smckusick } 1004*24294Smckusick 1005*24294Smckusick /* keep (virtually) nothing in memory */ 1006*24294Smckusick 1007*24294Smckusick plan_b(filename) 1008*24294Smckusick char *filename; 1009*24294Smckusick { 1010*24294Smckusick FILE *ifp; 1011*24294Smckusick register int i = 0; 1012*24294Smckusick register int maxlen = 1; 1013*24294Smckusick bool found_revision = (revision == Nullch); 1014*24294Smckusick 1015*24294Smckusick using_plan_a = FALSE; 1016*24294Smckusick if ((ifp = fopen(filename,"r")) == Nullfp) 1017*24294Smckusick fatal("Can't open file %s\n",filename); 1018*24294Smckusick if ((tifd = creat(TMPINNAME,0666)) < 0) 1019*24294Smckusick fatal("Can't open file %s\n",TMPINNAME); 1020*24294Smckusick while (fgets(buf,sizeof buf, ifp) != Nullch) { 1021*24294Smckusick if (revision != Nullch && !found_revision && rev_in_string(buf)) 1022*24294Smckusick found_revision = TRUE; 1023*24294Smckusick if ((i = strlen(buf)) > maxlen) 1024*24294Smckusick maxlen = i; /* find longest line */ 1025*24294Smckusick } 1026*24294Smckusick if (revision != Nullch) { 1027*24294Smckusick if (!found_revision) { 1028*24294Smckusick ask("This file doesn't appear to be the %s version--patch anyway? [n] ", 1029*24294Smckusick revision); 1030*24294Smckusick if (*buf != 'y') 1031*24294Smckusick fatal("Aborted.\n"); 1032*24294Smckusick } 1033*24294Smckusick else if (verbose) 1034*24294Smckusick say("Good. This file appears to be the %s version.\n", 1035*24294Smckusick revision); 1036*24294Smckusick } 1037*24294Smckusick Fseek(ifp,0L,0); /* rewind file */ 1038*24294Smckusick lines_per_buf = BUFFERSIZE / maxlen; 1039*24294Smckusick tireclen = maxlen; 1040*24294Smckusick tibuf[0] = malloc((MEM)(BUFFERSIZE + 1)); 1041*24294Smckusick tibuf[1] = malloc((MEM)(BUFFERSIZE + 1)); 1042*24294Smckusick if (tibuf[1] == Nullch) 1043*24294Smckusick fatal("Can't seem to get enough memory.\n"); 1044*24294Smckusick for (i=1; ; i++) { 1045*24294Smckusick if (! (i % lines_per_buf)) /* new block */ 1046*24294Smckusick if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE) 1047*24294Smckusick fatal("patch: can't write temp file.\n"); 1048*24294Smckusick if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp) 1049*24294Smckusick == Nullch) { 1050*24294Smckusick input_lines = i - 1; 1051*24294Smckusick if (i % lines_per_buf) 1052*24294Smckusick if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE) 1053*24294Smckusick fatal("patch: can't write temp file.\n"); 1054*24294Smckusick break; 1055*24294Smckusick } 1056*24294Smckusick } 1057*24294Smckusick Fclose(ifp); 1058*24294Smckusick Close(tifd); 1059*24294Smckusick if ((tifd = open(TMPINNAME,0)) < 0) { 1060*24294Smckusick fatal("Can't reopen file %s\n",TMPINNAME); 1061*24294Smckusick } 1062*24294Smckusick } 1063*24294Smckusick 1064*24294Smckusick /* fetch a line from the input file, \n terminated, not necessarily \0 */ 1065*24294Smckusick char * 1066*24294Smckusick ifetch(line,whichbuf) 1067*24294Smckusick register LINENUM line; 1068*24294Smckusick int whichbuf; /* ignored when file in memory */ 1069*24294Smckusick { 1070*24294Smckusick if (line < 1 || line > input_lines) 1071*24294Smckusick return ""; 1072*24294Smckusick if (using_plan_a) 1073*24294Smckusick return i_ptr[line]; 1074*24294Smckusick else { 1075*24294Smckusick LINENUM offline = line % lines_per_buf; 1076*24294Smckusick LINENUM baseline = line - offline; 1077*24294Smckusick 1078*24294Smckusick if (tiline[0] == baseline) 1079*24294Smckusick whichbuf = 0; 1080*24294Smckusick else if (tiline[1] == baseline) 1081*24294Smckusick whichbuf = 1; 1082*24294Smckusick else { 1083*24294Smckusick tiline[whichbuf] = baseline; 1084*24294Smckusick Lseek(tifd,(long)baseline / lines_per_buf * BUFFERSIZE,0); 1085*24294Smckusick if (read(tifd,tibuf[whichbuf],BUFFERSIZE) < 0) 1086*24294Smckusick fatal("Error reading tmp file %s.\n",TMPINNAME); 1087*24294Smckusick } 1088*24294Smckusick return tibuf[whichbuf] + (tireclen*offline); 1089*24294Smckusick } 1090*24294Smckusick } 1091*24294Smckusick 1092*24294Smckusick /* patch abstract type */ 1093*24294Smckusick 1094*24294Smckusick static long p_filesize; /* size of the patch file */ 1095*24294Smckusick static LINENUM p_first; /* 1st line number */ 1096*24294Smckusick static LINENUM p_newfirst; /* 1st line number of replacement */ 1097*24294Smckusick static LINENUM p_ptrn_lines; /* # lines in pattern */ 1098*24294Smckusick static LINENUM p_repl_lines; /* # lines in replacement text */ 1099*24294Smckusick static LINENUM p_end = -1; /* last line in hunk */ 1100*24294Smckusick static LINENUM p_max; /* max allowed value of p_end */ 1101*24294Smckusick static LINENUM p_context = 3; /* # of context lines */ 1102*24294Smckusick static LINENUM p_input_line = 0; /* current line # from patch file */ 1103*24294Smckusick static char *p_line[MAXHUNKSIZE]; /* the text of the hunk */ 1104*24294Smckusick static char p_char[MAXHUNKSIZE]; /* +, -, and ! */ 1105*24294Smckusick static int p_len[MAXHUNKSIZE]; /* length of each line */ 1106*24294Smckusick static int p_indent; /* indent to patch */ 1107*24294Smckusick static long p_base; /* where to intuit this time */ 1108*24294Smckusick static long p_start; /* where intuit found a patch */ 1109*24294Smckusick 1110*24294Smckusick re_patch() 1111*24294Smckusick { 1112*24294Smckusick p_first = (LINENUM)0; 1113*24294Smckusick p_newfirst = (LINENUM)0; 1114*24294Smckusick p_ptrn_lines = (LINENUM)0; 1115*24294Smckusick p_repl_lines = (LINENUM)0; 1116*24294Smckusick p_end = (LINENUM)-1; 1117*24294Smckusick p_max = (LINENUM)0; 1118*24294Smckusick p_indent = 0; 1119*24294Smckusick } 1120*24294Smckusick 1121*24294Smckusick open_patch_file(filename) 1122*24294Smckusick char *filename; 1123*24294Smckusick { 1124*24294Smckusick if (filename == Nullch || !*filename || strEQ(filename,"-")) { 1125*24294Smckusick pfp = fopen(TMPPATNAME,"w"); 1126*24294Smckusick if (pfp == Nullfp) 1127*24294Smckusick fatal("patch: can't create %s.\n",TMPPATNAME); 1128*24294Smckusick while (fgets(buf,sizeof buf,stdin) != NULL) 1129*24294Smckusick fputs(buf,pfp); 1130*24294Smckusick Fclose(pfp); 1131*24294Smckusick filename = TMPPATNAME; 1132*24294Smckusick } 1133*24294Smckusick pfp = fopen(filename,"r"); 1134*24294Smckusick if (pfp == Nullfp) 1135*24294Smckusick fatal("patch file %s not found\n",filename); 1136*24294Smckusick Fstat(fileno(pfp), &filestat); 1137*24294Smckusick p_filesize = filestat.st_size; 1138*24294Smckusick next_intuit_at(0L); /* start at the beginning */ 1139*24294Smckusick } 1140*24294Smckusick 1141*24294Smckusick bool 1142*24294Smckusick there_is_another_patch() 1143*24294Smckusick { 1144*24294Smckusick bool no_input_file = (filearg[0] == Nullch); 1145*24294Smckusick 1146*24294Smckusick if (p_base != 0L && p_base >= p_filesize) { 1147*24294Smckusick if (verbose) 1148*24294Smckusick say("done\n"); 1149*24294Smckusick return FALSE; 1150*24294Smckusick } 1151*24294Smckusick if (verbose) 1152*24294Smckusick say("Hmm..."); 1153*24294Smckusick diff_type = intuit_diff_type(); 1154*24294Smckusick if (!diff_type) { 1155*24294Smckusick if (p_base != 0L) { 1156*24294Smckusick if (verbose) 1157*24294Smckusick say(" Ignoring the trailing garbage.\ndone\n"); 1158*24294Smckusick } 1159*24294Smckusick else 1160*24294Smckusick say(" I can't seem to find a patch in there anywhere.\n"); 1161*24294Smckusick return FALSE; 1162*24294Smckusick } 1163*24294Smckusick if (verbose) 1164*24294Smckusick say(" %sooks like %s to me...\n", 1165*24294Smckusick (p_base == 0L ? "L" : "The next patch l"), 1166*24294Smckusick diff_type == CONTEXT_DIFF ? "a context diff" : 1167*24294Smckusick diff_type == NORMAL_DIFF ? "a normal diff" : 1168*24294Smckusick "an ed script" ); 1169*24294Smckusick if (p_indent && verbose) 1170*24294Smckusick say("(Patch is indented %d space%s.)\n",p_indent,p_indent==1?"":"s"); 1171*24294Smckusick skip_to(p_start); 1172*24294Smckusick if (no_input_file) { 1173*24294Smckusick if (filearg[0] == Nullch) { 1174*24294Smckusick ask("File to patch: "); 1175*24294Smckusick filearg[0] = fetchname(buf); 1176*24294Smckusick } 1177*24294Smckusick else if (verbose) { 1178*24294Smckusick say("Patching file %s...\n",filearg[0]); 1179*24294Smckusick } 1180*24294Smckusick } 1181*24294Smckusick return TRUE; 1182*24294Smckusick } 1183*24294Smckusick 1184*24294Smckusick intuit_diff_type() 1185*24294Smckusick { 1186*24294Smckusick long this_line = 0; 1187*24294Smckusick long previous_line; 1188*24294Smckusick long first_command_line = -1; 1189*24294Smckusick bool last_line_was_command = FALSE; 1190*24294Smckusick bool this_line_is_command = FALSE; 1191*24294Smckusick register int indent; 1192*24294Smckusick register char *s, *t; 1193*24294Smckusick char *oldname = Nullch; 1194*24294Smckusick char *newname = Nullch; 1195*24294Smckusick bool no_filearg = (filearg[0] == Nullch); 1196*24294Smckusick 1197*24294Smckusick Fseek(pfp,p_base,0); 1198*24294Smckusick for (;;) { 1199*24294Smckusick previous_line = this_line; 1200*24294Smckusick last_line_was_command = this_line_is_command; 1201*24294Smckusick this_line = ftell(pfp); 1202*24294Smckusick indent = 0; 1203*24294Smckusick if (fgets(buf,sizeof buf,pfp) == Nullch) { 1204*24294Smckusick if (first_command_line >= 0L) { 1205*24294Smckusick /* nothing but deletes!? */ 1206*24294Smckusick p_start = first_command_line; 1207*24294Smckusick return ED_DIFF; 1208*24294Smckusick } 1209*24294Smckusick else { 1210*24294Smckusick p_start = this_line; 1211*24294Smckusick return 0; 1212*24294Smckusick } 1213*24294Smckusick } 1214*24294Smckusick for (s = buf; *s == ' ' || *s == '\t'; s++) { 1215*24294Smckusick if (*s == '\t') 1216*24294Smckusick indent += 8 - (indent % 8); 1217*24294Smckusick else 1218*24294Smckusick indent++; 1219*24294Smckusick } 1220*24294Smckusick for (t=s; isdigit(*t) || *t == ','; t++) ; 1221*24294Smckusick this_line_is_command = (isdigit(*s) && 1222*24294Smckusick (*t == 'd' || *t == 'c' || *t == 'a') ); 1223*24294Smckusick if (first_command_line < 0L && this_line_is_command) { 1224*24294Smckusick first_command_line = this_line; 1225*24294Smckusick p_indent = indent; /* assume this for now */ 1226*24294Smckusick } 1227*24294Smckusick if (strnEQ(s,"*** ",4)) 1228*24294Smckusick oldname = fetchname(s+4); 1229*24294Smckusick else if (strnEQ(s,"--- ",4)) { 1230*24294Smckusick newname = fetchname(s+4); 1231*24294Smckusick if (no_filearg) { 1232*24294Smckusick if (oldname && newname) { 1233*24294Smckusick if (strlen(oldname) < strlen(newname)) 1234*24294Smckusick filearg[0] = oldname; 1235*24294Smckusick else 1236*24294Smckusick filearg[0] = newname; 1237*24294Smckusick } 1238*24294Smckusick else if (oldname) 1239*24294Smckusick filearg[0] = oldname; 1240*24294Smckusick else if (newname) 1241*24294Smckusick filearg[0] = newname; 1242*24294Smckusick } 1243*24294Smckusick } 1244*24294Smckusick else if (strnEQ(s,"Index:",6)) { 1245*24294Smckusick if (no_filearg) 1246*24294Smckusick filearg[0] = fetchname(s+6); 1247*24294Smckusick /* this filearg might get limboed */ 1248*24294Smckusick } 1249*24294Smckusick else if (strnEQ(s,"Prereq:",7)) { 1250*24294Smckusick for (t=s+7; isspace(*t); t++) ; 1251*24294Smckusick revision = savestr(t); 1252*24294Smckusick for (t=revision; *t && !isspace(*t); t++) ; 1253*24294Smckusick *t = '\0'; 1254*24294Smckusick if (!*revision) { 1255*24294Smckusick free(revision); 1256*24294Smckusick revision = Nullch; 1257*24294Smckusick } 1258*24294Smckusick } 1259*24294Smckusick if ((!diff_type || diff_type == ED_DIFF) && 1260*24294Smckusick first_command_line >= 0L && 1261*24294Smckusick strEQ(s,".\n") ) { 1262*24294Smckusick p_indent = indent; 1263*24294Smckusick p_start = first_command_line; 1264*24294Smckusick return ED_DIFF; 1265*24294Smckusick } 1266*24294Smckusick if ((!diff_type || diff_type == CONTEXT_DIFF) && 1267*24294Smckusick strnEQ(s,"********",8)) { 1268*24294Smckusick p_indent = indent; 1269*24294Smckusick p_start = this_line; 1270*24294Smckusick return CONTEXT_DIFF; 1271*24294Smckusick } 1272*24294Smckusick if ((!diff_type || diff_type == NORMAL_DIFF) && 1273*24294Smckusick last_line_was_command && 1274*24294Smckusick (strnEQ(s,"< ",2) || strnEQ(s,"> ",2)) ) { 1275*24294Smckusick p_start = previous_line; 1276*24294Smckusick p_indent = indent; 1277*24294Smckusick return NORMAL_DIFF; 1278*24294Smckusick } 1279*24294Smckusick } 1280*24294Smckusick } 1281*24294Smckusick 1282*24294Smckusick char * 1283*24294Smckusick fetchname(at) 1284*24294Smckusick char *at; 1285*24294Smckusick { 1286*24294Smckusick char *s = savestr(at); 1287*24294Smckusick char *name; 1288*24294Smckusick register char *t; 1289*24294Smckusick char tmpbuf[200]; 1290*24294Smckusick 1291*24294Smckusick for (t=s; isspace(*t); t++) ; 1292*24294Smckusick name = t; 1293*24294Smckusick for (; *t && !isspace(*t); t++) 1294*24294Smckusick if (!usepath) 1295*24294Smckusick if (*t == '/') 1296*24294Smckusick name = t+1; 1297*24294Smckusick *t = '\0'; 1298*24294Smckusick name = savestr(name); 1299*24294Smckusick Sprintf(tmpbuf,"RCS/%s",name); 1300*24294Smckusick free(s); 1301*24294Smckusick if (stat(name,&filestat) < 0) { 1302*24294Smckusick Strcat(tmpbuf,RCSSUFFIX); 1303*24294Smckusick if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+4,&filestat) < 0) { 1304*24294Smckusick Sprintf(tmpbuf,"SCCS/%s%s",SCCSPREFIX,name); 1305*24294Smckusick if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+5,&filestat) < 0) { 1306*24294Smckusick free(name); 1307*24294Smckusick name = Nullch; 1308*24294Smckusick } 1309*24294Smckusick } 1310*24294Smckusick } 1311*24294Smckusick return name; 1312*24294Smckusick } 1313*24294Smckusick 1314*24294Smckusick next_intuit_at(file_pos) 1315*24294Smckusick long file_pos; 1316*24294Smckusick { 1317*24294Smckusick p_base = file_pos; 1318*24294Smckusick } 1319*24294Smckusick 1320*24294Smckusick skip_to(file_pos) 1321*24294Smckusick long file_pos; 1322*24294Smckusick { 1323*24294Smckusick char *ret; 1324*24294Smckusick 1325*24294Smckusick assert(p_base <= file_pos); 1326*24294Smckusick if (verbose && p_base < file_pos) { 1327*24294Smckusick Fseek(pfp,p_base,0); 1328*24294Smckusick say("The text leading up to this was:\n--------------------------\n"); 1329*24294Smckusick while (ftell(pfp) < file_pos) { 1330*24294Smckusick ret = fgets(buf,sizeof buf,pfp); 1331*24294Smckusick assert(ret != Nullch); 1332*24294Smckusick say("|%s",buf); 1333*24294Smckusick } 1334*24294Smckusick say("--------------------------\n"); 1335*24294Smckusick } 1336*24294Smckusick else 1337*24294Smckusick Fseek(pfp,file_pos,0); 1338*24294Smckusick } 1339*24294Smckusick 1340*24294Smckusick bool 1341*24294Smckusick another_hunk() 1342*24294Smckusick { 1343*24294Smckusick register char *s; 1344*24294Smckusick char *ret; 1345*24294Smckusick int context = 0; 1346*24294Smckusick 1347*24294Smckusick while (p_end >= 0) { 1348*24294Smckusick free(p_line[p_end--]); 1349*24294Smckusick } 1350*24294Smckusick assert(p_end == -1); 1351*24294Smckusick 1352*24294Smckusick p_max = MAXHUNKSIZE; /* gets reduced when --- found */ 1353*24294Smckusick if (diff_type == CONTEXT_DIFF) { 1354*24294Smckusick long line_beginning = ftell(pfp); 1355*24294Smckusick LINENUM repl_beginning = 0; 1356*24294Smckusick 1357*24294Smckusick ret = pgets(buf,sizeof buf, pfp); 1358*24294Smckusick if (ret == Nullch || strnNE(buf,"********",8)) { 1359*24294Smckusick next_intuit_at(line_beginning); 1360*24294Smckusick return FALSE; 1361*24294Smckusick } 1362*24294Smckusick p_context = 100; 1363*24294Smckusick while (p_end < p_max) { 1364*24294Smckusick ret = pgets(buf,sizeof buf, pfp); 1365*24294Smckusick if (ret == Nullch) { 1366*24294Smckusick if (p_max - p_end < 4) 1367*24294Smckusick Strcpy(buf," \n"); /* assume blank lines got chopped */ 1368*24294Smckusick else 1369*24294Smckusick fatal("Unexpected end of file in patch.\n"); 1370*24294Smckusick } 1371*24294Smckusick p_input_line++; 1372*24294Smckusick if (strnEQ(buf,"********",8)) 1373*24294Smckusick fatal("Unexpected end of hunk at line %d.\n", 1374*24294Smckusick p_input_line); 1375*24294Smckusick p_char[++p_end] = *buf; 1376*24294Smckusick switch (*buf) { 1377*24294Smckusick case '*': 1378*24294Smckusick if (p_end != 0) 1379*24294Smckusick fatal("Unexpected *** at line %d: %s", p_input_line, buf); 1380*24294Smckusick context = 0; 1381*24294Smckusick p_line[p_end] = savestr(buf); 1382*24294Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 1383*24294Smckusick p_first = (LINENUM) atol(s); 1384*24294Smckusick while (isdigit(*s)) s++; 1385*24294Smckusick for (; *s && !isdigit(*s); s++) ; 1386*24294Smckusick p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; 1387*24294Smckusick break; 1388*24294Smckusick case '-': 1389*24294Smckusick if (buf[1] == '-') { 1390*24294Smckusick if (p_end != p_ptrn_lines + 1 && 1391*24294Smckusick p_end != p_ptrn_lines + 2) 1392*24294Smckusick fatal("Unexpected --- at line %d: %s", 1393*24294Smckusick p_input_line,buf); 1394*24294Smckusick repl_beginning = p_end; 1395*24294Smckusick context = 0; 1396*24294Smckusick p_line[p_end] = savestr(buf); 1397*24294Smckusick p_char[p_end] = '='; 1398*24294Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 1399*24294Smckusick p_newfirst = (LINENUM) atol(s); 1400*24294Smckusick while (isdigit(*s)) s++; 1401*24294Smckusick for (; *s && !isdigit(*s); s++) ; 1402*24294Smckusick p_max = ((LINENUM)atol(s)) - p_newfirst + 1 + p_end; 1403*24294Smckusick break; 1404*24294Smckusick } 1405*24294Smckusick /* FALL THROUGH */ 1406*24294Smckusick case '+': case '!': 1407*24294Smckusick if (context > 0) { 1408*24294Smckusick if (context < p_context) 1409*24294Smckusick p_context = context; 1410*24294Smckusick context = -100; 1411*24294Smckusick } 1412*24294Smckusick p_line[p_end] = savestr(buf+2); 1413*24294Smckusick break; 1414*24294Smckusick case '\t': case '\n': /* assume the 2 spaces got eaten */ 1415*24294Smckusick p_line[p_end] = savestr(buf); 1416*24294Smckusick if (p_end != p_ptrn_lines + 1) { 1417*24294Smckusick context++; 1418*24294Smckusick p_char[p_end] = ' '; 1419*24294Smckusick } 1420*24294Smckusick break; 1421*24294Smckusick case ' ': 1422*24294Smckusick context++; 1423*24294Smckusick p_line[p_end] = savestr(buf+2); 1424*24294Smckusick break; 1425*24294Smckusick default: 1426*24294Smckusick fatal("Malformed patch at line %d: %s",p_input_line,buf); 1427*24294Smckusick } 1428*24294Smckusick p_len[p_end] = strlen(p_line[p_end]); 1429*24294Smckusick /* for strncmp() so we do not have */ 1430*24294Smckusick /* to assume null termination */ 1431*24294Smckusick } 1432*24294Smckusick if (p_end >=0 && !p_ptrn_lines) 1433*24294Smckusick fatal("No --- found in patch at line %d\n", pch_hunk_beg()); 1434*24294Smckusick p_repl_lines = p_end - repl_beginning; 1435*24294Smckusick } 1436*24294Smckusick else { /* normal diff--fake it up */ 1437*24294Smckusick char hunk_type; 1438*24294Smckusick register int i; 1439*24294Smckusick LINENUM min, max; 1440*24294Smckusick long line_beginning = ftell(pfp); 1441*24294Smckusick 1442*24294Smckusick p_context = 0; 1443*24294Smckusick ret = pgets(buf,sizeof buf, pfp); 1444*24294Smckusick p_input_line++; 1445*24294Smckusick if (ret == Nullch || !isdigit(*buf)) { 1446*24294Smckusick next_intuit_at(line_beginning); 1447*24294Smckusick return FALSE; 1448*24294Smckusick } 1449*24294Smckusick p_first = (LINENUM)atol(buf); 1450*24294Smckusick for (s=buf; isdigit(*s); s++) ; 1451*24294Smckusick if (*s == ',') { 1452*24294Smckusick p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1; 1453*24294Smckusick while (isdigit(*s)) s++; 1454*24294Smckusick } 1455*24294Smckusick else 1456*24294Smckusick p_ptrn_lines = (*s != 'a'); 1457*24294Smckusick hunk_type = *s; 1458*24294Smckusick if (hunk_type == 'a') 1459*24294Smckusick p_first++; /* do append rather than insert */ 1460*24294Smckusick min = (LINENUM)atol(++s); 1461*24294Smckusick for (; isdigit(*s); s++) ; 1462*24294Smckusick if (*s == ',') 1463*24294Smckusick max = (LINENUM)atol(++s); 1464*24294Smckusick else 1465*24294Smckusick max = min; 1466*24294Smckusick if (hunk_type == 'd') 1467*24294Smckusick min++; 1468*24294Smckusick p_end = p_ptrn_lines + 1 + max - min + 1; 1469*24294Smckusick p_newfirst = min; 1470*24294Smckusick p_repl_lines = max - min + 1; 1471*24294Smckusick Sprintf(buf,"*** %d,%d\n", p_first, p_first + p_ptrn_lines - 1); 1472*24294Smckusick p_line[0] = savestr(buf); 1473*24294Smckusick p_char[0] = '*'; 1474*24294Smckusick for (i=1; i<=p_ptrn_lines; i++) { 1475*24294Smckusick ret = pgets(buf,sizeof buf, pfp); 1476*24294Smckusick p_input_line++; 1477*24294Smckusick if (ret == Nullch) 1478*24294Smckusick fatal("Unexpected end of file in patch at line %d.\n", 1479*24294Smckusick p_input_line); 1480*24294Smckusick if (*buf != '<') 1481*24294Smckusick fatal("< expected at line %d of patch.\n", p_input_line); 1482*24294Smckusick p_line[i] = savestr(buf+2); 1483*24294Smckusick p_len[i] = strlen(p_line[i]); 1484*24294Smckusick p_char[i] = '-'; 1485*24294Smckusick } 1486*24294Smckusick if (hunk_type == 'c') { 1487*24294Smckusick ret = pgets(buf,sizeof buf, pfp); 1488*24294Smckusick p_input_line++; 1489*24294Smckusick if (ret == Nullch) 1490*24294Smckusick fatal("Unexpected end of file in patch at line %d.\n", 1491*24294Smckusick p_input_line); 1492*24294Smckusick if (*buf != '-') 1493*24294Smckusick fatal("--- expected at line %d of patch.\n", p_input_line); 1494*24294Smckusick } 1495*24294Smckusick Sprintf(buf,"--- %d,%d\n",min,max); 1496*24294Smckusick p_line[i] = savestr(buf); 1497*24294Smckusick p_char[i] = '='; 1498*24294Smckusick for (i++; i<=p_end; i++) { 1499*24294Smckusick ret = pgets(buf,sizeof buf, pfp); 1500*24294Smckusick p_input_line++; 1501*24294Smckusick if (ret == Nullch) 1502*24294Smckusick fatal("Unexpected end of file in patch at line %d.\n", 1503*24294Smckusick p_input_line); 1504*24294Smckusick if (*buf != '>') 1505*24294Smckusick fatal("> expected at line %d of patch.\n", p_input_line); 1506*24294Smckusick p_line[i] = savestr(buf+2); 1507*24294Smckusick p_len[i] = strlen(p_line[i]); 1508*24294Smckusick p_char[i] = '+'; 1509*24294Smckusick } 1510*24294Smckusick } 1511*24294Smckusick if (reverse) /* backwards patch? */ 1512*24294Smckusick pch_swap(); 1513*24294Smckusick #ifdef DEBUGGING 1514*24294Smckusick if (debug & 2) { 1515*24294Smckusick int i; 1516*24294Smckusick char special; 1517*24294Smckusick 1518*24294Smckusick for (i=0; i <= p_end; i++) { 1519*24294Smckusick if (i == p_ptrn_lines) 1520*24294Smckusick special = '^'; 1521*24294Smckusick else 1522*24294Smckusick special = ' '; 1523*24294Smckusick printf("%3d %c %c %s",i,p_char[i],special,p_line[i]); 1524*24294Smckusick } 1525*24294Smckusick } 1526*24294Smckusick #endif 1527*24294Smckusick return TRUE; 1528*24294Smckusick } 1529*24294Smckusick 1530*24294Smckusick char * 1531*24294Smckusick pgets(bf,sz,fp) 1532*24294Smckusick char *bf; 1533*24294Smckusick int sz; 1534*24294Smckusick FILE *fp; 1535*24294Smckusick { 1536*24294Smckusick char *ret = fgets(bf,sz,fp); 1537*24294Smckusick register char *s; 1538*24294Smckusick register int indent = 0; 1539*24294Smckusick 1540*24294Smckusick if (p_indent && ret != Nullch) { 1541*24294Smckusick for (s=buf; indent < p_indent && (*s == ' ' || *s == '\t'); s++) { 1542*24294Smckusick if (*s == '\t') 1543*24294Smckusick indent += 8 - (indent % 7); 1544*24294Smckusick else 1545*24294Smckusick indent++; 1546*24294Smckusick } 1547*24294Smckusick if (buf != s) 1548*24294Smckusick Strcpy(buf,s); 1549*24294Smckusick } 1550*24294Smckusick return ret; 1551*24294Smckusick } 1552*24294Smckusick 1553*24294Smckusick pch_swap() 1554*24294Smckusick { 1555*24294Smckusick char *tp_line[MAXHUNKSIZE]; /* the text of the hunk */ 1556*24294Smckusick char tp_char[MAXHUNKSIZE]; /* +, -, and ! */ 1557*24294Smckusick int tp_len[MAXHUNKSIZE]; /* length of each line */ 1558*24294Smckusick register LINENUM i, n; 1559*24294Smckusick bool blankline = FALSE; 1560*24294Smckusick register char *s; 1561*24294Smckusick 1562*24294Smckusick i = p_first; 1563*24294Smckusick p_first = p_newfirst; 1564*24294Smckusick p_newfirst = i; 1565*24294Smckusick 1566*24294Smckusick /* make a scratch copy */ 1567*24294Smckusick 1568*24294Smckusick for (i=0; i<=p_end; i++) { 1569*24294Smckusick tp_line[i] = p_line[i]; 1570*24294Smckusick tp_char[i] = p_char[i]; 1571*24294Smckusick tp_len[i] = p_len[i]; 1572*24294Smckusick } 1573*24294Smckusick 1574*24294Smckusick /* now turn the new into the old */ 1575*24294Smckusick 1576*24294Smckusick i = p_ptrn_lines + 1; 1577*24294Smckusick if (tp_char[i] == '\n') { /* account for possible blank line */ 1578*24294Smckusick blankline = TRUE; 1579*24294Smckusick i++; 1580*24294Smckusick } 1581*24294Smckusick for (n=0; i <= p_end; i++,n++) { 1582*24294Smckusick p_line[n] = tp_line[i]; 1583*24294Smckusick p_char[n] = tp_char[i]; 1584*24294Smckusick if (p_char[n] == '+') 1585*24294Smckusick p_char[n] = '-'; 1586*24294Smckusick p_len[n] = tp_len[i]; 1587*24294Smckusick } 1588*24294Smckusick if (blankline) { 1589*24294Smckusick i = p_ptrn_lines + 1; 1590*24294Smckusick p_line[n] = tp_line[i]; 1591*24294Smckusick p_char[n] = tp_char[i]; 1592*24294Smckusick p_len[n] = tp_len[i]; 1593*24294Smckusick n++; 1594*24294Smckusick } 1595*24294Smckusick assert(p_char[0] == '='); 1596*24294Smckusick p_char[0] = '*'; 1597*24294Smckusick for (s=p_line[0]; *s; s++) 1598*24294Smckusick if (*s == '-') 1599*24294Smckusick *s = '*'; 1600*24294Smckusick 1601*24294Smckusick /* now turn the old into the new */ 1602*24294Smckusick 1603*24294Smckusick assert(tp_char[0] == '*'); 1604*24294Smckusick tp_char[0] = '='; 1605*24294Smckusick for (s=tp_line[0]; *s; s++) 1606*24294Smckusick if (*s == '*') 1607*24294Smckusick *s = '-'; 1608*24294Smckusick for (i=0; n <= p_end; i++,n++) { 1609*24294Smckusick p_line[n] = tp_line[i]; 1610*24294Smckusick p_char[n] = tp_char[i]; 1611*24294Smckusick if (p_char[n] == '-') 1612*24294Smckusick p_char[n] = '+'; 1613*24294Smckusick p_len[n] = tp_len[i]; 1614*24294Smckusick } 1615*24294Smckusick assert(i == p_ptrn_lines + 1); 1616*24294Smckusick i = p_ptrn_lines; 1617*24294Smckusick p_ptrn_lines = p_repl_lines; 1618*24294Smckusick p_repl_lines = i; 1619*24294Smckusick } 1620*24294Smckusick 1621*24294Smckusick LINENUM 1622*24294Smckusick pch_first() 1623*24294Smckusick { 1624*24294Smckusick return p_first; 1625*24294Smckusick } 1626*24294Smckusick 1627*24294Smckusick LINENUM 1628*24294Smckusick pch_ptrn_lines() 1629*24294Smckusick { 1630*24294Smckusick return p_ptrn_lines; 1631*24294Smckusick } 1632*24294Smckusick 1633*24294Smckusick LINENUM 1634*24294Smckusick pch_newfirst() 1635*24294Smckusick { 1636*24294Smckusick return p_newfirst; 1637*24294Smckusick } 1638*24294Smckusick 1639*24294Smckusick LINENUM 1640*24294Smckusick pch_repl_lines() 1641*24294Smckusick { 1642*24294Smckusick return p_repl_lines; 1643*24294Smckusick } 1644*24294Smckusick 1645*24294Smckusick LINENUM 1646*24294Smckusick pch_end() 1647*24294Smckusick { 1648*24294Smckusick return p_end; 1649*24294Smckusick } 1650*24294Smckusick 1651*24294Smckusick LINENUM 1652*24294Smckusick pch_context() 1653*24294Smckusick { 1654*24294Smckusick return p_context; 1655*24294Smckusick } 1656*24294Smckusick 1657*24294Smckusick pch_line_len(line) 1658*24294Smckusick LINENUM line; 1659*24294Smckusick { 1660*24294Smckusick return p_len[line]; 1661*24294Smckusick } 1662*24294Smckusick 1663*24294Smckusick char 1664*24294Smckusick pch_char(line) 1665*24294Smckusick LINENUM line; 1666*24294Smckusick { 1667*24294Smckusick return p_char[line]; 1668*24294Smckusick } 1669*24294Smckusick 1670*24294Smckusick char * 1671*24294Smckusick pfetch(line) 1672*24294Smckusick LINENUM line; 1673*24294Smckusick { 1674*24294Smckusick return p_line[line]; 1675*24294Smckusick } 1676*24294Smckusick 1677*24294Smckusick LINENUM 1678*24294Smckusick pch_hunk_beg() 1679*24294Smckusick { 1680*24294Smckusick return p_input_line - p_end - 1; 1681*24294Smckusick } 1682*24294Smckusick 1683*24294Smckusick char * 1684*24294Smckusick savestr(s) 1685*24294Smckusick register char *s; 1686*24294Smckusick { 1687*24294Smckusick register char *rv, 1688*24294Smckusick *t; 1689*24294Smckusick 1690*24294Smckusick t = s; 1691*24294Smckusick while (*t++); 1692*24294Smckusick rv = malloc((MEM) (t - s)); 1693*24294Smckusick if (rv == NULL) 1694*24294Smckusick fatal ("patch: out of memory (savestr)\n"); 1695*24294Smckusick t = rv; 1696*24294Smckusick while (*t++ = *s++); 1697*24294Smckusick return rv; 1698*24294Smckusick } 1699*24294Smckusick 1700*24294Smckusick my_exit(status) 1701*24294Smckusick int status; 1702*24294Smckusick { 1703*24294Smckusick Unlink(TMPINNAME); 1704*24294Smckusick Unlink(TMPOUTNAME); 1705*24294Smckusick Unlink(TMPREJNAME); 1706*24294Smckusick Unlink(TMPPATNAME); 1707*24294Smckusick exit(status); 1708*24294Smckusick } 1709*24294Smckusick 1710*24294Smckusick #ifdef lint 1711*24294Smckusick 1712*24294Smckusick /*VARARGS ARGSUSED*/ 1713*24294Smckusick say(pat) char *pat; { ; } 1714*24294Smckusick /*VARARGS ARGSUSED*/ 1715*24294Smckusick fatal(pat) char *pat; { ; } 1716*24294Smckusick /*VARARGS ARGSUSED*/ 1717*24294Smckusick ask(pat) char *pat; { ; } 1718*24294Smckusick 1719*24294Smckusick #else lint 1720*24294Smckusick 1721*24294Smckusick say(pat,arg1,arg2,arg3) 1722*24294Smckusick char *pat; 1723*24294Smckusick int arg1,arg2,arg3; 1724*24294Smckusick { 1725*24294Smckusick fprintf(stderr,pat,arg1,arg2,arg3); 1726*24294Smckusick Fflush(stderr); 1727*24294Smckusick } 1728*24294Smckusick 1729*24294Smckusick fatal(pat,arg1,arg2,arg3) 1730*24294Smckusick char *pat; 1731*24294Smckusick int arg1,arg2,arg3; 1732*24294Smckusick { 1733*24294Smckusick say(pat,arg1,arg2,arg3); 1734*24294Smckusick my_exit(1); 1735*24294Smckusick } 1736*24294Smckusick 1737*24294Smckusick ask(pat,arg1,arg2,arg3) 1738*24294Smckusick char *pat; 1739*24294Smckusick int arg1,arg2,arg3; 1740*24294Smckusick { 1741*24294Smckusick int ttyfd = open("/dev/tty",2); 1742*24294Smckusick int r; 1743*24294Smckusick 1744*24294Smckusick say(pat,arg1,arg2,arg3); 1745*24294Smckusick if (ttyfd >= 0) { 1746*24294Smckusick r = read(ttyfd, buf, sizeof buf); 1747*24294Smckusick Close(ttyfd); 1748*24294Smckusick } 1749*24294Smckusick else 1750*24294Smckusick r = read(2, buf, sizeof buf); 1751*24294Smckusick if (r <= 0) 1752*24294Smckusick buf[0] = 0; 1753*24294Smckusick } 1754*24294Smckusick #endif lint 1755*24294Smckusick 1756*24294Smckusick bool 1757*24294Smckusick rev_in_string(string) 1758*24294Smckusick char *string; 1759*24294Smckusick { 1760*24294Smckusick register char *s; 1761*24294Smckusick register int patlen; 1762*24294Smckusick 1763*24294Smckusick if (revision == Nullch) 1764*24294Smckusick return TRUE; 1765*24294Smckusick patlen = strlen(revision); 1766*24294Smckusick for (s = string; *s; s++) { 1767*24294Smckusick if (isspace(*s) && strnEQ(s+1,revision,patlen) && 1768*24294Smckusick isspace(s[patlen+1] )) { 1769*24294Smckusick return TRUE; 1770*24294Smckusick } 1771*24294Smckusick } 1772*24294Smckusick return FALSE; 1773*24294Smckusick } 1774*24294Smckusick 1775*24294Smckusick set_signals() 1776*24294Smckusick { 1777*24294Smckusick /*NOSTRICT*/ 1778*24294Smckusick if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 1779*24294Smckusick Signal(SIGHUP, my_exit); 1780*24294Smckusick /*NOSTRICT*/ 1781*24294Smckusick if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1782*24294Smckusick Signal(SIGINT, my_exit); 1783*24294Smckusick } 1784*24294Smckusick 1785*24294Smckusick ignore_signals() 1786*24294Smckusick { 1787*24294Smckusick /*NOSTRICT*/ 1788*24294Smckusick Signal(SIGHUP, SIG_IGN); 1789*24294Smckusick /*NOSTRICT*/ 1790*24294Smckusick Signal(SIGINT, SIG_IGN); 1791*24294Smckusick } 1792