4 * Revision 1.1 2005/04/21 14:55:11 beng
7 * Revision 1.1.1.1 2005/04/20 13:33:19 beng
8 * Initial import of minix 2.0.4
10 * Revision 2.0.1.7 88/06/03 15:13:28 lwall
11 * patch10: Can now find patches in shar scripts.
12 * patch10: Hunks that swapped and then swapped back could core dump.
14 * Revision 2.0.1.6 87/06/04 16:18:13 lwall
15 * pch_swap didn't swap p_bfake and p_efake.
17 * Revision 2.0.1.5 87/01/30 22:47:42 lwall
18 * Improved responses to mangled patches.
20 * Revision 2.0.1.4 87/01/05 16:59:53 lwall
21 * New-style context diffs caused double call to free().
23 * Revision 2.0.1.3 86/11/14 10:08:33 lwall
24 * Fixed problem where a long pattern wouldn't grow the hunk.
25 * Also restored p_input_line when backtracking so error messages are right.
27 * Revision 2.0.1.2 86/11/03 17:49:52 lwall
28 * New-style delete triggers spurious assertion error.
30 * Revision 2.0.1.1 86/10/29 15:52:08 lwall
31 * Could falsely report new-style context diff.
33 * Revision 2.0 86/09/17 15:39:37 lwall
34 * Baseline for netwide release.
44 /* Patch (diff listing) abstract type. */
46 static long p_filesize
; /* size of the patch file */
47 static LINENUM p_first
; /* 1st line number */
48 static LINENUM p_newfirst
; /* 1st line number of replacement */
49 static LINENUM p_ptrn_lines
; /* # lines in pattern */
50 static LINENUM p_repl_lines
; /* # lines in replacement text */
51 static LINENUM p_end
= -1; /* last line in hunk */
52 static LINENUM p_max
; /* max allowed value of p_end */
53 static LINENUM p_context
= 3; /* # of context lines */
54 static LINENUM p_input_line
= 0; /* current line # from patch file */
56 static long *p_line
= Null(long *); /* the text of the hunk */
58 static char **p_line
= Null(char**); /* the text of the hunk */
60 static short *p_len
= Null(short*); /* length of each line */
61 static char *p_char
= Nullch
; /* +, -, and ! */
62 static int hunkmax
= INITHUNKMAX
; /* size of above arrays to begin with */
63 static int p_indent
; /* indent to patch */
64 static LINENUM p_base
; /* where to intuit this time */
65 static LINENUM p_bline
; /* line # of p_base */
66 static LINENUM p_start
; /* where intuit found a patch */
67 static LINENUM p_sline
; /* and the line number for it */
68 static LINENUM p_hunk_beg
; /* line number of current hunk */
69 static LINENUM p_efake
= -1; /* end of faked up lines--don't free */
70 static LINENUM p_bfake
= -1; /* beg of faked up lines */
72 /* Prepare to look for the next patch in the patch file. */
79 p_ptrn_lines
= Nulline
;
80 p_repl_lines
= Nulline
;
86 /* Open the patch file at the beginning of time. */
89 open_patch_file(filename
)
92 if (filename
== Nullch
|| !*filename
|| strEQ(filename
, "-")) {
93 pfp
= fopen(TMPPATNAME
, "w");
95 fatal2("patch: can't create %s.\n", TMPPATNAME
);
96 while (fgets(buf
, sizeof buf
, stdin
) != Nullch
)
99 filename
= TMPPATNAME
;
101 pfp
= fopen(filename
, "r");
103 fatal2("patch file %s not found\n", filename
);
104 Fstat(fileno(pfp
), &filestat
);
105 p_filesize
= filestat
.st_size
;
106 next_intuit_at(0L,1L); /* start at the beginning */
110 /* Make sure our dynamically realloced tables are malloced to begin with. */
117 if (p_line
== Null(long*))
119 if (p_line
== Null(char**))
122 p_line
= (long *) malloc((MEM
)hunkmax
* sizeof(long));
124 p_line
= (char**) malloc((MEM
)hunkmax
* sizeof(char *));
126 if (p_len
== Null(short*))
127 p_len
= (short*) malloc((MEM
)hunkmax
* sizeof(short));
129 if (p_char
== Nullch
)
130 p_char
= (char*) malloc((MEM
)hunkmax
* sizeof(char));
133 /* Enlarge the arrays containing the current hunk of patch. */
140 * Note that on most systems, only the p_line array ever gets fresh memory
141 * since p_len can move into p_line's old space, and p_char can move into
142 * p_len's old space. Not on PDP-11's however. But it doesn't matter.
145 assert(p_line
!= Null(long*) && p_len
!= Null(short*) && p_char
!= Nullch
);
147 assert(p_line
!= Null(char**) && p_len
!= Null(short*) && p_char
!= Nullch
);
151 p_line
= (long*) realloc((char*)p_line
, (MEM
)hunkmax
* sizeof(long));
153 p_line
= (char**) realloc((char*)p_line
, (MEM
)hunkmax
* sizeof(char *));
155 p_len
= (short*) realloc((char*)p_len
, (MEM
)hunkmax
* sizeof(short));
156 p_char
= (char*) realloc((char*)p_char
, (MEM
)hunkmax
* sizeof(char));
159 if (p_line
!= Null(long*) && p_len
!= Null(short*) && p_char
!= Nullch
)
161 if (p_line
!= Null(char**) && p_len
!= Null(short*) && p_char
!= Nullch
)
165 fatal1("patch: out of memory (grow_hunkmax)\n");
166 out_of_mem
= TRUE
; /* whatever is null will be allocated again */
167 /* from within plan_a(), of all places */
170 /* True if the remainder of the patch file contains a diff of some sort. */
173 there_is_another_patch()
175 if (p_base
!= 0L && p_base
>= p_filesize
) {
182 diff_type
= intuit_diff_type();
186 say1(" Ignoring the trailing garbage.\ndone\n");
189 say1(" I can't seem to find a patch in there anywhere.\n");
193 say3(" %sooks like %s to me...\n",
194 (p_base
== 0L ? "L" : "The next patch l"),
195 diff_type
== CONTEXT_DIFF
? "a context diff" :
196 diff_type
== NEW_CONTEXT_DIFF
? "a new-style context diff" :
197 diff_type
== NORMAL_DIFF
? "a normal diff" :
199 if (p_indent
&& verbose
)
200 say3("(Patch is indented %d space%s.)\n", p_indent
, p_indent
==1?"":"s");
201 skip_to(p_start
,p_sline
);
202 while (filearg
[0] == Nullch
) {
204 say1("No file to patch. Skipping...\n");
205 filearg
[0] = savestr(bestguess
);
208 ask1("File to patch: ");
212 bestguess
= savestr(buf
);
213 filearg
[0] = fetchname(buf
, 0, FALSE
);
215 if (filearg
[0] == Nullch
) {
216 ask1("No file found--skip this patch? [n] ");
221 say1("Skipping patch...\n");
222 filearg
[0] = fetchname(bestguess
, 0, TRUE
);
223 skip_rest_of_patch
= TRUE
;
230 /* Determine what kind of diff is in the remaining part of the patch file. */
235 Reg4
long this_line
= 0;
236 Reg5
long previous_line
;
237 Reg6
long first_command_line
= -1;
239 Reg7
bool last_line_was_command
= FALSE
;
240 Reg8
bool this_is_a_command
= FALSE
;
241 Reg9
bool stars_last_line
= FALSE
;
242 Reg10
bool stars_this_line
= FALSE
;
246 char *indtmp
= Nullch
;
247 char *oldtmp
= Nullch
;
248 char *newtmp
= Nullch
;
249 char *indname
= Nullch
;
250 char *oldname
= Nullch
;
251 char *newname
= Nullch
;
253 bool no_filearg
= (filearg
[0] == Nullch
);
255 ok_to_create_file
= FALSE
;
256 Fseek(pfp
, p_base
, 0);
257 p_input_line
= p_bline
- 1;
259 previous_line
= this_line
;
260 last_line_was_command
= this_is_a_command
;
261 stars_last_line
= stars_this_line
;
262 this_line
= ftell(pfp
);
265 if (fgets(buf
, sizeof buf
, pfp
) == Nullch
) {
266 if (first_command_line
>= 0L) {
267 /* nothing but deletes!? */
268 p_start
= first_command_line
;
275 p_sline
= p_input_line
;
280 for (s
= buf
; *s
== ' ' || *s
== '\t' || *s
== 'X'; s
++) {
282 indent
+= 8 - (indent
% 8);
286 for (t
=s
; isdigit(*t
) || *t
== ','; t
++) ;
287 this_is_a_command
= (isdigit(*s
) &&
288 (*t
== 'd' || *t
== 'c' || *t
== 'a') );
289 if (first_command_line
< 0L && this_is_a_command
) {
290 first_command_line
= this_line
;
291 fcl_line
= p_input_line
;
292 p_indent
= indent
; /* assume this for now */
294 if (!stars_last_line
&& strnEQ(s
, "*** ", 4))
295 oldtmp
= savestr(s
+4);
296 else if (strnEQ(s
, "--- ", 4))
297 newtmp
= savestr(s
+4);
298 else if (strnEQ(s
, "Index:", 6))
299 indtmp
= savestr(s
+6);
300 else if (strnEQ(s
, "Prereq:", 7)) {
301 for (t
=s
+7; isspace(*t
); t
++) ;
302 revision
= savestr(t
);
303 for (t
=revision
; *t
&& !isspace(*t
); t
++) ;
310 if ((!diff_type
|| diff_type
== ED_DIFF
) &&
311 first_command_line
>= 0L &&
314 p_start
= first_command_line
;
319 stars_this_line
= strnEQ(s
, "********", 8);
320 if ((!diff_type
|| diff_type
== CONTEXT_DIFF
) && stars_last_line
&&
321 strnEQ(s
, "*** ", 4)) {
323 ok_to_create_file
= TRUE
;
324 /* if this is a new context diff the character just before */
325 /* the newline is a '*'. */
329 p_start
= previous_line
;
330 p_sline
= p_input_line
- 1;
331 retval
= (*(s
-1) == '*' ? NEW_CONTEXT_DIFF
: CONTEXT_DIFF
);
334 if ((!diff_type
|| diff_type
== NORMAL_DIFF
) &&
335 last_line_was_command
&&
336 (strnEQ(s
, "< ", 2) || strnEQ(s
, "> ", 2)) ) {
337 p_start
= previous_line
;
338 p_sline
= p_input_line
- 1;
340 retval
= NORMAL_DIFF
;
346 if (indtmp
!= Nullch
)
347 indname
= fetchname(indtmp
, strippath
, ok_to_create_file
);
348 if (oldtmp
!= Nullch
)
349 oldname
= fetchname(oldtmp
, strippath
, ok_to_create_file
);
350 if (newtmp
!= Nullch
)
351 newname
= fetchname(newtmp
, strippath
, ok_to_create_file
);
352 if (oldname
&& newname
) {
353 if (strlen(oldname
) < strlen(newname
))
354 filearg
[0] = savestr(oldname
);
356 filearg
[0] = savestr(newname
);
359 filearg
[0] = savestr(oldname
);
361 filearg
[0] = savestr(newname
);
363 filearg
[0] = savestr(indname
);
369 if (filearg
[0] != Nullch
)
370 bestguess
= savestr(filearg
[0]);
371 else if (indtmp
!= Nullch
)
372 bestguess
= fetchname(indtmp
, strippath
, TRUE
);
374 if (oldtmp
!= Nullch
)
375 oldname
= fetchname(oldtmp
, strippath
, TRUE
);
376 if (newtmp
!= Nullch
)
377 newname
= fetchname(newtmp
, strippath
, TRUE
);
378 if (oldname
&& newname
) {
379 if (strlen(oldname
) < strlen(newname
))
380 bestguess
= savestr(oldname
);
382 bestguess
= savestr(newname
);
385 bestguess
= savestr(oldname
);
387 bestguess
= savestr(newname
);
389 if (indtmp
!= Nullch
)
391 if (oldtmp
!= Nullch
)
393 if (newtmp
!= Nullch
)
395 if (indname
!= Nullch
)
397 if (oldname
!= Nullch
)
399 if (newname
!= Nullch
)
404 /* Remember where this patch ends so we know where to start up again. */
407 next_intuit_at(file_pos
,file_line
)
415 /* Basically a verbose fseek() to the actual diff listing. */
418 skip_to(file_pos
,file_line
)
424 assert(p_base
<= file_pos
);
425 if (verbose
&& p_base
< file_pos
) {
426 Fseek(pfp
, p_base
, 0);
427 say1("The text leading up to this was:\n--------------------------\n");
428 while (ftell(pfp
) < file_pos
) {
429 ret
= fgets(buf
, sizeof buf
, pfp
);
430 assert(ret
!= Nullch
);
433 say1("--------------------------\n");
436 Fseek(pfp
, file_pos
, 0);
437 p_input_line
= file_line
- 1;
440 /* True if there is more of the current diff listing to process. */
447 Reg2
int context
= 0;
450 if (p_end
== p_efake
)
451 p_end
= p_bfake
; /* don't free twice */
463 sfp
= fopen(TMPSTRNAME
, "w");
465 fatal2("patch: can't create %s.\n", TMPSTRNAME
);
468 p_max
= hunkmax
; /* gets reduced when --- found */
469 if (diff_type
== CONTEXT_DIFF
|| diff_type
== NEW_CONTEXT_DIFF
) {
470 long line_beginning
= ftell(pfp
);
471 /* file pos of the current line */
472 LINENUM repl_beginning
= 0; /* index of --- line */
473 Reg4 LINENUM fillcnt
= 0; /* #lines of missing ptrn or repl */
474 Reg5 LINENUM fillsrc
; /* index of first line to copy */
475 Reg6 LINENUM filldst
; /* index of first missing line */
476 bool ptrn_spaces_eaten
= FALSE
; /* ptrn was slightly misformed */
477 Reg9
bool repl_could_be_missing
= TRUE
;
478 /* no + or ! lines in this hunk */
479 bool repl_missing
= FALSE
; /* we are now backtracking */
480 long repl_backtrack_position
= 0;
481 /* file pos of first repl line */
482 LINENUM repl_patch_line
; /* input line number for same */
483 Reg7 LINENUM ptrn_copiable
= 0;
484 /* # of copiable lines in ptrn */
486 ret
= pgets(buf
, sizeof buf
, pfp
);
488 if (ret
== Nullch
|| strnNE(buf
, "********", 8)) {
489 next_intuit_at(line_beginning
,p_input_line
);
493 p_hunk_beg
= p_input_line
+ 1;
494 while (p_end
< p_max
) {
495 line_beginning
= ftell(pfp
);
496 ret
= pgets(buf
, sizeof buf
, pfp
);
499 if (p_max
- p_end
< 4)
500 Strcpy(buf
, " \n"); /* assume blank lines got chopped */
502 if (repl_beginning
&& repl_could_be_missing
) {
506 fatal1("Unexpected end of file in patch.\n");
510 assert(p_end
< hunkmax
);
511 p_char
[p_end
] = *buf
;
513 p_line
[(short)p_end
] = Nullch
;
519 p_line
[p_end
] = Nullch
;
524 if (strnEQ(buf
, "********", 8)) {
525 if (repl_beginning
&& repl_could_be_missing
) {
530 fatal2("Unexpected end of hunk at line %ld.\n",
534 if (repl_beginning
&& repl_could_be_missing
) {
538 fatal3("Unexpected *** at line %ld: %s", p_input_line
, buf
);
542 p_line
[p_end
] = saveStr(buf
, p_len
+p_end
);
544 p_line
[p_end
] = savestr(buf
);
550 for (s
=buf
; *s
&& !isdigit(*s
); s
++) ;
553 if (strnEQ(s
,"0,0",3))
555 p_first
= (LINENUM
) atol(s
);
556 while (isdigit(*s
)) s
++;
558 for (; *s
&& !isdigit(*s
); s
++) ;
561 p_ptrn_lines
= ((LINENUM
)atol(s
)) - p_first
+ 1;
569 p_max
= p_ptrn_lines
+ 6; /* we need this much at least */
570 while (p_max
>= hunkmax
)
576 if (repl_beginning
||
577 (p_end
!= p_ptrn_lines
+ 1 + (p_char
[p_end
-1] == '\n')))
580 /* `old' lines were omitted - set up to fill */
581 /* them in from 'new' context lines. */
582 p_end
= p_ptrn_lines
+ 1;
585 fillcnt
= p_ptrn_lines
;
588 if (repl_beginning
) {
589 if (repl_could_be_missing
){
594 "Duplicate \"---\" at line %ld--check line numbers at line %ld.\n",
595 p_input_line
, p_hunk_beg
+ repl_beginning
);
599 "%s \"---\" at line %ld--check line numbers at line %ld.\n",
600 (p_end
<= p_ptrn_lines
603 p_input_line
, p_hunk_beg
);
607 repl_beginning
= p_end
;
608 repl_backtrack_position
= ftell(pfp
);
609 repl_patch_line
= p_input_line
;
611 p_line
[p_end
] = saveStr(buf
, p_len
+p_end
);
613 p_line
[p_end
] = savestr(buf
);
620 for (s
=buf
; *s
&& !isdigit(*s
); s
++) ;
623 p_newfirst
= (LINENUM
) atol(s
);
624 while (isdigit(*s
)) s
++;
626 for (; *s
&& !isdigit(*s
); s
++) ;
629 p_repl_lines
= ((LINENUM
)atol(s
)) - p_newfirst
+ 1;
637 p_max
= p_repl_lines
+ p_end
;
638 if (p_max
> MAXHUNKSIZE
)
639 fatal4("Hunk too large (%ld lines) at line %ld: %s",
640 p_max
, p_input_line
, buf
);
641 while (p_max
>= hunkmax
)
643 if (p_repl_lines
!= ptrn_copiable
)
644 repl_could_be_missing
= FALSE
;
649 repl_could_be_missing
= FALSE
;
651 if (buf
[1] == '\n' && canonicalize
)
653 if (!isspace(buf
[1]) && buf
[1] != '>' && buf
[1] != '<' &&
654 repl_beginning
&& repl_could_be_missing
) {
659 if (context
< p_context
)
664 p_line
[p_end
] = saveStr(buf
+2, p_len
+p_end
);
666 p_line
[p_end
] = savestr(buf
+2);
673 case '\t': case '\n': /* assume the 2 spaces got eaten */
674 if (repl_beginning
&& repl_could_be_missing
&&
675 (!ptrn_spaces_eaten
|| diff_type
== NEW_CONTEXT_DIFF
) ) {
680 p_line
[p_end
] = saveStr(buf
, p_len
+p_end
);
682 p_line
[p_end
] = savestr(buf
);
688 if (p_end
!= p_ptrn_lines
+ 1) {
689 ptrn_spaces_eaten
|= (repl_beginning
!= 0);
697 if (!isspace(buf
[1]) &&
698 repl_beginning
&& repl_could_be_missing
) {
706 p_line
[p_end
] = saveStr(buf
+2, p_len
+p_end
);
708 p_line
[p_end
] = savestr(buf
+2);
716 if (repl_beginning
&& repl_could_be_missing
) {
722 /* set up p_len for strncmp() so we don't have to */
723 /* assume null termination */
726 p_len
[p_end
] = strlen(p_line
[p_end
]);
733 if (p_end
>=0 && !repl_beginning
)
734 fatal2("No --- found in patch at line %ld\n", pch_hunk_beg());
738 /* reset state back to just after --- */
739 p_input_line
= repl_patch_line
;
741 for (p_end
--; p_end
> repl_beginning
; p_end
--)
744 Fseek(pfp
, repl_backtrack_position
, 0);
746 /* redundant 'new' context lines were omitted - set */
747 /* up to fill them in from the old file context */
749 filldst
= repl_beginning
+1;
750 fillcnt
= p_repl_lines
;
754 if (diff_type
== CONTEXT_DIFF
&&
755 (fillcnt
|| (p_first
> 1 && ptrn_copiable
> 2*p_context
)) ) {
758 "(Fascinating--this is really a new-style context diff but without",
759 "the telltale extra asterisks on the *** line that usually indicate",
760 "the new style...)");
761 diff_type
= NEW_CONTEXT_DIFF
;
764 /* if there were omitted context lines, fill them in now */
766 p_bfake
= filldst
; /* remember where not to free() */
767 p_efake
= filldst
+ fillcnt
- 1;
768 while (fillcnt
-- > 0) {
769 while (fillsrc
<= p_end
&& p_char
[fillsrc
] != ' ')
772 fatal2("Replacement text or line numbers mangled in hunk at line %ld\n",
774 p_line
[filldst
] = p_line
[fillsrc
];
775 p_char
[filldst
] = p_char
[fillsrc
];
776 p_len
[filldst
] = p_len
[fillsrc
];
777 fillsrc
++; filldst
++;
779 while (fillsrc
<= p_end
&& fillsrc
!= repl_beginning
&&
780 p_char
[fillsrc
] != ' ')
784 printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
785 fillsrc
,filldst
,repl_beginning
,p_end
+1);
787 assert(fillsrc
==p_end
+1 || fillsrc
==repl_beginning
);
788 assert(filldst
==p_end
+1 || filldst
==repl_beginning
);
791 else { /* normal diff--fake it up */
795 long line_beginning
= ftell(pfp
);
798 ret
= pgets(buf
, sizeof buf
, pfp
);
800 if (ret
== Nullch
|| !isdigit(*buf
)) {
801 next_intuit_at(line_beginning
,p_input_line
);
804 p_first
= (LINENUM
)atol(buf
);
805 for (s
=buf
; isdigit(*s
); s
++) ;
807 p_ptrn_lines
= (LINENUM
)atol(++s
) - p_first
+ 1;
808 while (isdigit(*s
)) s
++;
811 p_ptrn_lines
= (*s
!= 'a');
813 if (hunk_type
== 'a')
814 p_first
++; /* do append rather than insert */
815 min
= (LINENUM
)atol(++s
);
816 for (; isdigit(*s
); s
++) ;
818 max
= (LINENUM
)atol(++s
);
821 if (hunk_type
== 'd')
823 p_end
= p_ptrn_lines
+ 1 + max
- min
+ 1;
824 if (p_end
> MAXHUNKSIZE
)
825 fatal4("Hunk too large (%ld lines) at line %ld: %s",
826 p_end
, p_input_line
, buf
);
827 while (p_end
>= hunkmax
)
830 p_repl_lines
= max
- min
+ 1;
831 Sprintf(buf
, "*** %ld,%ld\n", p_first
, p_first
+ p_ptrn_lines
- 1);
833 p_line
[0] = saveStr(buf
, p_len
);
835 p_line
[0] = savestr(buf
);
842 for (i
=1; i
<=p_ptrn_lines
; i
++) {
843 ret
= pgets(buf
, sizeof buf
, pfp
);
846 fatal2("Unexpected end of file in patch at line %ld.\n",
849 fatal2("< expected at line %ld of patch.\n", p_input_line
);
851 p_line
[i
] = saveStr(buf
+2, p_len
+i
);
853 p_line
[i
] = savestr(buf
+2);
860 p_len
[i
] = strlen(p_line
[i
]);
864 if (hunk_type
== 'c') {
865 ret
= pgets(buf
, sizeof buf
, pfp
);
868 fatal2("Unexpected end of file in patch at line %ld.\n",
871 fatal2("--- expected at line %ld of patch.\n", p_input_line
);
873 Sprintf(buf
, "--- %ld,%ld\n", min
, max
);
875 p_line
[i
] = saveStr(buf
, p_len
+i
);
877 p_line
[i
] = savestr(buf
);
884 for (i
++; i
<=p_end
; i
++) {
885 ret
= pgets(buf
, sizeof buf
, pfp
);
888 fatal2("Unexpected end of file in patch at line %ld.\n",
891 fatal2("> expected at line %ld of patch.\n", p_input_line
);
893 p_line
[i
] = saveStr(buf
+2, p_len
+i
);
895 p_line
[i
] = savestr(buf
+2);
902 p_len
[i
] = strlen(p_line
[i
]);
907 if (reverse
) /* backwards patch? */
909 say1("Not enough memory to swap next hunk!\n");
912 sfp
= fopen(TMPSTRNAME
, "r");
919 for (i
=0; i
<= p_end
; i
++) {
920 if (i
== p_ptrn_lines
)
925 fprintf(stderr
, "%3d %c %c %s", i
, p_char
[i
], special
, pfetch(i
));
927 fprintf(stderr
, "%3d %c %c %s", i
, p_char
[i
], special
, p_line
[i
]);
933 if (p_end
+1 < hunkmax
) /* paranoia reigns supreme... */
934 p_char
[p_end
+1] = '^'; /* add a stopper for apply_hunk */
942 fatal3("Malformed patch at line %ld: %s", p_input_line
, buf
);
943 /* about as informative as "Syntax error" in C */
944 return FALSE
; /* for lint */
947 /* Input a line from the patch file, worrying about indentation. */
955 char *ret
= fgets(bf
, sz
, fp
);
959 if (p_indent
&& ret
!= Nullch
) {
961 indent
< p_indent
&& (*s
== ' ' || *s
== '\t' || *s
== 'X'); s
++) {
963 indent
+= 8 - (indent
% 7);
973 /* Reverse the old and new portions of the current hunk. */
979 long *tp_line
; /* the text of the hunk */
981 char **tp_line
; /* the text of the hunk */
983 short *tp_len
; /* length of each line */
984 char *tp_char
; /* +, -, and ! */
987 bool blankline
= FALSE
;
991 p_first
= p_newfirst
;
994 /* make a scratch copy */
1000 p_line
= Null(long*); /* force set_hunkmax to allocate again */
1002 p_line
= Null(char**); /* force set_hunkmax to allocate again */
1004 p_len
= Null(short*);
1008 if (p_line
== Null(long*) || p_len
== Null(short*) || p_char
== Nullch
) {
1010 if (p_line
== Null(char**) || p_len
== Null(short*) || p_char
== Nullch
) {
1014 if (p_line
== Null(long*))
1016 if (p_line
== Null(char**))
1018 free((char*)p_line
);
1020 if (p_len
== Null(short*))
1024 if (p_char
== Nullch
)
1025 free((char*)p_char
);
1027 return FALSE
; /* not enough memory to swap hunk! */
1030 /* now turn the new into the old */
1032 i
= p_ptrn_lines
+ 1;
1033 if (tp_char
[i
] == '\n') { /* account for possible blank line */
1037 if (p_efake
>= 0) { /* fix non-freeable ptr range */
1045 for (n
=0; i
<= p_end
; i
++,n
++) {
1046 p_line
[n
] = tp_line
[i
];
1047 p_char
[n
] = tp_char
[i
];
1048 if (p_char
[n
] == '+')
1050 p_len
[n
] = tp_len
[i
];
1053 i
= p_ptrn_lines
+ 1;
1054 p_line
[n
] = tp_line
[i
];
1055 p_char
[n
] = tp_char
[i
];
1056 p_len
[n
] = tp_len
[i
];
1059 assert(p_char
[0] == '=');
1062 strEdit(p_line
[0], '*', '-');
1064 for (s
=p_line
[0]; *s
; s
++)
1069 /* now turn the old into the new */
1071 assert(tp_char
[0] == '*');
1074 strEdit(tp_line
[0], '-', '*');
1076 for (s
=tp_line
[0]; *s
; s
++)
1080 for (i
=0; n
<= p_end
; i
++,n
++) {
1081 p_line
[n
] = tp_line
[i
];
1082 p_char
[n
] = tp_char
[i
];
1083 if (p_char
[n
] == '-')
1085 p_len
[n
] = tp_len
[i
];
1087 assert(i
== p_ptrn_lines
+ 1);
1089 p_ptrn_lines
= p_repl_lines
;
1093 if (tp_line
== Null(long*))
1095 if (tp_line
== Null(char**))
1097 free((char*)tp_line
);
1098 if (tp_len
== Null(short*))
1099 free((char*)tp_len
);
1101 if (tp_char
== Nullch
)
1102 free((char*)tp_char
);
1106 /* Return the specified line position in the old file of the old context. */
1114 /* Return the number of lines of old context. */
1119 return p_ptrn_lines
;
1122 /* Return the probable line position in the new file of the first line. */
1130 /* Return the number of lines in the replacement text including context. */
1135 return p_repl_lines
;
1138 /* Return the number of lines in the whole hunk. */
1146 /* Return the number of context lines before the first changed line. */
1154 /* Return the length of a particular patch line. */
1163 /* Return the control character (+, -, *, !, etc) for a patch line. */
1169 return p_char
[line
];
1172 /* Return a pointer to a particular patch line. */
1185 fwrite(str
, sizeof(char), len
+1, sfp
);
1194 static char *s
, strbuf
[BUFSIZ
];
1197 if (p_line
[line
] == -1L)
1200 Fseek(sfp
, p_line
[line
], 0);
1201 for (i
= 0, s
= strbuf
;
1202 i
< BUFSIZ
&& (c
= fgetc(sfp
)) != EOF
&& c
; i
++)
1205 fatal2("too long line (%.40s ..\n", strbuf
);
1212 strEdit(pos
, to
, from
)
1216 static char *s
, strbuf
[BUFSIZ
];
1220 for (i
= 0, s
= strbuf
;
1221 i
< BUFSIZ
&& (c
= fgetc(sfp
)) != EOF
&& c
; i
++)
1223 for (s
= strbuf
; *s
; s
++)
1226 fwrite(strbuf
, sizeof(char), i
+1, sfp
);
1234 return p_line
[line
];
1238 /* Return where in the patch file this hunk began, for error messages. */
1246 /* Apply an ed script by feeding ed itself. */
1252 Reg2
long beginning_of_this_line
;
1253 Reg3
bool this_line_is_command
= FALSE
;
1256 if (!skip_rest_of_patch
) {
1258 copy_file(filearg
[0], TMPOUTNAME
);
1260 Sprintf(buf
, "/bin/ed %s", TMPOUTNAME
);
1262 Sprintf(buf
, "/bin/ed - %s", TMPOUTNAME
);
1263 pipefp
= popen(buf
, "w");
1266 beginning_of_this_line
= ftell(pfp
);
1267 if (pgets(buf
, sizeof buf
, pfp
) == Nullch
) {
1268 next_intuit_at(beginning_of_this_line
,p_input_line
);
1272 for (t
=buf
; isdigit(*t
) || *t
== ','; t
++) ;
1273 this_line_is_command
= (isdigit(*buf
) &&
1274 (*t
== 'd' || *t
== 'c' || *t
== 'a') );
1275 if (this_line_is_command
) {
1276 if (!skip_rest_of_patch
)
1279 while (pgets(buf
, sizeof buf
, pfp
) != Nullch
) {
1281 if (!skip_rest_of_patch
)
1283 if (strEQ(buf
, ".\n"))
1289 next_intuit_at(beginning_of_this_line
,p_input_line
);
1293 if (skip_rest_of_patch
)
1295 fprintf(pipefp
, "w\n");
1296 fprintf(pipefp
, "q\n");
1300 if (move_file(TMPOUTNAME
, outname
) < 0) {
1302 chmod(TMPOUTNAME
, filemode
);
1305 chmod(outname
, filemode
);