1 /* @(#)pch.c 1.38 19/08/17 2011-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)pch.c 1.38 19/08/17 2011-2019 J. Schilling";
6 #endif
7 /*
8 * Copyright (c) 1986-1988 Larry Wall
9 * Copyright (c) 1990 Wayne Davison
10 * Copyright (c) 2011-2019 J. Schilling
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following condition is met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this condition and the following disclaimer.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #define EXT extern
32 #include "common.h"
33 #include "util.h"
34 #undef EXT
35 #define EXT
36 #include "pch.h"
37
38 /* Patch (diff listing) abstract type. */
39
40 static FILE *pfp; /* patch file pointer */
41 static off_t p_filesize; /* size of the patch file */
42 static LINENUM p_first; /* 1st line number */
43 static LINENUM p_newfirst; /* 1st line number of replacement */
44 static LINENUM p_ptrn_lines; /* # lines in pattern */
45 EXT LINENUM p_repl_lines; /* # lines in replacement text */
46 static LINENUM p_end = -1; /* last line in hunk */
47 static LINENUM p_max; /* max allowed value of p_end */
48 static LINENUM p_context = 3; /* # of context lines */
49 static LINENUM p_input_line = 0; /* current line # from patch file */
50 static char **p_line = Null(char **); /* the text of the hunk */
51 static size_t *p_len = Null(size_t *); /* length of each line */
52 static char *p_char = Nullch; /* +, -, and ! */
53 static LINENUM hunkmax = INITHUNKMAX; /* size of above arrays to begin with */
54 static size_t p_indent; /* indent to patch */
55 static LINENUM p_base; /* where to intuit this time */
56 static LINENUM p_bline; /* line # of p_base */
57 static LINENUM p_start; /* where intuit found a patch */
58 static LINENUM p_sline; /* and the line number for it */
59 static LINENUM p_hunk_beg; /* line number of current hunk */
60 static LINENUM p_efake = -1; /* end of faked up lines--don't free */
61 static LINENUM p_bfake = -1; /* beg of faked up lines */
62
63 static void grow_hunkmax __PR((void));
64 static int intuit_diff_type __PR((void));
65 static void next_intuit_at __PR((LINENUM file_pos, LINENUM file_line));
66 static void skip_to __PR((off_t file_pos, off_t file_line));
67 static void malformed __PR((void));
68 static ssize_t pgets __PR((char **bfp, size_t *szp, FILE *fp));
69
70 /* Prepare to look for the next patch in the patch file. */
71
72 void
re_patch()73 re_patch()
74 {
75 p_first = Nulline;
76 p_newfirst = Nulline;
77 p_ptrn_lines = Nulline;
78 p_repl_lines = Nulline;
79 p_end = (LINENUM)-1;
80 p_max = Nulline;
81 p_indent = 0;
82 }
83
84 /* Open the patch file at the beginning of time. */
85
86 void
open_patch_file(filename)87 open_patch_file(filename)
88 char *filename;
89 {
90 if (filename == Nullch || !*filename || strEQ(filename, "-")) {
91 pfp = fopen(TMPPATNAME, "w");
92 if (pfp == Nullfp)
93 pfatal(_("can't create %s.\n"), TMPPATNAME);
94 while (fgetaline(stdin, &buf, &bufsize) > 0)
95 fputs(buf, pfp);
96 Fclose(pfp);
97 filename = TMPPATNAME;
98 }
99 pfp = fopen(filename, "r");
100 if (pfp == Nullfp)
101 pfatal(_("patch file %s not found\n"), filename);
102 Fstat(fileno(pfp), &file_stat);
103 p_filesize = file_stat.st_size;
104 next_intuit_at((LINENUM)0, (LINENUM)1); /* start at the beginning */
105 set_hunkmax();
106 }
107
108 /* Make sure our dynamically realloced tables are malloced to begin with. */
109
110 void
set_hunkmax()111 set_hunkmax()
112 {
113 if (p_line == Null(char **))
114 p_line = (char **) malloc(hunkmax * sizeof (char *));
115 if (p_len == Null(size_t *))
116 p_len = (size_t *) malloc(hunkmax * sizeof (size_t));
117 if (p_char == Nullch)
118 p_char = (char *) malloc(hunkmax * sizeof (char));
119 }
120
121 /* Enlarge the arrays containing the current hunk of patch. */
122
123 static void
grow_hunkmax()124 grow_hunkmax()
125 {
126 char **op_line = p_line;
127 size_t *op_len = p_len;
128 char *op_char = p_char;
129
130 hunkmax *= 2;
131 /*
132 * Note that on most systems, only the p_line array ever gets fresh
133 * memory since p_len can move into p_line's old space, and p_char can
134 * move into p_len's old space. Not on PDP-11's however. But it
135 * doesn't matter.
136 */
137 assert(p_line != Null(char **) &&
138 p_len != Null(size_t *) &&
139 p_char != Nullch);
140 p_line = (char **) realloc((char *)p_line, hunkmax * sizeof (char *));
141 p_len = (size_t *) realloc((char *)p_len, hunkmax * sizeof (size_t));
142 p_char = (char *) realloc((char *)p_char, hunkmax * sizeof (char));
143 if (p_line != Null(char **) &&
144 p_len != Null(size_t *) &&
145 p_char != Nullch) {
146 return;
147 }
148 if (p_line == Null(char **))
149 p_line = op_line;
150 if (p_len == Null(size_t *))
151 p_len = op_len;
152 if (p_char == Null(char *))
153 p_char = op_char;
154 hunkmax /= 2;
155
156 if (!using_plan_a)
157 fatal(_("patch: out of memory (grow_hunkmax)\n"));
158
159 out_of_mem = TRUE; /* whatever is null will be allocated again */
160 /* from within plan_a(), of all places */
161 }
162
163 /* True if the remainder of the patch file contains a diff of some sort. */
164
165 bool
there_is_another_patch()166 there_is_another_patch()
167 {
168 if (p_base != 0L && p_base >= p_filesize) {
169 if (verbose)
170 say(_("done\n"));
171 return (FALSE);
172 }
173 if (verbose)
174 say(_("Hmm..."));
175 diff_type = intuit_diff_type();
176 if (!diff_type) {
177 if (p_base != 0L) {
178 if (verbose)
179 say(_(" Ignoring the trailing garbage.\ndone\n"));
180 } else {
181 say(_(" I can't seem to find a patch in there anywhere.\n"));
182 }
183 return (FALSE);
184 }
185 if (verbose)
186 say(p_base == 0L ?
187 _(" Looks like %s to me...\n") :
188 _(" The next patch looks like %s to me...\n"),
189 diff_type == UNI_DIFF ? "a unified diff" :
190 diff_type == CONTEXT_DIFF ? "a context diff" :
191 diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
192 diff_type == NORMAL_DIFF ? "a normal diff" :
193 "an ed script");
194 if (p_indent && verbose) {
195 if (p_indent == 1)
196 say("(Patch is indented 1 space.)\n");
197 else
198 say("(Patch is indented %lld spaces.)\n",
199 (Llong)p_indent);
200 }
201 skip_to(p_start, p_sline);
202 while (filearg[0] == Nullch) {
203 if (force) {
204 say(_("No file to patch. Skipping...\n"));
205 filearg[0] = savestr(bestguess);
206 return (TRUE);
207 }
208 ask(_("File to patch: "));
209 if (*buf != '\n') {
210 if (bestguess)
211 free(bestguess);
212 bestguess = savestr(buf);
213 filearg[0] = fetchname(buf, 0, FALSE, NULL);
214 }
215 if (filearg[0] == Nullch) {
216 ask(_("No file found--skip this patch? [n] "));
217 if (*buf != 'y') {
218 continue;
219 }
220 if (verbose)
221 say(_("Skipping patch...\n"));
222 filearg[0] = fetchname(bestguess, 0, TRUE, NULL);
223 skip_rest_of_patch = TRUE;
224 return (TRUE);
225 }
226 }
227 return (TRUE);
228 }
229
230 /* Determine what kind of diff is in the remaining part of the patch file. */
231
232 static int
intuit_diff_type()233 intuit_diff_type()
234 {
235 off_t this_line = 0;
236 off_t previous_line;
237 off_t first_command_line = (off_t)-1;
238 LINENUM fcl_line = 0;
239 bool last_line_was_command = FALSE;
240 bool this_is_a_command = FALSE;
241 bool stars_last_line = FALSE;
242 bool stars_this_line = FALSE;
243 size_t indent;
244 char *s;
245 char *t;
246 char *indtmp = Nullch;
247 char *oldtmp = Nullch;
248 char *newtmp = Nullch;
249 char *indname = Nullch;
250 char *oldname = Nullch;
251 char *newname = Nullch;
252 int retval;
253 bool no_filearg = (filearg[0] == Nullch);
254
255 is_null_time[0] = is_null_time[1] = FALSE;
256 ok_to_create_file = FALSE;
257 Fseek(pfp, p_base, 0);
258 p_input_line = p_bline - 1;
259 for (;;) {
260 previous_line = this_line;
261 last_line_was_command = this_is_a_command;
262 stars_last_line = stars_this_line;
263 this_line = ftell(pfp);
264 indent = 0;
265 p_input_line++;
266 if (fgetaline(pfp, &buf, &bufsize) <= 0) {
267 if (first_command_line >= 0L) {
268 /* nothing but deletes!? */
269 p_start = first_command_line;
270 p_sline = fcl_line;
271 retval = ED_DIFF;
272 goto scan_exit;
273 } else {
274 p_start = this_line;
275 p_sline = p_input_line;
276 retval = 0;
277 goto scan_exit;
278 }
279 }
280 for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
281 if (*s == '\t')
282 indent += 8 - (indent % 8);
283 else
284 indent++;
285 }
286 for (t = s; isdigit(UCH *t) || *t == ','; t++) {
287 ;
288 /* LINTED */
289 }
290 this_is_a_command = (isdigit(UCH *s) &&
291 (*t == 'd' || *t == 'c' || *t == 'a'));
292 if (first_command_line < 0L && this_is_a_command) {
293 first_command_line = this_line;
294 fcl_line = p_input_line;
295 p_indent = indent; /* assume this for now */
296
297 if (t[1] == '\n') {
298 p_start = first_command_line;
299 p_sline = fcl_line;
300 retval = ED_DIFF;
301 goto scan_exit;
302 }
303 }
304 if (first_command_line < 0L && isdigit(UCH *s) &&
305 (*t == 'i' || *t == 's')) {
306 p_start = first_command_line;
307 p_sline = fcl_line;
308 retval = ED_DIFF;
309 goto scan_exit;
310 }
311 if (!stars_last_line && strnEQ(s, "*** ", 4)) {
312 oldtmp = savestr(s+4);
313 } else if (strnEQ(s, "--- ", 4)) {
314 newtmp = savestr(s+4);
315 } else if (strnEQ(s, "+++ ", 4)) {
316 oldtmp = savestr(s+4); /* pretend it is the old name */
317 } else if (strnEQ(s, "Index:", 6)) {
318 indtmp = savestr(s+6);
319 } else if (wall_plus &&
320 strnEQ(s, "Prereq:", 7)) {
321 for (t = s+7; isspace(UCH *t); t++) {
322 ;
323 /* LINTED */
324 }
325 revision = savestr(t);
326 for (t = revision; *t && !isspace(UCH *t); t++) {
327 ;
328 /* LINTED */
329 }
330 *t = '\0';
331 if (!*revision) {
332 free(revision);
333 revision = Nullch;
334 }
335 }
336 if ((!diff_type || diff_type == ED_DIFF) &&
337 first_command_line >= 0L &&
338 strEQ(s, ".\n")) {
339 p_indent = indent;
340 p_start = first_command_line;
341 p_sline = fcl_line;
342 retval = ED_DIFF;
343 goto scan_exit;
344 }
345 if ((!diff_type || diff_type == UNI_DIFF) &&
346 strnEQ(s, "@@ -", 4)) {
347 if (!atolnum(s+3))
348 ok_to_create_file = TRUE;
349 p_indent = indent;
350 p_start = this_line;
351 p_sline = p_input_line;
352 retval = UNI_DIFF;
353 /*
354 * "--- " was scanned as "newname" and
355 * "+++ " was scanned as "oldname".
356 * Swap names for correct POSIX name selcetion.
357 */
358 t = newtmp;
359 newtmp = oldtmp;
360 oldtmp = t;
361 goto scan_exit;
362 }
363 stars_this_line = strnEQ(s, "********", 8);
364 if ((!diff_type || diff_type == CONTEXT_DIFF) &&
365 stars_last_line &&
366 strnEQ(s, "*** ", 4)) {
367 if (!atolnum(s+4))
368 ok_to_create_file = TRUE;
369 /* if this is a new context diff the character just */
370 /* before the newline is a '*'. */
371 while (*s != '\n')
372 s++;
373 p_indent = indent;
374 p_start = previous_line;
375 p_sline = p_input_line - 1;
376 retval = (*(s-1) == '*' ?
377 NEW_CONTEXT_DIFF : CONTEXT_DIFF);
378 goto scan_exit;
379 }
380 if ((!diff_type || diff_type == NORMAL_DIFF) &&
381 last_line_was_command &&
382 (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
383 p_start = previous_line;
384 p_sline = p_input_line - 1;
385 p_indent = indent;
386 retval = NORMAL_DIFF;
387 goto scan_exit;
388 }
389 }
390
391 scan_exit:
392
393 if (no_filearg) {
394 if (indtmp != Nullch) {
395 indname = fetchname(indtmp, strippath,
396 ok_to_create_file, NULL);
397 }
398 if (oldtmp != Nullch) {
399 oldname = fetchname(oldtmp, strippath,
400 ok_to_create_file,
401 &file_times[0]);
402 is_null_time[0] = file_times[0].dt_sec == 0;
403 }
404 if (newtmp != Nullch) {
405 newname = fetchname(newtmp, strippath,
406 ok_to_create_file,
407 &file_times[1]);
408 is_null_time[1] = file_times[1].dt_sec == 0;
409 }
410
411 if (do_wall && oldname && newname) {
412 /*
413 * Old Larry Wall algorithm from patch-2.0.
414 * This heuristic works only if the old name is
415 * something like "file.orig" and the new name is just
416 * "file". For "original" vs. "changed", it fails.
417 */
418 if (strlen(oldname) < strlen(newname))
419 filearg[0] = savestr(oldname);
420 else
421 filearg[0] = savestr(newname);
422 } else if (oldname) {
423 filearg[0] = savestr(oldname);
424 } else if (newname) {
425 filearg[0] = savestr(newname);
426 } else if (indname) {
427 filearg[0] = savestr(indname);
428 }
429 }
430 if (bestguess) {
431 free(bestguess);
432 bestguess = Nullch;
433 }
434 if (filearg[0] != Nullch) {
435 bestguess = savestr(filearg[0]);
436 } else if (indtmp != Nullch) {
437 bestguess = fetchname(indtmp, strippath, TRUE, NULL);
438 } else {
439 if (oldtmp != Nullch)
440 oldname = fetchname(oldtmp, strippath, TRUE, NULL);
441 if (newtmp != Nullch)
442 newname = fetchname(newtmp, strippath, TRUE, NULL);
443
444 if (do_wall && oldname && newname) {
445 /*
446 * Old Larry Wall algorithm from patch-2.0.
447 * This heuristic works only if the old name is
448 * something like "file.orig" and the new name is just
449 * "file". For "original" vs. "changed", it fails.
450 */
451 if (strlen(oldname) < strlen(newname))
452 bestguess = savestr(oldname);
453 else
454 bestguess = savestr(newname);
455 } else if (oldname) {
456 bestguess = savestr(oldname);
457 } else if (newname) {
458 bestguess = savestr(newname);
459 }
460 }
461 if (indtmp != Nullch)
462 free(indtmp);
463 if (oldtmp != Nullch)
464 free(oldtmp);
465 if (newtmp != Nullch)
466 free(newtmp);
467 if (indname != Nullch)
468 free(indname);
469 if (oldname != Nullch)
470 free(oldname);
471 if (newname != Nullch)
472 free(newname);
473 return (retval);
474 }
475
476 /* Remember where this patch ends so we know where to start up again. */
477
478 static void
next_intuit_at(file_pos,file_line)479 next_intuit_at(file_pos, file_line)
480 LINENUM file_pos;
481 LINENUM file_line;
482 {
483 p_base = file_pos;
484 p_bline = file_line;
485 }
486
487 /* Basically a verbose fseek() to the actual diff listing. */
488
489 static void
skip_to(file_pos,file_line)490 skip_to(file_pos, file_line)
491 off_t file_pos;
492 off_t file_line;
493 {
494 ssize_t ret;
495
496 assert(p_base <= file_pos);
497 if (verbose && p_base < file_pos) {
498 Fseek(pfp, p_base, 0);
499 say(
500 _("The text leading up to this was:\n--------------------------\n"));
501 while (ftell(pfp) < file_pos) {
502 ret = fgetaline(pfp, &buf, &bufsize);
503 assert(ret > 0);
504 say("|%s", buf);
505 }
506 say("--------------------------\n");
507 } else {
508 Fseek(pfp, file_pos, 0);
509 }
510 p_input_line = file_line - 1;
511 }
512
513 /* Make this a function for better debugging. */
514 static void
malformed()515 malformed()
516 {
517 fatal(_("Malformed patch at line %lld: %s"), (Llong)p_input_line, buf);
518 /* about as informative as "Syntax error" in C */
519 }
520
521 /* True if there is more of the current diff listing to process. */
522
523 bool
another_hunk()524 another_hunk()
525 {
526 char *s;
527 ssize_t ret;
528 LINENUM context = 0;
529
530 while (p_end >= 0) {
531 if (p_end == p_efake)
532 p_end = p_bfake; /* don't free twice */
533 else
534 free(p_line[p_end]);
535 p_end--;
536 }
537 assert(p_end == -1);
538 p_efake = -1;
539
540 p_max = hunkmax; /* gets reduced when --- found */
541 if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
542 off_t line_beginning = ftell(pfp);
543 /* file pos of the current line */
544 LINENUM repl_beginning = 0; /* index of --- line */
545 LINENUM fillcnt = 0; /* #lines of missing ptrn or repl */
546 LINENUM fillsrc; /* index of first line to copy */
547 LINENUM filldst; /* index of first missing line */
548 bool ptrn_spaces_eaten = FALSE; /* ptrn w. slightly misformed */
549 bool repl_could_be_missing = TRUE;
550 /* no + or ! lines in this hunk */
551 bool repl_missing = FALSE; /* we are now backtracking */
552 off_t repl_backtrack_position = 0;
553 /* file pos of first repl line */
554 LINENUM repl_patch_line; /* input line number for same */
555 LINENUM ptrn_copiable = 0;
556 /* # of copiable lines in ptrn */
557
558 fillsrc = filldst = repl_patch_line = 0; /* Make gcc quiet */
559
560 ret = pgets(&buf, &bufsize, pfp);
561 p_input_line++;
562 if (ret <= 0 || strnNE(buf, "********", 8)) {
563 next_intuit_at(line_beginning, p_input_line);
564 return (FALSE);
565 }
566 p_context = 100;
567 p_hunk_beg = p_input_line + 1;
568 while (p_end < p_max) {
569 line_beginning = ftell(pfp);
570 ret = pgets(&buf, &bufsize, pfp);
571 p_input_line++;
572 if (ret <= 0) {
573 if (p_max - p_end < 4)
574 Strcpy(buf, " \n"); /* assume blank lines got chopped */
575 else {
576 if (repl_beginning &&
577 repl_could_be_missing) {
578 repl_missing = TRUE;
579 goto hunk_done;
580 }
581 fatal(
582 _("Unexpected end of file in patch.\n"));
583 }
584 }
585 p_end++;
586 assert(p_end < hunkmax);
587 p_char[p_end] = *buf;
588 #ifdef zilog
589 p_line[(short)p_end] = Nullch;
590 #else
591 p_line[p_end] = Nullch;
592 #endif
593 switch (*buf) {
594
595 case '*':
596 if (strnEQ(buf, "********", 8)) {
597 if (repl_beginning &&
598 repl_could_be_missing) {
599 repl_missing = TRUE;
600 goto hunk_done;
601 } else {
602 fatal(
603 _("Unexpected end of hunk at line %lld.\n"),
604 (Llong)p_input_line);
605 }
606 }
607 if (p_end != 0) {
608 if (repl_beginning &&
609 repl_could_be_missing) {
610 repl_missing = TRUE;
611 goto hunk_done;
612 }
613 fatal(_("Unexpected *** at line %lld: %s"),
614 (Llong)p_input_line, buf);
615 }
616 context = 0;
617 p_line[p_end] = savestr(buf);
618 if (out_of_mem) {
619 p_end--;
620 return (FALSE);
621 }
622 for (s = buf; *s && !isdigit(UCH *s); s++) {
623 ;
624 /* LINTED */
625 }
626 if (!*s)
627 malformed();
628 if (strnEQ(s, "0,0", 3))
629 strcpy(s, s+2);
630 p_first = atolnum(s);
631 while (isdigit(UCH *s))
632 s++;
633 if (*s == ',') {
634 for (; *s && !isdigit(UCH *s); s++) {
635 ;
636 /* LINTED */
637 }
638 if (!*s)
639 malformed();
640 p_ptrn_lines = atolnum(s) -
641 p_first + 1;
642 } else if (p_first) {
643 p_ptrn_lines = 1;
644 } else {
645 p_ptrn_lines = 0;
646 p_first = 1;
647 }
648 p_max = p_ptrn_lines + 6; /* we need this much at least */
649 while (p_max >= hunkmax && !out_of_mem)
650 grow_hunkmax();
651 p_max = hunkmax;
652 if (out_of_mem) {
653 p_end = -1;
654 return (FALSE);
655 }
656 break;
657 case '-':
658 if (buf[1] == '-') {
659 if (repl_beginning ||
660 (p_end != p_ptrn_lines + 1 +
661 (p_char[p_end-1] == '\n'))) {
662 if (p_end == 1) {
663 /* `old' lines were omitted - set up to fill */
664 /* them in from 'new' context lines. */
665 p_end = p_ptrn_lines + 1;
666 fillsrc = p_end + 1;
667 filldst = 1;
668 fillcnt = p_ptrn_lines;
669 } else {
670 if (repl_beginning) {
671 if (repl_could_be_missing) {
672 repl_missing = TRUE;
673 goto hunk_done;
674 }
675 fatal(
676 _("Duplicate \"---\" at line %lld--check line numbers at line %lld.\n"),
677 (Llong)p_input_line,
678 (Llong)(p_hunk_beg + repl_beginning));
679 } else {
680 fatal(
681 _("%s \"---\" at line %lld--check line numbers at line %lld.\n"),
682 (p_end <= p_ptrn_lines
683 ? _("Premature")
684 : _("Overdue")),
685 (Llong)p_input_line,
686 (Llong)p_hunk_beg);
687 }
688 }
689 }
690 repl_beginning = p_end;
691 repl_backtrack_position = ftell(pfp);
692 repl_patch_line = p_input_line;
693 p_line[p_end] = savestr(buf);
694 if (out_of_mem) {
695 p_end--;
696 return (FALSE);
697 }
698 p_char[p_end] = '=';
699 for (s = buf;
700 *s && !isdigit(UCH *s); s++) {
701 ;
702 /* LINTED */
703 }
704 if (!*s)
705 malformed();
706 p_newfirst = atolnum(s);
707 while (isdigit(UCH *s))
708 s++;
709 if (*s == ',') {
710 for (;
711 *s && !isdigit(UCH *s);
712 s++) {
713 ;
714 /* LINTED */
715 }
716 if (!*s)
717 malformed();
718 p_repl_lines = atolnum(s) - p_newfirst + 1;
719 } else if (p_newfirst) {
720 p_repl_lines = 1;
721 } else {
722 p_repl_lines = 0;
723 p_newfirst = 1;
724 }
725 p_max = p_repl_lines + p_end;
726 while (p_max >= hunkmax && !out_of_mem)
727 grow_hunkmax();
728 if (out_of_mem) {
729 p_end = -1;
730 return (FALSE);
731 }
732 if (p_repl_lines != ptrn_copiable &&
733 (p_context != 0 || p_repl_lines != 1))
734 repl_could_be_missing = FALSE;
735 break;
736 }
737 goto change_line;
738 case '+':
739 case '!':
740 repl_could_be_missing = FALSE;
741 change_line:
742 if (buf[1] == '\n' && canonicalize)
743 strcpy(buf+1, " \n");
744 if (!isspace(UCH buf[1]) &&
745 buf[1] != '>' && buf[1] != '<' &&
746 repl_beginning && repl_could_be_missing) {
747 repl_missing = TRUE;
748 goto hunk_done;
749 }
750 if (context >= 0) {
751 if (context < p_context)
752 p_context = context;
753 context = -1000;
754 }
755 p_line[p_end] = savestr(buf+2);
756 if (out_of_mem) {
757 p_end--;
758 return (FALSE);
759 }
760 break;
761 case '\t':
762 case '\n': /* assume the 2 spaces got eaten */
763 if (repl_beginning && repl_could_be_missing &&
764 (!ptrn_spaces_eaten || diff_type == NEW_CONTEXT_DIFF)) {
765 repl_missing = TRUE;
766 goto hunk_done;
767 }
768 p_line[p_end] = savestr(buf);
769 if (out_of_mem) {
770 p_end--;
771 return (FALSE);
772 }
773 if (p_end != p_ptrn_lines + 1) {
774 ptrn_spaces_eaten |= (repl_beginning != 0);
775 context++;
776 if (!repl_beginning)
777 ptrn_copiable++;
778 p_char[p_end] = ' ';
779 }
780 break;
781 case ' ':
782 if (!isspace(UCH buf[1]) &&
783 repl_beginning && repl_could_be_missing) {
784 repl_missing = TRUE;
785 goto hunk_done;
786 }
787 context++;
788 if (!repl_beginning)
789 ptrn_copiable++;
790 p_line[p_end] = savestr(buf+2);
791 if (out_of_mem) {
792 p_end--;
793 return (FALSE);
794 }
795 break;
796 default:
797 if (repl_beginning && repl_could_be_missing) {
798 repl_missing = TRUE;
799 goto hunk_done;
800 }
801 malformed();
802 }
803 /* set up p_len for strncmp() so we don't have to */
804 /* assume null termination */
805 if (p_line[p_end])
806 p_len[p_end] = strlen(p_line[p_end]);
807 else
808 p_len[p_end] = 0;
809 }
810
811 hunk_done:
812 if (p_end >= 0 && !repl_beginning)
813 fatal(_("No --- found in patch at line %lld\n"),
814 (Llong)pch_hunk_beg());
815
816 if (repl_missing) {
817 /* reset state back to just after --- */
818 p_input_line = repl_patch_line;
819 for (p_end--; p_end > repl_beginning; p_end--)
820 free(p_line[p_end]);
821 Fseek(pfp, repl_backtrack_position, 0);
822
823 /* redundant 'new' context lines were omitted - set */
824 /* up to fill them in from the old file context */
825 if (!p_context && p_repl_lines == 1) {
826 p_repl_lines = 0;
827 p_max--;
828 }
829 fillsrc = 1;
830 filldst = repl_beginning+1;
831 fillcnt = p_repl_lines;
832 p_end = p_max;
833 } else if (!p_context && fillcnt == 1) {
834 /* the first hunk was a null hunk with no context */
835 /* and we were expecting one line -- fix it up. */
836 while (filldst < p_end) {
837 p_line[filldst] = p_line[filldst+1];
838 p_char[filldst] = p_char[filldst+1];
839 p_len[filldst] = p_len[filldst+1];
840 filldst++;
841 }
842 #if 0
843 repl_beginning--; /* this doesn't need to be fixed */
844 #endif
845 p_end--;
846 p_first++; /* do append rather than insert */
847 fillcnt = 0;
848 p_ptrn_lines = 0;
849 }
850
851 if (diff_type == CONTEXT_DIFF &&
852 (fillcnt || (p_first > 1 && ptrn_copiable > 2*p_context))) {
853 if (verbose)
854 say("%s\n%s\n%s\n",
855 _("(Fascinating--this is really a new-style context diff but without"),
856 _("the telltale extra asterisks on the *** line that usually indicate"),
857 _("the new style...)"));
858 diff_type = NEW_CONTEXT_DIFF;
859 }
860
861 /* if there were omitted context lines, fill them in now */
862 if (fillcnt) {
863 p_bfake = filldst; /* remember where not to free() */
864 p_efake = filldst + fillcnt - 1;
865 while (fillcnt-- > 0) {
866 while (fillsrc <= p_end && p_char[fillsrc] != ' ')
867 fillsrc++;
868 if (fillsrc > p_end)
869 fatal(
870 _("Replacement text or line numbers mangled in hunk at line %lld\n"),
871 (Llong)p_hunk_beg);
872 p_line[filldst] = p_line[fillsrc];
873 p_char[filldst] = p_char[fillsrc];
874 p_len[filldst] = p_len[fillsrc];
875 fillsrc++; filldst++;
876 }
877 while (fillsrc <= p_end && fillsrc != repl_beginning &&
878 p_char[fillsrc] != ' ')
879 fillsrc++;
880 #ifdef DEBUGGING
881 if (debug & 64)
882 printf("fillsrc %lld, filldst %lld, rb %lld, e+1 %lld\n",
883 (Llong)fillsrc, (Llong)filldst,
884 (Llong)repl_beginning, (Llong)p_end+1);
885 #endif
886 assert(fillsrc == p_end+1 || fillsrc == repl_beginning);
887 assert(filldst == p_end+1 || filldst == repl_beginning);
888 }
889 } else if (diff_type == UNI_DIFF) {
890 off_t line_beginning = ftell(pfp);
891 /* file pos of the current line */
892 LINENUM fillsrc; /* index of old lines */
893 LINENUM filldst; /* index of new lines */
894 char ch;
895
896 ret = pgets(&buf, &bufsize, pfp);
897 p_input_line++;
898 if (ret <= 0 || strnNE(buf, "@@ -", 4)) {
899 next_intuit_at(line_beginning, p_input_line);
900 return (FALSE);
901 }
902 s = buf+4;
903 if (!*s)
904 malformed();
905 p_first = atolnum(s);
906 while (isdigit(UCH *s))
907 s++;
908 if (*s == ',') {
909 p_ptrn_lines = atolnum(++s);
910 while (isdigit(UCH *s))
911 s++;
912 } else {
913 p_ptrn_lines = 1;
914 }
915 if (*s == ' ')
916 s++;
917 if (*s != '+' || !*++s)
918 malformed();
919 p_newfirst = atolnum(s);
920 while (isdigit(UCH *s))
921 s++;
922 if (*s == ',') {
923 p_repl_lines = atolnum(++s);
924 while (isdigit(UCH *s)) s++;
925 } else {
926 p_repl_lines = 1;
927 }
928 if (*s == ' ')
929 s++;
930 if (*s != '@')
931 malformed();
932 if (!p_ptrn_lines)
933 p_first++; /* do append rather than insert */
934 p_max = p_ptrn_lines + p_repl_lines + 1;
935 while (p_max >= hunkmax && !out_of_mem)
936 grow_hunkmax();
937 if (out_of_mem) {
938 p_end = -1;
939 return (FALSE);
940 }
941 fillsrc = 1;
942 filldst = fillsrc + p_ptrn_lines;
943 p_end = filldst + p_repl_lines;
944 Snprintf(buf, bufsize, "*** %lld,%lld ****\n",
945 (Llong)p_first, (Llong)(p_first + p_ptrn_lines - 1));
946 p_line[0] = savestr(buf);
947 if (out_of_mem) {
948 p_end = -1;
949 return (FALSE);
950 }
951 p_char[0] = '*';
952 Snprintf(buf, bufsize, "--- %lld,%lld ----\n",
953 (Llong)p_newfirst, (Llong)(p_newfirst+p_repl_lines-1));
954 p_line[filldst] = savestr(buf);
955 if (out_of_mem) {
956 p_end = 0;
957 return (FALSE);
958 }
959 p_char[filldst++] = '=';
960 p_context = 100;
961 context = 0;
962 p_hunk_beg = p_input_line + 1;
963 while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
964 line_beginning = ftell(pfp);
965 ret = pgets(&buf, &bufsize, pfp);
966 p_input_line++;
967 if (ret <= 0) {
968 if (p_max - filldst < 3) {
969 Strcpy(buf, " \n"); /* assume blank lines got chopped */
970 } else {
971 fatal(
972 _("Unexpected end of file in patch.\n"));
973 }
974 }
975 if (*buf == '\t' || *buf == '\n') {
976 ch = ' '; /* assume the space got eaten */
977 s = savestr(buf);
978 } else {
979 ch = *buf;
980 s = savestr(buf+1);
981 }
982 if (out_of_mem) {
983 while (--filldst > p_ptrn_lines)
984 free(p_line[filldst]);
985 p_end = fillsrc-1;
986 return (FALSE);
987 }
988 switch (ch) {
989 case '-':
990 if (fillsrc > p_ptrn_lines) {
991 free(s);
992 p_end = filldst-1;
993 malformed();
994 }
995 p_char[fillsrc] = ch;
996 p_line[fillsrc] = s;
997 p_len[fillsrc++] = strlen(s);
998 break;
999 case '=':
1000 ch = ' ';
1001 /* FALLTHROUGH */
1002 case ' ':
1003 if (fillsrc > p_ptrn_lines) {
1004 free(s);
1005 while (--filldst > p_ptrn_lines)
1006 free(p_line[filldst]);
1007 p_end = fillsrc-1;
1008 malformed();
1009 }
1010 context++;
1011 p_char[fillsrc] = ch;
1012 p_line[fillsrc] = s;
1013 p_len[fillsrc++] = strlen(s);
1014 s = savestr(s);
1015 if (out_of_mem) {
1016 while (--filldst > p_ptrn_lines)
1017 free(p_line[filldst]);
1018 p_end = fillsrc-1;
1019 return (FALSE);
1020 }
1021 /* FALLTHROUGH */
1022 case '+':
1023 if (filldst > p_end) {
1024 free(s);
1025 while (--filldst > p_ptrn_lines)
1026 free(p_line[filldst]);
1027 p_end = fillsrc-1;
1028 malformed();
1029 }
1030 p_char[filldst] = ch;
1031 p_line[filldst] = s;
1032 p_len[filldst++] = strlen(s);
1033 break;
1034 default:
1035 p_end = filldst;
1036 malformed();
1037 }
1038 if (ch != ' ' && context > 0) {
1039 if (context < p_context)
1040 p_context = context;
1041 context = -1000;
1042 }
1043 } /* while */
1044 } else { /* normal diff--fake it up */
1045 char hunk_type;
1046 int i;
1047 #undef min
1048 #undef max
1049 LINENUM min, max;
1050 off_t line_beginning = ftell(pfp);
1051
1052 p_context = 0;
1053 ret = pgets(&buf, &bufsize, pfp);
1054 p_input_line++;
1055 if (ret <= 0 || !isdigit(UCH *buf)) {
1056 next_intuit_at(line_beginning, p_input_line);
1057 return (FALSE);
1058 }
1059 p_first = atolnum(buf);
1060 for (s = buf; isdigit(UCH *s); s++) {
1061 ;
1062 /* LINTED */
1063 }
1064 if (*s == ',') {
1065 p_ptrn_lines = atolnum(++s) - p_first + 1;
1066 while (isdigit(UCH *s))
1067 s++;
1068 } else {
1069 p_ptrn_lines = (*s != 'a');
1070 }
1071 hunk_type = *s;
1072 if (hunk_type == 'a')
1073 p_first++; /* do append rather than insert */
1074 min = atolnum(++s);
1075 for (; isdigit(UCH *s); s++) {
1076 ;
1077 /* LINTED */
1078 }
1079 if (*s == ',')
1080 max = atolnum(++s);
1081 else
1082 max = min;
1083 if (hunk_type == 'd')
1084 min++;
1085 p_end = p_ptrn_lines + 1 + max - min + 1;
1086 while (p_end >= hunkmax && !out_of_mem)
1087 grow_hunkmax();
1088 if (out_of_mem) {
1089 p_end = -1;
1090 return (FALSE);
1091 }
1092 p_newfirst = min;
1093 p_repl_lines = max - min + 1;
1094 Snprintf(buf, bufsize, "*** %lld,%lld\n",
1095 (Llong)p_first, (Llong)(p_first + p_ptrn_lines - 1));
1096 p_line[0] = savestr(buf);
1097 if (out_of_mem) {
1098 p_end = -1;
1099 return (FALSE);
1100 }
1101 p_char[0] = '*';
1102 for (i = 1; i <= p_ptrn_lines; i++) {
1103 ret = pgets(&buf, &bufsize, pfp);
1104 p_input_line++;
1105 if (ret <= 0)
1106 fatal(
1107 _("Unexpected end of file in patch at line %lld.\n"),
1108 (Llong)p_input_line);
1109 if (*buf != '<')
1110 fatal(_("< expected at line %lld of patch.\n"),
1111 (Llong)p_input_line);
1112 p_line[i] = savestr(buf+2);
1113 if (out_of_mem) {
1114 p_end = i-1;
1115 return (FALSE);
1116 }
1117 p_len[i] = strlen(p_line[i]);
1118 p_char[i] = '-';
1119 }
1120 if (hunk_type == 'c') {
1121 ret = pgets(&buf, &bufsize, pfp);
1122 p_input_line++;
1123 if (ret <= 0)
1124 fatal(
1125 _("Unexpected end of file in patch at line %lld.\n"),
1126 (Llong)p_input_line);
1127 if (*buf != '-')
1128 fatal(_("--- expected at line %lld of patch.\n"),
1129 (Llong)p_input_line);
1130 }
1131 Snprintf(buf, bufsize, "--- %lld,%lld\n", (Llong)min, (Llong)max);
1132 p_line[i] = savestr(buf);
1133 if (out_of_mem) {
1134 p_end = i-1;
1135 return (FALSE);
1136 }
1137 p_char[i] = '=';
1138 for (i++; i <= p_end; i++) {
1139 ret = pgets(&buf, &bufsize, pfp);
1140 p_input_line++;
1141 if (ret <= 0)
1142 fatal(
1143 _("Unexpected end of file in patch at line %lld.\n"),
1144 (Llong)p_input_line);
1145 if (*buf != '>')
1146 fatal(_("> expected at line %lld of patch.\n"),
1147 (Llong)p_input_line);
1148 p_line[i] = savestr(buf+2);
1149 if (out_of_mem) {
1150 p_end = i-1;
1151 return (FALSE);
1152 }
1153 p_len[i] = strlen(p_line[i]);
1154 p_char[i] = '+';
1155 }
1156 }
1157 if (reverse) /* backwards patch? */
1158 if (!pch_swap())
1159 say(_("Not enough memory to swap next hunk!\n"));
1160 #ifdef DEBUGGING
1161 if (debug & 2) {
1162 int i;
1163 char special;
1164
1165 for (i = 0; i <= p_end; i++) {
1166 if (i == p_ptrn_lines)
1167 special = '^';
1168 else
1169 special = ' ';
1170 fprintf(stderr, "%3d %c %c %s",
1171 i, p_char[i], special, p_line[i]);
1172 Fflush(stderr);
1173 }
1174 }
1175 #endif
1176 if (p_end+1 < hunkmax) /* paranoia reigns supreme... */
1177 p_char[p_end+1] = '^'; /* add a stopper for apply_hunk */
1178 return (TRUE);
1179 }
1180
1181 /* Input a line from the patch file, worrying about indentation. */
1182
1183 static ssize_t
pgets(bfp,szp,fp)1184 pgets(bfp, szp, fp)
1185 char **bfp;
1186 size_t *szp;
1187 FILE *fp;
1188 {
1189 ssize_t ret = fgetaline(fp, bfp, szp);
1190 char *s;
1191 size_t indent = 0;
1192
1193 if (p_indent && ret > 0) {
1194 for (s = *bfp;
1195 indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X');
1196 s++) {
1197 if (*s == '\t')
1198 indent += 8 - (indent % 7);
1199 else
1200 indent++;
1201 }
1202 if (*bfp != s)
1203 ovstrcpy(*bfp, s);
1204 }
1205 return (ret);
1206 }
1207
1208 /* Reverse the old and new portions of the current hunk. */
1209
1210 bool
pch_swap()1211 pch_swap()
1212 {
1213 char **tp_line; /* the text of the hunk */
1214 size_t *tp_len; /* length of each line */
1215 char *tp_char; /* +, -, and ! */
1216 LINENUM i;
1217 LINENUM n;
1218 bool blankline = FALSE;
1219 char *s;
1220
1221 i = p_first;
1222 p_first = p_newfirst;
1223 p_newfirst = i;
1224
1225 /* make a scratch copy */
1226
1227 tp_line = p_line;
1228 tp_len = p_len;
1229 tp_char = p_char;
1230 p_line = Null(char **); /* force set_hunkmax to allocate again */
1231 p_len = Null(size_t *);
1232 p_char = Nullch;
1233 set_hunkmax();
1234 if (p_line == Null(char **) ||
1235 p_len == Null(size_t *) ||
1236 p_char == Nullch) {
1237 if (p_line != Null(char **))
1238 free((char *)p_line);
1239 p_line = tp_line;
1240 if (p_len != Null(size_t *))
1241 free((char *)p_len);
1242 p_len = tp_len;
1243 if (p_char != Nullch)
1244 free((char *)p_char);
1245 p_char = tp_char;
1246 return (FALSE); /* not enough memory to swap hunk! */
1247 }
1248
1249 /* now turn the new into the old */
1250
1251 i = p_ptrn_lines + 1;
1252 if (tp_char[i] == '\n') { /* account for possible blank line */
1253 blankline = TRUE;
1254 i++;
1255 }
1256 if (p_efake >= 0) { /* fix non-freeable ptr range */
1257 if (p_efake <= i)
1258 n = p_end - i + 1;
1259 else
1260 n = -i;
1261 p_efake += n;
1262 p_bfake += n;
1263 }
1264 for (n = 0; i <= p_end; i++, n++) {
1265 p_line[n] = tp_line[i];
1266 p_char[n] = tp_char[i];
1267 if (p_char[n] == '+')
1268 p_char[n] = '-';
1269 p_len[n] = tp_len[i];
1270 }
1271 if (blankline) {
1272 i = p_ptrn_lines + 1;
1273 p_line[n] = tp_line[i];
1274 p_char[n] = tp_char[i];
1275 p_len[n] = tp_len[i];
1276 n++;
1277 }
1278 assert(p_char[0] == '=');
1279 p_char[0] = '*';
1280 for (s = p_line[0]; *s; s++)
1281 if (*s == '-')
1282 *s = '*';
1283
1284 /* now turn the old into the new */
1285
1286 assert(tp_char[0] == '*');
1287 tp_char[0] = '=';
1288 for (s = tp_line[0]; *s; s++)
1289 if (*s == '*')
1290 *s = '-';
1291 for (i = 0; n <= p_end; i++, n++) {
1292 p_line[n] = tp_line[i];
1293 p_char[n] = tp_char[i];
1294 if (p_char[n] == '-')
1295 p_char[n] = '+';
1296 p_len[n] = tp_len[i];
1297 }
1298 assert(i == p_ptrn_lines + 1);
1299 i = p_ptrn_lines;
1300 p_ptrn_lines = p_repl_lines;
1301 p_repl_lines = i;
1302 if (tp_line != Null(char **))
1303 free((char *)tp_line);
1304 if (tp_len != Null(size_t *))
1305 free((char *)tp_len);
1306 if (tp_char != Nullch)
1307 free((char *)tp_char);
1308 return (TRUE);
1309 }
1310
1311 /* Return the specified line position in the old file of the old context. */
1312
1313 LINENUM
pch_first()1314 pch_first()
1315 {
1316 return (p_first);
1317 }
1318
1319 /* Return the number of lines of old context. */
1320
1321 LINENUM
pch_ptrn_lines()1322 pch_ptrn_lines()
1323 {
1324 return (p_ptrn_lines);
1325 }
1326
1327 /* Return the probable line position in the new file of the first line. */
1328
1329 LINENUM
pch_newfirst()1330 pch_newfirst()
1331 {
1332 return (p_newfirst);
1333 }
1334
1335 /* Return the number of lines in the replacement text including context. */
1336
1337 LINENUM
pch_repl_lines()1338 pch_repl_lines()
1339 {
1340 return (p_repl_lines);
1341 }
1342
1343 /* Return the number of lines in the whole hunk. */
1344
1345 LINENUM
pch_end()1346 pch_end()
1347 {
1348 return (p_end);
1349 }
1350
1351 /* Return the number of context lines before the first changed line. */
1352
1353 LINENUM
pch_context()1354 pch_context()
1355 {
1356 return (p_context);
1357 }
1358
1359 /* Return the length of a particular patch line. */
1360
1361 size_t
pch_line_len(line)1362 pch_line_len(line)
1363 LINENUM line;
1364 {
1365 return (p_len[line]);
1366 }
1367
1368 /* Return the control character (+, -, *, !, etc) for a patch line. */
1369
1370 char
pch_char(line)1371 pch_char(line)
1372 LINENUM line;
1373 {
1374 return (p_char[line]);
1375 }
1376
1377 /* Return a pointer to a particular patch line. */
1378
1379 char *
pfetch(line)1380 pfetch(line)
1381 LINENUM line;
1382 {
1383 return (p_line[line]);
1384 }
1385
1386 /* Return where in the patch file this hunk began, for error messages. */
1387
1388 LINENUM
pch_hunk_beg()1389 pch_hunk_beg()
1390 {
1391 return (p_hunk_beg);
1392 }
1393
1394 /* Apply an ed script by feeding ed itself. */
1395
1396 void
do_ed_script()1397 do_ed_script()
1398 {
1399 char *t;
1400 off_t beginning_of_this_line;
1401 bool this_line_is_command = FALSE;
1402 FILE *pipefp = 0;
1403
1404 if (!skip_rest_of_patch) {
1405 Unlink(TMPOUTNAME);
1406 copy_file(filearg[0], TMPOUTNAME);
1407 /*
1408 * Warning: "ed" stays in command mode in case there is e.g.
1409 * a wrong line number before an "append" command.
1410 *
1411 * Using this "feature" could allow to hide a shell command
1412 * from the command filter. However in correctly implemented
1413 * "ed" versions, an error while reading from a file must
1414 * result in e non-zero exit. This was not true for older
1415 * GNU ed versions and resulted in the "beep" attack.
1416 *
1417 * To avoid related other probably unknown problems, we
1418 * use the "red" command instead and start "red" from /tmp
1419 * as it does not accept filenames with a '/' inside.
1420 */
1421 if (verbose) {
1422 Snprintf(buf, bufsize, "cd %s && %s %s",
1423 TMPDIR,
1424 CNF_PATH_RED,
1425 TMPOUTNAME + TMPDLEN);
1426 } else {
1427 Snprintf(buf, bufsize, "cd %s && %s - %s",
1428 TMPDIR,
1429 CNF_PATH_RED,
1430 TMPOUTNAME + TMPDLEN);
1431 }
1432 pipefp = popen(buf, "w");
1433 #ifdef __unsafe__
1434 if (pipefp == NULL) {
1435 if (verbose)
1436 Snprintf(buf, bufsize, "/bin/ed %s", TMPOUTNAME);
1437 else
1438 Snprintf(buf, bufsize, "/bin/ed - %s", TMPOUTNAME);
1439 pipefp = popen(buf, "w");
1440 }
1441 #endif
1442 }
1443 for (;;) {
1444 beginning_of_this_line = ftell(pfp);
1445 if (pgets(&buf, &bufsize, pfp) <= 0) {
1446 next_intuit_at(beginning_of_this_line, p_input_line);
1447 break;
1448 }
1449 p_input_line++;
1450 for (t = buf; isdigit(UCH *t) || *t == ','; t++) {
1451 ;
1452 /* LINTED */
1453 }
1454 this_line_is_command = (isdigit(UCH *buf) &&
1455 (*t == 'd' || *t == 'c' || *t == 'a'));
1456 if (!this_line_is_command) {
1457 /*
1458 * Check for the diff workaround for "." in a line
1459 * that inserts ".." and then substitites the result.
1460 * Most diff programs emit "s/.//\na\a", but diff from
1461 * OpenBSD emits the substitute program with address.
1462 */
1463 if (strEQ(buf, "a\n") || strEQ(t, "s/.//\n"))
1464 this_line_is_command = 1;
1465 }
1466 if (this_line_is_command) {
1467 if (!skip_rest_of_patch)
1468 fputs(buf, pipefp);
1469 if (*t != 'd' && *t != 's') {
1470 while (pgets(&buf, &bufsize, pfp) > 0) {
1471 p_input_line++;
1472 if (!skip_rest_of_patch)
1473 fputs(buf, pipefp);
1474 if (strEQ(buf, ".\n"))
1475 break;
1476 }
1477 }
1478 } else {
1479 next_intuit_at(beginning_of_this_line, p_input_line);
1480 break;
1481 }
1482 }
1483 if (skip_rest_of_patch)
1484 return;
1485 fprintf(pipefp, "w\n");
1486 fprintf(pipefp, "q\n");
1487 Fflush(pipefp);
1488 Pclose(pipefp);
1489 ignore_signals();
1490 if (move_file(TMPOUTNAME, outname) < 0) {
1491 toutkeep = TRUE;
1492 chmod(TMPOUTNAME, filemode);
1493 } else {
1494 chmod(outname, filemode);
1495 }
1496 set_signals(1);
1497 }
1498
1499 LINENUM
atolnum(s)1500 atolnum(s)
1501 char *s;
1502 {
1503 char *os;
1504 LINENUM l = 0;
1505 LINENUM multmax;
1506 LINENUM lmax;
1507 int c;
1508 int neg = 0;
1509
1510 lmax = TYPE_MAXVAL(LINENUM);
1511 multmax = TYPE_MAXVAL(LINENUM) / 10;
1512
1513 if (*s == '-') {
1514 neg++;
1515 s++;
1516 } else if (*s == '+')
1517 s++;
1518
1519 os = s;
1520 while ((c = *s++) != '\0') {
1521 if (c < '0' || c > '9')
1522 break;
1523 if (l > multmax) {
1524 if (p_input_line)
1525 malformed();
1526 else
1527 fatal(_("Number '%s' too large.\n"), os);
1528 }
1529 l *= 10;
1530 c -= '0';
1531 if (c > (lmax - l)) {
1532 if (p_input_line)
1533 malformed();
1534 else
1535 fatal(_("Number '%s' too large.\n"), os);
1536 }
1537 l += c;
1538 }
1539 if (s == ++os) {
1540 if (p_input_line)
1541 malformed();
1542 else
1543 fatal(_("Not a number '%s'.\n"), --os);
1544 }
1545 return (neg? -l:l);
1546 }
1547
1548 int
atoinum(s)1549 atoinum(s)
1550 char *s;
1551 {
1552 LINENUM l = atolnum(s);
1553 int ret;
1554
1555 ret = l;
1556 if (ret != l)
1557 fatal(_("Number '%lld' too large.\n"), (Llong)l);
1558
1559 return (ret);
1560 }
1561