1 /* $Header: pch.c,v 2.0.1.7 88/06/03 15:13:28 lwall Locked $
4 * Revision 2.0.2.0 90/05/01 22:17:51 davison
5 * patch12u: unidiff support added
7 * Revision 2.0.1.7 88/06/03 15:13:28 lwall
8 * patch10: Can now find patches in shar scripts.
9 * patch10: Hunks that swapped and then swapped back could core dump.
11 * Revision 2.0.1.6 87/06/04 16:18:13 lwall
12 * pch_swap didn't swap p_bfake and p_efake.
14 * Revision 2.0.1.5 87/01/30 22:47:42 lwall
15 * Improved responses to mangled patches.
17 * Revision 2.0.1.4 87/01/05 16:59:53 lwall
18 * New-style context diffs caused double call to free().
20 * Revision 2.0.1.3 86/11/14 10:08:33 lwall
21 * Fixed problem where a long pattern wouldn't grow the hunk.
22 * Also restored p_input_line when backtracking so error messages are right.
24 * Revision 2.0.1.2 86/11/03 17:49:52 lwall
25 * New-style delete triggers spurious assertion error.
27 * Revision 2.0.1.1 86/10/29 15:52:08 lwall
28 * Could falsely report new-style context diff.
30 * Revision 2.0 86/09/17 15:39:37 lwall
31 * Baseline for netwide release.
41 /* Patch (diff listing) abstract type. */
43 static long p_filesize
; /* size of the patch file */
44 static LINENUM p_first
; /* 1st line number */
45 static LINENUM p_newfirst
; /* 1st line number of replacement */
46 static LINENUM p_ptrn_lines
; /* # lines in pattern */
47 static LINENUM p_repl_lines
; /* # lines in replacement text */
48 static LINENUM p_end
= -1; /* last line in hunk */
49 static LINENUM p_max
; /* max allowed value of p_end */
50 static LINENUM p_context
= 3; /* # of context lines */
51 static LINENUM p_input_line
= 0; /* current line # from patch file */
52 static char **p_line
= Null(char**); /* the text of the hunk */
53 static short *p_len
= Null(short*); /* length of each line */
54 static char *p_char
= Nullch
; /* +, -, and ! */
55 static int hunkmax
= INITHUNKMAX
; /* size of above arrays to begin with */
56 static int p_indent
; /* indent to patch */
57 static LINENUM p_base
; /* where to intuit this time */
58 static LINENUM p_bline
; /* line # of p_base */
59 static LINENUM p_start
; /* where intuit found a patch */
60 static LINENUM p_sline
; /* and the line number for it */
61 static LINENUM p_hunk_beg
; /* line number of current hunk */
62 static LINENUM p_efake
= -1; /* end of faked up lines--don't free */
63 static LINENUM p_bfake
= -1; /* beg of faked up lines */
65 /* Prepare to look for the next patch in the patch file. */
72 p_ptrn_lines
= Nulline
;
73 p_repl_lines
= Nulline
;
79 /* Open the patch file at the beginning of time. */
82 open_patch_file(filename
)
85 if (filename
== Nullch
|| !*filename
|| strEQ(filename
, "-")) {
86 pfp
= fopen(TMPPATNAME
, "w");
88 pfatal2("can't create %s", TMPPATNAME
);
89 while (fgets(buf
, sizeof buf
, stdin
) != Nullch
)
92 filename
= TMPPATNAME
;
94 pfp
= fopen(filename
, "r");
96 pfatal2("patch file %s not found", filename
);
97 Fstat(fileno(pfp
), &filestat
);
98 p_filesize
= filestat
.st_size
;
99 next_intuit_at(0L,1L); /* start at the beginning */
103 /* Make sure our dynamically realloced tables are malloced to begin with. */
109 if (p_line
== Null(char**))
110 p_line
= (char**) malloc((MEM
)hunkmax
* sizeof(char *));
111 if (p_len
== Null(short*))
112 p_len
= (short*) malloc((MEM
)hunkmax
* sizeof(short));
114 if (p_char
== Nullch
)
115 p_char
= (char*) malloc((MEM
)hunkmax
* sizeof(char));
118 /* Enlarge the arrays containing the current hunk of patch. */
125 * Note that on most systems, only the p_line array ever gets fresh memory
126 * since p_len can move into p_line's old space, and p_char can move into
127 * p_len's old space. Not on PDP-11's however. But it doesn't matter.
129 assert(p_line
!= Null(char**) && p_len
!= Null(short*) && p_char
!= Nullch
);
131 p_line
= (char**) realloc((char*)p_line
, (MEM
)hunkmax
* sizeof(char *));
132 p_len
= (short*) realloc((char*)p_len
, (MEM
)hunkmax
* sizeof(short));
133 p_char
= (char*) realloc((char*)p_char
, (MEM
)hunkmax
* sizeof(char));
135 if (p_line
!= Null(char**) && p_len
!= Null(short*) && p_char
!= Nullch
)
138 fatal1("out of memory\n");
139 out_of_mem
= TRUE
; /* whatever is null will be allocated again */
140 /* from within plan_a(), of all places */
143 /* True if the remainder of the patch file contains a diff of some sort. */
146 there_is_another_patch()
148 if (p_base
!= 0L && p_base
>= p_filesize
) {
155 diff_type
= intuit_diff_type();
159 say1(" Ignoring the trailing garbage.\ndone\n");
162 say1(" I can't seem to find a patch in there anywhere.\n");
166 say3(" %sooks like %s to me...\n",
167 (p_base
== 0L ? "L" : "The next patch l"),
168 diff_type
== UNI_DIFF
? "a unified diff" :
169 diff_type
== CONTEXT_DIFF
? "a context diff" :
170 diff_type
== NEW_CONTEXT_DIFF
? "a new-style context diff" :
171 diff_type
== NORMAL_DIFF
? "a normal diff" :
173 if (p_indent
&& verbose
)
174 say3("(Patch is indented %d space%s.)\n", p_indent
, p_indent
==1?"":"s");
175 skip_to(p_start
,p_sline
);
176 while (filearg
[0] == Nullch
) {
177 if (force
|| batch
) {
178 say1("No file to patch. Skipping...\n");
179 filearg
[0] = savestr(bestguess
);
182 ask1("File to patch: ");
186 bestguess
= savestr(buf
);
187 filearg
[0] = fetchname(buf
, 0, FALSE
);
189 if (filearg
[0] == Nullch
) {
190 ask1("No file found--skip this patch? [n] ");
195 say1("Skipping patch...\n");
196 filearg
[0] = fetchname(bestguess
, 0, TRUE
);
197 skip_rest_of_patch
= TRUE
;
204 /* Determine what kind of diff is in the remaining part of the patch file. */
209 Reg4
long this_line
= 0;
210 Reg5
long previous_line
;
211 Reg6
long first_command_line
= -1;
213 Reg7
bool last_line_was_command
= FALSE
;
214 Reg8
bool this_is_a_command
= FALSE
;
215 Reg9
bool stars_last_line
= FALSE
;
216 Reg10
bool stars_this_line
= FALSE
;
220 char *indtmp
= Nullch
;
221 char *oldtmp
= Nullch
;
222 char *newtmp
= Nullch
;
223 char *indname
= Nullch
;
224 char *oldname
= Nullch
;
225 char *newname
= Nullch
;
227 bool no_filearg
= (filearg
[0] == Nullch
);
229 ok_to_create_file
= FALSE
;
230 Fseek(pfp
, p_base
, 0);
231 p_input_line
= p_bline
- 1;
233 previous_line
= this_line
;
234 last_line_was_command
= this_is_a_command
;
235 stars_last_line
= stars_this_line
;
236 this_line
= ftell(pfp
);
239 if (fgets(buf
, sizeof buf
, pfp
) == Nullch
) {
240 if (first_command_line
>= 0L) {
241 /* nothing but deletes!? */
242 p_start
= first_command_line
;
249 p_sline
= p_input_line
;
254 for (s
= buf
; *s
== ' ' || *s
== '\t' || *s
== 'X'; s
++) {
256 indent
+= 8 - (indent
% 8);
260 for (t
=s
; isdigit(*t
) || *t
== ','; t
++) ;
261 this_is_a_command
= (isdigit(*s
) &&
262 (*t
== 'd' || *t
== 'c' || *t
== 'a') );
263 if (first_command_line
< 0L && this_is_a_command
) {
264 first_command_line
= this_line
;
265 fcl_line
= p_input_line
;
266 p_indent
= indent
; /* assume this for now */
268 if (!stars_last_line
&& strnEQ(s
, "*** ", 4))
269 oldtmp
= savestr(s
+4);
270 else if (strnEQ(s
, "--- ", 4))
271 newtmp
= savestr(s
+4);
272 else if (strnEQ(s
, "+++ ", 4))
273 oldtmp
= savestr(s
+4); /* pretend it is the old name */
274 else if (strnEQ(s
, "Index:", 6))
275 indtmp
= savestr(s
+6);
276 else if (strnEQ(s
, "Prereq:", 7)) {
277 for (t
=s
+7; isspace(*t
); t
++) ;
278 revision
= savestr(t
);
279 for (t
=revision
; *t
&& !isspace(*t
); t
++) ;
286 if ((!diff_type
|| diff_type
== ED_DIFF
) &&
287 first_command_line
>= 0L &&
290 p_start
= first_command_line
;
295 if ((!diff_type
|| diff_type
== UNI_DIFF
) && strnEQ(s
, "@@ -", 4)) {
297 ok_to_create_file
= TRUE
;
300 p_sline
= p_input_line
;
304 stars_this_line
= strnEQ(s
, "********", 8);
305 if ((!diff_type
|| diff_type
== CONTEXT_DIFF
) && stars_last_line
&&
306 strnEQ(s
, "*** ", 4)) {
308 ok_to_create_file
= TRUE
;
309 /* if this is a new context diff the character just before */
310 /* the newline is a '*'. */
314 p_start
= previous_line
;
315 p_sline
= p_input_line
- 1;
316 retval
= (*(s
-1) == '*' ? NEW_CONTEXT_DIFF
: CONTEXT_DIFF
);
319 if ((!diff_type
|| diff_type
== NORMAL_DIFF
) &&
320 last_line_was_command
&&
321 (strnEQ(s
, "< ", 2) || strnEQ(s
, "> ", 2)) ) {
322 p_start
= previous_line
;
323 p_sline
= p_input_line
- 1;
325 retval
= NORMAL_DIFF
;
331 if (indtmp
!= Nullch
)
332 indname
= fetchname(indtmp
, strippath
, ok_to_create_file
);
333 if (oldtmp
!= Nullch
)
334 oldname
= fetchname(oldtmp
, strippath
, ok_to_create_file
);
335 if (newtmp
!= Nullch
)
336 newname
= fetchname(newtmp
, strippath
, ok_to_create_file
);
337 if (oldname
&& newname
) {
338 if (strlen(oldname
) < strlen(newname
))
339 filearg
[0] = savestr(oldname
);
341 filearg
[0] = savestr(newname
);
344 filearg
[0] = savestr(oldname
);
346 filearg
[0] = savestr(newname
);
348 filearg
[0] = savestr(indname
);
354 if (filearg
[0] != Nullch
)
355 bestguess
= savestr(filearg
[0]);
356 else if (indtmp
!= Nullch
)
357 bestguess
= fetchname(indtmp
, strippath
, TRUE
);
359 if (oldtmp
!= Nullch
)
360 oldname
= fetchname(oldtmp
, strippath
, TRUE
);
361 if (newtmp
!= Nullch
)
362 newname
= fetchname(newtmp
, strippath
, TRUE
);
363 if (oldname
&& newname
) {
364 if (strlen(oldname
) < strlen(newname
))
365 bestguess
= savestr(oldname
);
367 bestguess
= savestr(newname
);
370 bestguess
= savestr(oldname
);
372 bestguess
= savestr(newname
);
374 if (indtmp
!= Nullch
)
376 if (oldtmp
!= Nullch
)
378 if (newtmp
!= Nullch
)
380 if (indname
!= Nullch
)
382 if (oldname
!= Nullch
)
384 if (newname
!= Nullch
)
389 /* Remember where this patch ends so we know where to start up again. */
392 next_intuit_at(file_pos
,file_line
)
400 /* Basically a verbose fseek() to the actual diff listing. */
403 skip_to(file_pos
,file_line
)
409 assert(p_base
<= file_pos
);
410 if (verbose
&& p_base
< file_pos
) {
411 Fseek(pfp
, p_base
, 0);
412 say1("The text leading up to this was:\n--------------------------\n");
413 while (ftell(pfp
) < file_pos
) {
414 ret
= fgets(buf
, sizeof buf
, pfp
);
415 assert(ret
!= Nullch
);
418 say1("--------------------------\n");
421 Fseek(pfp
, file_pos
, 0);
422 p_input_line
= file_line
- 1;
425 /* Make this a function for better debugging. */
429 fatal3("malformed patch at line %ld: %s", p_input_line
, buf
);
430 /* about as informative as "Syntax error" in C */
433 /* True if there is more of the current diff listing to process. */
440 Reg2
int context
= 0;
443 if (p_end
== p_efake
)
444 p_end
= p_bfake
; /* don't free twice */
452 p_max
= hunkmax
; /* gets reduced when --- found */
453 if (diff_type
== CONTEXT_DIFF
|| diff_type
== NEW_CONTEXT_DIFF
) {
454 long line_beginning
= ftell(pfp
);
455 /* file pos of the current line */
456 LINENUM repl_beginning
= 0; /* index of --- line */
457 Reg4 LINENUM fillcnt
= 0; /* #lines of missing ptrn or repl */
458 Reg5 LINENUM fillsrc
; /* index of first line to copy */
459 Reg6 LINENUM filldst
; /* index of first missing line */
460 bool ptrn_spaces_eaten
= FALSE
; /* ptrn was slightly misformed */
461 Reg9
bool repl_could_be_missing
= TRUE
;
462 /* no + or ! lines in this hunk */
463 bool repl_missing
= FALSE
; /* we are now backtracking */
464 long repl_backtrack_position
= 0;
465 /* file pos of first repl line */
466 LINENUM repl_patch_line
; /* input line number for same */
467 Reg7 LINENUM ptrn_copiable
= 0;
468 /* # of copiable lines in ptrn */
470 ret
= pgets(buf
, sizeof buf
, pfp
);
472 if (ret
== Nullch
|| strnNE(buf
, "********", 8)) {
473 next_intuit_at(line_beginning
,p_input_line
);
477 p_hunk_beg
= p_input_line
+ 1;
478 while (p_end
< p_max
) {
479 line_beginning
= ftell(pfp
);
480 ret
= pgets(buf
, sizeof buf
, pfp
);
483 if (p_max
- p_end
< 4)
484 Strcpy(buf
, " \n"); /* assume blank lines got chopped */
486 if (repl_beginning
&& repl_could_be_missing
) {
490 fatal1("unexpected end of file in patch\n");
494 assert(p_end
< hunkmax
);
495 p_char
[p_end
] = *buf
;
497 p_line
[(short)p_end
] = Nullch
;
499 p_line
[p_end
] = Nullch
;
503 if (strnEQ(buf
, "********", 8)) {
504 if (repl_beginning
&& repl_could_be_missing
) {
509 fatal2("unexpected end of hunk at line %ld\n",
513 if (repl_beginning
&& repl_could_be_missing
) {
517 fatal3("unexpected *** at line %ld: %s", p_input_line
, buf
);
520 p_line
[p_end
] = savestr(buf
);
525 for (s
=buf
; *s
&& !isdigit(*s
); s
++) ;
528 if (strnEQ(s
,"0,0",3))
530 p_first
= (LINENUM
) atol(s
);
531 while (isdigit(*s
)) s
++;
533 for (; *s
&& !isdigit(*s
); s
++) ;
536 p_ptrn_lines
= ((LINENUM
)atol(s
)) - p_first
+ 1;
544 p_max
= p_ptrn_lines
+ 6; /* we need this much at least */
545 while (p_max
>= hunkmax
)
551 if (repl_beginning
||
552 (p_end
!= p_ptrn_lines
+ 1 + (p_char
[p_end
-1] == '\n')))
555 /* `old' lines were omitted - set up to fill */
556 /* them in from 'new' context lines. */
557 p_end
= p_ptrn_lines
+ 1;
560 fillcnt
= p_ptrn_lines
;
563 if (repl_beginning
) {
564 if (repl_could_be_missing
){
569 "duplicate \"---\" at line %ld--check line numbers at line %ld\n",
570 p_input_line
, p_hunk_beg
+ repl_beginning
);
574 "%s \"---\" at line %ld--check line numbers at line %ld\n",
575 (p_end
<= p_ptrn_lines
578 p_input_line
, p_hunk_beg
);
582 repl_beginning
= p_end
;
583 repl_backtrack_position
= ftell(pfp
);
584 repl_patch_line
= p_input_line
;
585 p_line
[p_end
] = savestr(buf
);
591 for (s
=buf
; *s
&& !isdigit(*s
); s
++) ;
594 p_newfirst
= (LINENUM
) atol(s
);
595 while (isdigit(*s
)) s
++;
597 for (; *s
&& !isdigit(*s
); s
++) ;
600 p_repl_lines
= ((LINENUM
)atol(s
)) - p_newfirst
+ 1;
608 p_max
= p_repl_lines
+ p_end
;
609 if (p_max
> MAXHUNKSIZE
)
610 fatal4("hunk too large (%ld lines) at line %ld: %s",
611 p_max
, p_input_line
, buf
);
612 while (p_max
>= hunkmax
)
614 if (p_repl_lines
!= ptrn_copiable
615 && (p_context
!= 0 || p_repl_lines
!= 1))
616 repl_could_be_missing
= FALSE
;
621 repl_could_be_missing
= FALSE
;
623 if (buf
[1] == '\n' && canonicalize
)
625 if (!isspace(buf
[1]) && buf
[1] != '>' && buf
[1] != '<' &&
626 repl_beginning
&& repl_could_be_missing
) {
631 if (context
< p_context
)
635 p_line
[p_end
] = savestr(buf
+2);
641 case '\t': case '\n': /* assume the 2 spaces got eaten */
642 if (repl_beginning
&& repl_could_be_missing
&&
643 (!ptrn_spaces_eaten
|| diff_type
== NEW_CONTEXT_DIFF
) ) {
647 p_line
[p_end
] = savestr(buf
);
652 if (p_end
!= p_ptrn_lines
+ 1) {
653 ptrn_spaces_eaten
|= (repl_beginning
!= 0);
661 if (!isspace(buf
[1]) &&
662 repl_beginning
&& repl_could_be_missing
) {
669 p_line
[p_end
] = savestr(buf
+2);
676 if (repl_beginning
&& repl_could_be_missing
) {
682 /* set up p_len for strncmp() so we don't have to */
683 /* assume null termination */
685 p_len
[p_end
] = strlen(p_line
[p_end
]);
691 if (p_end
>=0 && !repl_beginning
)
692 fatal2("no --- found in patch at line %ld\n", pch_hunk_beg());
696 /* reset state back to just after --- */
697 p_input_line
= repl_patch_line
;
698 for (p_end
--; p_end
> repl_beginning
; p_end
--)
700 Fseek(pfp
, repl_backtrack_position
, 0);
702 /* redundant 'new' context lines were omitted - set */
703 /* up to fill them in from the old file context */
704 if (!p_context
&& p_repl_lines
== 1) {
709 filldst
= repl_beginning
+1;
710 fillcnt
= p_repl_lines
;
713 else if (!p_context
&& fillcnt
== 1) {
714 /* the first hunk was a null hunk with no context */
715 /* and we were expecting one line -- fix it up. */
716 while (filldst
< p_end
) {
717 p_line
[filldst
] = p_line
[filldst
+1];
718 p_char
[filldst
] = p_char
[filldst
+1];
719 p_len
[filldst
] = p_len
[filldst
+1];
723 repl_beginning
--; /* this doesn't need to be fixed */
726 p_first
++; /* do append rather than insert */
731 if (diff_type
== CONTEXT_DIFF
&&
732 (fillcnt
|| (p_first
> 1 && ptrn_copiable
> 2*p_context
)) ) {
735 "(Fascinating--this is really a new-style context diff but without",
736 "the telltale extra asterisks on the *** line that usually indicate",
737 "the new style...)");
738 diff_type
= NEW_CONTEXT_DIFF
;
741 /* if there were omitted context lines, fill them in now */
743 p_bfake
= filldst
; /* remember where not to free() */
744 p_efake
= filldst
+ fillcnt
- 1;
745 while (fillcnt
-- > 0) {
746 while (fillsrc
<= p_end
&& p_char
[fillsrc
] != ' ')
749 fatal2("replacement text or line numbers mangled in hunk at line %ld\n",
751 p_line
[filldst
] = p_line
[fillsrc
];
752 p_char
[filldst
] = p_char
[fillsrc
];
753 p_len
[filldst
] = p_len
[fillsrc
];
754 fillsrc
++; filldst
++;
756 while (fillsrc
<= p_end
&& fillsrc
!= repl_beginning
&&
757 p_char
[fillsrc
] != ' ')
761 printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
762 fillsrc
,filldst
,repl_beginning
,p_end
+1);
764 assert(fillsrc
==p_end
+1 || fillsrc
==repl_beginning
);
765 assert(filldst
==p_end
+1 || filldst
==repl_beginning
);
768 else if (diff_type
== UNI_DIFF
) {
769 long line_beginning
= ftell(pfp
);
770 /* file pos of the current line */
771 Reg4 LINENUM fillsrc
; /* index of old lines */
772 Reg5 LINENUM filldst
; /* index of new lines */
775 ret
= pgets(buf
, sizeof buf
, pfp
);
777 if (ret
== Nullch
|| strnNE(buf
, "@@ -", 4)) {
778 next_intuit_at(line_beginning
,p_input_line
);
784 p_first
= (LINENUM
) atol(s
);
785 while (isdigit(*s
)) s
++;
787 p_ptrn_lines
= (LINENUM
) atol(++s
);
788 while (isdigit(*s
)) s
++;
792 if (*s
!= '+' || !*++s
)
794 p_newfirst
= (LINENUM
) atol(s
);
795 while (isdigit(*s
)) s
++;
797 p_repl_lines
= (LINENUM
) atol(++s
);
798 while (isdigit(*s
)) s
++;
805 p_first
++; /* do append rather than insert */
806 p_max
= p_ptrn_lines
+ p_repl_lines
+ 1;
807 while (p_max
>= hunkmax
)
810 filldst
= fillsrc
+ p_ptrn_lines
;
811 p_end
= filldst
+ p_repl_lines
;
812 Sprintf(buf
,"*** %ld,%ld ****\n",p_first
,p_first
+ p_ptrn_lines
- 1);
813 p_line
[0] = savestr(buf
);
819 Sprintf(buf
,"--- %ld,%ld ----\n",p_newfirst
,p_newfirst
+p_repl_lines
-1);
820 p_line
[filldst
] = savestr(buf
);
825 p_char
[filldst
++] = '=';
828 p_hunk_beg
= p_input_line
+ 1;
829 while (fillsrc
<= p_ptrn_lines
|| filldst
<= p_end
) {
830 line_beginning
= ftell(pfp
);
831 ret
= pgets(buf
, sizeof buf
, pfp
);
834 if (p_max
- filldst
< 3)
835 Strcpy(buf
, " \n"); /* assume blank lines got chopped */
837 fatal1("unexpected end of file in patch\n");
840 if (*buf
== '\t' || *buf
== '\n') {
841 ch
= ' '; /* assume the space got eaten */
849 while (--filldst
> p_ptrn_lines
)
850 free(p_line
[filldst
]);
856 if (fillsrc
> p_ptrn_lines
) {
861 p_char
[fillsrc
] = ch
;
863 p_len
[fillsrc
++] = strlen(s
);
869 if (fillsrc
> p_ptrn_lines
) {
871 while (--filldst
> p_ptrn_lines
)
872 free(p_line
[filldst
]);
877 p_char
[fillsrc
] = ch
;
879 p_len
[fillsrc
++] = strlen(s
);
882 while (--filldst
> p_ptrn_lines
)
883 free(p_line
[filldst
]);
889 if (filldst
> p_end
) {
891 while (--filldst
> p_ptrn_lines
)
892 free(p_line
[filldst
]);
896 p_char
[filldst
] = ch
;
898 p_len
[filldst
++] = strlen(s
);
904 if (ch
!= ' ' && context
> 0) {
905 if (context
< p_context
)
911 else { /* normal diff--fake it up */
915 long line_beginning
= ftell(pfp
);
918 ret
= pgets(buf
, sizeof buf
, pfp
);
920 if (ret
== Nullch
|| !isdigit(*buf
)) {
921 next_intuit_at(line_beginning
,p_input_line
);
924 p_first
= (LINENUM
)atol(buf
);
925 for (s
=buf
; isdigit(*s
); s
++) ;
927 p_ptrn_lines
= (LINENUM
)atol(++s
) - p_first
+ 1;
928 while (isdigit(*s
)) s
++;
931 p_ptrn_lines
= (*s
!= 'a');
933 if (hunk_type
== 'a')
934 p_first
++; /* do append rather than insert */
935 min
= (LINENUM
)atol(++s
);
936 for (; isdigit(*s
); s
++) ;
938 max
= (LINENUM
)atol(++s
);
941 if (hunk_type
== 'd')
943 p_end
= p_ptrn_lines
+ 1 + max
- min
+ 1;
944 if (p_end
> MAXHUNKSIZE
)
945 fatal4("hunk too large (%ld lines) at line %ld: %s",
946 p_end
, p_input_line
, buf
);
947 while (p_end
>= hunkmax
)
950 p_repl_lines
= max
- min
+ 1;
951 Sprintf(buf
, "*** %ld,%ld\n", p_first
, p_first
+ p_ptrn_lines
- 1);
952 p_line
[0] = savestr(buf
);
958 for (i
=1; i
<=p_ptrn_lines
; i
++) {
959 ret
= pgets(buf
, sizeof buf
, pfp
);
962 fatal2("unexpected end of file in patch at line %ld\n",
965 fatal2("< expected at line %ld of patch\n", p_input_line
);
966 p_line
[i
] = savestr(buf
+2);
971 p_len
[i
] = strlen(p_line
[i
]);
974 if (hunk_type
== 'c') {
975 ret
= pgets(buf
, sizeof buf
, pfp
);
978 fatal2("unexpected end of file in patch at line %ld\n",
981 fatal2("--- expected at line %ld of patch\n", p_input_line
);
983 Sprintf(buf
, "--- %ld,%ld\n", min
, max
);
984 p_line
[i
] = savestr(buf
);
990 for (i
++; i
<=p_end
; i
++) {
991 ret
= pgets(buf
, sizeof buf
, pfp
);
994 fatal2("unexpected end of file in patch at line %ld\n",
997 fatal2("> expected at line %ld of patch\n", p_input_line
);
998 p_line
[i
] = savestr(buf
+2);
1003 p_len
[i
] = strlen(p_line
[i
]);
1007 if (reverse
) /* backwards patch? */
1009 say1("Not enough memory to swap next hunk!\n");
1015 for (i
=0; i
<= p_end
; i
++) {
1016 if (i
== p_ptrn_lines
)
1020 fprintf(stderr
, "%3d %c %c %s", i
, p_char
[i
], special
, p_line
[i
]);
1025 if (p_end
+1 < hunkmax
) /* paranoia reigns supreme... */
1026 p_char
[p_end
+1] = '^'; /* add a stopper for apply_hunk */
1030 /* Input a line from the patch file, worrying about indentation. */
1038 char *ret
= fgets(bf
, sz
, fp
);
1040 Reg2
int indent
= 0;
1042 if (p_indent
&& ret
!= Nullch
) {
1044 indent
< p_indent
&& (*s
== ' ' || *s
== '\t' || *s
== 'X'); s
++) {
1046 indent
+= 8 - (indent
% 7);
1056 /* Reverse the old and new portions of the current hunk. */
1061 char **tp_line
; /* the text of the hunk */
1062 short *tp_len
; /* length of each line */
1063 char *tp_char
; /* +, -, and ! */
1066 bool blankline
= FALSE
;
1070 p_first
= p_newfirst
;
1073 /* make a scratch copy */
1078 p_line
= Null(char**); /* force set_hunkmax to allocate again */
1079 p_len
= Null(short*);
1082 if (p_line
== Null(char**) || p_len
== Null(short*) || p_char
== Nullch
) {
1084 if (p_line
== Null(char**))
1085 free((char*)p_line
);
1087 if (p_len
== Null(short*))
1091 if (p_char
== Nullch
)
1092 free((char*)p_char
);
1094 return FALSE
; /* not enough memory to swap hunk! */
1097 /* now turn the new into the old */
1099 i
= p_ptrn_lines
+ 1;
1100 if (tp_char
[i
] == '\n') { /* account for possible blank line */
1104 if (p_efake
>= 0) { /* fix non-freeable ptr range */
1112 for (n
=0; i
<= p_end
; i
++,n
++) {
1113 p_line
[n
] = tp_line
[i
];
1114 p_char
[n
] = tp_char
[i
];
1115 if (p_char
[n
] == '+')
1117 p_len
[n
] = tp_len
[i
];
1120 i
= p_ptrn_lines
+ 1;
1121 p_line
[n
] = tp_line
[i
];
1122 p_char
[n
] = tp_char
[i
];
1123 p_len
[n
] = tp_len
[i
];
1126 assert(p_char
[0] == '=');
1128 for (s
=p_line
[0]; *s
; s
++)
1132 /* now turn the old into the new */
1134 assert(tp_char
[0] == '*');
1136 for (s
=tp_line
[0]; *s
; s
++)
1139 for (i
=0; n
<= p_end
; i
++,n
++) {
1140 p_line
[n
] = tp_line
[i
];
1141 p_char
[n
] = tp_char
[i
];
1142 if (p_char
[n
] == '-')
1144 p_len
[n
] = tp_len
[i
];
1146 assert(i
== p_ptrn_lines
+ 1);
1148 p_ptrn_lines
= p_repl_lines
;
1151 if (tp_line
== Null(char**))
1152 free((char*)tp_line
);
1153 if (tp_len
== Null(short*))
1154 free((char*)tp_len
);
1156 if (tp_char
== Nullch
)
1157 free((char*)tp_char
);
1161 /* Return the specified line position in the old file of the old context. */
1169 /* Return the number of lines of old context. */
1174 return p_ptrn_lines
;
1177 /* Return the probable line position in the new file of the first line. */
1185 /* Return the number of lines in the replacement text including context. */
1190 return p_repl_lines
;
1193 /* Return the number of lines in the whole hunk. */
1201 /* Return the number of context lines before the first changed line. */
1209 /* Return the length of a particular patch line. */
1218 /* Return the control character (+, -, *, !, etc) for a patch line. */
1224 return p_char
[line
];
1227 /* Return a pointer to a particular patch line. */
1233 return p_line
[line
];
1236 /* Return where in the patch file this hunk began, for error messages. */
1244 /* Apply an ed script by feeding ed itself. */
1250 Reg2
long beginning_of_this_line
;
1251 Reg3
bool this_line_is_command
= FALSE
;
1254 if (!skip_rest_of_patch
) {
1256 copy_file(filearg
[0], TMPOUTNAME
);
1258 Sprintf(buf
, "/bin/ed %s", TMPOUTNAME
);
1260 Sprintf(buf
, "/bin/ed - %s", TMPOUTNAME
);
1261 pipefp
= popen(buf
, "w");
1264 beginning_of_this_line
= ftell(pfp
);
1265 if (pgets(buf
, sizeof buf
, pfp
) == Nullch
) {
1266 next_intuit_at(beginning_of_this_line
,p_input_line
);
1270 for (t
=buf
; isdigit(*t
) || *t
== ','; t
++) ;
1271 this_line_is_command
= (isdigit(*buf
) &&
1272 (*t
== 'd' || *t
== 'c' || *t
== 'a') );
1273 if (this_line_is_command
) {
1274 if (!skip_rest_of_patch
)
1277 while (pgets(buf
, sizeof buf
, pfp
) != Nullch
) {
1279 if (!skip_rest_of_patch
)
1281 if (strEQ(buf
, ".\n"))
1287 next_intuit_at(beginning_of_this_line
,p_input_line
);
1291 if (skip_rest_of_patch
)
1293 fprintf(pipefp
, "w\n");
1294 fprintf(pipefp
, "q\n");
1298 if (move_file(TMPOUTNAME
, outname
) < 0) {
1300 chmod(TMPOUTNAME
, filemode
);
1303 chmod(outname
, filemode
);