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