Annotation of src/usr.bin/patch/pch.c, Revision 1.27
1.27 ! millert 1: /* $OpenBSD: pch.c,v 1.26 2003/07/28 19:15:34 deraadt Exp $ */
1.2 niklas 2:
1.1 deraadt 3: #ifndef lint
1.27 ! millert 4: static const char rcsid[] = "$OpenBSD: pch.c,v 1.26 2003/07/28 19:15:34 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>
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"
1.27 ! millert 20: #include "pathnames.h"
1.1 deraadt 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.25 otto 33: static char **p_line = NULL;/* the text of the hunk */
1.21 otto 34: static short *p_len = NULL; /* length of each line */
1.25 otto 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.25 otto 45: static FILE *pfp = NULL; /* patch file pointer */
46: static char *bestguess = NULL; /* guess at correct filename */
1.1 deraadt 47:
1.21 otto 48: static void grow_hunkmax(void);
49: static int intuit_diff_type(void);
1.25 otto 50: static void next_intuit_at(LINENUM, LINENUM);
51: static void skip_to(LINENUM, LINENUM);
1.23 deraadt 52: static char *pgets(char *, int, FILE *);
1.21 otto 53:
1.25 otto 54:
1.17 deraadt 55: /*
56: * Prepare to look for the next patch in the patch file.
57: */
1.1 deraadt 58: void
1.17 deraadt 59: re_patch(void)
1.1 deraadt 60: {
1.25 otto 61: p_first = 0;
62: p_newfirst = 0;
63: p_ptrn_lines = 0;
64: p_repl_lines = 0;
1.17 deraadt 65: p_end = (LINENUM) - 1;
1.25 otto 66: p_max = 0;
1.17 deraadt 67: p_indent = 0;
1.1 deraadt 68: }
69:
1.17 deraadt 70: /*
71: * Open the patch file at the beginning of time.
72: */
1.1 deraadt 73: void
1.25 otto 74: open_patch_file(const char *filename)
1.1 deraadt 75: {
1.25 otto 76: struct stat filestat;
77:
78: if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) {
1.17 deraadt 79: pfp = fopen(TMPPATNAME, "w");
1.21 otto 80: if (pfp == NULL)
1.17 deraadt 81: pfatal("can't create %s", TMPPATNAME);
1.21 otto 82: while (fgets(buf, sizeof buf, stdin) != NULL)
1.17 deraadt 83: fputs(buf, pfp);
84: fclose(pfp);
85: filename = TMPPATNAME;
86: }
87: pfp = fopen(filename, "r");
1.21 otto 88: if (pfp == NULL)
1.17 deraadt 89: pfatal("patch file %s not found", filename);
90: fstat(fileno(pfp), &filestat);
91: p_filesize = filestat.st_size;
92: next_intuit_at(0L, 1L); /* start at the beginning */
93: set_hunkmax();
1.1 deraadt 94: }
95:
1.17 deraadt 96: /*
97: * Make sure our dynamically realloced tables are malloced to begin with.
98: */
1.1 deraadt 99: void
1.17 deraadt 100: set_hunkmax(void)
1.1 deraadt 101: {
1.21 otto 102: if (p_line == NULL)
103: p_line = malloc((size_t) hunkmax * sizeof(char *));
104: if (p_len == NULL)
105: p_len = malloc((size_t) hunkmax * sizeof(short));
106: if (p_char == NULL)
107: p_char = malloc((size_t) hunkmax * sizeof(char));
1.1 deraadt 108: }
109:
1.17 deraadt 110: /*
111: * Enlarge the arrays containing the current hunk of patch.
112: */
1.21 otto 113: static void
1.17 deraadt 114: grow_hunkmax(void)
1.1 deraadt 115: {
1.17 deraadt 116: hunkmax *= 2;
117:
118: /*
119: * Note that on most systems, only the p_line array ever gets fresh memory
120: * since p_len can move into p_line's old space, and p_char can move into
121: * p_len's old space. Not on PDP-11's however. But it doesn't matter.
122: */
1.25 otto 123: assert(p_line != NULL && p_len != NULL && p_char != NULL);
1.21 otto 124:
125: p_line = realloc(p_line, hunkmax * sizeof(char *));
126: p_len = realloc(p_len, hunkmax * sizeof(short));
127: p_char = realloc(p_char, hunkmax * sizeof(char));
128:
1.25 otto 129: if (p_line != NULL && p_len != NULL && p_char != NULL)
1.17 deraadt 130: return;
131: if (!using_plan_a)
132: fatal("out of memory\n");
133: out_of_mem = TRUE; /* whatever is null will be allocated again */
134: /* from within plan_a(), of all places */
1.1 deraadt 135: }
136:
137: /* True if the remainder of the patch file contains a diff of some sort. */
138:
139: bool
1.17 deraadt 140: there_is_another_patch(void)
1.1 deraadt 141: {
1.17 deraadt 142: if (p_base != 0L && p_base >= p_filesize) {
143: if (verbose)
144: say("done\n");
145: return FALSE;
146: }
1.1 deraadt 147: if (verbose)
1.17 deraadt 148: say("Hmm...");
149: diff_type = intuit_diff_type();
150: if (!diff_type) {
151: if (p_base != 0L) {
152: if (verbose)
153: say(" Ignoring the trailing garbage.\ndone\n");
154: } else
155: say(" I can't seem to find a patch in there anywhere.\n");
156: return FALSE;
1.1 deraadt 157: }
1.17 deraadt 158: if (verbose)
159: say(" %sooks like %s to me...\n",
160: (p_base == 0L ? "L" : "The next patch l"),
161: diff_type == UNI_DIFF ? "a unified diff" :
162: diff_type == CONTEXT_DIFF ? "a context diff" :
163: diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
164: diff_type == NORMAL_DIFF ? "a normal diff" :
165: "an ed script");
166: if (p_indent && verbose)
167: say("(Patch is indented %d space%s.)\n", p_indent,
168: p_indent == 1 ? "" : "s");
169: skip_to(p_start, p_sline);
1.21 otto 170: while (filearg[0] == NULL) {
1.17 deraadt 171: if (force || batch) {
172: say("No file to patch. Skipping...\n");
173: filearg[0] = savestr(bestguess);
174: skip_rest_of_patch = TRUE;
175: return TRUE;
176: }
177: ask("File to patch: ");
178: if (*buf != '\n') {
1.25 otto 179: free(bestguess);
1.17 deraadt 180: bestguess = savestr(buf);
181: filearg[0] = fetchname(buf, 0, FALSE);
182: }
1.21 otto 183: if (filearg[0] == NULL) {
1.17 deraadt 184: ask("No file found--skip this patch? [n] ");
185: if (*buf != 'y')
186: continue;
187: if (verbose)
188: say("Skipping patch...\n");
189: filearg[0] = fetchname(bestguess, 0, TRUE);
190: skip_rest_of_patch = TRUE;
191: return TRUE;
192: }
1.1 deraadt 193: }
1.17 deraadt 194: return TRUE;
1.1 deraadt 195: }
196:
197: /* Determine what kind of diff is in the remaining part of the patch file. */
198:
1.21 otto 199: static int
1.17 deraadt 200: intuit_diff_type(void)
1.1 deraadt 201: {
1.17 deraadt 202: long this_line = 0, previous_line;
203: long first_command_line = -1, fcl_line;
204: bool last_line_was_command = FALSE, this_is_a_command = FALSE;
205: bool stars_last_line = FALSE, stars_this_line = FALSE;
206: char *s, *t;
1.21 otto 207: char *indtmp = NULL;
208: char *oldtmp = NULL;
209: char *newtmp = NULL;
210: char *indname = NULL;
211: char *oldname = NULL;
212: char *newname = NULL;
1.17 deraadt 213: int indent, retval;
1.21 otto 214: bool no_filearg = (filearg[0] == NULL);
1.17 deraadt 215:
216: ok_to_create_file = FALSE;
1.21 otto 217: fseek(pfp, p_base, SEEK_SET);
1.17 deraadt 218: p_input_line = p_bline - 1;
219: for (;;) {
220: previous_line = this_line;
221: last_line_was_command = this_is_a_command;
222: stars_last_line = stars_this_line;
223: this_line = ftell(pfp);
224: indent = 0;
225: p_input_line++;
1.21 otto 226: if (fgets(buf, sizeof buf, pfp) == NULL) {
1.17 deraadt 227: if (first_command_line >= 0L) {
228: /* nothing but deletes!? */
229: p_start = first_command_line;
230: p_sline = fcl_line;
231: retval = ED_DIFF;
232: goto scan_exit;
233: } else {
234: p_start = this_line;
235: p_sline = p_input_line;
236: retval = 0;
237: goto scan_exit;
238: }
239: }
240: for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
241: if (*s == '\t')
242: indent += 8 - (indent % 8);
243: else
244: indent++;
245: }
246: for (t = s; isdigit(*t) || *t == ','; t++)
247: ;
248: this_is_a_command = (isdigit(*s) &&
249: (*t == 'd' || *t == 'c' || *t == 'a'));
250: if (first_command_line < 0L && this_is_a_command) {
251: first_command_line = this_line;
252: fcl_line = p_input_line;
253: p_indent = indent; /* assume this for now */
254: }
255: if (!stars_last_line && strnEQ(s, "*** ", 4))
256: oldtmp = savestr(s + 4);
257: else if (strnEQ(s, "--- ", 4))
258: newtmp = savestr(s + 4);
259: else if (strnEQ(s, "+++ ", 4))
1.26 deraadt 260: oldtmp = savestr(s + 4); /* pretend it is the old name */
1.17 deraadt 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: }
1.26 deraadt 552:
553: /* we need this much at least */
554: p_max = p_ptrn_lines + 6;
1.17 deraadt 555: while (p_max >= hunkmax)
556: grow_hunkmax();
557: p_max = hunkmax;
558: break;
559: case '-':
560: if (buf[1] == '-') {
561: if (repl_beginning ||
562: (p_end != p_ptrn_lines + 1 +
563: (p_char[p_end - 1] == '\n'))) {
564: if (p_end == 1) {
565: /*
566: * `old' lines were omitted;
567: * set up to fill them in
568: * from 'new' context lines.
569: */
570: p_end = p_ptrn_lines + 1;
571: fillsrc = p_end + 1;
572: filldst = 1;
573: fillcnt = p_ptrn_lines;
574: } else {
575: if (repl_beginning) {
576: if (repl_could_be_missing) {
577: repl_missing = TRUE;
578: goto hunk_done;
579: }
580: fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n",
581: p_input_line, p_hunk_beg + repl_beginning);
582: } else {
583: fatal("%s \"---\" at line %ld--check line numbers at line %ld\n",
584: (p_end <= p_ptrn_lines
585: ? "Premature"
586: : "Overdue"),
587: p_input_line, p_hunk_beg);
588: }
589: }
590: }
591: repl_beginning = p_end;
592: repl_backtrack_position = ftell(pfp);
593: repl_patch_line = p_input_line;
594: p_line[p_end] = savestr(buf);
595: if (out_of_mem) {
596: p_end--;
597: return FALSE;
598: }
599: p_char[p_end] = '=';
600: for (s = buf; *s && !isdigit(*s); s++)
601: ;
602: if (!*s)
603: malformed();
604: p_newfirst = (LINENUM) atol(s);
605: while (isdigit(*s))
606: s++;
607: if (*s == ',') {
608: for (; *s && !isdigit(*s); s++)
609: ;
610: if (!*s)
611: malformed();
612: p_repl_lines = ((LINENUM) atol(s)) -
613: p_newfirst + 1;
614: } else if (p_newfirst)
615: p_repl_lines = 1;
616: else {
617: p_repl_lines = 0;
618: p_newfirst = 1;
619: }
620: p_max = p_repl_lines + p_end;
621: if (p_max > MAXHUNKSIZE)
622: fatal("hunk too large (%ld lines) at line %ld: %s",
623: p_max, p_input_line, buf);
624: while (p_max >= hunkmax)
625: grow_hunkmax();
626: if (p_repl_lines != ptrn_copiable &&
627: (p_context != 0 || p_repl_lines != 1))
628: repl_could_be_missing = FALSE;
629: break;
630: }
631: goto change_line;
632: case '+':
633: case '!':
634: repl_could_be_missing = FALSE;
635: change_line:
636: if (buf[1] == '\n' && canonicalize)
637: strlcpy(buf + 1, " \n", sizeof buf - 1);
638: if (!isspace(buf[1]) && buf[1] != '>' &&
639: buf[1] != '<' &&
640: repl_beginning && repl_could_be_missing) {
641: repl_missing = TRUE;
642: goto hunk_done;
643: }
644: if (context >= 0) {
645: if (context < p_context)
646: p_context = context;
647: context = -1000;
648: }
649: p_line[p_end] = savestr(buf + 2);
650: if (out_of_mem) {
651: p_end--;
652: return FALSE;
653: }
654: if (p_end == p_ptrn_lines) {
655: if (remove_special_line()) {
656: int len;
657:
658: len = strlen(p_line[p_end]) - 1;
659: (p_line[p_end])[len] = 0;
660: }
661: }
662: break;
663: case '\t':
664: case '\n': /* assume the 2 spaces got eaten */
665: if (repl_beginning && repl_could_be_missing &&
666: (!ptrn_spaces_eaten ||
667: diff_type == NEW_CONTEXT_DIFF)) {
668: repl_missing = TRUE;
669: goto hunk_done;
670: }
671: p_line[p_end] = savestr(buf);
672: if (out_of_mem) {
673: p_end--;
674: return FALSE;
675: }
676: if (p_end != p_ptrn_lines + 1) {
677: ptrn_spaces_eaten |= (repl_beginning != 0);
678: context++;
679: if (!repl_beginning)
680: ptrn_copiable++;
681: p_char[p_end] = ' ';
682: }
683: break;
684: case ' ':
685: if (!isspace(buf[1]) &&
1.23 deraadt 686: repl_beginning && repl_could_be_missing) {
1.17 deraadt 687: repl_missing = TRUE;
688: goto hunk_done;
689: }
690: context++;
691: if (!repl_beginning)
692: ptrn_copiable++;
693: p_line[p_end] = savestr(buf + 2);
694: if (out_of_mem) {
695: p_end--;
696: return FALSE;
697: }
698: break;
699: default:
700: if (repl_beginning && repl_could_be_missing) {
701: repl_missing = TRUE;
702: goto hunk_done;
703: }
704: malformed();
705: }
706: /* set up p_len for strncmp() so we don't have to */
707: /* assume null termination */
708: if (p_line[p_end])
709: p_len[p_end] = strlen(p_line[p_end]);
710: else
711: p_len[p_end] = 0;
712: }
713:
714: hunk_done:
715: if (p_end >= 0 && !repl_beginning)
716: fatal("no --- found in patch at line %ld\n", pch_hunk_beg());
717:
718: if (repl_missing) {
719:
720: /* reset state back to just after --- */
721: p_input_line = repl_patch_line;
722: for (p_end--; p_end > repl_beginning; p_end--)
723: free(p_line[p_end]);
1.21 otto 724: fseek(pfp, repl_backtrack_position, SEEK_SET);
1.17 deraadt 725:
726: /* redundant 'new' context lines were omitted - set */
727: /* up to fill them in from the old file context */
728: if (!p_context && p_repl_lines == 1) {
729: p_repl_lines = 0;
730: p_max--;
731: }
732: fillsrc = 1;
733: filldst = repl_beginning + 1;
734: fillcnt = p_repl_lines;
735: p_end = p_max;
736: } else if (!p_context && fillcnt == 1) {
737: /* the first hunk was a null hunk with no context */
738: /* and we were expecting one line -- fix it up. */
739: while (filldst < p_end) {
740: p_line[filldst] = p_line[filldst + 1];
741: p_char[filldst] = p_char[filldst + 1];
742: p_len[filldst] = p_len[filldst + 1];
743: filldst++;
744: }
745: #if 0
1.26 deraadt 746: repl_beginning--; /* this doesn't need to be fixed */
1.17 deraadt 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) {
1.26 deraadt 764: p_bfake = filldst; /* remember where not to free() */
1.17 deraadt 765: p_efake = filldst + fillcnt - 1;
766: while (fillcnt-- > 0) {
767: while (fillsrc <= p_end && p_char[fillsrc] != ' ')
768: fillsrc++;
769: if (fillsrc > p_end)
770: fatal("replacement text or line numbers mangled in hunk at line %ld\n",
771: p_hunk_beg);
772: p_line[filldst] = p_line[fillsrc];
773: p_char[filldst] = p_char[fillsrc];
774: p_len[filldst] = p_len[fillsrc];
775: fillsrc++;
776: filldst++;
777: }
778: while (fillsrc <= p_end && fillsrc != repl_beginning &&
779: p_char[fillsrc] != ' ')
780: fillsrc++;
781: #ifdef DEBUGGING
782: if (debug & 64)
783: printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
784: fillsrc, filldst, repl_beginning, p_end + 1);
1.1 deraadt 785: #endif
1.17 deraadt 786: assert(fillsrc == p_end + 1 || fillsrc == repl_beginning);
787: assert(filldst == p_end + 1 || filldst == repl_beginning);
1.1 deraadt 788: }
1.17 deraadt 789: if (p_line[p_end] != NULL) {
790: if (remove_special_line()) {
791: p_len[p_end] -= 1;
792: (p_line[p_end])[p_len[p_end]] = 0;
793: }
794: }
795: } else if (diff_type == UNI_DIFF) {
796: long line_beginning = ftell(pfp); /* file pos of the current line */
797: LINENUM fillsrc; /* index of old lines */
798: LINENUM filldst; /* index of new lines */
799: char ch;
800:
801: ret = pgets(buf, sizeof buf, pfp);
802: p_input_line++;
1.21 otto 803: if (ret == NULL || strnNE(buf, "@@ -", 4)) {
1.17 deraadt 804: next_intuit_at(line_beginning, p_input_line);
805: return FALSE;
1.1 deraadt 806: }
1.17 deraadt 807: s = buf + 4;
1.1 deraadt 808: if (!*s)
1.17 deraadt 809: malformed();
1.1 deraadt 810: p_first = (LINENUM) atol(s);
1.17 deraadt 811: while (isdigit(*s))
812: s++;
813: if (*s == ',') {
814: p_ptrn_lines = (LINENUM) atol(++s);
815: while (isdigit(*s))
816: s++;
817: } else
818: p_ptrn_lines = 1;
819: if (*s == ' ')
820: s++;
821: if (*s != '+' || !*++s)
822: malformed();
823: p_newfirst = (LINENUM) atol(s);
824: while (isdigit(*s))
825: s++;
1.1 deraadt 826: if (*s == ',') {
1.17 deraadt 827: p_repl_lines = (LINENUM) atol(++s);
828: while (isdigit(*s))
829: s++;
830: } else
831: p_repl_lines = 1;
832: if (*s == ' ')
833: s++;
834: if (*s != '@')
835: malformed();
836: if (!p_ptrn_lines)
837: p_first++; /* do append rather than insert */
838: p_max = p_ptrn_lines + p_repl_lines + 1;
839: while (p_max >= hunkmax)
840: grow_hunkmax();
841: fillsrc = 1;
842: filldst = fillsrc + p_ptrn_lines;
843: p_end = filldst + p_repl_lines;
844: snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first,
1.26 deraadt 845: p_first + p_ptrn_lines - 1);
1.17 deraadt 846: p_line[0] = savestr(buf);
847: if (out_of_mem) {
848: p_end = -1;
849: return FALSE;
850: }
851: p_char[0] = '*';
852: snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,
1.26 deraadt 853: p_newfirst + p_repl_lines - 1);
1.17 deraadt 854: p_line[filldst] = savestr(buf);
855: if (out_of_mem) {
856: p_end = 0;
857: return FALSE;
1.1 deraadt 858: }
1.17 deraadt 859: p_char[filldst++] = '=';
860: p_context = 100;
861: context = 0;
862: p_hunk_beg = p_input_line + 1;
863: while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
864: line_beginning = ftell(pfp);
865: ret = pgets(buf, sizeof buf, pfp);
866: p_input_line++;
1.21 otto 867: if (ret == NULL) {
1.17 deraadt 868: if (p_max - filldst < 3) {
869: /* assume blank lines got chopped */
870: strlcpy(buf, " \n", sizeof buf);
871: } else {
872: fatal("unexpected end of file in patch\n");
873: }
874: }
875: if (*buf == '\t' || *buf == '\n') {
876: ch = ' '; /* assume the space got eaten */
877: s = savestr(buf);
878: } else {
879: ch = *buf;
880: s = savestr(buf + 1);
881: }
882: if (out_of_mem) {
883: while (--filldst > p_ptrn_lines)
884: free(p_line[filldst]);
885: p_end = fillsrc - 1;
886: return FALSE;
887: }
888: switch (ch) {
889: case '-':
890: if (fillsrc > p_ptrn_lines) {
891: free(s);
892: p_end = filldst - 1;
893: malformed();
894: }
895: p_char[fillsrc] = ch;
896: p_line[fillsrc] = s;
897: p_len[fillsrc++] = strlen(s);
898: if (fillsrc > p_ptrn_lines) {
899: if (remove_special_line()) {
900: p_len[fillsrc - 1] -= 1;
901: s[p_len[fillsrc - 1]] = 0;
902: }
903: }
904: break;
905: case '=':
906: ch = ' ';
907: /* FALL THROUGH */
908: case ' ':
909: if (fillsrc > p_ptrn_lines) {
910: free(s);
911: while (--filldst > p_ptrn_lines)
912: free(p_line[filldst]);
913: p_end = fillsrc - 1;
914: malformed();
915: }
916: context++;
917: p_char[fillsrc] = ch;
918: p_line[fillsrc] = s;
919: p_len[fillsrc++] = strlen(s);
920: s = savestr(s);
921: if (out_of_mem) {
922: while (--filldst > p_ptrn_lines)
923: free(p_line[filldst]);
924: p_end = fillsrc - 1;
925: return FALSE;
926: }
927: /* FALL THROUGH */
928: case '+':
929: if (filldst > p_end) {
930: free(s);
931: while (--filldst > p_ptrn_lines)
932: free(p_line[filldst]);
933: p_end = fillsrc - 1;
934: malformed();
935: }
936: p_char[filldst] = ch;
937: p_line[filldst] = s;
938: p_len[filldst++] = strlen(s);
939: if (fillsrc > p_ptrn_lines) {
940: if (remove_special_line()) {
941: p_len[filldst - 1] -= 1;
942: s[p_len[filldst - 1]] = 0;
943: }
944: }
945: break;
946: default:
947: p_end = filldst;
948: malformed();
1.1 deraadt 949: }
1.17 deraadt 950: if (ch != ' ' && context > 0) {
951: if (context < p_context)
952: p_context = context;
953: context = -1000;
1.1 deraadt 954: }
1.17 deraadt 955: } /* while */
956: } else { /* normal diff--fake it up */
957: char hunk_type;
958: int i;
959: LINENUM min, max;
960: long line_beginning = ftell(pfp);
961:
962: p_context = 0;
963: ret = pgets(buf, sizeof buf, pfp);
964: p_input_line++;
1.21 otto 965: if (ret == NULL || !isdigit(*buf)) {
1.17 deraadt 966: next_intuit_at(line_beginning, p_input_line);
1.1 deraadt 967: return FALSE;
1.17 deraadt 968: }
969: p_first = (LINENUM) atol(buf);
1.18 deraadt 970: for (s = buf; isdigit(*s); s++)
971: ;
1.17 deraadt 972: if (*s == ',') {
973: p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1;
974: while (isdigit(*s))
975: s++;
976: } else
977: p_ptrn_lines = (*s != 'a');
978: hunk_type = *s;
979: if (hunk_type == 'a')
980: p_first++; /* do append rather than insert */
981: min = (LINENUM) atol(++s);
1.18 deraadt 982: for (; isdigit(*s); s++)
983: ;
1.17 deraadt 984: if (*s == ',')
985: max = (LINENUM) atol(++s);
986: else
987: max = min;
988: if (hunk_type == 'd')
989: min++;
990: p_end = p_ptrn_lines + 1 + max - min + 1;
991: if (p_end > MAXHUNKSIZE)
1.16 deraadt 992: fatal("hunk too large (%ld lines) at line %ld: %s",
1.17 deraadt 993: p_end, p_input_line, buf);
994: while (p_end >= hunkmax)
1.1 deraadt 995: grow_hunkmax();
1.17 deraadt 996: p_newfirst = min;
997: p_repl_lines = max - min + 1;
998: snprintf(buf, sizeof buf, "*** %ld,%ld\n", p_first,
1.26 deraadt 999: p_first + p_ptrn_lines - 1);
1.17 deraadt 1000: p_line[0] = savestr(buf);
1.1 deraadt 1001: if (out_of_mem) {
1.17 deraadt 1002: p_end = -1;
1003: return FALSE;
1.1 deraadt 1004: }
1.17 deraadt 1005: p_char[0] = '*';
1006: for (i = 1; i <= p_ptrn_lines; i++) {
1007: ret = pgets(buf, sizeof buf, pfp);
1008: p_input_line++;
1.21 otto 1009: if (ret == NULL)
1.17 deraadt 1010: fatal("unexpected end of file in patch at line %ld\n",
1011: p_input_line);
1012: if (*buf != '<')
1013: fatal("< expected at line %ld of patch\n",
1014: p_input_line);
1015: p_line[i] = savestr(buf + 2);
1016: if (out_of_mem) {
1017: p_end = i - 1;
1018: return FALSE;
1.14 otto 1019: }
1.17 deraadt 1020: p_len[i] = strlen(p_line[i]);
1021: p_char[i] = '-';
1.14 otto 1022: }
1.17 deraadt 1023:
1024: if (remove_special_line()) {
1025: p_len[i - 1] -= 1;
1026: (p_line[i - 1])[p_len[i - 1]] = 0;
1.1 deraadt 1027: }
1.17 deraadt 1028: if (hunk_type == 'c') {
1029: ret = pgets(buf, sizeof buf, pfp);
1030: p_input_line++;
1.21 otto 1031: if (ret == NULL)
1.17 deraadt 1032: fatal("unexpected end of file in patch at line %ld\n",
1033: p_input_line);
1034: if (*buf != '-')
1035: fatal("--- expected at line %ld of patch\n",
1036: p_input_line);
1.1 deraadt 1037: }
1.17 deraadt 1038: snprintf(buf, sizeof(buf), "--- %ld,%ld\n", min, max);
1039: p_line[i] = savestr(buf);
1.1 deraadt 1040: if (out_of_mem) {
1.17 deraadt 1041: p_end = i - 1;
1042: return FALSE;
1.1 deraadt 1043: }
1.17 deraadt 1044: p_char[i] = '=';
1045: for (i++; i <= p_end; i++) {
1046: ret = pgets(buf, sizeof buf, pfp);
1047: p_input_line++;
1.21 otto 1048: if (ret == NULL)
1.17 deraadt 1049: fatal("unexpected end of file in patch at line %ld\n",
1050: p_input_line);
1051: if (*buf != '>')
1052: fatal("> expected at line %ld of patch\n",
1053: p_input_line);
1054: p_line[i] = savestr(buf + 2);
1055: if (out_of_mem) {
1056: p_end = i - 1;
1057: return FALSE;
1.14 otto 1058: }
1.17 deraadt 1059: p_len[i] = strlen(p_line[i]);
1060: p_char[i] = '+';
1.14 otto 1061: }
1.17 deraadt 1062:
1063: if (remove_special_line()) {
1064: p_len[i - 1] -= 1;
1065: (p_line[i - 1])[p_len[i - 1]] = 0;
1.14 otto 1066: }
1.1 deraadt 1067: }
1.17 deraadt 1068: if (reverse) /* backwards patch? */
1069: if (!pch_swap())
1070: say("Not enough memory to swap next hunk!\n");
1.1 deraadt 1071: #ifdef DEBUGGING
1.17 deraadt 1072: if (debug & 2) {
1073: int i;
1074: char special;
1075:
1076: for (i = 0; i <= p_end; i++) {
1077: if (i == p_ptrn_lines)
1078: special = '^';
1079: else
1080: special = ' ';
1081: fprintf(stderr, "%3d %c %c %s", i, p_char[i],
1082: special, p_line[i]);
1083: fflush(stderr);
1084: }
1.1 deraadt 1085: }
1086: #endif
1.17 deraadt 1087: if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */
1088: p_char[p_end + 1] = '^'; /* add a stopper for apply_hunk */
1089: return TRUE;
1.1 deraadt 1090: }
1091:
1.17 deraadt 1092: /*
1093: * Input a line from the patch file, worrying about indentation.
1094: */
1.21 otto 1095: static char *
1.17 deraadt 1096: pgets(char *bf, int sz, FILE *fp)
1097: {
1098: char *s, *ret = fgets(bf, sz, fp);
1099: int indent = 0;
1.1 deraadt 1100:
1.21 otto 1101: if (p_indent && ret != NULL) {
1.17 deraadt 1102: for (s = buf;
1103: indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X');
1104: s++) {
1105: if (*s == '\t')
1106: indent += 8 - (indent % 7);
1107: else
1108: indent++;
1109: }
1110: if (buf != s && strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
1111: fatal("buffer too small in pgets()\n");
1112: }
1113: return ret;
1.1 deraadt 1114: }
1115:
1.17 deraadt 1116: /*
1117: * Reverse the old and new portions of the current hunk.
1118: */
1.1 deraadt 1119: bool
1.17 deraadt 1120: pch_swap(void)
1.1 deraadt 1121: {
1.17 deraadt 1122: char **tp_line; /* the text of the hunk */
1123: short *tp_len; /* length of each line */
1124: char *tp_char; /* +, -, and ! */
1125: LINENUM i;
1126: LINENUM n;
1127: bool blankline = FALSE;
1128: char *s;
1129:
1130: i = p_first;
1131: p_first = p_newfirst;
1132: p_newfirst = i;
1133:
1134: /* make a scratch copy */
1135:
1136: tp_line = p_line;
1137: tp_len = p_len;
1138: tp_char = p_char;
1.21 otto 1139: p_line = NULL; /* force set_hunkmax to allocate again */
1140: p_len = NULL;
1141: p_char = NULL;
1.17 deraadt 1142: set_hunkmax();
1.21 otto 1143: if (p_line == NULL ||p_len == NULL ||p_char == NULL) {
1144:
1145: if (p_line == NULL) /* XXX */
1146: free(p_line);
1.17 deraadt 1147: p_line = tp_line;
1.21 otto 1148: if (p_len == NULL) /* XXX */
1149: free(p_len);
1.17 deraadt 1150: p_len = tp_len;
1.21 otto 1151: if (p_char == NULL) /* XXX */
1152: free(p_char);
1.17 deraadt 1153: p_char = tp_char;
1154: return FALSE; /* not enough memory to swap hunk! */
1155: }
1156: /* now turn the new into the old */
1157:
1.1 deraadt 1158: i = p_ptrn_lines + 1;
1.17 deraadt 1159: if (tp_char[i] == '\n') { /* account for possible blank line */
1160: blankline = TRUE;
1161: i++;
1162: }
1163: if (p_efake >= 0) { /* fix non-freeable ptr range */
1164: if (p_efake <= i)
1165: n = p_end - i + 1;
1166: else
1167: n = -i;
1168: p_efake += n;
1169: p_bfake += n;
1170: }
1171: for (n = 0; i <= p_end; i++, n++) {
1172: p_line[n] = tp_line[i];
1173: p_char[n] = tp_char[i];
1174: if (p_char[n] == '+')
1175: p_char[n] = '-';
1176: p_len[n] = tp_len[i];
1177: }
1178: if (blankline) {
1179: i = p_ptrn_lines + 1;
1180: p_line[n] = tp_line[i];
1181: p_char[n] = tp_char[i];
1182: p_len[n] = tp_len[i];
1183: n++;
1184: }
1185: assert(p_char[0] == '=');
1186: p_char[0] = '*';
1187: for (s = p_line[0]; *s; s++)
1188: if (*s == '-')
1189: *s = '*';
1190:
1191: /* now turn the old into the new */
1192:
1193: assert(tp_char[0] == '*');
1194: tp_char[0] = '=';
1195: for (s = tp_line[0]; *s; s++)
1196: if (*s == '*')
1197: *s = '-';
1198: for (i = 0; n <= p_end; i++, n++) {
1199: p_line[n] = tp_line[i];
1200: p_char[n] = tp_char[i];
1201: if (p_char[n] == '-')
1202: p_char[n] = '+';
1203: p_len[n] = tp_len[i];
1204: }
1205: assert(i == p_ptrn_lines + 1);
1206: i = p_ptrn_lines;
1207: p_ptrn_lines = p_repl_lines;
1208: p_repl_lines = i;
1.21 otto 1209:
1210: if (tp_line == NULL) /* XXX */
1211: free(tp_line);
1212: if (tp_len == NULL) /* XXX */
1213: free(tp_len);
1214: if (tp_char == NULL) /* XXX */
1215: free(tp_char);
1.17 deraadt 1216: return TRUE;
1.1 deraadt 1217: }
1218:
1.17 deraadt 1219: /*
1220: * Return the specified line position in the old file of the old context.
1221: */
1.1 deraadt 1222: LINENUM
1.17 deraadt 1223: pch_first(void)
1.1 deraadt 1224: {
1.17 deraadt 1225: return p_first;
1.1 deraadt 1226: }
1227:
1.17 deraadt 1228: /*
1229: * Return the number of lines of old context.
1230: */
1.1 deraadt 1231: LINENUM
1.17 deraadt 1232: pch_ptrn_lines(void)
1.1 deraadt 1233: {
1.17 deraadt 1234: return p_ptrn_lines;
1.1 deraadt 1235: }
1236:
1.17 deraadt 1237: /*
1238: * Return the probable line position in the new file of the first line.
1239: */
1.1 deraadt 1240: LINENUM
1.17 deraadt 1241: pch_newfirst(void)
1.1 deraadt 1242: {
1.17 deraadt 1243: return p_newfirst;
1.1 deraadt 1244: }
1245:
1.17 deraadt 1246: /*
1247: * Return the number of lines in the replacement text including context.
1248: */
1.1 deraadt 1249: LINENUM
1.17 deraadt 1250: pch_repl_lines(void)
1.1 deraadt 1251: {
1.17 deraadt 1252: return p_repl_lines;
1.1 deraadt 1253: }
1254:
1.17 deraadt 1255: /*
1256: * Return the number of lines in the whole hunk.
1257: */
1.1 deraadt 1258: LINENUM
1.17 deraadt 1259: pch_end(void)
1.1 deraadt 1260: {
1.17 deraadt 1261: return p_end;
1.1 deraadt 1262: }
1263:
1.17 deraadt 1264: /*
1265: * Return the number of context lines before the first changed line.
1266: */
1.1 deraadt 1267: LINENUM
1.17 deraadt 1268: pch_context(void)
1.1 deraadt 1269: {
1.17 deraadt 1270: return p_context;
1.1 deraadt 1271: }
1272:
1.17 deraadt 1273: /*
1274: * Return the length of a particular patch line.
1275: */
1.1 deraadt 1276: short
1.17 deraadt 1277: pch_line_len(LINENUM line)
1.1 deraadt 1278: {
1.17 deraadt 1279: return p_len[line];
1.1 deraadt 1280: }
1281:
1.17 deraadt 1282: /*
1283: * Return the control character (+, -, *, !, etc) for a patch line.
1284: */
1.1 deraadt 1285: char
1.17 deraadt 1286: pch_char(LINENUM line)
1.1 deraadt 1287: {
1.17 deraadt 1288: return p_char[line];
1.1 deraadt 1289: }
1290:
1.17 deraadt 1291: /*
1292: * Return a pointer to a particular patch line.
1293: */
1.1 deraadt 1294: char *
1.17 deraadt 1295: pfetch(LINENUM line)
1.1 deraadt 1296: {
1.17 deraadt 1297: return p_line[line];
1.1 deraadt 1298: }
1299:
1.17 deraadt 1300: /*
1301: * Return where in the patch file this hunk began, for error messages.
1302: */
1.1 deraadt 1303: LINENUM
1.17 deraadt 1304: pch_hunk_beg(void)
1.1 deraadt 1305: {
1.17 deraadt 1306: return p_hunk_beg;
1.1 deraadt 1307: }
1308:
1.17 deraadt 1309: /*
1310: * Apply an ed script by feeding ed itself.
1311: */
1.1 deraadt 1312: void
1.17 deraadt 1313: do_ed_script(void)
1.1 deraadt 1314: {
1.17 deraadt 1315: char *t;
1316: long beginning_of_this_line;
1317: FILE *pipefp;
1318:
1319: if (!skip_rest_of_patch) {
1.24 millert 1320: if (copy_file(filearg[0], TMPOUTNAME) < 0) {
1321: unlink(TMPOUTNAME);
1322: fatal("can't create temp file %s", TMPOUTNAME);
1323: }
1.27 ! millert 1324: snprintf(buf, sizeof buf, "%s%s%s", _PATH_ED,
! 1325: verbose ? " " : " -s ", TMPOUTNAME);
1.17 deraadt 1326: pipefp = popen(buf, "w");
1327: }
1328: for (;;) {
1329: beginning_of_this_line = ftell(pfp);
1.21 otto 1330: if (pgets(buf, sizeof buf, pfp) == NULL) {
1.17 deraadt 1331: next_intuit_at(beginning_of_this_line, p_input_line);
1332: break;
1333: }
1334: p_input_line++;
1.18 deraadt 1335: for (t = buf; isdigit(*t) || *t == ','; t++)
1336: ;
1.22 millert 1337: /* POSIX defines allowed commands as {a,c,d,i,s} */
1338: if (isdigit(*buf) && (*t == 'a' || *t == 'c' || *t == 'd' ||
1339: *t == 'i' || *t == 's')) {
1.17 deraadt 1340: if (!skip_rest_of_patch)
1341: fputs(buf, pipefp);
1342: if (*t != 'd') {
1.21 otto 1343: while (pgets(buf, sizeof buf, pfp) != NULL) {
1.17 deraadt 1344: p_input_line++;
1345: if (!skip_rest_of_patch)
1346: fputs(buf, pipefp);
1347: if (strEQ(buf, ".\n"))
1348: break;
1349: }
1350: }
1351: } else {
1352: next_intuit_at(beginning_of_this_line, p_input_line);
1.1 deraadt 1353: break;
1354: }
1355: }
1.17 deraadt 1356: if (skip_rest_of_patch)
1357: return;
1358: fprintf(pipefp, "w\n");
1359: fprintf(pipefp, "q\n");
1360: fflush(pipefp);
1361: pclose(pipefp);
1362: ignore_signals();
1363: if (!check_only) {
1364: if (move_file(TMPOUTNAME, outname) < 0) {
1365: toutkeep = TRUE;
1366: chmod(TMPOUTNAME, filemode);
1367: } else
1368: chmod(outname, filemode);
1.1 deraadt 1369: }
1.17 deraadt 1370: set_signals(1);
1.1 deraadt 1371: }