Annotation of src/usr.bin/patch/pch.c, Revision 1.25
1.25 ! otto 1: /* $OpenBSD: pch.c,v 1.24 2003/07/25 02:12:45 millert Exp $ */
1.2 niklas 2:
1.1 deraadt 3: #ifndef lint
1.25 ! otto 4: static const char rcsid[] = "$OpenBSD: pch.c,v 1.24 2003/07/25 02:12:45 millert 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))
259: oldtmp = savestr(s + 4); /* pretend it is the old
260: * name */
261: else if (strnEQ(s, "Index:", 6))
262: indtmp = savestr(s + 6);
263: else if (strnEQ(s, "Prereq:", 7)) {
1.18 deraadt 264: for (t = s + 7; isspace(*t); t++)
265: ;
1.17 deraadt 266: revision = savestr(t);
1.18 deraadt 267: for (t = revision; *t && !isspace(*t); t++)
268: ;
1.17 deraadt 269: *t = '\0';
1.25 ! otto 270: if (*revision == '\0') {
1.17 deraadt 271: free(revision);
1.21 otto 272: revision = NULL;
1.17 deraadt 273: }
274: }
275: if ((!diff_type || diff_type == ED_DIFF) &&
276: first_command_line >= 0L &&
277: strEQ(s, ".\n")) {
278: p_indent = indent;
279: p_start = first_command_line;
280: p_sline = fcl_line;
281: retval = ED_DIFF;
282: goto scan_exit;
283: }
284: if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
285: if (!atol(s + 3))
286: ok_to_create_file = TRUE;
287: p_indent = indent;
288: p_start = this_line;
289: p_sline = p_input_line;
290: retval = UNI_DIFF;
291: goto scan_exit;
292: }
293: stars_this_line = strnEQ(s, "********", 8);
294: if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
295: strnEQ(s, "*** ", 4)) {
296: if (!atol(s + 4))
297: ok_to_create_file = TRUE;
298: /*
299: * if this is a new context diff the character just
300: * before
301: */
302: /* the newline is a '*'. */
303: while (*s != '\n')
304: s++;
305: p_indent = indent;
306: p_start = previous_line;
307: p_sline = p_input_line - 1;
308: retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
309: goto scan_exit;
310: }
311: if ((!diff_type || diff_type == NORMAL_DIFF) &&
312: last_line_was_command &&
313: (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
314: p_start = previous_line;
315: p_sline = p_input_line - 1;
316: p_indent = indent;
317: retval = NORMAL_DIFF;
318: goto scan_exit;
319: }
320: }
321: scan_exit:
322: if (no_filearg) {
1.21 otto 323: if (indtmp != NULL)
1.17 deraadt 324: indname = fetchname(indtmp, strippath, ok_to_create_file);
1.21 otto 325: if (oldtmp != NULL)
1.17 deraadt 326: oldname = fetchname(oldtmp, strippath, ok_to_create_file);
1.21 otto 327: if (newtmp != NULL)
1.17 deraadt 328: newname = fetchname(newtmp, strippath, ok_to_create_file);
329: if (indname)
330: filearg[0] = savestr(indname);
331: else if (oldname && newname) {
332: if (strlen(oldname) < strlen(newname))
333: filearg[0] = savestr(oldname);
334: else
335: filearg[0] = savestr(newname);
336: } else if (oldname)
337: filearg[0] = savestr(oldname);
338: else if (newname)
339: filearg[0] = savestr(newname);
340: }
1.25 ! otto 341:
! 342: free(bestguess);
! 343: bestguess = NULL;
! 344:
1.21 otto 345: if (filearg[0] != NULL)
1.17 deraadt 346: bestguess = savestr(filearg[0]);
1.21 otto 347: else if (indtmp != NULL)
1.17 deraadt 348: bestguess = fetchname(indtmp, strippath, TRUE);
349: else {
1.21 otto 350: if (oldtmp != NULL)
1.17 deraadt 351: oldname = fetchname(oldtmp, strippath, TRUE);
1.21 otto 352: if (newtmp != NULL)
1.17 deraadt 353: newname = fetchname(newtmp, strippath, TRUE);
354: if (oldname && newname) {
355: if (strlen(oldname) < strlen(newname))
356: bestguess = savestr(oldname);
357: else
358: bestguess = savestr(newname);
359: } else if (oldname)
360: bestguess = savestr(oldname);
361: else if (newname)
362: bestguess = savestr(newname);
363: }
1.21 otto 364: free(indtmp);
365: free(oldtmp);
366: free(newtmp);
367: free(indname);
368: free(oldname);
369: free(newname);
1.17 deraadt 370: return retval;
1.1 deraadt 371: }
372:
1.17 deraadt 373: /*
374: * Remember where this patch ends so we know where to start up again.
375: */
1.21 otto 376: static void
1.25 ! otto 377: next_intuit_at(LINENUM file_pos, LINENUM file_line)
1.1 deraadt 378: {
1.17 deraadt 379: p_base = file_pos;
380: p_bline = file_line;
1.1 deraadt 381: }
382:
1.17 deraadt 383: /*
384: * Basically a verbose fseek() to the actual diff listing.
385: */
1.21 otto 386: static void
1.25 ! otto 387: skip_to(LINENUM file_pos, LINENUM file_line)
1.1 deraadt 388: {
1.17 deraadt 389: char *ret;
1.1 deraadt 390:
1.17 deraadt 391: assert(p_base <= file_pos);
392: if (verbose && p_base < file_pos) {
1.21 otto 393: fseek(pfp, p_base, SEEK_SET);
1.17 deraadt 394: say("The text leading up to this was:\n--------------------------\n");
395: while (ftell(pfp) < file_pos) {
396: ret = fgets(buf, sizeof buf, pfp);
1.21 otto 397: assert(ret != NULL);
1.17 deraadt 398: say("|%s", buf);
399: }
400: say("--------------------------\n");
401: } else
1.21 otto 402: fseek(pfp, file_pos, SEEK_SET);
1.17 deraadt 403: p_input_line = file_line - 1;
1.1 deraadt 404: }
405:
406: /* Make this a function for better debugging. */
407: static void
1.16 deraadt 408: malformed(void)
1.1 deraadt 409: {
1.17 deraadt 410: fatal("malformed patch at line %ld: %s", p_input_line, buf);
411: /* about as informative as "Syntax error" in C */
1.1 deraadt 412: }
413:
1.14 otto 414: /*
415: * True if the line has been discarded (i.e. it is a line saying
416: * "\ No newline at end of file".)
417: */
418: static bool
419: remove_special_line(void)
420: {
1.17 deraadt 421: int c;
1.14 otto 422:
423: c = fgetc(pfp);
424: if (c == '\\') {
425: do {
426: c = fgetc(pfp);
427: } while (c != EOF && c != '\n');
428:
429: return TRUE;
430: }
431: if (c != EOF)
432: fseek(pfp, -1L, SEEK_CUR);
433:
434: return FALSE;
435: }
436:
1.17 deraadt 437: /*
438: * True if there is more of the current diff listing to process.
439: */
1.1 deraadt 440: bool
1.17 deraadt 441: another_hunk(void)
1.1 deraadt 442: {
1.17 deraadt 443: long line_beginning; /* file pos of the current line */
444: LINENUM repl_beginning; /* index of --- line */
445: LINENUM fillcnt; /* #lines of missing ptrn or repl */
446: LINENUM fillsrc; /* index of first line to copy */
447: LINENUM filldst; /* index of first missing line */
448: bool ptrn_spaces_eaten; /* ptrn was slightly misformed */
449: bool repl_could_be_missing; /* no + or ! lines in this hunk */
450: bool repl_missing; /* we are now backtracking */
451: long repl_backtrack_position; /* file pos of first repl line */
452: LINENUM repl_patch_line; /* input line number for same */
453: LINENUM ptrn_copiable; /* # of copiable lines in ptrn */
454: char *s, *ret;
455: int context = 0;
456:
457: while (p_end >= 0) {
458: if (p_end == p_efake)
459: p_end = p_bfake; /* don't free twice */
460: else
461: free(p_line[p_end]);
462: p_end--;
463: }
464: assert(p_end == -1);
465: p_efake = -1;
466:
467: p_max = hunkmax; /* gets reduced when --- found */
468: if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
469: line_beginning = ftell(pfp);
470: repl_beginning = 0;
471: fillcnt = 0;
472: ptrn_spaces_eaten = FALSE;
473: repl_could_be_missing = TRUE;
474: repl_missing = FALSE;
475: repl_backtrack_position = 0;
476: ptrn_copiable = 0;
477:
478: ret = pgets(buf, sizeof buf, pfp);
479: p_input_line++;
1.21 otto 480: if (ret == NULL || strnNE(buf, "********", 8)) {
1.17 deraadt 481: next_intuit_at(line_beginning, p_input_line);
482: return FALSE;
483: }
484: p_context = 100;
485: p_hunk_beg = p_input_line + 1;
486: while (p_end < p_max) {
487: line_beginning = ftell(pfp);
488: ret = pgets(buf, sizeof buf, pfp);
489: p_input_line++;
1.21 otto 490: if (ret == NULL) {
1.17 deraadt 491: if (p_max - p_end < 4) {
492: /* assume blank lines got chopped */
493: strlcpy(buf, " \n", sizeof buf);
494: } else {
495: if (repl_beginning && repl_could_be_missing) {
496: repl_missing = TRUE;
497: goto hunk_done;
498: }
499: fatal("unexpected end of file in patch\n");
500: }
501: }
502: p_end++;
503: assert(p_end < hunkmax);
504: p_char[p_end] = *buf;
1.21 otto 505: p_line[p_end] = NULL;
1.17 deraadt 506: switch (*buf) {
507: case '*':
508: if (strnEQ(buf, "********", 8)) {
509: if (repl_beginning && repl_could_be_missing) {
510: repl_missing = TRUE;
511: goto hunk_done;
512: } else
513: fatal("unexpected end of hunk "
514: "at line %ld\n",
515: p_input_line);
516: }
517: if (p_end != 0) {
518: if (repl_beginning && repl_could_be_missing) {
519: repl_missing = TRUE;
520: goto hunk_done;
521: }
522: fatal("unexpected *** at line %ld: %s",
523: p_input_line, buf);
524: }
525: context = 0;
526: p_line[p_end] = savestr(buf);
527: if (out_of_mem) {
528: p_end--;
529: return FALSE;
530: }
531: for (s = buf; *s && !isdigit(*s); s++)
532: ;
533: if (!*s)
534: malformed();
535: if (strnEQ(s, "0,0", 3))
536: memmove(s, s + 2, strlen(s + 2) + 1);
537: p_first = (LINENUM) atol(s);
538: while (isdigit(*s))
539: s++;
540: if (*s == ',') {
1.18 deraadt 541: for (; *s && !isdigit(*s); s++)
542: ;
1.17 deraadt 543: if (!*s)
544: malformed();
545: p_ptrn_lines = ((LINENUM) atol(s)) - p_first + 1;
546: } else if (p_first)
547: p_ptrn_lines = 1;
548: else {
549: p_ptrn_lines = 0;
550: p_first = 1;
551: }
552: p_max = p_ptrn_lines + 6; /* we need this much at
553: * least */
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
745: repl_beginning--; /* this doesn't need to be
746: * fixed */
747: #endif
748: p_end--;
749: p_first++; /* do append rather than insert */
750: fillcnt = 0;
751: p_ptrn_lines = 0;
752: }
753: if (diff_type == CONTEXT_DIFF &&
754: (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) {
755: if (verbose)
756: say("%s\n%s\n%s\n",
757: "(Fascinating--this is really a new-style context diff but without",
758: "the telltale extra asterisks on the *** line that usually indicate",
759: "the new style...)");
760: diff_type = NEW_CONTEXT_DIFF;
761: }
762: /* if there were omitted context lines, fill them in now */
763: if (fillcnt) {
764: p_bfake = filldst; /* remember where not to
765: * free() */
766: p_efake = filldst + fillcnt - 1;
767: while (fillcnt-- > 0) {
768: while (fillsrc <= p_end && p_char[fillsrc] != ' ')
769: fillsrc++;
770: if (fillsrc > p_end)
771: fatal("replacement text or line numbers mangled in hunk at line %ld\n",
772: p_hunk_beg);
773: p_line[filldst] = p_line[fillsrc];
774: p_char[filldst] = p_char[fillsrc];
775: p_len[filldst] = p_len[fillsrc];
776: fillsrc++;
777: filldst++;
778: }
779: while (fillsrc <= p_end && fillsrc != repl_beginning &&
780: p_char[fillsrc] != ' ')
781: fillsrc++;
782: #ifdef DEBUGGING
783: if (debug & 64)
784: printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
785: fillsrc, filldst, repl_beginning, p_end + 1);
1.1 deraadt 786: #endif
1.17 deraadt 787: assert(fillsrc == p_end + 1 || fillsrc == repl_beginning);
788: assert(filldst == p_end + 1 || filldst == repl_beginning);
1.1 deraadt 789: }
1.17 deraadt 790: if (p_line[p_end] != NULL) {
791: if (remove_special_line()) {
792: p_len[p_end] -= 1;
793: (p_line[p_end])[p_len[p_end]] = 0;
794: }
795: }
796: } else if (diff_type == UNI_DIFF) {
797: long line_beginning = ftell(pfp); /* file pos of the current line */
798: LINENUM fillsrc; /* index of old lines */
799: LINENUM filldst; /* index of new lines */
800: char ch;
801:
802: ret = pgets(buf, sizeof buf, pfp);
803: p_input_line++;
1.21 otto 804: if (ret == NULL || strnNE(buf, "@@ -", 4)) {
1.17 deraadt 805: next_intuit_at(line_beginning, p_input_line);
806: return FALSE;
1.1 deraadt 807: }
1.17 deraadt 808: s = buf + 4;
1.1 deraadt 809: if (!*s)
1.17 deraadt 810: malformed();
1.1 deraadt 811: p_first = (LINENUM) atol(s);
1.17 deraadt 812: while (isdigit(*s))
813: s++;
814: if (*s == ',') {
815: p_ptrn_lines = (LINENUM) atol(++s);
816: while (isdigit(*s))
817: s++;
818: } else
819: p_ptrn_lines = 1;
820: if (*s == ' ')
821: s++;
822: if (*s != '+' || !*++s)
823: malformed();
824: p_newfirst = (LINENUM) atol(s);
825: while (isdigit(*s))
826: s++;
1.1 deraadt 827: if (*s == ',') {
1.17 deraadt 828: p_repl_lines = (LINENUM) atol(++s);
829: while (isdigit(*s))
830: s++;
831: } else
832: p_repl_lines = 1;
833: if (*s == ' ')
834: s++;
835: if (*s != '@')
836: malformed();
837: if (!p_ptrn_lines)
838: p_first++; /* do append rather than insert */
839: p_max = p_ptrn_lines + p_repl_lines + 1;
840: while (p_max >= hunkmax)
841: grow_hunkmax();
842: fillsrc = 1;
843: filldst = fillsrc + p_ptrn_lines;
844: p_end = filldst + p_repl_lines;
845: snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first,
846: p_first + p_ptrn_lines - 1);
847: p_line[0] = savestr(buf);
848: if (out_of_mem) {
849: p_end = -1;
850: return FALSE;
851: }
852: p_char[0] = '*';
853: snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,
854: p_newfirst + p_repl_lines - 1);
855: p_line[filldst] = savestr(buf);
856: if (out_of_mem) {
857: p_end = 0;
858: return FALSE;
1.1 deraadt 859: }
1.17 deraadt 860: p_char[filldst++] = '=';
861: p_context = 100;
862: context = 0;
863: p_hunk_beg = p_input_line + 1;
864: while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
865: line_beginning = ftell(pfp);
866: ret = pgets(buf, sizeof buf, pfp);
867: p_input_line++;
1.21 otto 868: if (ret == NULL) {
1.17 deraadt 869: if (p_max - filldst < 3) {
870: /* assume blank lines got chopped */
871: strlcpy(buf, " \n", sizeof buf);
872: } else {
873: fatal("unexpected end of file in patch\n");
874: }
875: }
876: if (*buf == '\t' || *buf == '\n') {
877: ch = ' '; /* assume the space got eaten */
878: s = savestr(buf);
879: } else {
880: ch = *buf;
881: s = savestr(buf + 1);
882: }
883: if (out_of_mem) {
884: while (--filldst > p_ptrn_lines)
885: free(p_line[filldst]);
886: p_end = fillsrc - 1;
887: return FALSE;
888: }
889: switch (ch) {
890: case '-':
891: if (fillsrc > p_ptrn_lines) {
892: free(s);
893: p_end = filldst - 1;
894: malformed();
895: }
896: p_char[fillsrc] = ch;
897: p_line[fillsrc] = s;
898: p_len[fillsrc++] = strlen(s);
899: if (fillsrc > p_ptrn_lines) {
900: if (remove_special_line()) {
901: p_len[fillsrc - 1] -= 1;
902: s[p_len[fillsrc - 1]] = 0;
903: }
904: }
905: break;
906: case '=':
907: ch = ' ';
908: /* FALL THROUGH */
909: case ' ':
910: if (fillsrc > p_ptrn_lines) {
911: free(s);
912: while (--filldst > p_ptrn_lines)
913: free(p_line[filldst]);
914: p_end = fillsrc - 1;
915: malformed();
916: }
917: context++;
918: p_char[fillsrc] = ch;
919: p_line[fillsrc] = s;
920: p_len[fillsrc++] = strlen(s);
921: s = savestr(s);
922: if (out_of_mem) {
923: while (--filldst > p_ptrn_lines)
924: free(p_line[filldst]);
925: p_end = fillsrc - 1;
926: return FALSE;
927: }
928: /* FALL THROUGH */
929: case '+':
930: if (filldst > p_end) {
931: free(s);
932: while (--filldst > p_ptrn_lines)
933: free(p_line[filldst]);
934: p_end = fillsrc - 1;
935: malformed();
936: }
937: p_char[filldst] = ch;
938: p_line[filldst] = s;
939: p_len[filldst++] = strlen(s);
940: if (fillsrc > p_ptrn_lines) {
941: if (remove_special_line()) {
942: p_len[filldst - 1] -= 1;
943: s[p_len[filldst - 1]] = 0;
944: }
945: }
946: break;
947: default:
948: p_end = filldst;
949: malformed();
1.1 deraadt 950: }
1.17 deraadt 951: if (ch != ' ' && context > 0) {
952: if (context < p_context)
953: p_context = context;
954: context = -1000;
1.1 deraadt 955: }
1.17 deraadt 956: } /* while */
957: } else { /* normal diff--fake it up */
958: char hunk_type;
959: int i;
960: LINENUM min, max;
961: long line_beginning = ftell(pfp);
962:
963: p_context = 0;
964: ret = pgets(buf, sizeof buf, pfp);
965: p_input_line++;
1.21 otto 966: if (ret == NULL || !isdigit(*buf)) {
1.17 deraadt 967: next_intuit_at(line_beginning, p_input_line);
1.1 deraadt 968: return FALSE;
1.17 deraadt 969: }
970: p_first = (LINENUM) atol(buf);
1.18 deraadt 971: for (s = buf; isdigit(*s); s++)
972: ;
1.17 deraadt 973: if (*s == ',') {
974: p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1;
975: while (isdigit(*s))
976: s++;
977: } else
978: p_ptrn_lines = (*s != 'a');
979: hunk_type = *s;
980: if (hunk_type == 'a')
981: p_first++; /* do append rather than insert */
982: min = (LINENUM) atol(++s);
1.18 deraadt 983: for (; isdigit(*s); s++)
984: ;
1.17 deraadt 985: if (*s == ',')
986: max = (LINENUM) atol(++s);
987: else
988: max = min;
989: if (hunk_type == 'd')
990: min++;
991: p_end = p_ptrn_lines + 1 + max - min + 1;
992: if (p_end > MAXHUNKSIZE)
1.16 deraadt 993: fatal("hunk too large (%ld lines) at line %ld: %s",
1.17 deraadt 994: p_end, p_input_line, buf);
995: while (p_end >= hunkmax)
1.1 deraadt 996: grow_hunkmax();
1.17 deraadt 997: p_newfirst = min;
998: p_repl_lines = max - min + 1;
999: snprintf(buf, sizeof buf, "*** %ld,%ld\n", p_first,
1000: p_first + p_ptrn_lines - 1);
1001: p_line[0] = savestr(buf);
1.1 deraadt 1002: if (out_of_mem) {
1.17 deraadt 1003: p_end = -1;
1004: return FALSE;
1.1 deraadt 1005: }
1.17 deraadt 1006: p_char[0] = '*';
1007: for (i = 1; i <= p_ptrn_lines; i++) {
1008: ret = pgets(buf, sizeof buf, pfp);
1009: p_input_line++;
1.21 otto 1010: if (ret == NULL)
1.17 deraadt 1011: fatal("unexpected end of file in patch at line %ld\n",
1012: p_input_line);
1013: if (*buf != '<')
1014: fatal("< expected at line %ld of patch\n",
1015: p_input_line);
1016: p_line[i] = savestr(buf + 2);
1017: if (out_of_mem) {
1018: p_end = i - 1;
1019: return FALSE;
1.14 otto 1020: }
1.17 deraadt 1021: p_len[i] = strlen(p_line[i]);
1022: p_char[i] = '-';
1.14 otto 1023: }
1.17 deraadt 1024:
1025: if (remove_special_line()) {
1026: p_len[i - 1] -= 1;
1027: (p_line[i - 1])[p_len[i - 1]] = 0;
1.1 deraadt 1028: }
1.17 deraadt 1029: if (hunk_type == 'c') {
1030: ret = pgets(buf, sizeof buf, pfp);
1031: p_input_line++;
1.21 otto 1032: if (ret == NULL)
1.17 deraadt 1033: fatal("unexpected end of file in patch at line %ld\n",
1034: p_input_line);
1035: if (*buf != '-')
1036: fatal("--- expected at line %ld of patch\n",
1037: p_input_line);
1.1 deraadt 1038: }
1.17 deraadt 1039: snprintf(buf, sizeof(buf), "--- %ld,%ld\n", min, max);
1040: p_line[i] = savestr(buf);
1.1 deraadt 1041: if (out_of_mem) {
1.17 deraadt 1042: p_end = i - 1;
1043: return FALSE;
1.1 deraadt 1044: }
1.17 deraadt 1045: p_char[i] = '=';
1046: for (i++; i <= p_end; i++) {
1047: ret = pgets(buf, sizeof buf, pfp);
1048: p_input_line++;
1.21 otto 1049: if (ret == NULL)
1.17 deraadt 1050: fatal("unexpected end of file in patch at line %ld\n",
1051: p_input_line);
1052: if (*buf != '>')
1053: fatal("> expected at line %ld of patch\n",
1054: p_input_line);
1055: p_line[i] = savestr(buf + 2);
1056: if (out_of_mem) {
1057: p_end = i - 1;
1058: return FALSE;
1.14 otto 1059: }
1.17 deraadt 1060: p_len[i] = strlen(p_line[i]);
1061: p_char[i] = '+';
1.14 otto 1062: }
1.17 deraadt 1063:
1064: if (remove_special_line()) {
1065: p_len[i - 1] -= 1;
1066: (p_line[i - 1])[p_len[i - 1]] = 0;
1.14 otto 1067: }
1.1 deraadt 1068: }
1.17 deraadt 1069: if (reverse) /* backwards patch? */
1070: if (!pch_swap())
1071: say("Not enough memory to swap next hunk!\n");
1.1 deraadt 1072: #ifdef DEBUGGING
1.17 deraadt 1073: if (debug & 2) {
1074: int i;
1075: char special;
1076:
1077: for (i = 0; i <= p_end; i++) {
1078: if (i == p_ptrn_lines)
1079: special = '^';
1080: else
1081: special = ' ';
1082: fprintf(stderr, "%3d %c %c %s", i, p_char[i],
1083: special, p_line[i]);
1084: fflush(stderr);
1085: }
1.1 deraadt 1086: }
1087: #endif
1.17 deraadt 1088: if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */
1089: p_char[p_end + 1] = '^'; /* add a stopper for apply_hunk */
1090: return TRUE;
1.1 deraadt 1091: }
1092:
1.17 deraadt 1093: /*
1094: * Input a line from the patch file, worrying about indentation.
1095: */
1.21 otto 1096: static char *
1.17 deraadt 1097: pgets(char *bf, int sz, FILE *fp)
1098: {
1099: char *s, *ret = fgets(bf, sz, fp);
1100: int indent = 0;
1.1 deraadt 1101:
1.21 otto 1102: if (p_indent && ret != NULL) {
1.17 deraadt 1103: for (s = buf;
1104: indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X');
1105: s++) {
1106: if (*s == '\t')
1107: indent += 8 - (indent % 7);
1108: else
1109: indent++;
1110: }
1111: if (buf != s && strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
1112: fatal("buffer too small in pgets()\n");
1113: }
1114: return ret;
1.1 deraadt 1115: }
1116:
1.17 deraadt 1117: /*
1118: * Reverse the old and new portions of the current hunk.
1119: */
1.1 deraadt 1120: bool
1.17 deraadt 1121: pch_swap(void)
1.1 deraadt 1122: {
1.17 deraadt 1123: char **tp_line; /* the text of the hunk */
1124: short *tp_len; /* length of each line */
1125: char *tp_char; /* +, -, and ! */
1126: LINENUM i;
1127: LINENUM n;
1128: bool blankline = FALSE;
1129: char *s;
1130:
1131: i = p_first;
1132: p_first = p_newfirst;
1133: p_newfirst = i;
1134:
1135: /* make a scratch copy */
1136:
1137: tp_line = p_line;
1138: tp_len = p_len;
1139: tp_char = p_char;
1.21 otto 1140: p_line = NULL; /* force set_hunkmax to allocate again */
1141: p_len = NULL;
1142: p_char = NULL;
1.17 deraadt 1143: set_hunkmax();
1.21 otto 1144: if (p_line == NULL ||p_len == NULL ||p_char == NULL) {
1145:
1146: if (p_line == NULL) /* XXX */
1147: free(p_line);
1.17 deraadt 1148: p_line = tp_line;
1.21 otto 1149: if (p_len == NULL) /* XXX */
1150: free(p_len);
1.17 deraadt 1151: p_len = tp_len;
1.21 otto 1152: if (p_char == NULL) /* XXX */
1153: free(p_char);
1.17 deraadt 1154: p_char = tp_char;
1155: return FALSE; /* not enough memory to swap hunk! */
1156: }
1157: /* now turn the new into the old */
1158:
1.1 deraadt 1159: i = p_ptrn_lines + 1;
1.17 deraadt 1160: if (tp_char[i] == '\n') { /* account for possible blank line */
1161: blankline = TRUE;
1162: i++;
1163: }
1164: if (p_efake >= 0) { /* fix non-freeable ptr range */
1165: if (p_efake <= i)
1166: n = p_end - i + 1;
1167: else
1168: n = -i;
1169: p_efake += n;
1170: p_bfake += n;
1171: }
1172: for (n = 0; i <= p_end; i++, n++) {
1173: p_line[n] = tp_line[i];
1174: p_char[n] = tp_char[i];
1175: if (p_char[n] == '+')
1176: p_char[n] = '-';
1177: p_len[n] = tp_len[i];
1178: }
1179: if (blankline) {
1180: i = p_ptrn_lines + 1;
1181: p_line[n] = tp_line[i];
1182: p_char[n] = tp_char[i];
1183: p_len[n] = tp_len[i];
1184: n++;
1185: }
1186: assert(p_char[0] == '=');
1187: p_char[0] = '*';
1188: for (s = p_line[0]; *s; s++)
1189: if (*s == '-')
1190: *s = '*';
1191:
1192: /* now turn the old into the new */
1193:
1194: assert(tp_char[0] == '*');
1195: tp_char[0] = '=';
1196: for (s = tp_line[0]; *s; s++)
1197: if (*s == '*')
1198: *s = '-';
1199: for (i = 0; n <= p_end; i++, n++) {
1200: p_line[n] = tp_line[i];
1201: p_char[n] = tp_char[i];
1202: if (p_char[n] == '-')
1203: p_char[n] = '+';
1204: p_len[n] = tp_len[i];
1205: }
1206: assert(i == p_ptrn_lines + 1);
1207: i = p_ptrn_lines;
1208: p_ptrn_lines = p_repl_lines;
1209: p_repl_lines = i;
1.21 otto 1210:
1211: if (tp_line == NULL) /* XXX */
1212: free(tp_line);
1213: if (tp_len == NULL) /* XXX */
1214: free(tp_len);
1215: if (tp_char == NULL) /* XXX */
1216: free(tp_char);
1.17 deraadt 1217: return TRUE;
1.1 deraadt 1218: }
1219:
1.17 deraadt 1220: /*
1221: * Return the specified line position in the old file of the old context.
1222: */
1.1 deraadt 1223: LINENUM
1.17 deraadt 1224: pch_first(void)
1.1 deraadt 1225: {
1.17 deraadt 1226: return p_first;
1.1 deraadt 1227: }
1228:
1.17 deraadt 1229: /*
1230: * Return the number of lines of old context.
1231: */
1.1 deraadt 1232: LINENUM
1.17 deraadt 1233: pch_ptrn_lines(void)
1.1 deraadt 1234: {
1.17 deraadt 1235: return p_ptrn_lines;
1.1 deraadt 1236: }
1237:
1.17 deraadt 1238: /*
1239: * Return the probable line position in the new file of the first line.
1240: */
1.1 deraadt 1241: LINENUM
1.17 deraadt 1242: pch_newfirst(void)
1.1 deraadt 1243: {
1.17 deraadt 1244: return p_newfirst;
1.1 deraadt 1245: }
1246:
1.17 deraadt 1247: /*
1248: * Return the number of lines in the replacement text including context.
1249: */
1.1 deraadt 1250: LINENUM
1.17 deraadt 1251: pch_repl_lines(void)
1.1 deraadt 1252: {
1.17 deraadt 1253: return p_repl_lines;
1.1 deraadt 1254: }
1255:
1.17 deraadt 1256: /*
1257: * Return the number of lines in the whole hunk.
1258: */
1.1 deraadt 1259: LINENUM
1.17 deraadt 1260: pch_end(void)
1.1 deraadt 1261: {
1.17 deraadt 1262: return p_end;
1.1 deraadt 1263: }
1264:
1.17 deraadt 1265: /*
1266: * Return the number of context lines before the first changed line.
1267: */
1.1 deraadt 1268: LINENUM
1.17 deraadt 1269: pch_context(void)
1.1 deraadt 1270: {
1.17 deraadt 1271: return p_context;
1.1 deraadt 1272: }
1273:
1.17 deraadt 1274: /*
1275: * Return the length of a particular patch line.
1276: */
1.1 deraadt 1277: short
1.17 deraadt 1278: pch_line_len(LINENUM line)
1.1 deraadt 1279: {
1.17 deraadt 1280: return p_len[line];
1.1 deraadt 1281: }
1282:
1.17 deraadt 1283: /*
1284: * Return the control character (+, -, *, !, etc) for a patch line.
1285: */
1.1 deraadt 1286: char
1.17 deraadt 1287: pch_char(LINENUM line)
1.1 deraadt 1288: {
1.17 deraadt 1289: return p_char[line];
1.1 deraadt 1290: }
1291:
1.17 deraadt 1292: /*
1293: * Return a pointer to a particular patch line.
1294: */
1.1 deraadt 1295: char *
1.17 deraadt 1296: pfetch(LINENUM line)
1.1 deraadt 1297: {
1.17 deraadt 1298: return p_line[line];
1.1 deraadt 1299: }
1300:
1.17 deraadt 1301: /*
1302: * Return where in the patch file this hunk began, for error messages.
1303: */
1.1 deraadt 1304: LINENUM
1.17 deraadt 1305: pch_hunk_beg(void)
1.1 deraadt 1306: {
1.17 deraadt 1307: return p_hunk_beg;
1.1 deraadt 1308: }
1309:
1.17 deraadt 1310: /*
1311: * Apply an ed script by feeding ed itself.
1312: */
1.1 deraadt 1313: void
1.17 deraadt 1314: do_ed_script(void)
1.1 deraadt 1315: {
1.17 deraadt 1316: char *t;
1317: long beginning_of_this_line;
1318: FILE *pipefp;
1319:
1320: if (!skip_rest_of_patch) {
1.24 millert 1321: if (copy_file(filearg[0], TMPOUTNAME) < 0) {
1322: unlink(TMPOUTNAME);
1323: fatal("can't create temp file %s", TMPOUTNAME);
1324: }
1.17 deraadt 1325: if (verbose)
1326: snprintf(buf, sizeof buf, "/bin/ed %s", TMPOUTNAME);
1327: else
1328: snprintf(buf, sizeof buf, "/bin/ed - %s", TMPOUTNAME);
1329: pipefp = popen(buf, "w");
1330: }
1331: for (;;) {
1332: beginning_of_this_line = ftell(pfp);
1.21 otto 1333: if (pgets(buf, sizeof buf, pfp) == NULL) {
1.17 deraadt 1334: next_intuit_at(beginning_of_this_line, p_input_line);
1335: break;
1336: }
1337: p_input_line++;
1.18 deraadt 1338: for (t = buf; isdigit(*t) || *t == ','; t++)
1339: ;
1.22 millert 1340: /* POSIX defines allowed commands as {a,c,d,i,s} */
1341: if (isdigit(*buf) && (*t == 'a' || *t == 'c' || *t == 'd' ||
1342: *t == 'i' || *t == 's')) {
1.17 deraadt 1343: if (!skip_rest_of_patch)
1344: fputs(buf, pipefp);
1345: if (*t != 'd') {
1.21 otto 1346: while (pgets(buf, sizeof buf, pfp) != NULL) {
1.17 deraadt 1347: p_input_line++;
1348: if (!skip_rest_of_patch)
1349: fputs(buf, pipefp);
1350: if (strEQ(buf, ".\n"))
1351: break;
1352: }
1353: }
1354: } else {
1355: next_intuit_at(beginning_of_this_line, p_input_line);
1.1 deraadt 1356: break;
1357: }
1358: }
1.17 deraadt 1359: if (skip_rest_of_patch)
1360: return;
1361: fprintf(pipefp, "w\n");
1362: fprintf(pipefp, "q\n");
1363: fflush(pipefp);
1364: pclose(pipefp);
1365: ignore_signals();
1366: if (!check_only) {
1367: if (move_file(TMPOUTNAME, outname) < 0) {
1368: toutkeep = TRUE;
1369: chmod(TMPOUTNAME, filemode);
1370: } else
1371: chmod(outname, filemode);
1.1 deraadt 1372: }
1.17 deraadt 1373: set_signals(1);
1.1 deraadt 1374: }