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