Annotation of src/usr.bin/patch/pch.c, Revision 1.21
1.21 ! otto 1: /* $OpenBSD: pch.c,v 1.20 2003/07/21 14:32:21 deraadt Exp $ */
1.2 niklas 2:
1.1 deraadt 3: #ifndef lint
1.21 ! otto 4: static const char rcsid[] = "$OpenBSD: pch.c,v 1.20 2003/07/21 14:32:21 deraadt Exp $";
1.1 deraadt 5: #endif /* not lint */
6:
1.21 ! otto 7: #include <sys/types.h>
! 8: #include <sys/stat.h>
! 9:
! 10: #include <assert.h>
! 11: #include <ctype.h>
! 12: #include <stdlib.h>
! 13: #include <string.h>
! 14: #include <unistd.h>
! 15:
1.1 deraadt 16: #include "EXTERN.h"
17: #include "common.h"
18: #include "util.h"
19: #include "INTERN.h"
20: #include "pch.h"
21:
22: /* Patch (diff listing) abstract type. */
23:
1.17 deraadt 24: static long p_filesize; /* size of the patch file */
25: static LINENUM p_first; /* 1st line number */
26: static LINENUM p_newfirst; /* 1st line number of replacement */
27: static LINENUM p_ptrn_lines; /* # lines in pattern */
28: static LINENUM p_repl_lines; /* # lines in replacement text */
29: static LINENUM p_end = -1; /* last line in hunk */
30: static LINENUM p_max; /* max allowed value of p_end */
31: static LINENUM p_context = 3; /* # of context lines */
32: static LINENUM p_input_line = 0; /* current line # from patch file */
1.21 ! otto 33: static char **p_line = NULL; /* the text of the hunk */
! 34: static short *p_len = NULL; /* length of each line */
! 35: static char *p_char = NULL;/* +, -, and ! */
1.17 deraadt 36: static int hunkmax = INITHUNKMAX; /* size of above arrays to begin with */
37: static int p_indent; /* indent to patch */
38: static LINENUM p_base; /* where to intuit this time */
39: static LINENUM p_bline; /* line # of p_base */
40: static LINENUM p_start; /* where intuit found a patch */
41: static LINENUM p_sline; /* and the line number for it */
42: static LINENUM p_hunk_beg; /* line number of current hunk */
43: static LINENUM p_efake = -1; /* end of faked up lines--don't free */
44: static LINENUM p_bfake = -1; /* beg of faked up lines */
1.1 deraadt 45:
1.21 ! otto 46: static void grow_hunkmax(void);
! 47: static int intuit_diff_type(void);
! 48: static void next_intuit_at(long, long);
! 49: static void skip_to(long, long);
! 50: static char *pgets(char *, int, FILE *);
! 51:
1.17 deraadt 52: /*
53: * Prepare to look for the next patch in the patch file.
54: */
1.1 deraadt 55: void
1.17 deraadt 56: re_patch(void)
1.1 deraadt 57: {
1.21 ! otto 58: p_first = NULL;
! 59: p_newfirst = NULL;
! 60: p_ptrn_lines = NULL;
! 61: p_repl_lines = NULL;
1.17 deraadt 62: p_end = (LINENUM) - 1;
1.21 ! otto 63: p_max = NULL;
1.17 deraadt 64: p_indent = 0;
1.1 deraadt 65: }
66:
1.17 deraadt 67: /*
68: * Open the patch file at the beginning of time.
69: */
1.1 deraadt 70: void
1.17 deraadt 71: open_patch_file(char *filename)
1.1 deraadt 72: {
1.21 ! otto 73: if (filename == NULL || !*filename || strEQ(filename, "-")) {
1.17 deraadt 74: pfp = fopen(TMPPATNAME, "w");
1.21 ! otto 75: if (pfp == NULL)
1.17 deraadt 76: pfatal("can't create %s", TMPPATNAME);
1.21 ! otto 77: while (fgets(buf, sizeof buf, stdin) != NULL)
1.17 deraadt 78: fputs(buf, pfp);
79: fclose(pfp);
80: filename = TMPPATNAME;
81: }
82: pfp = fopen(filename, "r");
1.21 ! otto 83: if (pfp == NULL)
1.17 deraadt 84: pfatal("patch file %s not found", filename);
85: fstat(fileno(pfp), &filestat);
86: p_filesize = filestat.st_size;
87: next_intuit_at(0L, 1L); /* start at the beginning */
88: set_hunkmax();
1.1 deraadt 89: }
90:
1.17 deraadt 91: /*
92: * Make sure our dynamically realloced tables are malloced to begin with.
93: */
1.1 deraadt 94: void
1.17 deraadt 95: set_hunkmax(void)
1.1 deraadt 96: {
1.21 ! otto 97: if (p_line == NULL)
! 98: p_line = malloc((size_t) hunkmax * sizeof(char *));
! 99: if (p_len == NULL)
! 100: p_len = malloc((size_t) hunkmax * sizeof(short));
! 101: if (p_char == NULL)
! 102: p_char = malloc((size_t) hunkmax * sizeof(char));
1.1 deraadt 103: }
104:
1.17 deraadt 105: /*
106: * Enlarge the arrays containing the current hunk of patch.
107: */
1.21 ! otto 108: static void
1.17 deraadt 109: grow_hunkmax(void)
1.1 deraadt 110: {
1.17 deraadt 111: hunkmax *= 2;
112:
113: /*
114: * Note that on most systems, only the p_line array ever gets fresh memory
115: * since p_len can move into p_line's old space, and p_char can move into
116: * p_len's old space. Not on PDP-11's however. But it doesn't matter.
117: */
1.21 ! otto 118: assert(p_line != NULL &&p_len != NULL &&p_char != NULL);
! 119:
! 120: p_line = realloc(p_line, hunkmax * sizeof(char *));
! 121: p_len = realloc(p_len, hunkmax * sizeof(short));
! 122: p_char = realloc(p_char, hunkmax * sizeof(char));
! 123:
! 124: if (p_line != NULL &&p_len != NULL &&p_char != NULL)
1.17 deraadt 125: return;
126: if (!using_plan_a)
127: fatal("out of memory\n");
128: out_of_mem = TRUE; /* whatever is null will be allocated again */
129: /* from within plan_a(), of all places */
1.1 deraadt 130: }
131:
132: /* True if the remainder of the patch file contains a diff of some sort. */
133:
134: bool
1.17 deraadt 135: there_is_another_patch(void)
1.1 deraadt 136: {
1.17 deraadt 137: if (p_base != 0L && p_base >= p_filesize) {
138: if (verbose)
139: say("done\n");
140: return FALSE;
141: }
1.1 deraadt 142: if (verbose)
1.17 deraadt 143: say("Hmm...");
144: diff_type = intuit_diff_type();
145: if (!diff_type) {
146: if (p_base != 0L) {
147: if (verbose)
148: say(" Ignoring the trailing garbage.\ndone\n");
149: } else
150: say(" I can't seem to find a patch in there anywhere.\n");
151: return FALSE;
1.1 deraadt 152: }
1.17 deraadt 153: if (verbose)
154: say(" %sooks like %s to me...\n",
155: (p_base == 0L ? "L" : "The next patch l"),
156: diff_type == UNI_DIFF ? "a unified diff" :
157: diff_type == CONTEXT_DIFF ? "a context diff" :
158: diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
159: diff_type == NORMAL_DIFF ? "a normal diff" :
160: "an ed script");
161: if (p_indent && verbose)
162: say("(Patch is indented %d space%s.)\n", p_indent,
163: p_indent == 1 ? "" : "s");
164: skip_to(p_start, p_sline);
1.21 ! otto 165: while (filearg[0] == NULL) {
1.17 deraadt 166: if (force || batch) {
167: say("No file to patch. Skipping...\n");
168: filearg[0] = savestr(bestguess);
169: skip_rest_of_patch = TRUE;
170: return TRUE;
171: }
172: ask("File to patch: ");
173: if (*buf != '\n') {
174: if (bestguess)
175: free(bestguess);
176: bestguess = savestr(buf);
177: filearg[0] = fetchname(buf, 0, FALSE);
178: }
1.21 ! otto 179: if (filearg[0] == NULL) {
1.17 deraadt 180: ask("No file found--skip this patch? [n] ");
181: if (*buf != 'y')
182: continue;
183: if (verbose)
184: say("Skipping patch...\n");
185: filearg[0] = fetchname(bestguess, 0, TRUE);
186: skip_rest_of_patch = TRUE;
187: return TRUE;
188: }
1.1 deraadt 189: }
1.17 deraadt 190: return TRUE;
1.1 deraadt 191: }
192:
193: /* Determine what kind of diff is in the remaining part of the patch file. */
194:
1.21 ! otto 195: static int
1.17 deraadt 196: intuit_diff_type(void)
1.1 deraadt 197: {
1.17 deraadt 198: long this_line = 0, previous_line;
199: long first_command_line = -1, fcl_line;
200: bool last_line_was_command = FALSE, this_is_a_command = FALSE;
201: bool stars_last_line = FALSE, stars_this_line = FALSE;
202: char *s, *t;
1.21 ! otto 203: char *indtmp = NULL;
! 204: char *oldtmp = NULL;
! 205: char *newtmp = NULL;
! 206: char *indname = NULL;
! 207: char *oldname = NULL;
! 208: char *newname = NULL;
1.17 deraadt 209: int indent, retval;
1.21 ! otto 210: bool no_filearg = (filearg[0] == NULL);
1.17 deraadt 211:
212: ok_to_create_file = FALSE;
1.21 ! otto 213: fseek(pfp, p_base, SEEK_SET);
1.17 deraadt 214: p_input_line = p_bline - 1;
215: for (;;) {
216: previous_line = this_line;
217: last_line_was_command = this_is_a_command;
218: stars_last_line = stars_this_line;
219: this_line = ftell(pfp);
220: indent = 0;
221: p_input_line++;
1.21 ! otto 222: if (fgets(buf, sizeof buf, pfp) == NULL) {
1.17 deraadt 223: if (first_command_line >= 0L) {
224: /* nothing but deletes!? */
225: p_start = first_command_line;
226: p_sline = fcl_line;
227: retval = ED_DIFF;
228: goto scan_exit;
229: } else {
230: p_start = this_line;
231: p_sline = p_input_line;
232: retval = 0;
233: goto scan_exit;
234: }
235: }
236: for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
237: if (*s == '\t')
238: indent += 8 - (indent % 8);
239: else
240: indent++;
241: }
242: for (t = s; isdigit(*t) || *t == ','; t++)
243: ;
244: this_is_a_command = (isdigit(*s) &&
245: (*t == 'd' || *t == 'c' || *t == 'a'));
246: if (first_command_line < 0L && this_is_a_command) {
247: first_command_line = this_line;
248: fcl_line = p_input_line;
249: p_indent = indent; /* assume this for now */
250: }
251: if (!stars_last_line && strnEQ(s, "*** ", 4))
252: oldtmp = savestr(s + 4);
253: else if (strnEQ(s, "--- ", 4))
254: newtmp = savestr(s + 4);
255: else if (strnEQ(s, "+++ ", 4))
256: oldtmp = savestr(s + 4); /* pretend it is the old
257: * name */
258: else if (strnEQ(s, "Index:", 6))
259: indtmp = savestr(s + 6);
260: else if (strnEQ(s, "Prereq:", 7)) {
1.18 deraadt 261: for (t = s + 7; isspace(*t); t++)
262: ;
1.17 deraadt 263: revision = savestr(t);
1.18 deraadt 264: for (t = revision; *t && !isspace(*t); t++)
265: ;
1.17 deraadt 266: *t = '\0';
267: if (!*revision) {
268: free(revision);
1.21 ! otto 269: revision = NULL;
1.17 deraadt 270: }
271: }
272: if ((!diff_type || diff_type == ED_DIFF) &&
273: first_command_line >= 0L &&
274: strEQ(s, ".\n")) {
275: p_indent = indent;
276: p_start = first_command_line;
277: p_sline = fcl_line;
278: retval = ED_DIFF;
279: goto scan_exit;
280: }
281: if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
282: if (!atol(s + 3))
283: ok_to_create_file = TRUE;
284: p_indent = indent;
285: p_start = this_line;
286: p_sline = p_input_line;
287: retval = UNI_DIFF;
288: goto scan_exit;
289: }
290: stars_this_line = strnEQ(s, "********", 8);
291: if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
292: strnEQ(s, "*** ", 4)) {
293: if (!atol(s + 4))
294: ok_to_create_file = TRUE;
295: /*
296: * if this is a new context diff the character just
297: * before
298: */
299: /* the newline is a '*'. */
300: while (*s != '\n')
301: s++;
302: p_indent = indent;
303: p_start = previous_line;
304: p_sline = p_input_line - 1;
305: retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
306: goto scan_exit;
307: }
308: if ((!diff_type || diff_type == NORMAL_DIFF) &&
309: last_line_was_command &&
310: (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
311: p_start = previous_line;
312: p_sline = p_input_line - 1;
313: p_indent = indent;
314: retval = NORMAL_DIFF;
315: goto scan_exit;
316: }
317: }
318: scan_exit:
319: if (no_filearg) {
1.21 ! otto 320: if (indtmp != NULL)
1.17 deraadt 321: indname = fetchname(indtmp, strippath, ok_to_create_file);
1.21 ! otto 322: if (oldtmp != NULL)
1.17 deraadt 323: oldname = fetchname(oldtmp, strippath, ok_to_create_file);
1.21 ! otto 324: if (newtmp != NULL)
1.17 deraadt 325: newname = fetchname(newtmp, strippath, ok_to_create_file);
326: if (indname)
327: filearg[0] = savestr(indname);
328: else if (oldname && newname) {
329: if (strlen(oldname) < strlen(newname))
330: filearg[0] = savestr(oldname);
331: else
332: filearg[0] = savestr(newname);
333: } else if (oldname)
334: filearg[0] = savestr(oldname);
335: else if (newname)
336: filearg[0] = savestr(newname);
337: }
338: if (bestguess) {
339: free(bestguess);
1.21 ! otto 340: bestguess = NULL;
1.17 deraadt 341: }
1.21 ! otto 342: if (filearg[0] != NULL)
1.17 deraadt 343: bestguess = savestr(filearg[0]);
1.21 ! otto 344: else if (indtmp != NULL)
1.17 deraadt 345: bestguess = fetchname(indtmp, strippath, TRUE);
346: else {
1.21 ! otto 347: if (oldtmp != NULL)
1.17 deraadt 348: oldname = fetchname(oldtmp, strippath, TRUE);
1.21 ! otto 349: if (newtmp != NULL)
1.17 deraadt 350: newname = fetchname(newtmp, strippath, TRUE);
351: if (oldname && newname) {
352: if (strlen(oldname) < strlen(newname))
353: bestguess = savestr(oldname);
354: else
355: bestguess = savestr(newname);
356: } else if (oldname)
357: bestguess = savestr(oldname);
358: else if (newname)
359: bestguess = savestr(newname);
360: }
1.21 ! otto 361: free(indtmp);
! 362: free(oldtmp);
! 363: free(newtmp);
! 364: free(indname);
! 365: free(oldname);
! 366: free(newname);
1.17 deraadt 367: return retval;
1.1 deraadt 368: }
369:
1.17 deraadt 370: /*
371: * Remember where this patch ends so we know where to start up again.
372: */
1.21 ! otto 373: static void
1.17 deraadt 374: next_intuit_at(long file_pos, long file_line)
1.1 deraadt 375: {
1.17 deraadt 376: p_base = file_pos;
377: p_bline = file_line;
1.1 deraadt 378: }
379:
1.17 deraadt 380: /*
381: * Basically a verbose fseek() to the actual diff listing.
382: */
1.21 ! otto 383: static void
1.17 deraadt 384: skip_to(long file_pos, long file_line)
1.1 deraadt 385: {
1.17 deraadt 386: char *ret;
1.1 deraadt 387:
1.17 deraadt 388: assert(p_base <= file_pos);
389: if (verbose && p_base < file_pos) {
1.21 ! otto 390: fseek(pfp, p_base, SEEK_SET);
1.17 deraadt 391: say("The text leading up to this was:\n--------------------------\n");
392: while (ftell(pfp) < file_pos) {
393: ret = fgets(buf, sizeof buf, pfp);
1.21 ! otto 394: assert(ret != NULL);
1.17 deraadt 395: say("|%s", buf);
396: }
397: say("--------------------------\n");
398: } else
1.21 ! otto 399: fseek(pfp, file_pos, SEEK_SET);
1.17 deraadt 400: p_input_line = file_line - 1;
1.1 deraadt 401: }
402:
403: /* Make this a function for better debugging. */
404: static void
1.16 deraadt 405: malformed(void)
1.1 deraadt 406: {
1.17 deraadt 407: fatal("malformed patch at line %ld: %s", p_input_line, buf);
408: /* about as informative as "Syntax error" in C */
1.1 deraadt 409: }
410:
1.14 otto 411: /*
412: * True if the line has been discarded (i.e. it is a line saying
413: * "\ No newline at end of file".)
414: */
415: static bool
416: remove_special_line(void)
417: {
1.17 deraadt 418: int c;
1.14 otto 419:
420: c = fgetc(pfp);
421: if (c == '\\') {
422: do {
423: c = fgetc(pfp);
424: } while (c != EOF && c != '\n');
425:
426: return TRUE;
427: }
428: if (c != EOF)
429: fseek(pfp, -1L, SEEK_CUR);
430:
431: return FALSE;
432: }
433:
1.17 deraadt 434: /*
435: * True if there is more of the current diff listing to process.
436: */
1.1 deraadt 437: bool
1.17 deraadt 438: another_hunk(void)
1.1 deraadt 439: {
1.17 deraadt 440: long line_beginning; /* file pos of the current line */
441: LINENUM repl_beginning; /* index of --- line */
442: LINENUM fillcnt; /* #lines of missing ptrn or repl */
443: LINENUM fillsrc; /* index of first line to copy */
444: LINENUM filldst; /* index of first missing line */
445: bool ptrn_spaces_eaten; /* ptrn was slightly misformed */
446: bool repl_could_be_missing; /* no + or ! lines in this hunk */
447: bool repl_missing; /* we are now backtracking */
448: long repl_backtrack_position; /* file pos of first repl line */
449: LINENUM repl_patch_line; /* input line number for same */
450: LINENUM ptrn_copiable; /* # of copiable lines in ptrn */
451: char *s, *ret;
452: int context = 0;
453:
454: while (p_end >= 0) {
455: if (p_end == p_efake)
456: p_end = p_bfake; /* don't free twice */
457: else
458: free(p_line[p_end]);
459: p_end--;
460: }
461: assert(p_end == -1);
462: p_efake = -1;
463:
464: p_max = hunkmax; /* gets reduced when --- found */
465: if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
466: line_beginning = ftell(pfp);
467: repl_beginning = 0;
468: fillcnt = 0;
469: ptrn_spaces_eaten = FALSE;
470: repl_could_be_missing = TRUE;
471: repl_missing = FALSE;
472: repl_backtrack_position = 0;
473: ptrn_copiable = 0;
474:
475: ret = pgets(buf, sizeof buf, pfp);
476: p_input_line++;
1.21 ! otto 477: if (ret == NULL || strnNE(buf, "********", 8)) {
1.17 deraadt 478: next_intuit_at(line_beginning, p_input_line);
479: return FALSE;
480: }
481: p_context = 100;
482: p_hunk_beg = p_input_line + 1;
483: while (p_end < p_max) {
484: line_beginning = ftell(pfp);
485: ret = pgets(buf, sizeof buf, pfp);
486: p_input_line++;
1.21 ! otto 487: if (ret == NULL) {
1.17 deraadt 488: if (p_max - p_end < 4) {
489: /* assume blank lines got chopped */
490: strlcpy(buf, " \n", sizeof buf);
491: } else {
492: if (repl_beginning && repl_could_be_missing) {
493: repl_missing = TRUE;
494: goto hunk_done;
495: }
496: fatal("unexpected end of file in patch\n");
497: }
498: }
499: p_end++;
500: assert(p_end < hunkmax);
501: p_char[p_end] = *buf;
1.21 ! otto 502: p_line[p_end] = NULL;
1.17 deraadt 503: switch (*buf) {
504: case '*':
505: if (strnEQ(buf, "********", 8)) {
506: if (repl_beginning && repl_could_be_missing) {
507: repl_missing = TRUE;
508: goto hunk_done;
509: } else
510: fatal("unexpected end of hunk "
511: "at line %ld\n",
512: p_input_line);
513: }
514: if (p_end != 0) {
515: if (repl_beginning && repl_could_be_missing) {
516: repl_missing = TRUE;
517: goto hunk_done;
518: }
519: fatal("unexpected *** at line %ld: %s",
520: p_input_line, buf);
521: }
522: context = 0;
523: p_line[p_end] = savestr(buf);
524: if (out_of_mem) {
525: p_end--;
526: return FALSE;
527: }
528: for (s = buf; *s && !isdigit(*s); s++)
529: ;
530: if (!*s)
531: malformed();
532: if (strnEQ(s, "0,0", 3))
533: memmove(s, s + 2, strlen(s + 2) + 1);
534: p_first = (LINENUM) atol(s);
535: while (isdigit(*s))
536: s++;
537: if (*s == ',') {
1.18 deraadt 538: for (; *s && !isdigit(*s); s++)
539: ;
1.17 deraadt 540: if (!*s)
541: malformed();
542: p_ptrn_lines = ((LINENUM) atol(s)) - p_first + 1;
543: } else if (p_first)
544: p_ptrn_lines = 1;
545: else {
546: p_ptrn_lines = 0;
547: p_first = 1;
548: }
549: p_max = p_ptrn_lines + 6; /* we need this much at
550: * least */
551: while (p_max >= hunkmax)
552: grow_hunkmax();
553: p_max = hunkmax;
554: break;
555: case '-':
556: if (buf[1] == '-') {
557: if (repl_beginning ||
558: (p_end != p_ptrn_lines + 1 +
559: (p_char[p_end - 1] == '\n'))) {
560: if (p_end == 1) {
561: /*
562: * `old' lines were omitted;
563: * set up to fill them in
564: * from 'new' context lines.
565: */
566: p_end = p_ptrn_lines + 1;
567: fillsrc = p_end + 1;
568: filldst = 1;
569: fillcnt = p_ptrn_lines;
570: } else {
571: if (repl_beginning) {
572: if (repl_could_be_missing) {
573: repl_missing = TRUE;
574: goto hunk_done;
575: }
576: fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n",
577: p_input_line, p_hunk_beg + repl_beginning);
578: } else {
579: fatal("%s \"---\" at line %ld--check line numbers at line %ld\n",
580: (p_end <= p_ptrn_lines
581: ? "Premature"
582: : "Overdue"),
583: p_input_line, p_hunk_beg);
584: }
585: }
586: }
587: repl_beginning = p_end;
588: repl_backtrack_position = ftell(pfp);
589: repl_patch_line = p_input_line;
590: p_line[p_end] = savestr(buf);
591: if (out_of_mem) {
592: p_end--;
593: return FALSE;
594: }
595: p_char[p_end] = '=';
596: for (s = buf; *s && !isdigit(*s); s++)
597: ;
598: if (!*s)
599: malformed();
600: p_newfirst = (LINENUM) atol(s);
601: while (isdigit(*s))
602: s++;
603: if (*s == ',') {
604: for (; *s && !isdigit(*s); s++)
605: ;
606: if (!*s)
607: malformed();
608: p_repl_lines = ((LINENUM) atol(s)) -
609: p_newfirst + 1;
610: } else if (p_newfirst)
611: p_repl_lines = 1;
612: else {
613: p_repl_lines = 0;
614: p_newfirst = 1;
615: }
616: p_max = p_repl_lines + p_end;
617: if (p_max > MAXHUNKSIZE)
618: fatal("hunk too large (%ld lines) at line %ld: %s",
619: p_max, p_input_line, buf);
620: while (p_max >= hunkmax)
621: grow_hunkmax();
622: if (p_repl_lines != ptrn_copiable &&
623: (p_context != 0 || p_repl_lines != 1))
624: repl_could_be_missing = FALSE;
625: break;
626: }
627: goto change_line;
628: case '+':
629: case '!':
630: repl_could_be_missing = FALSE;
631: change_line:
632: if (buf[1] == '\n' && canonicalize)
633: strlcpy(buf + 1, " \n", sizeof buf - 1);
634: if (!isspace(buf[1]) && buf[1] != '>' &&
635: buf[1] != '<' &&
636: repl_beginning && repl_could_be_missing) {
637: repl_missing = TRUE;
638: goto hunk_done;
639: }
640: if (context >= 0) {
641: if (context < p_context)
642: p_context = context;
643: context = -1000;
644: }
645: p_line[p_end] = savestr(buf + 2);
646: if (out_of_mem) {
647: p_end--;
648: return FALSE;
649: }
650: if (p_end == p_ptrn_lines) {
651: if (remove_special_line()) {
652: int len;
653:
654: len = strlen(p_line[p_end]) - 1;
655: (p_line[p_end])[len] = 0;
656: }
657: }
658: break;
659: case '\t':
660: case '\n': /* assume the 2 spaces got eaten */
661: if (repl_beginning && repl_could_be_missing &&
662: (!ptrn_spaces_eaten ||
663: diff_type == NEW_CONTEXT_DIFF)) {
664: repl_missing = TRUE;
665: goto hunk_done;
666: }
667: p_line[p_end] = savestr(buf);
668: if (out_of_mem) {
669: p_end--;
670: return FALSE;
671: }
672: if (p_end != p_ptrn_lines + 1) {
673: ptrn_spaces_eaten |= (repl_beginning != 0);
674: context++;
675: if (!repl_beginning)
676: ptrn_copiable++;
677: p_char[p_end] = ' ';
678: }
679: break;
680: case ' ':
681: if (!isspace(buf[1]) &&
682: repl_beginning && repl_could_be_missing) {
683: repl_missing = TRUE;
684: goto hunk_done;
685: }
686: context++;
687: if (!repl_beginning)
688: ptrn_copiable++;
689: p_line[p_end] = savestr(buf + 2);
690: if (out_of_mem) {
691: p_end--;
692: return FALSE;
693: }
694: break;
695: default:
696: if (repl_beginning && repl_could_be_missing) {
697: repl_missing = TRUE;
698: goto hunk_done;
699: }
700: malformed();
701: }
702: /* set up p_len for strncmp() so we don't have to */
703: /* assume null termination */
704: if (p_line[p_end])
705: p_len[p_end] = strlen(p_line[p_end]);
706: else
707: p_len[p_end] = 0;
708: }
709:
710: hunk_done:
711: if (p_end >= 0 && !repl_beginning)
712: fatal("no --- found in patch at line %ld\n", pch_hunk_beg());
713:
714: if (repl_missing) {
715:
716: /* reset state back to just after --- */
717: p_input_line = repl_patch_line;
718: for (p_end--; p_end > repl_beginning; p_end--)
719: free(p_line[p_end]);
1.21 ! otto 720: fseek(pfp, repl_backtrack_position, SEEK_SET);
1.17 deraadt 721:
722: /* redundant 'new' context lines were omitted - set */
723: /* up to fill them in from the old file context */
724: if (!p_context && p_repl_lines == 1) {
725: p_repl_lines = 0;
726: p_max--;
727: }
728: fillsrc = 1;
729: filldst = repl_beginning + 1;
730: fillcnt = p_repl_lines;
731: p_end = p_max;
732: } else if (!p_context && fillcnt == 1) {
733: /* the first hunk was a null hunk with no context */
734: /* and we were expecting one line -- fix it up. */
735: while (filldst < p_end) {
736: p_line[filldst] = p_line[filldst + 1];
737: p_char[filldst] = p_char[filldst + 1];
738: p_len[filldst] = p_len[filldst + 1];
739: filldst++;
740: }
741: #if 0
742: repl_beginning--; /* this doesn't need to be
743: * fixed */
744: #endif
745: p_end--;
746: p_first++; /* do append rather than insert */
747: fillcnt = 0;
748: p_ptrn_lines = 0;
749: }
750: if (diff_type == CONTEXT_DIFF &&
751: (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) {
752: if (verbose)
753: say("%s\n%s\n%s\n",
754: "(Fascinating--this is really a new-style context diff but without",
755: "the telltale extra asterisks on the *** line that usually indicate",
756: "the new style...)");
757: diff_type = NEW_CONTEXT_DIFF;
758: }
759: /* if there were omitted context lines, fill them in now */
760: if (fillcnt) {
761: p_bfake = filldst; /* remember where not to
762: * free() */
763: p_efake = filldst + fillcnt - 1;
764: while (fillcnt-- > 0) {
765: while (fillsrc <= p_end && p_char[fillsrc] != ' ')
766: fillsrc++;
767: if (fillsrc > p_end)
768: fatal("replacement text or line numbers mangled in hunk at line %ld\n",
769: p_hunk_beg);
770: p_line[filldst] = p_line[fillsrc];
771: p_char[filldst] = p_char[fillsrc];
772: p_len[filldst] = p_len[fillsrc];
773: fillsrc++;
774: filldst++;
775: }
776: while (fillsrc <= p_end && fillsrc != repl_beginning &&
777: p_char[fillsrc] != ' ')
778: fillsrc++;
779: #ifdef DEBUGGING
780: if (debug & 64)
781: printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
782: fillsrc, filldst, repl_beginning, p_end + 1);
1.1 deraadt 783: #endif
1.17 deraadt 784: assert(fillsrc == p_end + 1 || fillsrc == repl_beginning);
785: assert(filldst == p_end + 1 || filldst == repl_beginning);
1.1 deraadt 786: }
1.17 deraadt 787: if (p_line[p_end] != NULL) {
788: if (remove_special_line()) {
789: p_len[p_end] -= 1;
790: (p_line[p_end])[p_len[p_end]] = 0;
791: }
792: }
793: } else if (diff_type == UNI_DIFF) {
794: long line_beginning = ftell(pfp); /* file pos of the current line */
795: LINENUM fillsrc; /* index of old lines */
796: LINENUM filldst; /* index of new lines */
797: char ch;
798:
799: ret = pgets(buf, sizeof buf, pfp);
800: p_input_line++;
1.21 ! otto 801: if (ret == NULL || strnNE(buf, "@@ -", 4)) {
1.17 deraadt 802: next_intuit_at(line_beginning, p_input_line);
803: return FALSE;
1.1 deraadt 804: }
1.17 deraadt 805: s = buf + 4;
1.1 deraadt 806: if (!*s)
1.17 deraadt 807: malformed();
1.1 deraadt 808: p_first = (LINENUM) atol(s);
1.17 deraadt 809: while (isdigit(*s))
810: s++;
811: if (*s == ',') {
812: p_ptrn_lines = (LINENUM) atol(++s);
813: while (isdigit(*s))
814: s++;
815: } else
816: p_ptrn_lines = 1;
817: if (*s == ' ')
818: s++;
819: if (*s != '+' || !*++s)
820: malformed();
821: p_newfirst = (LINENUM) atol(s);
822: while (isdigit(*s))
823: s++;
1.1 deraadt 824: if (*s == ',') {
1.17 deraadt 825: p_repl_lines = (LINENUM) atol(++s);
826: while (isdigit(*s))
827: s++;
828: } else
829: p_repl_lines = 1;
830: if (*s == ' ')
831: s++;
832: if (*s != '@')
833: malformed();
834: if (!p_ptrn_lines)
835: p_first++; /* do append rather than insert */
836: p_max = p_ptrn_lines + p_repl_lines + 1;
837: while (p_max >= hunkmax)
838: grow_hunkmax();
839: fillsrc = 1;
840: filldst = fillsrc + p_ptrn_lines;
841: p_end = filldst + p_repl_lines;
842: snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first,
843: p_first + p_ptrn_lines - 1);
844: p_line[0] = savestr(buf);
845: if (out_of_mem) {
846: p_end = -1;
847: return FALSE;
848: }
849: p_char[0] = '*';
850: snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,
851: p_newfirst + p_repl_lines - 1);
852: p_line[filldst] = savestr(buf);
853: if (out_of_mem) {
854: p_end = 0;
855: return FALSE;
1.1 deraadt 856: }
1.17 deraadt 857: p_char[filldst++] = '=';
858: p_context = 100;
859: context = 0;
860: p_hunk_beg = p_input_line + 1;
861: while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
862: line_beginning = ftell(pfp);
863: ret = pgets(buf, sizeof buf, pfp);
864: p_input_line++;
1.21 ! otto 865: if (ret == NULL) {
1.17 deraadt 866: if (p_max - filldst < 3) {
867: /* assume blank lines got chopped */
868: strlcpy(buf, " \n", sizeof buf);
869: } else {
870: fatal("unexpected end of file in patch\n");
871: }
872: }
873: if (*buf == '\t' || *buf == '\n') {
874: ch = ' '; /* assume the space got eaten */
875: s = savestr(buf);
876: } else {
877: ch = *buf;
878: s = savestr(buf + 1);
879: }
880: if (out_of_mem) {
881: while (--filldst > p_ptrn_lines)
882: free(p_line[filldst]);
883: p_end = fillsrc - 1;
884: return FALSE;
885: }
886: switch (ch) {
887: case '-':
888: if (fillsrc > p_ptrn_lines) {
889: free(s);
890: p_end = filldst - 1;
891: malformed();
892: }
893: p_char[fillsrc] = ch;
894: p_line[fillsrc] = s;
895: p_len[fillsrc++] = strlen(s);
896: if (fillsrc > p_ptrn_lines) {
897: if (remove_special_line()) {
898: p_len[fillsrc - 1] -= 1;
899: s[p_len[fillsrc - 1]] = 0;
900: }
901: }
902: break;
903: case '=':
904: ch = ' ';
905: /* FALL THROUGH */
906: case ' ':
907: if (fillsrc > p_ptrn_lines) {
908: free(s);
909: while (--filldst > p_ptrn_lines)
910: free(p_line[filldst]);
911: p_end = fillsrc - 1;
912: malformed();
913: }
914: context++;
915: p_char[fillsrc] = ch;
916: p_line[fillsrc] = s;
917: p_len[fillsrc++] = strlen(s);
918: s = savestr(s);
919: if (out_of_mem) {
920: while (--filldst > p_ptrn_lines)
921: free(p_line[filldst]);
922: p_end = fillsrc - 1;
923: return FALSE;
924: }
925: /* FALL THROUGH */
926: case '+':
927: if (filldst > p_end) {
928: free(s);
929: while (--filldst > p_ptrn_lines)
930: free(p_line[filldst]);
931: p_end = fillsrc - 1;
932: malformed();
933: }
934: p_char[filldst] = ch;
935: p_line[filldst] = s;
936: p_len[filldst++] = strlen(s);
937: if (fillsrc > p_ptrn_lines) {
938: if (remove_special_line()) {
939: p_len[filldst - 1] -= 1;
940: s[p_len[filldst - 1]] = 0;
941: }
942: }
943: break;
944: default:
945: p_end = filldst;
946: malformed();
1.1 deraadt 947: }
1.17 deraadt 948: if (ch != ' ' && context > 0) {
949: if (context < p_context)
950: p_context = context;
951: context = -1000;
1.1 deraadt 952: }
1.17 deraadt 953: } /* while */
954: } else { /* normal diff--fake it up */
955: char hunk_type;
956: int i;
957: LINENUM min, max;
958: long line_beginning = ftell(pfp);
959:
960: p_context = 0;
961: ret = pgets(buf, sizeof buf, pfp);
962: p_input_line++;
1.21 ! otto 963: if (ret == NULL || !isdigit(*buf)) {
1.17 deraadt 964: next_intuit_at(line_beginning, p_input_line);
1.1 deraadt 965: return FALSE;
1.17 deraadt 966: }
967: p_first = (LINENUM) atol(buf);
1.18 deraadt 968: for (s = buf; isdigit(*s); s++)
969: ;
1.17 deraadt 970: if (*s == ',') {
971: p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1;
972: while (isdigit(*s))
973: s++;
974: } else
975: p_ptrn_lines = (*s != 'a');
976: hunk_type = *s;
977: if (hunk_type == 'a')
978: p_first++; /* do append rather than insert */
979: min = (LINENUM) atol(++s);
1.18 deraadt 980: for (; isdigit(*s); s++)
981: ;
1.17 deraadt 982: if (*s == ',')
983: max = (LINENUM) atol(++s);
984: else
985: max = min;
986: if (hunk_type == 'd')
987: min++;
988: p_end = p_ptrn_lines + 1 + max - min + 1;
989: if (p_end > MAXHUNKSIZE)
1.16 deraadt 990: fatal("hunk too large (%ld lines) at line %ld: %s",
1.17 deraadt 991: p_end, p_input_line, buf);
992: while (p_end >= hunkmax)
1.1 deraadt 993: grow_hunkmax();
1.17 deraadt 994: p_newfirst = min;
995: p_repl_lines = max - min + 1;
996: snprintf(buf, sizeof buf, "*** %ld,%ld\n", p_first,
997: p_first + p_ptrn_lines - 1);
998: p_line[0] = savestr(buf);
1.1 deraadt 999: if (out_of_mem) {
1.17 deraadt 1000: p_end = -1;
1001: return FALSE;
1.1 deraadt 1002: }
1.17 deraadt 1003: p_char[0] = '*';
1004: for (i = 1; i <= p_ptrn_lines; i++) {
1005: ret = pgets(buf, sizeof buf, pfp);
1006: p_input_line++;
1.21 ! otto 1007: if (ret == NULL)
1.17 deraadt 1008: fatal("unexpected end of file in patch at line %ld\n",
1009: p_input_line);
1010: if (*buf != '<')
1011: fatal("< expected at line %ld of patch\n",
1012: p_input_line);
1013: p_line[i] = savestr(buf + 2);
1014: if (out_of_mem) {
1015: p_end = i - 1;
1016: return FALSE;
1.14 otto 1017: }
1.17 deraadt 1018: p_len[i] = strlen(p_line[i]);
1019: p_char[i] = '-';
1.14 otto 1020: }
1.17 deraadt 1021:
1022: if (remove_special_line()) {
1023: p_len[i - 1] -= 1;
1024: (p_line[i - 1])[p_len[i - 1]] = 0;
1.1 deraadt 1025: }
1.17 deraadt 1026: if (hunk_type == 'c') {
1027: ret = pgets(buf, sizeof buf, pfp);
1028: p_input_line++;
1.21 ! otto 1029: if (ret == NULL)
1.17 deraadt 1030: fatal("unexpected end of file in patch at line %ld\n",
1031: p_input_line);
1032: if (*buf != '-')
1033: fatal("--- expected at line %ld of patch\n",
1034: p_input_line);
1.1 deraadt 1035: }
1.17 deraadt 1036: snprintf(buf, sizeof(buf), "--- %ld,%ld\n", min, max);
1037: p_line[i] = savestr(buf);
1.1 deraadt 1038: if (out_of_mem) {
1.17 deraadt 1039: p_end = i - 1;
1040: return FALSE;
1.1 deraadt 1041: }
1.17 deraadt 1042: p_char[i] = '=';
1043: for (i++; i <= p_end; i++) {
1044: ret = pgets(buf, sizeof buf, pfp);
1045: p_input_line++;
1.21 ! otto 1046: if (ret == NULL)
1.17 deraadt 1047: fatal("unexpected end of file in patch at line %ld\n",
1048: p_input_line);
1049: if (*buf != '>')
1050: fatal("> expected at line %ld of patch\n",
1051: p_input_line);
1052: p_line[i] = savestr(buf + 2);
1053: if (out_of_mem) {
1054: p_end = i - 1;
1055: return FALSE;
1.14 otto 1056: }
1.17 deraadt 1057: p_len[i] = strlen(p_line[i]);
1058: p_char[i] = '+';
1.14 otto 1059: }
1.17 deraadt 1060:
1061: if (remove_special_line()) {
1062: p_len[i - 1] -= 1;
1063: (p_line[i - 1])[p_len[i - 1]] = 0;
1.14 otto 1064: }
1.1 deraadt 1065: }
1.17 deraadt 1066: if (reverse) /* backwards patch? */
1067: if (!pch_swap())
1068: say("Not enough memory to swap next hunk!\n");
1.1 deraadt 1069: #ifdef DEBUGGING
1.17 deraadt 1070: if (debug & 2) {
1071: int i;
1072: char special;
1073:
1074: for (i = 0; i <= p_end; i++) {
1075: if (i == p_ptrn_lines)
1076: special = '^';
1077: else
1078: special = ' ';
1079: fprintf(stderr, "%3d %c %c %s", i, p_char[i],
1080: special, p_line[i]);
1081: fflush(stderr);
1082: }
1.1 deraadt 1083: }
1084: #endif
1.17 deraadt 1085: if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */
1086: p_char[p_end + 1] = '^'; /* add a stopper for apply_hunk */
1087: return TRUE;
1.1 deraadt 1088: }
1089:
1.17 deraadt 1090: /*
1091: * Input a line from the patch file, worrying about indentation.
1092: */
1.21 ! otto 1093: static char *
1.17 deraadt 1094: pgets(char *bf, int sz, FILE *fp)
1095: {
1096: char *s, *ret = fgets(bf, sz, fp);
1097: int indent = 0;
1.1 deraadt 1098:
1.21 ! otto 1099: if (p_indent && ret != NULL) {
1.17 deraadt 1100: for (s = buf;
1101: indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X');
1102: s++) {
1103: if (*s == '\t')
1104: indent += 8 - (indent % 7);
1105: else
1106: indent++;
1107: }
1108: if (buf != s && strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
1109: fatal("buffer too small in pgets()\n");
1110: }
1111: return ret;
1.1 deraadt 1112: }
1113:
1.17 deraadt 1114: /*
1115: * Reverse the old and new portions of the current hunk.
1116: */
1.1 deraadt 1117: bool
1.17 deraadt 1118: pch_swap(void)
1.1 deraadt 1119: {
1.17 deraadt 1120: char **tp_line; /* the text of the hunk */
1121: short *tp_len; /* length of each line */
1122: char *tp_char; /* +, -, and ! */
1123: LINENUM i;
1124: LINENUM n;
1125: bool blankline = FALSE;
1126: char *s;
1127:
1128: i = p_first;
1129: p_first = p_newfirst;
1130: p_newfirst = i;
1131:
1132: /* make a scratch copy */
1133:
1134: tp_line = p_line;
1135: tp_len = p_len;
1136: tp_char = p_char;
1.21 ! otto 1137: p_line = NULL; /* force set_hunkmax to allocate again */
! 1138: p_len = NULL;
! 1139: p_char = NULL;
1.17 deraadt 1140: set_hunkmax();
1.21 ! otto 1141: if (p_line == NULL ||p_len == NULL ||p_char == NULL) {
! 1142:
! 1143: if (p_line == NULL) /* XXX */
! 1144: free(p_line);
1.17 deraadt 1145: p_line = tp_line;
1.21 ! otto 1146: if (p_len == NULL) /* XXX */
! 1147: free(p_len);
1.17 deraadt 1148: p_len = tp_len;
1.21 ! otto 1149: if (p_char == NULL) /* XXX */
! 1150: free(p_char);
1.17 deraadt 1151: p_char = tp_char;
1152: return FALSE; /* not enough memory to swap hunk! */
1153: }
1154: /* now turn the new into the old */
1155:
1.1 deraadt 1156: i = p_ptrn_lines + 1;
1.17 deraadt 1157: if (tp_char[i] == '\n') { /* account for possible blank line */
1158: blankline = TRUE;
1159: i++;
1160: }
1161: if (p_efake >= 0) { /* fix non-freeable ptr range */
1162: if (p_efake <= i)
1163: n = p_end - i + 1;
1164: else
1165: n = -i;
1166: p_efake += n;
1167: p_bfake += n;
1168: }
1169: for (n = 0; i <= p_end; i++, n++) {
1170: p_line[n] = tp_line[i];
1171: p_char[n] = tp_char[i];
1172: if (p_char[n] == '+')
1173: p_char[n] = '-';
1174: p_len[n] = tp_len[i];
1175: }
1176: if (blankline) {
1177: i = p_ptrn_lines + 1;
1178: p_line[n] = tp_line[i];
1179: p_char[n] = tp_char[i];
1180: p_len[n] = tp_len[i];
1181: n++;
1182: }
1183: assert(p_char[0] == '=');
1184: p_char[0] = '*';
1185: for (s = p_line[0]; *s; s++)
1186: if (*s == '-')
1187: *s = '*';
1188:
1189: /* now turn the old into the new */
1190:
1191: assert(tp_char[0] == '*');
1192: tp_char[0] = '=';
1193: for (s = tp_line[0]; *s; s++)
1194: if (*s == '*')
1195: *s = '-';
1196: for (i = 0; n <= p_end; i++, n++) {
1197: p_line[n] = tp_line[i];
1198: p_char[n] = tp_char[i];
1199: if (p_char[n] == '-')
1200: p_char[n] = '+';
1201: p_len[n] = tp_len[i];
1202: }
1203: assert(i == p_ptrn_lines + 1);
1204: i = p_ptrn_lines;
1205: p_ptrn_lines = p_repl_lines;
1206: p_repl_lines = i;
1.21 ! otto 1207:
! 1208: if (tp_line == NULL) /* XXX */
! 1209: free(tp_line);
! 1210: if (tp_len == NULL) /* XXX */
! 1211: free(tp_len);
! 1212: if (tp_char == NULL) /* XXX */
! 1213: free(tp_char);
1.17 deraadt 1214: return TRUE;
1.1 deraadt 1215: }
1216:
1.17 deraadt 1217: /*
1218: * Return the specified line position in the old file of the old context.
1219: */
1.1 deraadt 1220: LINENUM
1.17 deraadt 1221: pch_first(void)
1.1 deraadt 1222: {
1.17 deraadt 1223: return p_first;
1.1 deraadt 1224: }
1225:
1.17 deraadt 1226: /*
1227: * Return the number of lines of old context.
1228: */
1.1 deraadt 1229: LINENUM
1.17 deraadt 1230: pch_ptrn_lines(void)
1.1 deraadt 1231: {
1.17 deraadt 1232: return p_ptrn_lines;
1.1 deraadt 1233: }
1234:
1.17 deraadt 1235: /*
1236: * Return the probable line position in the new file of the first line.
1237: */
1.1 deraadt 1238: LINENUM
1.17 deraadt 1239: pch_newfirst(void)
1.1 deraadt 1240: {
1.17 deraadt 1241: return p_newfirst;
1.1 deraadt 1242: }
1243:
1.17 deraadt 1244: /*
1245: * Return the number of lines in the replacement text including context.
1246: */
1.1 deraadt 1247: LINENUM
1.17 deraadt 1248: pch_repl_lines(void)
1.1 deraadt 1249: {
1.17 deraadt 1250: return p_repl_lines;
1.1 deraadt 1251: }
1252:
1.17 deraadt 1253: /*
1254: * Return the number of lines in the whole hunk.
1255: */
1.1 deraadt 1256: LINENUM
1.17 deraadt 1257: pch_end(void)
1.1 deraadt 1258: {
1.17 deraadt 1259: return p_end;
1.1 deraadt 1260: }
1261:
1.17 deraadt 1262: /*
1263: * Return the number of context lines before the first changed line.
1264: */
1.1 deraadt 1265: LINENUM
1.17 deraadt 1266: pch_context(void)
1.1 deraadt 1267: {
1.17 deraadt 1268: return p_context;
1.1 deraadt 1269: }
1270:
1.17 deraadt 1271: /*
1272: * Return the length of a particular patch line.
1273: */
1.1 deraadt 1274: short
1.17 deraadt 1275: pch_line_len(LINENUM line)
1.1 deraadt 1276: {
1.17 deraadt 1277: return p_len[line];
1.1 deraadt 1278: }
1279:
1.17 deraadt 1280: /*
1281: * Return the control character (+, -, *, !, etc) for a patch line.
1282: */
1.1 deraadt 1283: char
1.17 deraadt 1284: pch_char(LINENUM line)
1.1 deraadt 1285: {
1.17 deraadt 1286: return p_char[line];
1.1 deraadt 1287: }
1288:
1.17 deraadt 1289: /*
1290: * Return a pointer to a particular patch line.
1291: */
1.1 deraadt 1292: char *
1.17 deraadt 1293: pfetch(LINENUM line)
1.1 deraadt 1294: {
1.17 deraadt 1295: return p_line[line];
1.1 deraadt 1296: }
1297:
1.17 deraadt 1298: /*
1299: * Return where in the patch file this hunk began, for error messages.
1300: */
1.1 deraadt 1301: LINENUM
1.17 deraadt 1302: pch_hunk_beg(void)
1.1 deraadt 1303: {
1.17 deraadt 1304: return p_hunk_beg;
1.1 deraadt 1305: }
1306:
1.17 deraadt 1307: /*
1308: * Apply an ed script by feeding ed itself.
1309: */
1.1 deraadt 1310: void
1.17 deraadt 1311: do_ed_script(void)
1.1 deraadt 1312: {
1.17 deraadt 1313: char *t;
1314: long beginning_of_this_line;
1315: bool this_line_is_command = FALSE;
1316: FILE *pipefp;
1317:
1318: if (!skip_rest_of_patch) {
1319: unlink(TMPOUTNAME);
1320: copy_file(filearg[0], TMPOUTNAME);
1321: if (verbose)
1322: snprintf(buf, sizeof buf, "/bin/ed %s", TMPOUTNAME);
1323: else
1324: snprintf(buf, sizeof buf, "/bin/ed - %s", TMPOUTNAME);
1325: pipefp = popen(buf, "w");
1326: }
1327: for (;;) {
1328: beginning_of_this_line = ftell(pfp);
1.21 ! otto 1329: if (pgets(buf, sizeof buf, pfp) == NULL) {
1.17 deraadt 1330: next_intuit_at(beginning_of_this_line, p_input_line);
1331: break;
1332: }
1333: p_input_line++;
1.18 deraadt 1334: for (t = buf; isdigit(*t) || *t == ','; t++)
1335: ;
1.17 deraadt 1336: this_line_is_command = (isdigit(*buf) &&
1337: (*t == 'd' || *t == 'c' || *t == 'a'));
1338: if (this_line_is_command) {
1339: if (!skip_rest_of_patch)
1340: fputs(buf, pipefp);
1341: if (*t != 'd') {
1.21 ! otto 1342: while (pgets(buf, sizeof buf, pfp) != NULL) {
1.17 deraadt 1343: p_input_line++;
1344: if (!skip_rest_of_patch)
1345: fputs(buf, pipefp);
1346: if (strEQ(buf, ".\n"))
1347: break;
1348: }
1349: }
1350: } else {
1351: next_intuit_at(beginning_of_this_line, p_input_line);
1.1 deraadt 1352: break;
1353: }
1354: }
1.17 deraadt 1355: if (skip_rest_of_patch)
1356: return;
1357: fprintf(pipefp, "w\n");
1358: fprintf(pipefp, "q\n");
1359: fflush(pipefp);
1360: pclose(pipefp);
1361: ignore_signals();
1362: if (!check_only) {
1363: if (move_file(TMPOUTNAME, outname) < 0) {
1364: toutkeep = TRUE;
1365: chmod(TMPOUTNAME, filemode);
1366: } else
1367: chmod(outname, filemode);
1.1 deraadt 1368: }
1.17 deraadt 1369: set_signals(1);
1.1 deraadt 1370: }