static char sccsid
[] = "@(#)patch.c 5.3 (Berkeley) 8/16/85";
/* patch - a program to apply diffs to original files
* $Header: patch.c,v 1.3 85/03/26 15:07:43 lwall Exp $
* Copyright 1984, Larry Wall
* This program may be copied as long as you don't try to make any
* money off of it, or pretend that you wrote it.
* 85/08/15 van%ucbmonet@berkeley
* Changes for 4.3bsd diff -c.
* Revision 1.3 85/03/26 15:07:43 lwall
* Revision 1.2.1.9 85/03/12 17:03:35 lwall
* Changed pfp->_file to fileno(pfp).
* Revision 1.2.1.8 85/03/12 16:30:43 lwall
* Check i_ptr and i_womp to make sure they aren't null before freeing.
* Also allow ed output to be suppressed.
* Revision 1.2.1.7 85/03/12 15:56:13 lwall
* Added -p option from jromine@uci-750a.
* Revision 1.2.1.6 85/03/12 12:12:51 lwall
* Now checks for normalness of file to patch.
* Revision 1.2.1.5 85/03/12 11:52:12 lwall
* Added -D (#ifdef) option from joe@fluke.
* Revision 1.2.1.4 84/12/06 11:14:15 lwall
* Made smarter about SCCS subdirectories.
* Revision 1.2.1.3 84/12/05 11:18:43 lwall
* Added -l switch to do loose string comparison.
* Revision 1.2.1.2 84/12/04 09:47:13 lwall
* Failed hunk count not reset on multiple patch file.
* Revision 1.2.1.1 84/12/04 09:42:37 lwall
* Branch for sdcrdcf changes.
* Revision 1.2 84/11/29 13:29:51 lwall
* Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed
* multiple calls to mktemp(). Will now work on machines that can only
* read 32767 chars. Added -R option for diffs with new and old swapped.
* Various cosmetic changes.
* Revision 1.1 84/11/09 17:03:58 lwall
/* shut lint up about the following when return value ignored */
#define Signal (void)signal
#define Unlink (void)unlink
#define Lseek (void)lseek
#define Fseek (void)fseek
#define Fstat (void)fstat
#define Pclose (void)pclose
#define Close (void)close
#define Fclose (void)fclose
#define Fflush (void)fflush
#define Sprintf (void)sprintf
#define Mktemp (void)mktemp
#define Strcpy (void)strcpy
#define Strcat (void)strcat
#define CHECKOUT "co -l %s"
#define Nullch Null(char *)
#define Nullfp Null(FILE *)
#define Ctl(ch) (ch & 037)
#define strNE(s1,s2) (strcmp(s1,s2))
#define strEQ(s1,s2) (!strcmp(s1,s2))
#define strnNE(s1,s2,l) (strncmp(s1,s2,l))
#define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
typedef long LINENUM
; /* must be signed */
typedef unsigned MEM
; /* what to feed malloc */
struct stat filestat
; /* file statistics area */
char serrbuf
[BUFSIZ
]; /* buffer for stderr */
char buf
[MAXLINELEN
]; /* general purpose buffer */
FILE *pfp
= Nullfp
; /* patch file pointer */
FILE *ofp
= Nullfp
; /* output file pointer */
FILE *rejfp
= Nullfp
; /* reject file pointer */
LINENUM input_lines
= 0; /* how long is input file in lines */
LINENUM last_frozen_line
= 0; /* how many input lines have been */
/* irretractibly output */
int filec
= 0; /* how many file arguments? */
char TMPOUTNAME
[] = "/tmp/patchoXXXXXX";
char TMPINNAME
[] = "/tmp/patchiXXXXXX"; /* you might want /usr/tmp here */
char TMPREJNAME
[] = "/tmp/patchrXXXXXX";
char TMPPATNAME
[] = "/tmp/patchpXXXXXX";
bool canonicalize
= FALSE
;
#define NEW_CONTEXT_DIFF 4
int do_defines
= 0; /* patch using ifdef, ifndef, etc. */
char if_defined
[128]; /* #ifdef xyzzy */
char not_defined
[128]; /* #ifndef xyzzy */
char else_defined
[] = "#else\n"; /* #else */
char end_defined
[128]; /* #endif xyzzy */
char *revision
= Nullch
; /* prerequisite revision, if any */
char *sprintf(); /* usually */
bool there_is_another_patch();
LINENUM
pch_ptrn_lines();
LINENUM
pch_repl_lines();
/* apply a context patch to a named file */
for (i
= 0; i
<MAXFILEC
; i
++)
/* make sure we clean up /tmp in case of disaster */
open_patch_file(filearg
[1]);
there_is_another_patch();
reinitialize_almost_everything()
) { /* for each patch in patch file */
outname
= savestr(filearg
[0]);
/* initialize the patched file */
/* for ed script just up and do it and exit */
if (diff_type
== ED_DIFF
) {
/* initialize reject file */
/* find out where all the lines are */
/* from here on, open no standard i/o files, because malloc */
/* apply each hunk of patch */
if (hunk
== 1 && where
== Null(LINENUM
)) {
/* dwim for reversed patch? */
where
= locate_hunk(); /* try again */
if (where
== Null(LINENUM
)) {
pch_swap(); /* no, put it back to normal */
say("%seversed (or previously applied) patch detected! %s -R.\n",
reverse
? "Assuming" : "Ignoring");
if (where
== Null(LINENUM
)) {
say("Hunk #%d failed.\n",hunk
);
say("Hunk #%d succeeded (offset %d line%s).\n",
hunk
,last_offset
,last_offset
==1?"":"s");
say("Hunk #%d succeeded.\n", hunk
);
/* finish spewing out the new file */
/* and put the output where desired */
move_file(TMPOUTNAME
,outname
);
Strcpy(rejname
, outname
);
say("%d out of %d hunks failed--saving rejects to %s\n",
move_file(TMPREJNAME
,rejname
);
reinitialize_almost_everything()
if (filearg
[0] != Nullch
) {
if (revision
!= Nullch
) {
fatal("You may not change to a different patch file.\n");
for (Argc
--,Argv
++; Argc
; Argc
--,Argv
++) {
return; /* + will be skipped by for loop */
if (*s
!= '-' || !s
[1]) {
fatal("Too many file arguments.\n");
filearg
[filec
++] = savestr(s
);
origext
= savestr(Argv
[1]);
diff_type
= CONTEXT_DIFF
;
fatal("Can't cd to %s.\n",Argv
[1]);
Sprintf(if_defined
, "#ifdef %s\n", Argv
[1]);
Sprintf(not_defined
, "#ifndef %s\n", Argv
[1]);
Sprintf(end_defined
, "#endif %s\n", Argv
[1]);
outname
= savestr(Argv
[1]);
usepath
= TRUE
; /* do not strip path names */
fatal("Unrecognized switch: %s\n",Argv
[0]);
register LINENUM first_guess
= pch_first() + last_offset
;
LINENUM pat_lines
= pch_ptrn_lines();
register LINENUM max_pos_offset
= input_lines
- first_guess
register LINENUM max_neg_offset
= first_guess
- last_frozen_line
- 1
if (!pat_lines
) /* null range matches always */
if (max_neg_offset
>= first_guess
) /* do not try lines < 0 */
max_neg_offset
= first_guess
- 1;
if (first_guess
<= input_lines
&& patch_match(first_guess
,(LINENUM
)0))
for (offset
= 1; ; offset
++) {
bool check_after
= (offset
<= max_pos_offset
);
bool check_before
= (offset
<= max_pos_offset
);
if (check_after
&& patch_match(first_guess
,offset
)) {
printf("Offset changing from %d to %d\n",last_offset
,offset
);
return first_guess
+offset
;
else if (check_before
&& patch_match(first_guess
,-offset
)) {
printf("Offset changing from %d to %d\n",last_offset
,-offset
);
return first_guess
-offset
;
else if (!check_before
&& !check_after
)
/* we did not find the pattern, dump out the hunk so they can handle it */
register LINENUM pat_end
= pch_end();
/* add in last_offset to guess the same as the previous successful hunk */
int oldfirst
= pch_first() + last_offset
;
int newfirst
= pch_newfirst() + last_offset
;
int oldlast
= oldfirst
+ pch_ptrn_lines() - 1;
int newlast
= newfirst
+ pch_repl_lines() - 1;
fprintf(rejfp
,"***************\n");
for (i
=0; i
<=pat_end
; i
++) {
fprintf(rejfp
,"*** %d,%d\n", oldfirst
, oldlast
);
fprintf(rejfp
,"--- %d,%d -----\n", newfirst
, newlast
);
fprintf(rejfp
,"%s", pfetch(i
));
case ' ': case '-': case '+': case '!':
fprintf(rejfp
,"%c %s", pch_char(i
), pfetch(i
));
say("Fatal internal error in abort_hunk().\n");
/* we found where to apply it (we hope), so do it */
register LINENUM old
= 1;
register LINENUM lastline
= pch_ptrn_lines();
register LINENUM
new = lastline
+1;
register int def_state
= 0; /* -1 = ifndef, 1 = ifdef */
while (pch_char(new) == '=' || pch_char(new) == '\n')
while (old
<= lastline
) {
if (pch_char(old
) == '-') {
copy_till(where
+ old
- 1);
fputs(else_defined
, ofp
);
else if (pch_char(new) == '+') {
copy_till(where
+ old
- 1);
fputs(else_defined
, ofp
);
if (pch_char(new) != pch_char(old
)) {
say("Out-of-sync patch, lines %d,%d\n",
pch_hunk_beg() + old
- 1,
pch_hunk_beg() + new - 1);
printf("oldchar = '%c', newchar = '%c'\n",
pch_char(old
), pch_char(new));
if (pch_char(new) == '!') {
copy_till(where
+ old
- 1);
while (pch_char(old
) == '!') {
fputs(else_defined
, ofp
);
while (pch_char(new) == '!') {
assert(pch_char(new) == ' ');
if (new <= pch_end() && pch_char(new) == '+') {
copy_till(where
+ old
- 1);
fputs(else_defined
, ofp
);
while (new <= pch_end() && pch_char(new) == '+') {
if (do_defines
&& def_state
) {
bool this_line_is_command
= FALSE
;
long beginning_of_this_line
;
copy_file(filearg
[0],TMPOUTNAME
);
Sprintf(buf
,"/bin/ed %s",TMPOUTNAME
);
Sprintf(buf
,"/bin/ed - %s",TMPOUTNAME
);
beginning_of_this_line
= ftell(pfp
);
if (pgets(buf
,sizeof buf
,pfp
) == Nullch
) {
next_intuit_at(beginning_of_this_line
);
for (t
=buf
; isdigit(*t
) || *t
== ','; t
++) ;
this_line_is_command
= (isdigit(*buf
) &&
(*t
== 'd' || *t
== 'c' || *t
== 'a') );
if (this_line_is_command
) {
while (pgets(buf
,sizeof buf
,pfp
) != Nullch
) {
next_intuit_at(beginning_of_this_line
);
move_file(TMPOUTNAME
,outname
);
fatal("patch: can't create %s.\n",name
);
fatal("patch: can't create %s.\n",name
);
say("Moving %s to stdout.\n",from
);
fatal("patch: internal error, can't reopen %s\n",from
);
while ((i
=read(fromfd
,buf
,sizeof buf
)) > 0)
fatal("patch: write failed\n");
Strcat(bakname
,origext
?origext
:ORIGEXT
);
if (stat(to
,&filestat
) >= 0) { /* output file exists */
dev_t to_device
= filestat
.st_dev
;
ino_t to_inode
= filestat
.st_ino
;
char *simplename
= bakname
;
for (s
=bakname
; *s
; s
++) {
/* find a backup name that is not the same file */
while (stat(bakname
,&filestat
) >= 0 &&
to_device
== filestat
.st_dev
&& to_inode
== filestat
.st_ino
) {
for (s
=simplename
; *s
&& !islower(*s
); s
++) ;
Strcpy(simplename
, simplename
+1);
while (unlink(bakname
) >= 0) ; /* while() is for benefit of Eunice */
say("Moving %s to %s.\n",to
,bakname
);
if (link(to
,bakname
) < 0) {
say("patch: can't backup %s, output is in %s\n",
while (unlink(to
) >= 0) ;
say("Moving %s to %s.\n",from
,to
);
if (link(from
,to
) < 0) { /* different file system? */
say("patch: can't create %s, output is in %s.\n",
fatal("patch: internal error, can't reopen %s\n",from
);
while ((i
=read(fromfd
,buf
,sizeof buf
)) > 0)
if (write(tofd
,buf
,i
) != i
)
fatal("patch: write failed\n");
fatal("patch: can't create %s.\n", to
);
fatal("patch: internal error, can't reopen %s\n",from
);
while ((i
=read(fromfd
,buf
,sizeof buf
)) > 0)
if (write(tofd
,buf
,i
) != i
)
fatal("patch: write (%s) failed\n", to
);
register LINENUM lastline
;
if (last_frozen_line
> lastline
)
say("patch: misordered hunks! output will be garbled.\n");
while (last_frozen_line
< lastline
) {
dump_line(++last_frozen_line
);
copy_till(input_lines
); /* dump remainder of file */
for (s
=ifetch(line
,0); putc(*s
,ofp
) != '\n'; s
++) ;
/* does the patch pattern match at line base+offset? */
register LINENUM pat_lines
= pch_ptrn_lines();
for (pline
= 1, iline
=base
+offset
; pline
<= pat_lines
; pline
++,iline
++) {
if (!similar(ifetch(iline
,(offset
>= 0)),
else if (strnNE(ifetch(iline
,(offset
>= 0)),
/* match two lines with canonicalized white space */
if (isspace(*b
)) { /* whitespace (or \n) to match? */
if (!isspace(*a
)) /* no corresponding whitespace? */
while (len
&& isspace(*b
) && *b
!= '\n')
b
++,len
--; /* skip pattern whitespace */
while (isspace(*a
) && *a
!= '\n')
a
++; /* skip target whitespace */
if (*a
== '\n' || *b
== '\n')
return (*a
== *b
); /* should end in sync */
else if (*a
++ != *b
++) /* match non-whitespace chars */
len
--; /* probably not necessary */
return TRUE
; /* actually, this is not reached */
/* since there is always a \n */
/* input file with indexable lines abstract type */
bool using_plan_a
= TRUE
;
static long i_size
; /* size of the input file */
static char *i_womp
; /* plan a buffer for entire file */
static char **i_ptr
; /* pointers to lines in i_womp */
static int tifd
= -1; /* plan b virtual string array */
static char *tibuf
[2]; /* plan b buffers */
static LINENUM tiline
[2] = {-1,-1}; /* 1st line in each buffer */
static LINENUM lines_per_buf
; /* how many lines per buffer */
static int tireclen
; /* length of records in tmp file */
if (i_ptr
!= Null(char**))
using_plan_a
= TRUE
; /* maybe the next one is smaller */
tibuf
[0] = tibuf
[1] = Nullch
;
tiline
[0] = tiline
[1] = -1;
/* try keeping everything in memory */
if (stat(filename
,&filestat
) < 0) {
Sprintf(buf
,"RCS/%s%s",filename
,RCSSUFFIX
);
if (stat(buf
,&filestat
) >= 0 || stat(buf
+4,&filestat
) >= 0) {
Sprintf(buf
,CHECKOUT
,filename
);
say("Can't find %s--attempting to check it out from RCS.\n",
if (system(buf
) || stat(filename
,&filestat
))
fatal("Can't check out %s.\n",filename
);
Sprintf(buf
,"SCCS/%s%s",SCCSPREFIX
,filename
);
if (stat(buf
,&filestat
) >= 0 || stat(buf
+5,&filestat
) >= 0) {
Sprintf(buf
,GET
,filename
);
say("Can't find %s--attempting to get it from SCCS.\n",
if (system(buf
) || stat(filename
,&filestat
))
fatal("Can't get %s.\n",filename
);
fatal("Can't find %s.\n",filename
);
if ((filestat
.st_mode
& S_IFMT
) & ~S_IFREG
)
fatal("%s is not a normal file--can't patch.\n",filename
);
i_size
= filestat
.st_size
;
i_womp
= malloc((MEM
)(i_size
+2));
if ((ifd
= open(filename
,0)) < 0)
fatal("Can't open file %s\n",filename
);
if (read(ifd
,i_womp
,(int)i_size
) != i_size
) {
if (i_womp
[i_size
-1] != '\n')
/* count the lines in the buffer so we know how many pointers we need */
for (s
=i_womp
; *s
; s
++) {
i_ptr
= (char **)malloc((MEM
)((iline
+ 2) * sizeof(char *)));
if (i_ptr
== Null(char **)) { /* shucks, it was a near thing */
/* now scan the buffer and build pointer array */
for (s
=i_womp
; *s
; s
++) {
i_ptr
[++iline
] = s
+1; /* these are NOT null terminated */
/* now check for revision, if any */
if (revision
!= Nullch
) {
if (!rev_in_string(i_womp
)) {
ask("This file doesn't appear to be the %s version--patch anyway? [n] ",
say("Good. This file appears to be the %s version.\n",
return TRUE
; /* plan a will work */
/* keep (virtually) nothing in memory */
bool found_revision
= (revision
== Nullch
);
if ((ifp
= fopen(filename
,"r")) == Nullfp
)
fatal("Can't open file %s\n",filename
);
if ((tifd
= creat(TMPINNAME
,0666)) < 0)
fatal("Can't open file %s\n",TMPINNAME
);
while (fgets(buf
,sizeof buf
, ifp
) != Nullch
) {
if (revision
!= Nullch
&& !found_revision
&& rev_in_string(buf
))
if ((i
= strlen(buf
)) > maxlen
)
maxlen
= i
; /* find longest line */
if (revision
!= Nullch
) {
ask("This file doesn't appear to be the %s version--patch anyway? [n] ",
say("Good. This file appears to be the %s version.\n",
Fseek(ifp
,0L,0); /* rewind file */
lines_per_buf
= BUFFERSIZE
/ maxlen
;
tibuf
[0] = malloc((MEM
)(BUFFERSIZE
+ 1));
tibuf
[1] = malloc((MEM
)(BUFFERSIZE
+ 1));
fatal("Can't seem to get enough memory.\n");
if (! (i
% lines_per_buf
)) /* new block */
if (write(tifd
,tibuf
[0],BUFFERSIZE
) < BUFFERSIZE
)
fatal("patch: can't write temp file.\n");
if (fgets(tibuf
[0] + maxlen
* (i
%lines_per_buf
), maxlen
+ 1, ifp
)
if (write(tifd
,tibuf
[0],BUFFERSIZE
) < BUFFERSIZE
)
fatal("patch: can't write temp file.\n");
if ((tifd
= open(TMPINNAME
,0)) < 0) {
fatal("Can't reopen file %s\n",TMPINNAME
);
/* fetch a line from the input file, \n terminated, not necessarily \0 */
int whichbuf
; /* ignored when file in memory */
if (line
< 1 || line
> input_lines
)
LINENUM offline
= line
% lines_per_buf
;
LINENUM baseline
= line
- offline
;
if (tiline
[0] == baseline
)
else if (tiline
[1] == baseline
)
tiline
[whichbuf
] = baseline
;
Lseek(tifd
,(long)baseline
/ lines_per_buf
* BUFFERSIZE
,0);
if (read(tifd
,tibuf
[whichbuf
],BUFFERSIZE
) < 0)
fatal("Error reading tmp file %s.\n",TMPINNAME
);
return tibuf
[whichbuf
] + (tireclen
*offline
);
/* patch abstract type */
static long p_filesize
; /* size of the patch file */
static LINENUM p_first
; /* 1st line number */
static LINENUM p_newfirst
; /* 1st line number of replacement */
static LINENUM p_ptrn_lines
; /* # lines in pattern */
static LINENUM p_repl_lines
; /* # lines in replacement text */
static LINENUM p_end
= -1; /* last line in hunk */
static LINENUM p_max
; /* max allowed value of p_end */
static LINENUM p_context
= 3; /* # of context lines */
static LINENUM p_input_line
= 0; /* current line # from patch file */
static char *p_line
[MAXHUNKSIZE
]; /* the text of the hunk */
static char p_char
[MAXHUNKSIZE
]; /* +, -, and ! */
static int p_len
[MAXHUNKSIZE
]; /* length of each line */
static int p_indent
; /* indent to patch */
static long p_base
; /* where to intuit this time */
static long p_start
; /* where intuit found a patch */
p_ptrn_lines
= (LINENUM
)0;
p_repl_lines
= (LINENUM
)0;
open_patch_file(filename
)
if (filename
== Nullch
|| !*filename
|| strEQ(filename
,"-")) {
pfp
= fopen(TMPPATNAME
,"w");
fatal("patch: can't create %s.\n",TMPPATNAME
);
while (fgets(buf
,sizeof buf
,stdin
) != NULL
)
pfp
= fopen(filename
,"r");
fatal("patch file %s not found\n",filename
);
Fstat(fileno(pfp
), &filestat
);
p_filesize
= filestat
.st_size
;
next_intuit_at(0L); /* start at the beginning */
bool no_input_file
= (filearg
[0] == Nullch
);
if (p_base
!= 0L && p_base
>= p_filesize
) {
diff_type
= intuit_diff_type();
say(" Ignoring the trailing garbage.\ndone\n");
say(" I can't seem to find a patch in there anywhere.\n");
say(" %sooks like %s to me...\n",
(p_base
== 0L ? "L" : "The next patch l"),
diff_type
== CONTEXT_DIFF
? "a context diff" :
diff_type
== NEW_CONTEXT_DIFF
? "a new-style context diff" :
diff_type
== NORMAL_DIFF
? "a normal diff" :
say("(Patch is indented %d space%s.)\n",p_indent
,p_indent
==1?"":"s");
if (filearg
[0] == Nullch
) {
filearg
[0] = fetchname(buf
);
say("Patching file %s...\n",filearg
[0]);
long first_command_line
= -1;
bool last_line_was_command
= FALSE
;
bool this_line_is_command
= FALSE
;
bool last_line_was_stars
= FALSE
;
bool this_line_is_stars
= FALSE
;
bool no_filearg
= (filearg
[0] == Nullch
);
previous_line
= this_line
;
last_line_was_command
= this_line_is_command
;
last_line_was_stars
= this_line_is_stars
;
if (fgets(buf
,sizeof buf
,pfp
) == Nullch
) {
if (first_command_line
>= 0L) {
/* nothing but deletes!? */
p_start
= first_command_line
;
for (s
= buf
; *s
== ' ' || *s
== '\t'; s
++) {
indent
+= 8 - (indent
% 8);
for (t
=s
; isdigit(*t
) || *t
== ','; t
++) ;
this_line_is_command
= (isdigit(*s
) &&
(*t
== 'd' || *t
== 'c' || *t
== 'a') );
if (first_command_line
< 0L && this_line_is_command
) {
first_command_line
= this_line
;
p_indent
= indent
; /* assume this for now */
oldname
= fetchname(s
+4);
else if (strnEQ(s
,"--- ",4)) {
newname
= fetchname(s
+4);
if (oldname
&& newname
) {
if (strlen(oldname
) < strlen(newname
))
else if (strnEQ(s
,"Index:",6)) {
filearg
[0] = fetchname(s
+6);
/* this filearg might get limboed */
else if (strnEQ(s
,"Prereq:",7)) {
for (t
=s
+7; isspace(*t
); t
++) ;
for (t
=revision
; *t
&& !isspace(*t
); t
++) ;
if ((!diff_type
|| diff_type
== ED_DIFF
) &&
first_command_line
>= 0L &&
p_start
= first_command_line
;
this_line_is_stars
= strnEQ(s
,"********",8);
if ((!diff_type
|| diff_type
== CONTEXT_DIFF
) && last_line_was_stars
&&
/* if this is a new context diff the character just before */
/* the newline is a '*'. */
return (*(s
-1) == '*' ? NEW_CONTEXT_DIFF
: CONTEXT_DIFF
);
if ((!diff_type
|| diff_type
== NORMAL_DIFF
) &&
(strnEQ(s
,"< ",2) || strnEQ(s
,"> ",2)) ) {
for (t
=s
; isspace(*t
); t
++) ;
for (; *t
&& !isspace(*t
); t
++)
Sprintf(tmpbuf
,"RCS/%s",name
);
if (stat(name
,&filestat
) < 0) {
Strcat(tmpbuf
,RCSSUFFIX
);
if (stat(tmpbuf
,&filestat
) < 0 && stat(tmpbuf
+4,&filestat
) < 0) {
Sprintf(tmpbuf
,"SCCS/%s%s",SCCSPREFIX
,name
);
if (stat(tmpbuf
,&filestat
) < 0 && stat(tmpbuf
+5,&filestat
) < 0) {
assert(p_base
<= file_pos
);
if (verbose
&& p_base
< file_pos
) {
say("The text leading up to this was:\n--------------------------\n");
while (ftell(pfp
) < file_pos
) {
ret
= fgets(buf
,sizeof buf
,pfp
);
say("--------------------------\n");
register int context
= 0;
p_max
= MAXHUNKSIZE
; /* gets reduced when --- found */
if (diff_type
== CONTEXT_DIFF
) {
long line_beginning
= ftell(pfp
);
LINENUM repl_beginning
= 0;
ret
= pgets(buf
,sizeof buf
, pfp
);
if (ret
== Nullch
|| strnNE(buf
,"********",8)) {
next_intuit_at(line_beginning
);
ret
= pgets(buf
,sizeof buf
, pfp
);
Strcpy(buf
," \n"); /* assume blank lines got chopped */
fatal("Unexpected end of file in patch.\n");
if (strnEQ(buf
,"********",8))
fatal("Unexpected end of hunk at line %d.\n",
fatal("Unexpected *** at line %d: %s", p_input_line
, buf
);
p_line
[p_end
] = savestr(buf
);
for (s
=buf
; *s
&& !isdigit(*s
); s
++) ;
p_first
= (LINENUM
) atol(s
);
for (; *s
&& !isdigit(*s
); s
++) ;
p_ptrn_lines
= ((LINENUM
)atol(s
)) - p_first
+ 1;
if (p_end
!= p_ptrn_lines
+ 1 &&
p_end
!= p_ptrn_lines
+ 2)
fatal("Unexpected --- at line %d: %s",
p_line
[p_end
] = savestr(buf
);
for (s
=buf
; *s
&& !isdigit(*s
); s
++) ;
p_newfirst
= (LINENUM
) atol(s
);
for (; *s
&& !isdigit(*s
); s
++) ;
p_max
= ((LINENUM
)atol(s
)) - p_newfirst
+ 1 + p_end
;
p_line
[p_end
] = savestr(buf
+2);
case '\t': case '\n': /* assume the 2 spaces got eaten */
p_line
[p_end
] = savestr(buf
);
if (p_end
!= p_ptrn_lines
+ 1) {
p_line
[p_end
] = savestr(buf
+2);
fatal("Malformed patch at line %d: %s",p_input_line
,buf
);
p_len
[p_end
] = strlen(p_line
[p_end
]);
/* for strncmp() so we do not have */
/* to assume null termination */
if (p_end
>=0 && !p_ptrn_lines
)
fatal("No --- found in patch at line %d\n", pch_hunk_beg());
p_repl_lines
= p_end
- repl_beginning
;
else if (diff_type
== NEW_CONTEXT_DIFF
) {
long line_beginning
= ftell(pfp
);
LINENUM repl_beginning
= 0;
ret
= pgets(buf
,sizeof buf
, pfp
);
if (ret
== Nullch
|| strnNE(buf
,"********",8)) {
next_intuit_at(line_beginning
);
line_beginning
= ftell(pfp
);
ret
= pgets(buf
,sizeof buf
, pfp
);
Strcpy(buf
," \n"); /* assume blank lines got chopped */
fatal("Unexpected end of file in patch.\n");
if (strnEQ(buf
,"********",8)) {
if (p_end
!= repl_beginning
+ 1)
fatal("Unexpected end of hunk at line %d.\n",
/* redundant 'new' context lines were omitted - set up */
/* to fill them in from the the old file's context */
fillcnt
= p_max
- repl_beginning
;
Fseek(pfp
, line_beginning
, 0); /* backup the diff input */
fatal("Unexpected *** at line %d: %s", p_input_line
, buf
);
p_line
[p_end
] = savestr(buf
);
for (s
=buf
; *s
&& !isdigit(*s
); s
++) ;
p_first
= (LINENUM
) atol(s
);
for (; *s
&& !isdigit(*s
); s
++) ;
p_ptrn_lines
= ((LINENUM
)atol(s
)) - p_first
+ 1;
if (p_end
!= p_ptrn_lines
+ 1) {
/* `old' lines were omitted - set up to fill them */
/* in from 'new' context lines. */
p_end
= p_ptrn_lines
+ 1;
fatal("Unexpected --- at line %d: %s",
p_line
[p_end
] = savestr(buf
);
for (s
=buf
; *s
&& !isdigit(*s
); s
++) ;
p_newfirst
= (LINENUM
) atol(s
);
for (; *s
&& !isdigit(*s
); s
++) ;
p_max
= ((LINENUM
)atol(s
)) - p_newfirst
+ 1 + p_end
;
if (context
> 0 && p_context
== 0) {
p_line
[p_end
] = savestr(buf
+2);
case '\t': case '\n': /* assume the 2 spaces got eaten */
p_line
[p_end
] = savestr(buf
);
if (p_end
!= p_ptrn_lines
+ 1) {
p_line
[p_end
] = savestr(buf
+2);
fatal("Malformed patch at line %d: %s",p_input_line
,buf
);
p_len
[p_end
] = strlen(p_line
[p_end
]);
/* for strncmp() so we do not have */
/* to assume null termination */
if (p_end
>=0 && !p_ptrn_lines
)
fatal("No --- found in patch at line %d\n", pch_hunk_beg());
/* if there were omitted context lines, fill them in */
while (p_char
[fillsrc
] != ' ')
p_line
[filldst
] = p_line
[fillsrc
];
p_char
[filldst
] = p_char
[fillsrc
];
p_len
[filldst
] = p_len
[fillsrc
];
assert(fillsrc
==p_end
+1 || fillsrc
==repl_beginning
);
assert(filldst
==p_end
+1 || filldst
==repl_beginning
);
p_repl_lines
= p_end
- repl_beginning
;
else { /* normal diff--fake it up */
long line_beginning
= ftell(pfp
);
ret
= pgets(buf
,sizeof buf
, pfp
);
if (ret
== Nullch
|| !isdigit(*buf
)) {
next_intuit_at(line_beginning
);
p_first
= (LINENUM
)atol(buf
);
for (s
=buf
; isdigit(*s
); s
++) ;
p_ptrn_lines
= (LINENUM
)atol(++s
) - p_first
+ 1;
p_ptrn_lines
= (*s
!= 'a');
p_first
++; /* do append rather than insert */
min
= (LINENUM
)atol(++s
);
for (; isdigit(*s
); s
++) ;
max
= (LINENUM
)atol(++s
);
p_end
= p_ptrn_lines
+ 1 + max
- min
+ 1;
p_repl_lines
= max
- min
+ 1;
Sprintf(buf
,"*** %d,%d\n", p_first
, p_first
+ p_ptrn_lines
- 1);
p_line
[0] = savestr(buf
);
for (i
=1; i
<=p_ptrn_lines
; i
++) {
ret
= pgets(buf
,sizeof buf
, pfp
);
fatal("Unexpected end of file in patch at line %d.\n",
fatal("< expected at line %d of patch.\n", p_input_line
);
p_line
[i
] = savestr(buf
+2);
p_len
[i
] = strlen(p_line
[i
]);
ret
= pgets(buf
,sizeof buf
, pfp
);
fatal("Unexpected end of file in patch at line %d.\n",
fatal("--- expected at line %d of patch.\n", p_input_line
);
Sprintf(buf
,"--- %d,%d\n",min
,max
);
p_line
[i
] = savestr(buf
);
for (i
++; i
<=p_end
; i
++) {
ret
= pgets(buf
,sizeof buf
, pfp
);
fatal("Unexpected end of file in patch at line %d.\n",
fatal("> expected at line %d of patch.\n", p_input_line
);
p_line
[i
] = savestr(buf
+2);
p_len
[i
] = strlen(p_line
[i
]);
if (reverse
) /* backwards patch? */
for (i
=0; i
<= p_end
; i
++) {
printf("%3d %c %c %s",i
,p_char
[i
],special
,p_line
[i
]);
char *ret
= fgets(bf
,sz
,fp
);
if (p_indent
&& ret
!= Nullch
) {
for (s
=buf
; indent
< p_indent
&& (*s
== ' ' || *s
== '\t'); s
++) {
indent
+= 8 - (indent
% 7);
char *tp_line
[MAXHUNKSIZE
]; /* the text of the hunk */
char tp_char
[MAXHUNKSIZE
]; /* +, -, and ! */
int tp_len
[MAXHUNKSIZE
]; /* length of each line */
/* make a scratch copy */
for (i
=0; i
<=p_end
; i
++) {
/* now turn the new into the old */
if (tp_char
[i
] == '\n') { /* account for possible blank line */
for (n
=0; i
<= p_end
; i
++,n
++) {
assert(p_char
[0] == '=');
for (s
=p_line
[0]; *s
; s
++)
/* now turn the old into the new */
assert(tp_char
[0] == '*');
for (s
=tp_line
[0]; *s
; s
++)
for (i
=0; n
<= p_end
; i
++,n
++) {
assert(i
== p_ptrn_lines
+ 1);
p_ptrn_lines
= p_repl_lines
;
return p_input_line
- p_end
- 1;
rv
= malloc((MEM
) (t
- s
));
fatal ("patch: out of memory (savestr)\n");
say(pat
) char *pat
; { ; }
fatal(pat
) char *pat
; { ; }
ask(pat
) char *pat
; { ; }
fprintf(stderr
,pat
,arg1
,arg2
,arg3
);
fatal(pat
,arg1
,arg2
,arg3
)
int ttyfd
= open("/dev/tty",2);
r
= read(ttyfd
, buf
, sizeof buf
);
r
= read(2, buf
, sizeof buf
);
patlen
= strlen(revision
);
for (s
= string
; *s
; s
++) {
if (isspace(*s
) && strnEQ(s
+1,revision
,patlen
) &&
if (signal(SIGHUP
, SIG_IGN
) != SIG_IGN
)
if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)