124294Smckusick #ifndef lint 2*26977Svan static char sccsid[] = "@(#)patch.c 5.7 (Berkeley) 03/29/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 90*26977Svan #define MAXHUNKSIZE 2000 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; 15526490Sbloom bool noreverse = FALSE; 15626490Sbloom 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; 28026490Sbloom } else if (noreverse) { 28126490Sbloom pch_swap(); /* put it back to normal */ 28226490Sbloom reverse = !reverse; 28326490Sbloom say("Ignoring previously applied (or reversed) patch.\n"); 28426490Sbloom 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 } 29226490Sbloom 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; 36226490Sbloom 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; 43126490Sbloom case 'N': 43226490Sbloom noreverse = TRUE; 43326490Sbloom 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 '*': 507*26977Svan if (diff_type == NEW_CONTEXT_DIFF) 508*26977Svan fprintf(rejfp,"*** %d,%d ****\n", oldfirst, oldlast); 509*26977Svan else 510*26977Svan fprintf(rejfp,"*** %d,%d\n", oldfirst, oldlast); 51124294Smckusick break; 51224294Smckusick case '=': 51324294Smckusick fprintf(rejfp,"--- %d,%d -----\n", newfirst, newlast); 51424294Smckusick break; 51524294Smckusick case '\n': 51624294Smckusick fprintf(rejfp,"%s", pfetch(i)); 51724294Smckusick break; 51824294Smckusick case ' ': case '-': case '+': case '!': 51924294Smckusick fprintf(rejfp,"%c %s", pch_char(i), pfetch(i)); 52024294Smckusick break; 52124294Smckusick default: 52224294Smckusick say("Fatal internal error in abort_hunk().\n"); 52324294Smckusick abort(); 52424294Smckusick } 52524294Smckusick } 52624294Smckusick } 52724294Smckusick 52824294Smckusick /* we found where to apply it (we hope), so do it */ 52924294Smckusick 53024294Smckusick apply_hunk(where) 53124294Smckusick LINENUM where; 53224294Smckusick { 53324294Smckusick register LINENUM old = 1; 53424294Smckusick register LINENUM lastline = pch_ptrn_lines(); 53524294Smckusick register LINENUM new = lastline+1; 53624294Smckusick register int def_state = 0; /* -1 = ifndef, 1 = ifdef */ 53724294Smckusick 53824294Smckusick where--; 53924294Smckusick while (pch_char(new) == '=' || pch_char(new) == '\n') 54024294Smckusick new++; 54124294Smckusick 54224294Smckusick while (old <= lastline) { 54324294Smckusick if (pch_char(old) == '-') { 54424294Smckusick copy_till(where + old - 1); 54524294Smckusick if (do_defines) { 54624294Smckusick if (def_state == 0) { 54724294Smckusick fputs(not_defined, ofp); 54824294Smckusick def_state = -1; 54924294Smckusick } else 55024294Smckusick if (def_state == 1) { 55124294Smckusick fputs(else_defined, ofp); 55224294Smckusick def_state = 2; 55324294Smckusick } 55424294Smckusick fputs(pfetch(old), ofp); 55524294Smckusick } 55624294Smckusick last_frozen_line++; 55724294Smckusick old++; 55824294Smckusick } 55924294Smckusick else if (pch_char(new) == '+') { 56024294Smckusick copy_till(where + old - 1); 56124294Smckusick if (do_defines) { 56224294Smckusick if (def_state == -1) { 56324294Smckusick fputs(else_defined, ofp); 56424294Smckusick def_state = 2; 56524294Smckusick } else 56624294Smckusick if (def_state == 0) { 56724294Smckusick fputs(if_defined, ofp); 56824294Smckusick def_state = 1; 56924294Smckusick } 57024294Smckusick } 57124294Smckusick fputs(pfetch(new),ofp); 57224294Smckusick new++; 57324294Smckusick } 57424294Smckusick else { 57524294Smckusick if (pch_char(new) != pch_char(old)) { 57624294Smckusick say("Out-of-sync patch, lines %d,%d\n", 57724294Smckusick pch_hunk_beg() + old - 1, 57824294Smckusick pch_hunk_beg() + new - 1); 57924294Smckusick #ifdef DEBUGGING 58024294Smckusick printf("oldchar = '%c', newchar = '%c'\n", 58124294Smckusick pch_char(old), pch_char(new)); 58224294Smckusick #endif 58324294Smckusick my_exit(1); 58424294Smckusick } 58524294Smckusick if (pch_char(new) == '!') { 58624294Smckusick copy_till(where + old - 1); 58724294Smckusick if (do_defines) { 58824294Smckusick fputs(not_defined,ofp); 58924294Smckusick def_state = -1; 59024294Smckusick } 59124294Smckusick while (pch_char(old) == '!') { 59224294Smckusick if (do_defines) { 59324294Smckusick fputs(pfetch(old),ofp); 59424294Smckusick } 59524294Smckusick last_frozen_line++; 59624294Smckusick old++; 59724294Smckusick } 59824294Smckusick if (do_defines) { 59924294Smckusick fputs(else_defined, ofp); 60024294Smckusick def_state = 2; 60124294Smckusick } 60224294Smckusick while (pch_char(new) == '!') { 60324294Smckusick fputs(pfetch(new),ofp); 60424294Smckusick new++; 60524294Smckusick } 60624294Smckusick if (do_defines) { 60724294Smckusick fputs(end_defined, ofp); 60824294Smckusick def_state = 0; 60924294Smckusick } 61024294Smckusick } 61124294Smckusick else { 61224294Smckusick assert(pch_char(new) == ' '); 61324294Smckusick old++; 61424294Smckusick new++; 61524294Smckusick } 61624294Smckusick } 61724294Smckusick } 61824294Smckusick if (new <= pch_end() && pch_char(new) == '+') { 61924294Smckusick copy_till(where + old - 1); 62024294Smckusick if (do_defines) { 62124294Smckusick if (def_state == 0) { 62224294Smckusick fputs(if_defined, ofp); 62324294Smckusick def_state = 1; 62424294Smckusick } else 62524294Smckusick if (def_state == -1) { 62624294Smckusick fputs(else_defined, ofp); 62724294Smckusick def_state = 2; 62824294Smckusick } 62924294Smckusick } 63024294Smckusick while (new <= pch_end() && pch_char(new) == '+') { 63124294Smckusick fputs(pfetch(new),ofp); 63224294Smckusick new++; 63324294Smckusick } 63424294Smckusick } 63524294Smckusick if (do_defines && def_state) { 63624294Smckusick fputs(end_defined, ofp); 63724294Smckusick } 63824294Smckusick } 63924294Smckusick 64024294Smckusick do_ed_script() 64124294Smckusick { 64224294Smckusick FILE *pipefp, *popen(); 64324294Smckusick bool this_line_is_command = FALSE; 64424294Smckusick register char *t; 64524294Smckusick long beginning_of_this_line; 64624294Smckusick 64724294Smckusick Unlink(TMPOUTNAME); 64824294Smckusick copy_file(filearg[0],TMPOUTNAME); 64924294Smckusick if (verbose) 65024294Smckusick Sprintf(buf,"/bin/ed %s",TMPOUTNAME); 65124294Smckusick else 65224294Smckusick Sprintf(buf,"/bin/ed - %s",TMPOUTNAME); 65324294Smckusick pipefp = popen(buf,"w"); 65424294Smckusick for (;;) { 65524294Smckusick beginning_of_this_line = ftell(pfp); 65624294Smckusick if (pgets(buf,sizeof buf,pfp) == Nullch) { 65724294Smckusick next_intuit_at(beginning_of_this_line); 65824294Smckusick break; 65924294Smckusick } 66024294Smckusick for (t=buf; isdigit(*t) || *t == ','; t++) ; 66124294Smckusick this_line_is_command = (isdigit(*buf) && 66224294Smckusick (*t == 'd' || *t == 'c' || *t == 'a') ); 66324294Smckusick if (this_line_is_command) { 66424294Smckusick fputs(buf,pipefp); 66524294Smckusick if (*t != 'd') { 66624294Smckusick while (pgets(buf,sizeof buf,pfp) != Nullch) { 66724294Smckusick fputs(buf,pipefp); 66824294Smckusick if (strEQ(buf,".\n")) 66924294Smckusick break; 67024294Smckusick } 67124294Smckusick } 67224294Smckusick } 67324294Smckusick else { 67424294Smckusick next_intuit_at(beginning_of_this_line); 67524294Smckusick break; 67624294Smckusick } 67724294Smckusick } 67824294Smckusick fprintf(pipefp,"w\n"); 67924294Smckusick fprintf(pipefp,"q\n"); 68024294Smckusick Fflush(pipefp); 68124294Smckusick Pclose(pipefp); 68224294Smckusick ignore_signals(); 68324294Smckusick move_file(TMPOUTNAME,outname); 68424294Smckusick set_signals(); 68524294Smckusick } 68624294Smckusick 68724294Smckusick init_output(name) 68824294Smckusick char *name; 68924294Smckusick { 69024294Smckusick ofp = fopen(name,"w"); 69124294Smckusick if (ofp == Nullfp) 69224294Smckusick fatal("patch: can't create %s.\n",name); 69324294Smckusick } 69424294Smckusick 69524294Smckusick init_reject(name) 69624294Smckusick char *name; 69724294Smckusick { 69824294Smckusick rejfp = fopen(name,"w"); 69924294Smckusick if (rejfp == Nullfp) 70024294Smckusick fatal("patch: can't create %s.\n",name); 70124294Smckusick } 70224294Smckusick 70324294Smckusick move_file(from,to) 70424294Smckusick char *from, *to; 70524294Smckusick { 70624294Smckusick char bakname[512]; 70724294Smckusick register char *s; 70824294Smckusick int fromfd; 70924294Smckusick register int i; 71024294Smckusick 71124294Smckusick /* to stdout? */ 71224294Smckusick 71324294Smckusick if (strEQ(to,"-")) { 71424294Smckusick #ifdef DEBUGGING 71524294Smckusick if (debug & 4) 71624294Smckusick say("Moving %s to stdout.\n",from); 71724294Smckusick #endif 71824294Smckusick fromfd = open(from,0); 71924294Smckusick if (fromfd < 0) 72024294Smckusick fatal("patch: internal error, can't reopen %s\n",from); 72124294Smckusick while ((i=read(fromfd,buf,sizeof buf)) > 0) 72224294Smckusick if (write(1,buf,i) != 1) 72324294Smckusick fatal("patch: write failed\n"); 72424294Smckusick Close(fromfd); 72524294Smckusick return; 72624294Smckusick } 72724294Smckusick 72824294Smckusick Strcpy(bakname,to); 72924294Smckusick Strcat(bakname,origext?origext:ORIGEXT); 73024294Smckusick if (stat(to,&filestat) >= 0) { /* output file exists */ 73124294Smckusick dev_t to_device = filestat.st_dev; 73224294Smckusick ino_t to_inode = filestat.st_ino; 73324294Smckusick char *simplename = bakname; 73424294Smckusick 73524294Smckusick for (s=bakname; *s; s++) { 73624294Smckusick if (*s == '/') 73724294Smckusick simplename = s+1; 73824294Smckusick } 73924294Smckusick /* find a backup name that is not the same file */ 74024294Smckusick while (stat(bakname,&filestat) >= 0 && 74124294Smckusick to_device == filestat.st_dev && to_inode == filestat.st_ino) { 74224294Smckusick for (s=simplename; *s && !islower(*s); s++) ; 74324294Smckusick if (*s) 74424294Smckusick *s = toupper(*s); 74524294Smckusick else 74624294Smckusick Strcpy(simplename, simplename+1); 74724294Smckusick } 74824294Smckusick while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */ 74924294Smckusick #ifdef DEBUGGING 75024294Smckusick if (debug & 4) 75124294Smckusick say("Moving %s to %s.\n",to,bakname); 75224294Smckusick #endif 75324294Smckusick if (link(to,bakname) < 0) { 75424294Smckusick say("patch: can't backup %s, output is in %s\n", 75524294Smckusick to,from); 75624294Smckusick return; 75724294Smckusick } 75824294Smckusick while (unlink(to) >= 0) ; 75924294Smckusick } 76024294Smckusick #ifdef DEBUGGING 76124294Smckusick if (debug & 4) 76224294Smckusick say("Moving %s to %s.\n",from,to); 76324294Smckusick #endif 76424294Smckusick if (link(from,to) < 0) { /* different file system? */ 76524294Smckusick int tofd; 76624294Smckusick 76724294Smckusick tofd = creat(to,0666); 76824294Smckusick if (tofd < 0) { 76924294Smckusick say("patch: can't create %s, output is in %s.\n", 77024294Smckusick to, from); 77124294Smckusick return; 77224294Smckusick } 77324294Smckusick fromfd = open(from,0); 77424294Smckusick if (fromfd < 0) 77524294Smckusick fatal("patch: internal error, can't reopen %s\n",from); 77624294Smckusick while ((i=read(fromfd,buf,sizeof buf)) > 0) 77724294Smckusick if (write(tofd,buf,i) != i) 77824294Smckusick fatal("patch: write failed\n"); 77924294Smckusick Close(fromfd); 78024294Smckusick Close(tofd); 78124294Smckusick } 78224294Smckusick Unlink(from); 78324294Smckusick } 78424294Smckusick 78524294Smckusick copy_file(from,to) 78624294Smckusick char *from, *to; 78724294Smckusick { 78824294Smckusick int tofd; 78924294Smckusick int fromfd; 79024294Smckusick register int i; 79124294Smckusick 79224294Smckusick tofd = creat(to,0666); 79324294Smckusick if (tofd < 0) 79424294Smckusick fatal("patch: can't create %s.\n", to); 79524294Smckusick fromfd = open(from,0); 79624294Smckusick if (fromfd < 0) 79724294Smckusick fatal("patch: internal error, can't reopen %s\n",from); 79824294Smckusick while ((i=read(fromfd,buf,sizeof buf)) > 0) 79924294Smckusick if (write(tofd,buf,i) != i) 80024294Smckusick fatal("patch: write (%s) failed\n", to); 80124294Smckusick Close(fromfd); 80224294Smckusick Close(tofd); 80324294Smckusick } 80424294Smckusick 80524294Smckusick copy_till(lastline) 80624294Smckusick register LINENUM lastline; 80724294Smckusick { 80824294Smckusick if (last_frozen_line > lastline) 80924294Smckusick say("patch: misordered hunks! output will be garbled.\n"); 81024294Smckusick while (last_frozen_line < lastline) { 81124294Smckusick dump_line(++last_frozen_line); 81224294Smckusick } 81324294Smckusick } 81424294Smckusick 81524294Smckusick spew_output() 81624294Smckusick { 81724294Smckusick copy_till(input_lines); /* dump remainder of file */ 81824294Smckusick Fclose(ofp); 81924294Smckusick ofp = Nullfp; 82024294Smckusick } 82124294Smckusick 82224294Smckusick dump_line(line) 82324294Smckusick LINENUM line; 82424294Smckusick { 82524294Smckusick register char *s; 82624294Smckusick 82724294Smckusick for (s=ifetch(line,0); putc(*s,ofp) != '\n'; s++) ; 82824294Smckusick } 82924294Smckusick 83024294Smckusick /* does the patch pattern match at line base+offset? */ 83124294Smckusick 83224294Smckusick bool 83324294Smckusick patch_match(base,offset) 83424294Smckusick LINENUM base; 83524294Smckusick LINENUM offset; 83624294Smckusick { 83724294Smckusick register LINENUM pline; 83824294Smckusick register LINENUM iline; 83924294Smckusick register LINENUM pat_lines = pch_ptrn_lines(); 84024294Smckusick 84124294Smckusick for (pline = 1, iline=base+offset; pline <= pat_lines; pline++,iline++) { 84224294Smckusick if (canonicalize) { 84324294Smckusick if (!similar(ifetch(iline,(offset >= 0)), 84424294Smckusick pfetch(pline), 84524294Smckusick pch_line_len(pline) )) 84624294Smckusick return FALSE; 84724294Smckusick } 84824294Smckusick else if (strnNE(ifetch(iline,(offset >= 0)), 84924294Smckusick pfetch(pline), 85024294Smckusick pch_line_len(pline) )) 85124294Smckusick return FALSE; 85224294Smckusick } 85324294Smckusick return TRUE; 85424294Smckusick } 85524294Smckusick 85624294Smckusick /* match two lines with canonicalized white space */ 85724294Smckusick 85824294Smckusick bool 85924294Smckusick similar(a,b,len) 86024294Smckusick register char *a, *b; 86124294Smckusick register int len; 86224294Smckusick { 86324294Smckusick while (len) { 86424294Smckusick if (isspace(*b)) { /* whitespace (or \n) to match? */ 86524294Smckusick if (!isspace(*a)) /* no corresponding whitespace? */ 86624294Smckusick return FALSE; 86724294Smckusick while (len && isspace(*b) && *b != '\n') 86824294Smckusick b++,len--; /* skip pattern whitespace */ 86924294Smckusick while (isspace(*a) && *a != '\n') 87024294Smckusick a++; /* skip target whitespace */ 87124294Smckusick if (*a == '\n' || *b == '\n') 87224294Smckusick return (*a == *b); /* should end in sync */ 87324294Smckusick } 87424294Smckusick else if (*a++ != *b++) /* match non-whitespace chars */ 87524294Smckusick return FALSE; 87624294Smckusick else 87724294Smckusick len--; /* probably not necessary */ 87824294Smckusick } 87924294Smckusick return TRUE; /* actually, this is not reached */ 88024294Smckusick /* since there is always a \n */ 88124294Smckusick } 88224294Smckusick 88324294Smckusick /* input file with indexable lines abstract type */ 88424294Smckusick 88524294Smckusick bool using_plan_a = TRUE; 88624294Smckusick static long i_size; /* size of the input file */ 88724294Smckusick static char *i_womp; /* plan a buffer for entire file */ 88824294Smckusick static char **i_ptr; /* pointers to lines in i_womp */ 88924294Smckusick 89024294Smckusick static int tifd = -1; /* plan b virtual string array */ 89124294Smckusick static char *tibuf[2]; /* plan b buffers */ 89224294Smckusick static LINENUM tiline[2] = {-1,-1}; /* 1st line in each buffer */ 89324294Smckusick static LINENUM lines_per_buf; /* how many lines per buffer */ 89424294Smckusick static int tireclen; /* length of records in tmp file */ 89524294Smckusick 89624294Smckusick re_input() 89724294Smckusick { 89824294Smckusick if (using_plan_a) { 89924294Smckusick i_size = 0; 90024294Smckusick /*NOSTRICT*/ 90124294Smckusick if (i_ptr != Null(char**)) 90224294Smckusick free((char *)i_ptr); 90324294Smckusick if (i_womp != Nullch) 90424294Smckusick free(i_womp); 90524294Smckusick i_womp = Nullch; 90624294Smckusick i_ptr = Null(char **); 90724294Smckusick } 90824294Smckusick else { 90924294Smckusick using_plan_a = TRUE; /* maybe the next one is smaller */ 91024294Smckusick Close(tifd); 91124294Smckusick tifd = -1; 91224294Smckusick free(tibuf[0]); 91324294Smckusick free(tibuf[1]); 91424294Smckusick tibuf[0] = tibuf[1] = Nullch; 91524294Smckusick tiline[0] = tiline[1] = -1; 91624294Smckusick tireclen = 0; 91724294Smckusick } 91824294Smckusick } 91924294Smckusick 92024294Smckusick scan_input(filename) 92124294Smckusick char *filename; 92224294Smckusick { 92324294Smckusick bool plan_a(); 92424294Smckusick 92524294Smckusick if (!plan_a(filename)) 92624294Smckusick plan_b(filename); 92724294Smckusick } 92824294Smckusick 92924294Smckusick /* try keeping everything in memory */ 93024294Smckusick 93124294Smckusick bool 93224294Smckusick plan_a(filename) 93324294Smckusick char *filename; 93424294Smckusick { 93524294Smckusick int ifd; 93624294Smckusick register char *s; 93724294Smckusick register LINENUM iline; 93824294Smckusick 93924294Smckusick if (stat(filename,&filestat) < 0) { 94024294Smckusick Sprintf(buf,"RCS/%s%s",filename,RCSSUFFIX); 94124294Smckusick if (stat(buf,&filestat) >= 0 || stat(buf+4,&filestat) >= 0) { 94224294Smckusick Sprintf(buf,CHECKOUT,filename); 94324294Smckusick if (verbose) 94424294Smckusick say("Can't find %s--attempting to check it out from RCS.\n", 94524294Smckusick filename); 94624294Smckusick if (system(buf) || stat(filename,&filestat)) 94724294Smckusick fatal("Can't check out %s.\n",filename); 94824294Smckusick } 94924294Smckusick else { 95024294Smckusick Sprintf(buf,"SCCS/%s%s",SCCSPREFIX,filename); 95124294Smckusick if (stat(buf,&filestat) >= 0 || stat(buf+5,&filestat) >= 0) { 95224294Smckusick Sprintf(buf,GET,filename); 95324294Smckusick if (verbose) 95424294Smckusick say("Can't find %s--attempting to get it from SCCS.\n", 95524294Smckusick filename); 95624294Smckusick if (system(buf) || stat(filename,&filestat)) 95724294Smckusick fatal("Can't get %s.\n",filename); 95824294Smckusick } 95924294Smckusick else 96024294Smckusick fatal("Can't find %s.\n",filename); 96124294Smckusick } 96224294Smckusick } 96324294Smckusick if ((filestat.st_mode & S_IFMT) & ~S_IFREG) 96424294Smckusick fatal("%s is not a normal file--can't patch.\n",filename); 96524294Smckusick i_size = filestat.st_size; 96624294Smckusick /*NOSTRICT*/ 96724294Smckusick i_womp = malloc((MEM)(i_size+2)); 96824294Smckusick if (i_womp == Nullch) 96924294Smckusick return FALSE; 97024294Smckusick if ((ifd = open(filename,0)) < 0) 97124294Smckusick fatal("Can't open file %s\n",filename); 97224294Smckusick /*NOSTRICT*/ 97324294Smckusick if (read(ifd,i_womp,(int)i_size) != i_size) { 97424294Smckusick Close(ifd); 97524294Smckusick free(i_womp); 97624294Smckusick return FALSE; 97724294Smckusick } 97824294Smckusick Close(ifd); 97924294Smckusick if (i_womp[i_size-1] != '\n') 98024294Smckusick i_womp[i_size++] = '\n'; 98124294Smckusick i_womp[i_size] = '\0'; 98224294Smckusick 98324294Smckusick /* count the lines in the buffer so we know how many pointers we need */ 98424294Smckusick 98524294Smckusick iline = 0; 98624294Smckusick for (s=i_womp; *s; s++) { 98724294Smckusick if (*s == '\n') 98824294Smckusick iline++; 98924294Smckusick } 99024294Smckusick /*NOSTRICT*/ 99124294Smckusick i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *))); 99224294Smckusick if (i_ptr == Null(char **)) { /* shucks, it was a near thing */ 99324294Smckusick free((char *)i_womp); 99424294Smckusick return FALSE; 99524294Smckusick } 99624294Smckusick 99724294Smckusick /* now scan the buffer and build pointer array */ 99824294Smckusick 99924294Smckusick iline = 1; 100024294Smckusick i_ptr[iline] = i_womp; 100124294Smckusick for (s=i_womp; *s; s++) { 100224294Smckusick if (*s == '\n') 100324294Smckusick i_ptr[++iline] = s+1; /* these are NOT null terminated */ 100424294Smckusick } 100524294Smckusick input_lines = iline - 1; 100624294Smckusick 100724294Smckusick /* now check for revision, if any */ 100824294Smckusick 100924294Smckusick if (revision != Nullch) { 101024294Smckusick if (!rev_in_string(i_womp)) { 101124294Smckusick ask("This file doesn't appear to be the %s version--patch anyway? [n] ", 101224294Smckusick revision); 101324294Smckusick if (*buf != 'y') 101424294Smckusick fatal("Aborted.\n"); 101524294Smckusick } 101624294Smckusick else if (verbose) 101724294Smckusick say("Good. This file appears to be the %s version.\n", 101824294Smckusick revision); 101924294Smckusick } 102024294Smckusick return TRUE; /* plan a will work */ 102124294Smckusick } 102224294Smckusick 102324294Smckusick /* keep (virtually) nothing in memory */ 102424294Smckusick 102524294Smckusick plan_b(filename) 102624294Smckusick char *filename; 102724294Smckusick { 102824294Smckusick FILE *ifp; 102924294Smckusick register int i = 0; 103024294Smckusick register int maxlen = 1; 103124294Smckusick bool found_revision = (revision == Nullch); 103224294Smckusick 103324294Smckusick using_plan_a = FALSE; 103424294Smckusick if ((ifp = fopen(filename,"r")) == Nullfp) 103524294Smckusick fatal("Can't open file %s\n",filename); 103624294Smckusick if ((tifd = creat(TMPINNAME,0666)) < 0) 103724294Smckusick fatal("Can't open file %s\n",TMPINNAME); 103824294Smckusick while (fgets(buf,sizeof buf, ifp) != Nullch) { 103924294Smckusick if (revision != Nullch && !found_revision && rev_in_string(buf)) 104024294Smckusick found_revision = TRUE; 104124294Smckusick if ((i = strlen(buf)) > maxlen) 104224294Smckusick maxlen = i; /* find longest line */ 104324294Smckusick } 104424294Smckusick if (revision != Nullch) { 104524294Smckusick if (!found_revision) { 104624294Smckusick ask("This file doesn't appear to be the %s version--patch anyway? [n] ", 104724294Smckusick revision); 104824294Smckusick if (*buf != 'y') 104924294Smckusick fatal("Aborted.\n"); 105024294Smckusick } 105124294Smckusick else if (verbose) 105224294Smckusick say("Good. This file appears to be the %s version.\n", 105324294Smckusick revision); 105424294Smckusick } 105524294Smckusick Fseek(ifp,0L,0); /* rewind file */ 105624294Smckusick lines_per_buf = BUFFERSIZE / maxlen; 105724294Smckusick tireclen = maxlen; 105824294Smckusick tibuf[0] = malloc((MEM)(BUFFERSIZE + 1)); 105924294Smckusick tibuf[1] = malloc((MEM)(BUFFERSIZE + 1)); 106024294Smckusick if (tibuf[1] == Nullch) 106124294Smckusick fatal("Can't seem to get enough memory.\n"); 106224294Smckusick for (i=1; ; i++) { 106324294Smckusick if (! (i % lines_per_buf)) /* new block */ 106424294Smckusick if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE) 106524294Smckusick fatal("patch: can't write temp file.\n"); 106624294Smckusick if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp) 106724294Smckusick == Nullch) { 106824294Smckusick input_lines = i - 1; 106924294Smckusick if (i % lines_per_buf) 107024294Smckusick if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE) 107124294Smckusick fatal("patch: can't write temp file.\n"); 107224294Smckusick break; 107324294Smckusick } 107424294Smckusick } 107524294Smckusick Fclose(ifp); 107624294Smckusick Close(tifd); 107724294Smckusick if ((tifd = open(TMPINNAME,0)) < 0) { 107824294Smckusick fatal("Can't reopen file %s\n",TMPINNAME); 107924294Smckusick } 108024294Smckusick } 108124294Smckusick 108224294Smckusick /* fetch a line from the input file, \n terminated, not necessarily \0 */ 108324294Smckusick char * 108424294Smckusick ifetch(line,whichbuf) 108524294Smckusick register LINENUM line; 108624294Smckusick int whichbuf; /* ignored when file in memory */ 108724294Smckusick { 108824294Smckusick if (line < 1 || line > input_lines) 108924294Smckusick return ""; 109024294Smckusick if (using_plan_a) 109124294Smckusick return i_ptr[line]; 109224294Smckusick else { 109324294Smckusick LINENUM offline = line % lines_per_buf; 109424294Smckusick LINENUM baseline = line - offline; 109524294Smckusick 109624294Smckusick if (tiline[0] == baseline) 109724294Smckusick whichbuf = 0; 109824294Smckusick else if (tiline[1] == baseline) 109924294Smckusick whichbuf = 1; 110024294Smckusick else { 110124294Smckusick tiline[whichbuf] = baseline; 110224294Smckusick Lseek(tifd,(long)baseline / lines_per_buf * BUFFERSIZE,0); 110324294Smckusick if (read(tifd,tibuf[whichbuf],BUFFERSIZE) < 0) 110424294Smckusick fatal("Error reading tmp file %s.\n",TMPINNAME); 110524294Smckusick } 110624294Smckusick return tibuf[whichbuf] + (tireclen*offline); 110724294Smckusick } 110824294Smckusick } 110924294Smckusick 111024294Smckusick /* patch abstract type */ 111124294Smckusick 111224294Smckusick static long p_filesize; /* size of the patch file */ 111324294Smckusick static LINENUM p_first; /* 1st line number */ 111424294Smckusick static LINENUM p_newfirst; /* 1st line number of replacement */ 111524294Smckusick static LINENUM p_ptrn_lines; /* # lines in pattern */ 111624294Smckusick static LINENUM p_repl_lines; /* # lines in replacement text */ 111724294Smckusick static LINENUM p_end = -1; /* last line in hunk */ 111824294Smckusick static LINENUM p_max; /* max allowed value of p_end */ 111924294Smckusick static LINENUM p_context = 3; /* # of context lines */ 112024294Smckusick static LINENUM p_input_line = 0; /* current line # from patch file */ 112124294Smckusick static char *p_line[MAXHUNKSIZE]; /* the text of the hunk */ 112224294Smckusick static char p_char[MAXHUNKSIZE]; /* +, -, and ! */ 112324294Smckusick static int p_len[MAXHUNKSIZE]; /* length of each line */ 112424294Smckusick static int p_indent; /* indent to patch */ 112524294Smckusick static long p_base; /* where to intuit this time */ 112624294Smckusick static long p_start; /* where intuit found a patch */ 112724294Smckusick 112824294Smckusick re_patch() 112924294Smckusick { 113024294Smckusick p_first = (LINENUM)0; 113124294Smckusick p_newfirst = (LINENUM)0; 113224294Smckusick p_ptrn_lines = (LINENUM)0; 113324294Smckusick p_repl_lines = (LINENUM)0; 113424294Smckusick p_end = (LINENUM)-1; 113524294Smckusick p_max = (LINENUM)0; 113624294Smckusick p_indent = 0; 113724294Smckusick } 113824294Smckusick 113924294Smckusick open_patch_file(filename) 114024294Smckusick char *filename; 114124294Smckusick { 114224294Smckusick if (filename == Nullch || !*filename || strEQ(filename,"-")) { 114324294Smckusick pfp = fopen(TMPPATNAME,"w"); 114424294Smckusick if (pfp == Nullfp) 114524294Smckusick fatal("patch: can't create %s.\n",TMPPATNAME); 114624294Smckusick while (fgets(buf,sizeof buf,stdin) != NULL) 114724294Smckusick fputs(buf,pfp); 114824294Smckusick Fclose(pfp); 114924294Smckusick filename = TMPPATNAME; 115024294Smckusick } 115124294Smckusick pfp = fopen(filename,"r"); 115224294Smckusick if (pfp == Nullfp) 115324294Smckusick fatal("patch file %s not found\n",filename); 115424294Smckusick Fstat(fileno(pfp), &filestat); 115524294Smckusick p_filesize = filestat.st_size; 115624294Smckusick next_intuit_at(0L); /* start at the beginning */ 115724294Smckusick } 115824294Smckusick 115924294Smckusick bool 116024294Smckusick there_is_another_patch() 116124294Smckusick { 116224294Smckusick bool no_input_file = (filearg[0] == Nullch); 116324294Smckusick 116424294Smckusick if (p_base != 0L && p_base >= p_filesize) { 116524294Smckusick if (verbose) 116624294Smckusick say("done\n"); 116724294Smckusick return FALSE; 116824294Smckusick } 116924294Smckusick if (verbose) 117024294Smckusick say("Hmm..."); 117124294Smckusick diff_type = intuit_diff_type(); 117224294Smckusick if (!diff_type) { 117324294Smckusick if (p_base != 0L) { 117424294Smckusick if (verbose) 117524294Smckusick say(" Ignoring the trailing garbage.\ndone\n"); 117624294Smckusick } 117724294Smckusick else 117824294Smckusick say(" I can't seem to find a patch in there anywhere.\n"); 117924294Smckusick return FALSE; 118024294Smckusick } 118124294Smckusick if (verbose) 118224294Smckusick say(" %sooks like %s to me...\n", 118324294Smckusick (p_base == 0L ? "L" : "The next patch l"), 118424294Smckusick diff_type == CONTEXT_DIFF ? "a context diff" : 118524295Smckusick diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : 118624294Smckusick diff_type == NORMAL_DIFF ? "a normal diff" : 118724294Smckusick "an ed script" ); 118824294Smckusick if (p_indent && verbose) 118924294Smckusick say("(Patch is indented %d space%s.)\n",p_indent,p_indent==1?"":"s"); 119024294Smckusick skip_to(p_start); 119124294Smckusick if (no_input_file) { 119226490Sbloom while (filearg[0] == Nullch) { 119324294Smckusick ask("File to patch: "); 119424294Smckusick filearg[0] = fetchname(buf); 119524294Smckusick } 119626490Sbloom if (verbose) { 119724294Smckusick say("Patching file %s...\n",filearg[0]); 119824294Smckusick } 119924294Smckusick } 120024294Smckusick return TRUE; 120124294Smckusick } 120224294Smckusick 120324294Smckusick intuit_diff_type() 120424294Smckusick { 120524294Smckusick long this_line = 0; 120624294Smckusick long previous_line; 120724294Smckusick long first_command_line = -1; 120824294Smckusick bool last_line_was_command = FALSE; 120924294Smckusick bool this_line_is_command = FALSE; 121024295Smckusick bool last_line_was_stars = FALSE; 121124295Smckusick bool this_line_is_stars = FALSE; 121224294Smckusick register int indent; 121324294Smckusick register char *s, *t; 121424294Smckusick char *oldname = Nullch; 121524294Smckusick char *newname = Nullch; 121624294Smckusick bool no_filearg = (filearg[0] == Nullch); 121724294Smckusick 121824294Smckusick Fseek(pfp,p_base,0); 121924294Smckusick for (;;) { 122024294Smckusick previous_line = this_line; 122124294Smckusick last_line_was_command = this_line_is_command; 122224295Smckusick last_line_was_stars = this_line_is_stars; 122324294Smckusick this_line = ftell(pfp); 122424294Smckusick indent = 0; 122524294Smckusick if (fgets(buf,sizeof buf,pfp) == Nullch) { 122624294Smckusick if (first_command_line >= 0L) { 122724294Smckusick /* nothing but deletes!? */ 122824294Smckusick p_start = first_command_line; 122924294Smckusick return ED_DIFF; 123024294Smckusick } 123124294Smckusick else { 123224294Smckusick p_start = this_line; 123324294Smckusick return 0; 123424294Smckusick } 123524294Smckusick } 123624294Smckusick for (s = buf; *s == ' ' || *s == '\t'; s++) { 123724294Smckusick if (*s == '\t') 123824294Smckusick indent += 8 - (indent % 8); 123924294Smckusick else 124024294Smckusick indent++; 124124294Smckusick } 124224294Smckusick for (t=s; isdigit(*t) || *t == ','; t++) ; 124324294Smckusick this_line_is_command = (isdigit(*s) && 124424294Smckusick (*t == 'd' || *t == 'c' || *t == 'a') ); 124524294Smckusick if (first_command_line < 0L && this_line_is_command) { 124624294Smckusick first_command_line = this_line; 124724294Smckusick p_indent = indent; /* assume this for now */ 124824294Smckusick } 124924294Smckusick if (strnEQ(s,"*** ",4)) 125024294Smckusick oldname = fetchname(s+4); 125124294Smckusick else if (strnEQ(s,"--- ",4)) { 125224294Smckusick newname = fetchname(s+4); 125324294Smckusick if (no_filearg) { 125424294Smckusick if (oldname && newname) { 125524294Smckusick if (strlen(oldname) < strlen(newname)) 125624294Smckusick filearg[0] = oldname; 125724294Smckusick else 125824294Smckusick filearg[0] = newname; 125924294Smckusick } 126024294Smckusick else if (oldname) 126124294Smckusick filearg[0] = oldname; 126224294Smckusick else if (newname) 126324294Smckusick filearg[0] = newname; 126424294Smckusick } 126524294Smckusick } 126624294Smckusick else if (strnEQ(s,"Index:",6)) { 126724294Smckusick if (no_filearg) 126824294Smckusick filearg[0] = fetchname(s+6); 126924294Smckusick /* this filearg might get limboed */ 127024294Smckusick } 127124294Smckusick else if (strnEQ(s,"Prereq:",7)) { 127224294Smckusick for (t=s+7; isspace(*t); t++) ; 127324294Smckusick revision = savestr(t); 127424294Smckusick for (t=revision; *t && !isspace(*t); t++) ; 127524294Smckusick *t = '\0'; 127624294Smckusick if (!*revision) { 127724294Smckusick free(revision); 127824294Smckusick revision = Nullch; 127924294Smckusick } 128024294Smckusick } 128124294Smckusick if ((!diff_type || diff_type == ED_DIFF) && 128224294Smckusick first_command_line >= 0L && 128324294Smckusick strEQ(s,".\n") ) { 128424294Smckusick p_indent = indent; 128524294Smckusick p_start = first_command_line; 128624294Smckusick return ED_DIFF; 128724294Smckusick } 128824295Smckusick this_line_is_stars = strnEQ(s,"********",8); 128924295Smckusick if ((!diff_type || diff_type == CONTEXT_DIFF) && last_line_was_stars && 129024295Smckusick strnEQ(s,"*** ",4)) { 129124295Smckusick /* if this is a new context diff the character just before */ 129224295Smckusick /* the newline is a '*'. */ 129324295Smckusick while (*s != '\n') 129424295Smckusick s++; 129524294Smckusick p_indent = indent; 129624295Smckusick p_start = previous_line; 129724295Smckusick return (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); 129824294Smckusick } 129924294Smckusick if ((!diff_type || diff_type == NORMAL_DIFF) && 130024294Smckusick last_line_was_command && 130124294Smckusick (strnEQ(s,"< ",2) || strnEQ(s,"> ",2)) ) { 130224294Smckusick p_start = previous_line; 130324294Smckusick p_indent = indent; 130424294Smckusick return NORMAL_DIFF; 130524294Smckusick } 130624294Smckusick } 130724294Smckusick } 130824294Smckusick 130924294Smckusick char * 131024294Smckusick fetchname(at) 131124294Smckusick char *at; 131224294Smckusick { 131324294Smckusick char *s = savestr(at); 131424294Smckusick char *name; 131524294Smckusick register char *t; 131624294Smckusick char tmpbuf[200]; 131724294Smckusick 131824294Smckusick for (t=s; isspace(*t); t++) ; 131924294Smckusick name = t; 132024294Smckusick for (; *t && !isspace(*t); t++) 132124294Smckusick if (!usepath) 132224294Smckusick if (*t == '/') 132324294Smckusick name = t+1; 132424294Smckusick *t = '\0'; 132524294Smckusick name = savestr(name); 132624294Smckusick Sprintf(tmpbuf,"RCS/%s",name); 132724294Smckusick free(s); 132824294Smckusick if (stat(name,&filestat) < 0) { 132924294Smckusick Strcat(tmpbuf,RCSSUFFIX); 133024294Smckusick if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+4,&filestat) < 0) { 133124294Smckusick Sprintf(tmpbuf,"SCCS/%s%s",SCCSPREFIX,name); 133224294Smckusick if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+5,&filestat) < 0) { 133324294Smckusick free(name); 133424294Smckusick name = Nullch; 133524294Smckusick } 133624294Smckusick } 133724294Smckusick } 133824294Smckusick return name; 133924294Smckusick } 134024294Smckusick 134124294Smckusick next_intuit_at(file_pos) 134224294Smckusick long file_pos; 134324294Smckusick { 134424294Smckusick p_base = file_pos; 134524294Smckusick } 134624294Smckusick 134724294Smckusick skip_to(file_pos) 134824294Smckusick long file_pos; 134924294Smckusick { 135024294Smckusick char *ret; 135124294Smckusick 135224294Smckusick assert(p_base <= file_pos); 135324294Smckusick if (verbose && p_base < file_pos) { 135424294Smckusick Fseek(pfp,p_base,0); 135524294Smckusick say("The text leading up to this was:\n--------------------------\n"); 135624294Smckusick while (ftell(pfp) < file_pos) { 135724294Smckusick ret = fgets(buf,sizeof buf,pfp); 135824294Smckusick assert(ret != Nullch); 135924294Smckusick say("|%s",buf); 136024294Smckusick } 136124294Smckusick say("--------------------------\n"); 136224294Smckusick } 136324294Smckusick else 136424294Smckusick Fseek(pfp,file_pos,0); 136524294Smckusick } 136624294Smckusick 136724294Smckusick bool 136824294Smckusick another_hunk() 136924294Smckusick { 137024294Smckusick register char *s; 137124294Smckusick char *ret; 137224295Smckusick register int context = 0; 137324294Smckusick 137424294Smckusick while (p_end >= 0) { 137524294Smckusick free(p_line[p_end--]); 137624294Smckusick } 137724294Smckusick assert(p_end == -1); 137824294Smckusick 137924294Smckusick p_max = MAXHUNKSIZE; /* gets reduced when --- found */ 138024294Smckusick if (diff_type == CONTEXT_DIFF) { 138124294Smckusick long line_beginning = ftell(pfp); 138224294Smckusick LINENUM repl_beginning = 0; 138324294Smckusick 138424294Smckusick ret = pgets(buf,sizeof buf, pfp); 138524294Smckusick if (ret == Nullch || strnNE(buf,"********",8)) { 138624294Smckusick next_intuit_at(line_beginning); 138724294Smckusick return FALSE; 138824294Smckusick } 138924294Smckusick p_context = 100; 139024294Smckusick while (p_end < p_max) { 139124294Smckusick ret = pgets(buf,sizeof buf, pfp); 139224294Smckusick if (ret == Nullch) { 139324294Smckusick if (p_max - p_end < 4) 139424294Smckusick Strcpy(buf," \n"); /* assume blank lines got chopped */ 139524294Smckusick else 139624294Smckusick fatal("Unexpected end of file in patch.\n"); 139724294Smckusick } 139824294Smckusick p_input_line++; 139924294Smckusick if (strnEQ(buf,"********",8)) 140024294Smckusick fatal("Unexpected end of hunk at line %d.\n", 140124294Smckusick p_input_line); 140224294Smckusick p_char[++p_end] = *buf; 140324294Smckusick switch (*buf) { 140424294Smckusick case '*': 140524294Smckusick if (p_end != 0) 140624294Smckusick fatal("Unexpected *** at line %d: %s", p_input_line, buf); 140724294Smckusick context = 0; 140824294Smckusick p_line[p_end] = savestr(buf); 140924294Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 1410*26977Svan if (!isdigit(*s)) 1411*26977Svan fatal("Malformed patch at line %d: %s", p_input_line, buf); 141224294Smckusick p_first = (LINENUM) atol(s); 141324294Smckusick while (isdigit(*s)) s++; 141424294Smckusick for (; *s && !isdigit(*s); s++) ; 1415*26977Svan if (!isdigit(*s)) 1416*26977Svan p_ptrn_lines = 1; 1417*26977Svan else 1418*26977Svan p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; 141924294Smckusick break; 142024294Smckusick case '-': 142124294Smckusick if (buf[1] == '-') { 142224294Smckusick if (p_end != p_ptrn_lines + 1 && 142324294Smckusick p_end != p_ptrn_lines + 2) 142424294Smckusick fatal("Unexpected --- at line %d: %s", 142524294Smckusick p_input_line,buf); 142624294Smckusick repl_beginning = p_end; 142724294Smckusick context = 0; 142824294Smckusick p_line[p_end] = savestr(buf); 142924294Smckusick p_char[p_end] = '='; 143024294Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 1431*26977Svan if (!isdigit(*s)) 1432*26977Svan fatal("Malformed patch at line %d: %s", 1433*26977Svan p_input_line, buf); 143424294Smckusick p_newfirst = (LINENUM) atol(s); 143524294Smckusick while (isdigit(*s)) s++; 143624294Smckusick for (; *s && !isdigit(*s); s++) ; 1437*26977Svan if (!isdigit(*s)) 1438*26977Svan p_max = p_newfirst; 1439*26977Svan else 1440*26977Svan p_max = ((LINENUM)atol(s)); 1441*26977Svan p_max += 1 + p_end - p_newfirst; 1442*26977Svan if (p_max >= MAXHUNKSIZE) 1443*26977Svan fatal("Hunk too large (%d lines) at line %d: %s", 1444*26977Svan p_max - p_end, p_input_line, buf); 144524294Smckusick break; 144624294Smckusick } 144724294Smckusick /* FALL THROUGH */ 144824294Smckusick case '+': case '!': 144924294Smckusick if (context > 0) { 145024294Smckusick if (context < p_context) 145124294Smckusick p_context = context; 145224294Smckusick context = -100; 145324294Smckusick } 145424294Smckusick p_line[p_end] = savestr(buf+2); 145524294Smckusick break; 145624294Smckusick case '\t': case '\n': /* assume the 2 spaces got eaten */ 145724294Smckusick p_line[p_end] = savestr(buf); 145824294Smckusick if (p_end != p_ptrn_lines + 1) { 145924294Smckusick context++; 146024294Smckusick p_char[p_end] = ' '; 146124294Smckusick } 146224294Smckusick break; 146324294Smckusick case ' ': 146424294Smckusick context++; 146524294Smckusick p_line[p_end] = savestr(buf+2); 146624294Smckusick break; 146724294Smckusick default: 146824294Smckusick fatal("Malformed patch at line %d: %s",p_input_line,buf); 146924294Smckusick } 1470*26977Svan /* set up p_len for strncmp() so we don't have to */ 1471*26977Svan /* assume null termination */ 1472*26977Svan if (p_line[p_end]) 147325795Smckusick p_len[p_end] = strlen(p_line[p_end]); 1474*26977Svan else 1475*26977Svan p_len[p_end] = 0; 147624294Smckusick } 147724294Smckusick if (p_end >=0 && !p_ptrn_lines) 147824294Smckusick fatal("No --- found in patch at line %d\n", pch_hunk_beg()); 147924294Smckusick p_repl_lines = p_end - repl_beginning; 148024294Smckusick } 148124295Smckusick else if (diff_type == NEW_CONTEXT_DIFF) { 148224295Smckusick long line_beginning = ftell(pfp); 148324295Smckusick LINENUM repl_beginning = 0; 148424295Smckusick LINENUM fillcnt = 0; 148524295Smckusick LINENUM fillsrc; 148624295Smckusick LINENUM filldst; 148724295Smckusick 148824295Smckusick ret = pgets(buf,sizeof buf, pfp); 148924295Smckusick if (ret == Nullch || strnNE(buf,"********",8)) { 149024295Smckusick next_intuit_at(line_beginning); 149124295Smckusick return FALSE; 149224295Smckusick } 149324295Smckusick p_context = 0; 149424295Smckusick while (p_end < p_max) { 149524295Smckusick ret = pgets(buf,sizeof buf, pfp); 149624295Smckusick if (ret == Nullch) { 149724295Smckusick if (p_max - p_end < 4) 149824295Smckusick Strcpy(buf," \n"); /* assume blank lines got chopped */ 1499*26977Svan else 150024295Smckusick fatal("Unexpected end of file in patch.\n"); 150124295Smckusick } 150224295Smckusick p_input_line++; 150324295Smckusick p_char[++p_end] = *buf; 150424295Smckusick switch (*buf) { 150526490Sbloom case '*': /* another hunk */ 1506*26977Svan if (strnEQ(buf,"********",8)) 1507*26977Svan fatal("Unexpected end of hunk at line %d.\n", 1508*26977Svan p_input_line); 1509*26977Svan 151024295Smckusick if (p_end != 0) 151124295Smckusick fatal("Unexpected *** at line %d: %s", p_input_line, buf); 151224295Smckusick context = 0; 151324295Smckusick p_line[p_end] = savestr(buf); 151424295Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 1515*26977Svan if (!isdigit(*s)) 1516*26977Svan fatal("Malformed patch at line %d: %s", p_input_line, buf); 151724295Smckusick p_first = (LINENUM) atol(s); 151824295Smckusick while (isdigit(*s)) s++; 151924295Smckusick for (; *s && !isdigit(*s); s++) ; 1520*26977Svan if (!isdigit(*s)) 1521*26977Svan p_ptrn_lines = 1; 1522*26977Svan else 1523*26977Svan p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; 152424295Smckusick break; 152524295Smckusick case '-': 152624295Smckusick if (buf[1] == '-') { 152724295Smckusick if (p_end != p_ptrn_lines + 1) { 152824295Smckusick if (p_end == 1) { 152924295Smckusick /* `old' lines were omitted - set up to fill them */ 153024295Smckusick /* in from 'new' context lines. */ 153124295Smckusick p_end = p_ptrn_lines + 1; 153224295Smckusick fillsrc = p_end + 1; 153324295Smckusick filldst = 1; 153424295Smckusick fillcnt = p_ptrn_lines; 153524295Smckusick } else 153624295Smckusick fatal("Unexpected --- at line %d: %s", 153724295Smckusick p_input_line,buf); 153824295Smckusick } 153924295Smckusick repl_beginning = p_end; 154024295Smckusick p_line[p_end] = savestr(buf); 154124295Smckusick p_char[p_end] = '='; 154224295Smckusick for (s=buf; *s && !isdigit(*s); s++) ; 1543*26977Svan if (!isdigit(*s)) 1544*26977Svan fatal("Malformed patch at line %d: %s", 1545*26977Svan p_input_line, buf); 154624295Smckusick p_newfirst = (LINENUM) atol(s); 154724295Smckusick while (isdigit(*s)) s++; 154824295Smckusick for (; *s && !isdigit(*s); s++) ; 1549*26977Svan if (!isdigit(*s)) 1550*26977Svan p_max = p_newfirst; 1551*26977Svan else 1552*26977Svan p_max = ((LINENUM)atol(s)); 1553*26977Svan p_max += 1 + p_end - p_newfirst; 1554*26977Svan if (p_max >= MAXHUNKSIZE) 1555*26977Svan fatal("Hunk too large (%d lines) at line %d: %s", 1556*26977Svan p_max - p_end, p_input_line, buf); 1557*26977Svan if (p_max - p_end == context) { 1558*26977Svan /* redundant 'new' context lines were omitted */ 1559*26977Svan /* set up to fill them in from the the old file's */ 1560*26977Svan /* context */ 1561*26977Svan fillsrc = 1; 1562*26977Svan filldst = p_end + 1; 1563*26977Svan fillcnt = p_max - repl_beginning; 1564*26977Svan p_end = p_max; 1565*26977Svan } 156624295Smckusick break; 156724295Smckusick } 156824295Smckusick /* FALL THROUGH */ 156924295Smckusick case '+': case '!': 157024295Smckusick if (context > 0 && p_context == 0) { 157124295Smckusick p_context = context; 157224295Smckusick } 157324295Smckusick p_line[p_end] = savestr(buf+2); 157424295Smckusick break; 157524295Smckusick case '\t': case '\n': /* assume the 2 spaces got eaten */ 157624295Smckusick p_line[p_end] = savestr(buf); 157724295Smckusick if (p_end != p_ptrn_lines + 1) { 157824295Smckusick context++; 157924295Smckusick p_char[p_end] = ' '; 158024295Smckusick } 158124295Smckusick break; 158224295Smckusick case ' ': 158324295Smckusick context++; 158424295Smckusick p_line[p_end] = savestr(buf+2); 158524295Smckusick break; 158624295Smckusick default: 158724295Smckusick fatal("Malformed patch at line %d: %s",p_input_line,buf); 158824295Smckusick } 1589*26977Svan /* set up p_len for strncmp() so we don't have to */ 1590*26977Svan /* assume null termination */ 1591*26977Svan if (p_line[p_end]) 159225795Smckusick p_len[p_end] = strlen(p_line[p_end]); 1593*26977Svan else 1594*26977Svan p_len[p_end] = 0; 159524295Smckusick } 159624295Smckusick if (p_end >=0 && !p_ptrn_lines) 159724295Smckusick fatal("No --- found in patch at line %d\n", pch_hunk_beg()); 159824295Smckusick 159924295Smckusick /* if there were omitted context lines, fill them in */ 160024295Smckusick if (fillcnt) { 160124295Smckusick while (fillcnt-- > 0) { 160224295Smckusick while (p_char[fillsrc] != ' ') 160324295Smckusick fillsrc++; 1604*26977Svan if (p_line[fillsrc]) 1605*26977Svan p_line[filldst] = savestr (p_line[fillsrc]); 1606*26977Svan else 1607*26977Svan p_line[filldst] = p_line[fillsrc]; 160824295Smckusick p_char[filldst] = p_char[fillsrc]; 160924295Smckusick p_len[filldst] = p_len[fillsrc]; 161024295Smckusick fillsrc++; filldst++; 161124295Smckusick } 1612*26977Svan assert(filldst==p_end+1 || filldst==repl_beginning); 161324295Smckusick } 161424295Smckusick p_repl_lines = p_end - repl_beginning; 161524295Smckusick } 161624294Smckusick else { /* normal diff--fake it up */ 161724294Smckusick char hunk_type; 161824294Smckusick register int i; 161924294Smckusick LINENUM min, max; 162024294Smckusick long line_beginning = ftell(pfp); 162124294Smckusick 162224294Smckusick p_context = 0; 162324294Smckusick ret = pgets(buf,sizeof buf, pfp); 162424294Smckusick p_input_line++; 162524294Smckusick if (ret == Nullch || !isdigit(*buf)) { 162624294Smckusick next_intuit_at(line_beginning); 162724294Smckusick return FALSE; 162824294Smckusick } 162924294Smckusick p_first = (LINENUM)atol(buf); 163024294Smckusick for (s=buf; isdigit(*s); s++) ; 163124294Smckusick if (*s == ',') { 163224294Smckusick p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1; 163324294Smckusick while (isdigit(*s)) s++; 163424294Smckusick } 163524294Smckusick else 163624294Smckusick p_ptrn_lines = (*s != 'a'); 163724294Smckusick hunk_type = *s; 163824294Smckusick if (hunk_type == 'a') 163924294Smckusick p_first++; /* do append rather than insert */ 164024294Smckusick min = (LINENUM)atol(++s); 164124294Smckusick for (; isdigit(*s); s++) ; 164224294Smckusick if (*s == ',') 164324294Smckusick max = (LINENUM)atol(++s); 164424294Smckusick else 164524294Smckusick max = min; 164624294Smckusick if (hunk_type == 'd') 164724294Smckusick min++; 164824294Smckusick p_end = p_ptrn_lines + 1 + max - min + 1; 164924294Smckusick p_newfirst = min; 165024294Smckusick p_repl_lines = max - min + 1; 165124294Smckusick Sprintf(buf,"*** %d,%d\n", p_first, p_first + p_ptrn_lines - 1); 165224294Smckusick p_line[0] = savestr(buf); 165324294Smckusick p_char[0] = '*'; 165424294Smckusick for (i=1; i<=p_ptrn_lines; i++) { 165524294Smckusick ret = pgets(buf,sizeof buf, pfp); 165624294Smckusick p_input_line++; 165724294Smckusick if (ret == Nullch) 165824294Smckusick fatal("Unexpected end of file in patch at line %d.\n", 165924294Smckusick p_input_line); 166024294Smckusick if (*buf != '<') 166124294Smckusick fatal("< expected at line %d of patch.\n", p_input_line); 166224294Smckusick p_line[i] = savestr(buf+2); 1663*26977Svan if (p_line[i]) 166425795Smckusick p_len[i] = strlen(p_line[i]); 1665*26977Svan else 1666*26977Svan p_len[i] = 0; 166724294Smckusick p_char[i] = '-'; 166824294Smckusick } 166924294Smckusick if (hunk_type == 'c') { 167024294Smckusick ret = pgets(buf,sizeof buf, pfp); 167124294Smckusick p_input_line++; 167224294Smckusick if (ret == Nullch) 167324294Smckusick fatal("Unexpected end of file in patch at line %d.\n", 167424294Smckusick p_input_line); 167524294Smckusick if (*buf != '-') 167624294Smckusick fatal("--- expected at line %d of patch.\n", p_input_line); 167724294Smckusick } 167824294Smckusick Sprintf(buf,"--- %d,%d\n",min,max); 167924294Smckusick p_line[i] = savestr(buf); 168024294Smckusick p_char[i] = '='; 168124294Smckusick for (i++; i<=p_end; i++) { 168224294Smckusick ret = pgets(buf,sizeof buf, pfp); 168324294Smckusick p_input_line++; 168424294Smckusick if (ret == Nullch) 168524294Smckusick fatal("Unexpected end of file in patch at line %d.\n", 168624294Smckusick p_input_line); 168724294Smckusick if (*buf != '>') 168824294Smckusick fatal("> expected at line %d of patch.\n", p_input_line); 168924294Smckusick p_line[i] = savestr(buf+2); 1690*26977Svan /* set up p_len for strncmp() so we don't have to */ 1691*26977Svan /* assume null termination */ 1692*26977Svan if (p_line[i]) 169325795Smckusick p_len[i] = strlen(p_line[i]); 1694*26977Svan else 1695*26977Svan p_len[i] = 0; 169624294Smckusick p_char[i] = '+'; 169724294Smckusick } 169824294Smckusick } 169924294Smckusick if (reverse) /* backwards patch? */ 170024294Smckusick pch_swap(); 170124294Smckusick #ifdef DEBUGGING 170224294Smckusick if (debug & 2) { 170324294Smckusick int i; 170424294Smckusick char special; 170524294Smckusick 170624294Smckusick for (i=0; i <= p_end; i++) { 170724294Smckusick if (i == p_ptrn_lines) 170824294Smckusick special = '^'; 170924294Smckusick else 171024294Smckusick special = ' '; 171124294Smckusick printf("%3d %c %c %s",i,p_char[i],special,p_line[i]); 171224294Smckusick } 171324294Smckusick } 171424294Smckusick #endif 171524294Smckusick return TRUE; 171624294Smckusick } 171724294Smckusick 171824294Smckusick char * 171924294Smckusick pgets(bf,sz,fp) 172024294Smckusick char *bf; 172124294Smckusick int sz; 172224294Smckusick FILE *fp; 172324294Smckusick { 172424294Smckusick char *ret = fgets(bf,sz,fp); 172524294Smckusick register char *s; 172624294Smckusick register int indent = 0; 172724294Smckusick 172824294Smckusick if (p_indent && ret != Nullch) { 172924294Smckusick for (s=buf; indent < p_indent && (*s == ' ' || *s == '\t'); s++) { 173024294Smckusick if (*s == '\t') 173124294Smckusick indent += 8 - (indent % 7); 173224294Smckusick else 173324294Smckusick indent++; 173424294Smckusick } 173524294Smckusick if (buf != s) 173624294Smckusick Strcpy(buf,s); 173724294Smckusick } 173824294Smckusick return ret; 173924294Smckusick } 174024294Smckusick 174124294Smckusick pch_swap() 174224294Smckusick { 174324294Smckusick char *tp_line[MAXHUNKSIZE]; /* the text of the hunk */ 174424294Smckusick char tp_char[MAXHUNKSIZE]; /* +, -, and ! */ 174524294Smckusick int tp_len[MAXHUNKSIZE]; /* length of each line */ 174624294Smckusick register LINENUM i, n; 174724294Smckusick bool blankline = FALSE; 174824294Smckusick register char *s; 174924294Smckusick 175024294Smckusick i = p_first; 175124294Smckusick p_first = p_newfirst; 175224294Smckusick p_newfirst = i; 175324294Smckusick 175424294Smckusick /* make a scratch copy */ 175524294Smckusick 175624294Smckusick for (i=0; i<=p_end; i++) { 175724294Smckusick tp_line[i] = p_line[i]; 175824294Smckusick tp_char[i] = p_char[i]; 175924294Smckusick tp_len[i] = p_len[i]; 176024294Smckusick } 176124294Smckusick 176224294Smckusick /* now turn the new into the old */ 176324294Smckusick 176424294Smckusick i = p_ptrn_lines + 1; 176524294Smckusick if (tp_char[i] == '\n') { /* account for possible blank line */ 176624294Smckusick blankline = TRUE; 176724294Smckusick i++; 176824294Smckusick } 176924294Smckusick for (n=0; i <= p_end; i++,n++) { 177024294Smckusick p_line[n] = tp_line[i]; 177124294Smckusick p_char[n] = tp_char[i]; 177224294Smckusick if (p_char[n] == '+') 177324294Smckusick p_char[n] = '-'; 177424294Smckusick p_len[n] = tp_len[i]; 177524294Smckusick } 177624294Smckusick if (blankline) { 177724294Smckusick i = p_ptrn_lines + 1; 177824294Smckusick p_line[n] = tp_line[i]; 177924294Smckusick p_char[n] = tp_char[i]; 178024294Smckusick p_len[n] = tp_len[i]; 178124294Smckusick n++; 178224294Smckusick } 178324294Smckusick assert(p_char[0] == '='); 178424294Smckusick p_char[0] = '*'; 178524294Smckusick for (s=p_line[0]; *s; s++) 178624294Smckusick if (*s == '-') 178724294Smckusick *s = '*'; 178824294Smckusick 178924294Smckusick /* now turn the old into the new */ 179024294Smckusick 179124294Smckusick assert(tp_char[0] == '*'); 179224294Smckusick tp_char[0] = '='; 179324294Smckusick for (s=tp_line[0]; *s; s++) 179424294Smckusick if (*s == '*') 179524294Smckusick *s = '-'; 179624294Smckusick for (i=0; n <= p_end; i++,n++) { 179724294Smckusick p_line[n] = tp_line[i]; 179824294Smckusick p_char[n] = tp_char[i]; 179924294Smckusick if (p_char[n] == '-') 180024294Smckusick p_char[n] = '+'; 180124294Smckusick p_len[n] = tp_len[i]; 180224294Smckusick } 180324294Smckusick assert(i == p_ptrn_lines + 1); 180424294Smckusick i = p_ptrn_lines; 180524294Smckusick p_ptrn_lines = p_repl_lines; 180624294Smckusick p_repl_lines = i; 180724294Smckusick } 180824294Smckusick 180924294Smckusick LINENUM 181024294Smckusick pch_first() 181124294Smckusick { 181224294Smckusick return p_first; 181324294Smckusick } 181424294Smckusick 181524294Smckusick LINENUM 181624294Smckusick pch_ptrn_lines() 181724294Smckusick { 181824294Smckusick return p_ptrn_lines; 181924294Smckusick } 182024294Smckusick 182124294Smckusick LINENUM 182224294Smckusick pch_newfirst() 182324294Smckusick { 182424294Smckusick return p_newfirst; 182524294Smckusick } 182624294Smckusick 182724294Smckusick LINENUM 182824294Smckusick pch_repl_lines() 182924294Smckusick { 183024294Smckusick return p_repl_lines; 183124294Smckusick } 183224294Smckusick 183324294Smckusick LINENUM 183424294Smckusick pch_end() 183524294Smckusick { 183624294Smckusick return p_end; 183724294Smckusick } 183824294Smckusick 183924294Smckusick LINENUM 184024294Smckusick pch_context() 184124294Smckusick { 184224294Smckusick return p_context; 184324294Smckusick } 184424294Smckusick 184524294Smckusick pch_line_len(line) 184624294Smckusick LINENUM line; 184724294Smckusick { 184824294Smckusick return p_len[line]; 184924294Smckusick } 185024294Smckusick 185124294Smckusick char 185224294Smckusick pch_char(line) 185324294Smckusick LINENUM line; 185424294Smckusick { 185524294Smckusick return p_char[line]; 185624294Smckusick } 185724294Smckusick 185824294Smckusick char * 185924294Smckusick pfetch(line) 186024294Smckusick LINENUM line; 186124294Smckusick { 186224294Smckusick return p_line[line]; 186324294Smckusick } 186424294Smckusick 186524294Smckusick LINENUM 186624294Smckusick pch_hunk_beg() 186724294Smckusick { 186824294Smckusick return p_input_line - p_end - 1; 186924294Smckusick } 187024294Smckusick 187124294Smckusick char * 187224294Smckusick savestr(s) 187324294Smckusick register char *s; 187424294Smckusick { 187524294Smckusick register char *rv, 187624294Smckusick *t; 187724294Smckusick 187824294Smckusick t = s; 187924294Smckusick while (*t++); 188024294Smckusick rv = malloc((MEM) (t - s)); 188124294Smckusick if (rv == NULL) 188224294Smckusick fatal ("patch: out of memory (savestr)\n"); 188324294Smckusick t = rv; 188424294Smckusick while (*t++ = *s++); 188524294Smckusick return rv; 188624294Smckusick } 188724294Smckusick 188824294Smckusick my_exit(status) 188924294Smckusick int status; 189024294Smckusick { 189124294Smckusick Unlink(TMPINNAME); 189224294Smckusick Unlink(TMPOUTNAME); 189324294Smckusick Unlink(TMPREJNAME); 189424294Smckusick Unlink(TMPPATNAME); 189524294Smckusick exit(status); 189624294Smckusick } 189724294Smckusick 189824294Smckusick #ifdef lint 189924294Smckusick 190024294Smckusick /*VARARGS ARGSUSED*/ 190124294Smckusick say(pat) char *pat; { ; } 190224294Smckusick /*VARARGS ARGSUSED*/ 190324294Smckusick fatal(pat) char *pat; { ; } 190424294Smckusick /*VARARGS ARGSUSED*/ 190524294Smckusick ask(pat) char *pat; { ; } 190624294Smckusick 190724294Smckusick #else lint 190824294Smckusick 190924294Smckusick say(pat,arg1,arg2,arg3) 191024294Smckusick char *pat; 191124294Smckusick int arg1,arg2,arg3; 191224294Smckusick { 191324294Smckusick fprintf(stderr,pat,arg1,arg2,arg3); 191424294Smckusick Fflush(stderr); 191524294Smckusick } 191624294Smckusick 191724294Smckusick fatal(pat,arg1,arg2,arg3) 191824294Smckusick char *pat; 191924294Smckusick int arg1,arg2,arg3; 192024294Smckusick { 192124294Smckusick say(pat,arg1,arg2,arg3); 192224294Smckusick my_exit(1); 192324294Smckusick } 192424294Smckusick 192524294Smckusick ask(pat,arg1,arg2,arg3) 192624294Smckusick char *pat; 192724294Smckusick int arg1,arg2,arg3; 192824294Smckusick { 192924294Smckusick int ttyfd = open("/dev/tty",2); 193024294Smckusick int r; 193124294Smckusick 193224294Smckusick say(pat,arg1,arg2,arg3); 193324294Smckusick if (ttyfd >= 0) { 193424294Smckusick r = read(ttyfd, buf, sizeof buf); 193524294Smckusick Close(ttyfd); 193624294Smckusick } 193724294Smckusick else 193824294Smckusick r = read(2, buf, sizeof buf); 193924294Smckusick if (r <= 0) 194024294Smckusick buf[0] = 0; 194124294Smckusick } 194224294Smckusick #endif lint 194324294Smckusick 194424294Smckusick bool 194524294Smckusick rev_in_string(string) 194624294Smckusick char *string; 194724294Smckusick { 194824294Smckusick register char *s; 194924294Smckusick register int patlen; 195024294Smckusick 195124294Smckusick if (revision == Nullch) 195224294Smckusick return TRUE; 195324294Smckusick patlen = strlen(revision); 195424294Smckusick for (s = string; *s; s++) { 195524294Smckusick if (isspace(*s) && strnEQ(s+1,revision,patlen) && 195624294Smckusick isspace(s[patlen+1] )) { 195724294Smckusick return TRUE; 195824294Smckusick } 195924294Smckusick } 196024294Smckusick return FALSE; 196124294Smckusick } 196224294Smckusick 196324294Smckusick set_signals() 196424294Smckusick { 196524294Smckusick /*NOSTRICT*/ 196624294Smckusick if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 196724294Smckusick Signal(SIGHUP, my_exit); 196824294Smckusick /*NOSTRICT*/ 196924294Smckusick if (signal(SIGINT, SIG_IGN) != SIG_IGN) 197024294Smckusick Signal(SIGINT, my_exit); 197124294Smckusick } 197224294Smckusick 197324294Smckusick ignore_signals() 197424294Smckusick { 197524294Smckusick /*NOSTRICT*/ 197624294Smckusick Signal(SIGHUP, SIG_IGN); 197724294Smckusick /*NOSTRICT*/ 197824294Smckusick Signal(SIGINT, SIG_IGN); 197924294Smckusick } 1980