Annotation of src/usr.bin/patch/pch.c, Revision 1.29
1.29 ! deraadt 1: /* $OpenBSD: pch.c,v 1.28 2003/08/01 20:30:48 otto Exp $ */
1.2 niklas 2:
1.1 deraadt 3: #ifndef lint
1.29 ! deraadt 4: static const char rcsid[] = "$OpenBSD: pch.c,v 1.28 2003/08/01 20:30:48 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 <ctype.h>
1.25 otto 11: #include <stdio.h>
1.21 otto 12: #include <stdlib.h>
13: #include <string.h>
14: #include <unistd.h>
15:
1.1 deraadt 16: #include "common.h"
17: #include "util.h"
18: #include "pch.h"
1.27 millert 19: #include "pathnames.h"
1.1 deraadt 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:
1.28 otto 117: if (p_line == NULL || p_len == NULL || p_char == NULL)
118: fatal("Internal memory allocation error\n");
1.21 otto 119:
120: p_line = realloc(p_line, hunkmax * sizeof(char *));
121: p_len = realloc(p_len, hunkmax * sizeof(short));
122: p_char = realloc(p_char, hunkmax * sizeof(char));
123:
1.25 otto 124: if (p_line != NULL && p_len != NULL && p_char != NULL)
1.17 deraadt 125: return;
126: if (!using_plan_a)
127: fatal("out of memory\n");
1.28 otto 128: out_of_mem = true; /* whatever is null will be allocated again */
129: /* from within plan_a(), of all places */
1.1 deraadt 130: }
131:
132: /* True if the remainder of the patch file contains a diff of some sort. */
133:
134: bool
1.17 deraadt 135: there_is_another_patch(void)
1.1 deraadt 136: {
1.17 deraadt 137: if (p_base != 0L && p_base >= p_filesize) {
138: if (verbose)
139: say("done\n");
1.28 otto 140: return false;
1.17 deraadt 141: }
1.1 deraadt 142: if (verbose)
1.17 deraadt 143: say("Hmm...");
144: diff_type = intuit_diff_type();
145: if (!diff_type) {
146: if (p_base != 0L) {
147: if (verbose)
148: say(" Ignoring the trailing garbage.\ndone\n");
149: } else
150: say(" I can't seem to find a patch in there anywhere.\n");
1.28 otto 151: return false;
1.1 deraadt 152: }
1.17 deraadt 153: if (verbose)
154: say(" %sooks like %s to me...\n",
155: (p_base == 0L ? "L" : "The next patch l"),
156: diff_type == UNI_DIFF ? "a unified diff" :
157: diff_type == CONTEXT_DIFF ? "a context diff" :
158: diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
159: diff_type == NORMAL_DIFF ? "a normal diff" :
160: "an ed script");
161: if (p_indent && verbose)
162: say("(Patch is indented %d space%s.)\n", p_indent,
163: p_indent == 1 ? "" : "s");
164: skip_to(p_start, p_sline);
1.21 otto 165: while (filearg[0] == NULL) {
1.17 deraadt 166: if (force || batch) {
167: say("No file to patch. Skipping...\n");
168: filearg[0] = savestr(bestguess);
1.28 otto 169: skip_rest_of_patch = true;
170: return true;
1.17 deraadt 171: }
172: ask("File to patch: ");
173: if (*buf != '\n') {
1.25 otto 174: free(bestguess);
1.17 deraadt 175: bestguess = savestr(buf);
1.28 otto 176: filearg[0] = fetchname(buf, 0, false);
1.17 deraadt 177: }
1.21 otto 178: if (filearg[0] == NULL) {
1.17 deraadt 179: ask("No file found--skip this patch? [n] ");
180: if (*buf != 'y')
181: continue;
182: if (verbose)
183: say("Skipping patch...\n");
1.28 otto 184: filearg[0] = fetchname(bestguess, 0, true);
185: skip_rest_of_patch = true;
186: return true;
1.17 deraadt 187: }
1.1 deraadt 188: }
1.28 otto 189: return true;
1.1 deraadt 190: }
191:
192: /* Determine what kind of diff is in the remaining part of the patch file. */
193:
1.21 otto 194: static int
1.17 deraadt 195: intuit_diff_type(void)
1.1 deraadt 196: {
1.17 deraadt 197: long this_line = 0, previous_line;
1.28 otto 198: long first_command_line = -1;
199: LINENUM fcl_line = -1;
200: bool last_line_was_command = false, this_is_a_command = false;
201: bool stars_last_line = false, stars_this_line = false;
1.17 deraadt 202: char *s, *t;
1.21 otto 203: char *indtmp = NULL;
204: char *oldtmp = NULL;
205: char *newtmp = NULL;
206: char *indname = NULL;
207: char *oldname = NULL;
208: char *newname = NULL;
1.17 deraadt 209: int indent, retval;
1.21 otto 210: bool no_filearg = (filearg[0] == NULL);
1.17 deraadt 211:
1.28 otto 212: ok_to_create_file = false;
1.21 otto 213: fseek(pfp, p_base, SEEK_SET);
1.17 deraadt 214: p_input_line = p_bline - 1;
215: for (;;) {
216: previous_line = this_line;
217: last_line_was_command = this_is_a_command;
218: stars_last_line = stars_this_line;
219: this_line = ftell(pfp);
220: indent = 0;
221: p_input_line++;
1.21 otto 222: if (fgets(buf, sizeof buf, pfp) == NULL) {
1.17 deraadt 223: if (first_command_line >= 0L) {
224: /* nothing but deletes!? */
225: p_start = first_command_line;
226: p_sline = fcl_line;
227: retval = ED_DIFF;
228: goto scan_exit;
229: } else {
230: p_start = this_line;
231: p_sline = p_input_line;
232: retval = 0;
233: goto scan_exit;
234: }
235: }
236: for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
237: if (*s == '\t')
238: indent += 8 - (indent % 8);
239: else
240: indent++;
241: }
242: for (t = s; isdigit(*t) || *t == ','; t++)
243: ;
244: this_is_a_command = (isdigit(*s) &&
245: (*t == 'd' || *t == 'c' || *t == 'a'));
246: if (first_command_line < 0L && this_is_a_command) {
247: first_command_line = this_line;
248: fcl_line = p_input_line;
249: p_indent = indent; /* assume this for now */
250: }
251: if (!stars_last_line && strnEQ(s, "*** ", 4))
252: oldtmp = savestr(s + 4);
253: else if (strnEQ(s, "--- ", 4))
254: newtmp = savestr(s + 4);
255: else if (strnEQ(s, "+++ ", 4))
1.26 deraadt 256: oldtmp = savestr(s + 4); /* pretend it is the old name */
1.17 deraadt 257: else if (strnEQ(s, "Index:", 6))
258: indtmp = savestr(s + 6);
259: else if (strnEQ(s, "Prereq:", 7)) {
1.18 deraadt 260: for (t = s + 7; isspace(*t); t++)
261: ;
1.17 deraadt 262: revision = savestr(t);
1.18 deraadt 263: for (t = revision; *t && !isspace(*t); t++)
264: ;
1.17 deraadt 265: *t = '\0';
1.25 otto 266: if (*revision == '\0') {
1.17 deraadt 267: free(revision);
1.21 otto 268: revision = NULL;
1.17 deraadt 269: }
270: }
271: if ((!diff_type || diff_type == ED_DIFF) &&
272: first_command_line >= 0L &&
273: strEQ(s, ".\n")) {
274: p_indent = indent;
275: p_start = first_command_line;
276: p_sline = fcl_line;
277: retval = ED_DIFF;
278: goto scan_exit;
279: }
280: if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
281: if (!atol(s + 3))
1.28 otto 282: ok_to_create_file = true;
1.17 deraadt 283: p_indent = indent;
284: p_start = this_line;
285: p_sline = p_input_line;
286: retval = UNI_DIFF;
287: goto scan_exit;
288: }
289: stars_this_line = strnEQ(s, "********", 8);
290: if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
291: strnEQ(s, "*** ", 4)) {
292: if (!atol(s + 4))
1.28 otto 293: ok_to_create_file = true;
1.17 deraadt 294: /*
295: * if this is a new context diff the character just
296: * before
297: */
298: /* the newline is a '*'. */
299: while (*s != '\n')
300: s++;
301: p_indent = indent;
302: p_start = previous_line;
303: p_sline = p_input_line - 1;
304: retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
305: goto scan_exit;
306: }
307: if ((!diff_type || diff_type == NORMAL_DIFF) &&
308: last_line_was_command &&
309: (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
310: p_start = previous_line;
311: p_sline = p_input_line - 1;
312: p_indent = indent;
313: retval = NORMAL_DIFF;
314: goto scan_exit;
315: }
316: }
317: scan_exit:
318: if (no_filearg) {
1.21 otto 319: if (indtmp != NULL)
1.17 deraadt 320: indname = fetchname(indtmp, strippath, ok_to_create_file);
1.21 otto 321: if (oldtmp != NULL)
1.17 deraadt 322: oldname = fetchname(oldtmp, strippath, ok_to_create_file);
1.21 otto 323: if (newtmp != NULL)
1.17 deraadt 324: newname = fetchname(newtmp, strippath, ok_to_create_file);
325: if (indname)
326: filearg[0] = savestr(indname);
327: else if (oldname && newname) {
328: if (strlen(oldname) < strlen(newname))
329: filearg[0] = savestr(oldname);
330: else
331: filearg[0] = savestr(newname);
332: } else if (oldname)
333: filearg[0] = savestr(oldname);
334: else if (newname)
335: filearg[0] = savestr(newname);
336: }
1.25 otto 337:
338: free(bestguess);
339: bestguess = NULL;
340:
1.21 otto 341: if (filearg[0] != NULL)
1.17 deraadt 342: bestguess = savestr(filearg[0]);
1.21 otto 343: else if (indtmp != NULL)
1.28 otto 344: bestguess = fetchname(indtmp, strippath, true);
1.17 deraadt 345: else {
1.21 otto 346: if (oldtmp != NULL)
1.28 otto 347: oldname = fetchname(oldtmp, strippath, true);
1.21 otto 348: if (newtmp != NULL)
1.28 otto 349: newname = fetchname(newtmp, strippath, true);
1.17 deraadt 350: if (oldname && newname) {
351: if (strlen(oldname) < strlen(newname))
352: bestguess = savestr(oldname);
353: else
354: bestguess = savestr(newname);
355: } else if (oldname)
356: bestguess = savestr(oldname);
357: else if (newname)
358: bestguess = savestr(newname);
359: }
1.21 otto 360: free(indtmp);
361: free(oldtmp);
362: free(newtmp);
363: free(indname);
364: free(oldname);
365: free(newname);
1.17 deraadt 366: return retval;
1.1 deraadt 367: }
368:
1.17 deraadt 369: /*
370: * Remember where this patch ends so we know where to start up again.
371: */
1.21 otto 372: static void
1.25 otto 373: next_intuit_at(LINENUM file_pos, LINENUM file_line)
1.1 deraadt 374: {
1.17 deraadt 375: p_base = file_pos;
376: p_bline = file_line;
1.1 deraadt 377: }
378:
1.17 deraadt 379: /*
380: * Basically a verbose fseek() to the actual diff listing.
381: */
1.21 otto 382: static void
1.25 otto 383: skip_to(LINENUM file_pos, LINENUM file_line)
1.1 deraadt 384: {
1.17 deraadt 385: char *ret;
1.1 deraadt 386:
1.28 otto 387: if (p_base > file_pos)
388: fatal("Internal error: seek %ld>%ld\n", p_base, file_pos);
1.17 deraadt 389: if (verbose && p_base < file_pos) {
1.21 otto 390: fseek(pfp, p_base, SEEK_SET);
1.17 deraadt 391: say("The text leading up to this was:\n--------------------------\n");
392: while (ftell(pfp) < file_pos) {
393: ret = fgets(buf, sizeof buf, pfp);
1.28 otto 394: if (ret == NULL)
395: fatal("Unexpected end of file\n");
1.17 deraadt 396: say("|%s", buf);
397: }
398: say("--------------------------\n");
399: } else
1.21 otto 400: fseek(pfp, file_pos, SEEK_SET);
1.17 deraadt 401: p_input_line = file_line - 1;
1.1 deraadt 402: }
403:
404: /* Make this a function for better debugging. */
405: static void
1.16 deraadt 406: malformed(void)
1.1 deraadt 407: {
1.17 deraadt 408: fatal("malformed patch at line %ld: %s", p_input_line, buf);
409: /* about as informative as "Syntax error" in C */
1.1 deraadt 410: }
411:
1.14 otto 412: /*
413: * True if the line has been discarded (i.e. it is a line saying
414: * "\ No newline at end of file".)
415: */
416: static bool
417: remove_special_line(void)
418: {
1.17 deraadt 419: int c;
1.14 otto 420:
421: c = fgetc(pfp);
422: if (c == '\\') {
423: do {
424: c = fgetc(pfp);
425: } while (c != EOF && c != '\n');
426:
1.28 otto 427: return true;
1.14 otto 428: }
429: if (c != EOF)
430: fseek(pfp, -1L, SEEK_CUR);
431:
1.28 otto 432: return false;
1.14 otto 433: }
434:
1.17 deraadt 435: /*
436: * True if there is more of the current diff listing to process.
437: */
1.1 deraadt 438: bool
1.17 deraadt 439: another_hunk(void)
1.1 deraadt 440: {
1.17 deraadt 441: long line_beginning; /* file pos of the current line */
442: LINENUM repl_beginning; /* index of --- line */
443: LINENUM fillcnt; /* #lines of missing ptrn or repl */
444: LINENUM fillsrc; /* index of first line to copy */
445: LINENUM filldst; /* index of first missing line */
446: bool ptrn_spaces_eaten; /* ptrn was slightly misformed */
447: bool repl_could_be_missing; /* no + or ! lines in this hunk */
448: bool repl_missing; /* we are now backtracking */
449: long repl_backtrack_position; /* file pos of first repl line */
450: LINENUM repl_patch_line; /* input line number for same */
451: LINENUM ptrn_copiable; /* # of copiable lines in ptrn */
452: char *s, *ret;
453: int context = 0;
454:
455: while (p_end >= 0) {
456: if (p_end == p_efake)
457: p_end = p_bfake; /* don't free twice */
458: else
459: free(p_line[p_end]);
460: p_end--;
461: }
462: p_efake = -1;
463:
464: p_max = hunkmax; /* gets reduced when --- found */
465: if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
466: line_beginning = ftell(pfp);
467: repl_beginning = 0;
468: fillcnt = 0;
1.28 otto 469: ptrn_spaces_eaten = false;
470: repl_could_be_missing = true;
471: repl_missing = false;
1.17 deraadt 472: repl_backtrack_position = 0;
473: ptrn_copiable = 0;
474:
475: ret = pgets(buf, sizeof buf, pfp);
476: p_input_line++;
1.21 otto 477: if (ret == NULL || strnNE(buf, "********", 8)) {
1.17 deraadt 478: next_intuit_at(line_beginning, p_input_line);
1.28 otto 479: return false;
1.17 deraadt 480: }
481: p_context = 100;
482: p_hunk_beg = p_input_line + 1;
483: while (p_end < p_max) {
484: line_beginning = ftell(pfp);
485: ret = pgets(buf, sizeof buf, pfp);
486: p_input_line++;
1.21 otto 487: if (ret == NULL) {
1.17 deraadt 488: if (p_max - p_end < 4) {
489: /* assume blank lines got chopped */
490: strlcpy(buf, " \n", sizeof buf);
491: } else {
492: if (repl_beginning && repl_could_be_missing) {
1.28 otto 493: repl_missing = true;
1.17 deraadt 494: goto hunk_done;
495: }
496: fatal("unexpected end of file in patch\n");
497: }
498: }
499: p_end++;
1.28 otto 500: if (p_end >= hunkmax)
501: fatal("Internal error: hunk larger than hunk "
1.29 ! deraadt 502: "buffer size");
1.17 deraadt 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) {
1.28 otto 509: repl_missing = true;
1.17 deraadt 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) {
1.28 otto 518: repl_missing = true;
1.17 deraadt 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--;
1.28 otto 528: return false;
1.17 deraadt 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) {
1.28 otto 576: repl_missing = true;
1.17 deraadt 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--;
1.28 otto 596: return false;
1.17 deraadt 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))
1.28 otto 627: repl_could_be_missing = false;
1.17 deraadt 628: break;
629: }
630: goto change_line;
631: case '+':
632: case '!':
1.28 otto 633: repl_could_be_missing = false;
1.17 deraadt 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) {
1.28 otto 640: repl_missing = true;
1.17 deraadt 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--;
1.28 otto 651: return false;
1.17 deraadt 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)) {
1.28 otto 667: repl_missing = true;
1.17 deraadt 668: goto hunk_done;
669: }
670: p_line[p_end] = savestr(buf);
671: if (out_of_mem) {
672: p_end--;
1.28 otto 673: return false;
1.17 deraadt 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.28 otto 686: repl_missing = true;
1.17 deraadt 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--;
1.28 otto 695: return false;
1.17 deraadt 696: }
697: break;
698: default:
699: if (repl_beginning && repl_could_be_missing) {
1.28 otto 700: repl_missing = true;
1.17 deraadt 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.28 otto 785: if (fillsrc != p_end + 1 && fillsrc != repl_beginning)
786: malformed();
787: if (filldst != p_end + 1 && filldst != repl_beginning)
788: malformed();
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);
1.28 otto 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,
1.26 deraadt 846: p_first + p_ptrn_lines - 1);
1.17 deraadt 847: p_line[0] = savestr(buf);
848: if (out_of_mem) {
849: p_end = -1;
1.28 otto 850: return false;
1.17 deraadt 851: }
852: p_char[0] = '*';
853: snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,
1.26 deraadt 854: p_newfirst + p_repl_lines - 1);
1.17 deraadt 855: p_line[filldst] = savestr(buf);
856: if (out_of_mem) {
857: p_end = 0;
1.28 otto 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;
1.28 otto 887: return false;
1.17 deraadt 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;
1.28 otto 926: return false;
1.17 deraadt 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.28 otto 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,
1.26 deraadt 1000: p_first + p_ptrn_lines - 1);
1.17 deraadt 1001: p_line[0] = savestr(buf);
1.1 deraadt 1002: if (out_of_mem) {
1.17 deraadt 1003: p_end = -1;
1.28 otto 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;
1.28 otto 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;
1.28 otto 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;
1.28 otto 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 */
1.28 otto 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;
1.28 otto 1128: bool blankline = false;
1.17 deraadt 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.28 otto 1144: if (p_line == NULL || p_len == NULL || p_char == NULL) {
1.21 otto 1145:
1.28 otto 1146: free(p_line);
1.17 deraadt 1147: p_line = tp_line;
1.28 otto 1148: free(p_len);
1.17 deraadt 1149: p_len = tp_len;
1.28 otto 1150: free(p_char);
1.17 deraadt 1151: p_char = tp_char;
1.28 otto 1152: return false; /* not enough memory to swap hunk! */
1.17 deraadt 1153: }
1154: /* now turn the new into the old */
1155:
1.1 deraadt 1156: i = p_ptrn_lines + 1;
1.17 deraadt 1157: if (tp_char[i] == '\n') { /* account for possible blank line */
1.28 otto 1158: blankline = true;
1.17 deraadt 1159: i++;
1160: }
1161: if (p_efake >= 0) { /* fix non-freeable ptr range */
1162: if (p_efake <= i)
1163: n = p_end - i + 1;
1164: else
1165: n = -i;
1166: p_efake += n;
1167: p_bfake += n;
1168: }
1169: for (n = 0; i <= p_end; i++, n++) {
1170: p_line[n] = tp_line[i];
1171: p_char[n] = tp_char[i];
1172: if (p_char[n] == '+')
1173: p_char[n] = '-';
1174: p_len[n] = tp_len[i];
1175: }
1176: if (blankline) {
1177: i = p_ptrn_lines + 1;
1178: p_line[n] = tp_line[i];
1179: p_char[n] = tp_char[i];
1180: p_len[n] = tp_len[i];
1181: n++;
1182: }
1.28 otto 1183: if (p_char[0] != '=')
1.29 ! deraadt 1184: fatal("Malformed patch at line %ld: expected '=' found '%c'\n",
1.28 otto 1185: p_input_line, p_char[0]);
1.17 deraadt 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:
1.28 otto 1193: if (p_char[0] != '*')
1.29 ! deraadt 1194: fatal("Malformed patch at line %ld: expected '*' found '%c'\n",
! 1195: p_input_line, p_char[0]);
1.17 deraadt 1196: tp_char[0] = '=';
1197: for (s = tp_line[0]; *s; s++)
1198: if (*s == '*')
1199: *s = '-';
1200: for (i = 0; n <= p_end; i++, n++) {
1201: p_line[n] = tp_line[i];
1202: p_char[n] = tp_char[i];
1203: if (p_char[n] == '-')
1204: p_char[n] = '+';
1205: p_len[n] = tp_len[i];
1206: }
1.28 otto 1207:
1208: if (i != p_ptrn_lines + 1)
1209: fatal("Malformed patch at line %ld: expected %ld lines, "
1.29 ! deraadt 1210: "got %ld\n",
! 1211: p_input_line, p_ptrn_lines + 1, i);
1.28 otto 1212:
1.17 deraadt 1213: i = p_ptrn_lines;
1214: p_ptrn_lines = p_repl_lines;
1215: p_repl_lines = i;
1.21 otto 1216:
1.28 otto 1217: free(tp_line);
1218: free(tp_len);
1219: free(tp_char);
1220:
1221: return true;
1.1 deraadt 1222: }
1223:
1.17 deraadt 1224: /*
1225: * Return the specified line position in the old file of the old context.
1226: */
1.1 deraadt 1227: LINENUM
1.17 deraadt 1228: pch_first(void)
1.1 deraadt 1229: {
1.17 deraadt 1230: return p_first;
1.1 deraadt 1231: }
1232:
1.17 deraadt 1233: /*
1234: * Return the number of lines of old context.
1235: */
1.1 deraadt 1236: LINENUM
1.17 deraadt 1237: pch_ptrn_lines(void)
1.1 deraadt 1238: {
1.17 deraadt 1239: return p_ptrn_lines;
1.1 deraadt 1240: }
1241:
1.17 deraadt 1242: /*
1243: * Return the probable line position in the new file of the first line.
1244: */
1.1 deraadt 1245: LINENUM
1.17 deraadt 1246: pch_newfirst(void)
1.1 deraadt 1247: {
1.17 deraadt 1248: return p_newfirst;
1.1 deraadt 1249: }
1250:
1.17 deraadt 1251: /*
1252: * Return the number of lines in the replacement text including context.
1253: */
1.1 deraadt 1254: LINENUM
1.17 deraadt 1255: pch_repl_lines(void)
1.1 deraadt 1256: {
1.17 deraadt 1257: return p_repl_lines;
1.1 deraadt 1258: }
1259:
1.17 deraadt 1260: /*
1261: * Return the number of lines in the whole hunk.
1262: */
1.1 deraadt 1263: LINENUM
1.17 deraadt 1264: pch_end(void)
1.1 deraadt 1265: {
1.17 deraadt 1266: return p_end;
1.1 deraadt 1267: }
1268:
1.17 deraadt 1269: /*
1270: * Return the number of context lines before the first changed line.
1271: */
1.1 deraadt 1272: LINENUM
1.17 deraadt 1273: pch_context(void)
1.1 deraadt 1274: {
1.17 deraadt 1275: return p_context;
1.1 deraadt 1276: }
1277:
1.17 deraadt 1278: /*
1279: * Return the length of a particular patch line.
1280: */
1.1 deraadt 1281: short
1.17 deraadt 1282: pch_line_len(LINENUM line)
1.1 deraadt 1283: {
1.17 deraadt 1284: return p_len[line];
1.1 deraadt 1285: }
1286:
1.17 deraadt 1287: /*
1288: * Return the control character (+, -, *, !, etc) for a patch line.
1289: */
1.1 deraadt 1290: char
1.17 deraadt 1291: pch_char(LINENUM line)
1.1 deraadt 1292: {
1.17 deraadt 1293: return p_char[line];
1.1 deraadt 1294: }
1295:
1.17 deraadt 1296: /*
1297: * Return a pointer to a particular patch line.
1298: */
1.1 deraadt 1299: char *
1.17 deraadt 1300: pfetch(LINENUM line)
1.1 deraadt 1301: {
1.17 deraadt 1302: return p_line[line];
1.1 deraadt 1303: }
1304:
1.17 deraadt 1305: /*
1306: * Return where in the patch file this hunk began, for error messages.
1307: */
1.1 deraadt 1308: LINENUM
1.17 deraadt 1309: pch_hunk_beg(void)
1.1 deraadt 1310: {
1.17 deraadt 1311: return p_hunk_beg;
1.1 deraadt 1312: }
1313:
1.17 deraadt 1314: /*
1315: * Apply an ed script by feeding ed itself.
1316: */
1.1 deraadt 1317: void
1.17 deraadt 1318: do_ed_script(void)
1.1 deraadt 1319: {
1.17 deraadt 1320: char *t;
1321: long beginning_of_this_line;
1322: FILE *pipefp;
1323:
1.28 otto 1324: pipefp = NULL;
1.17 deraadt 1325: if (!skip_rest_of_patch) {
1.24 millert 1326: if (copy_file(filearg[0], TMPOUTNAME) < 0) {
1327: unlink(TMPOUTNAME);
1328: fatal("can't create temp file %s", TMPOUTNAME);
1329: }
1.27 millert 1330: snprintf(buf, sizeof buf, "%s%s%s", _PATH_ED,
1331: verbose ? " " : " -s ", TMPOUTNAME);
1.17 deraadt 1332: pipefp = popen(buf, "w");
1333: }
1334: for (;;) {
1335: beginning_of_this_line = ftell(pfp);
1.21 otto 1336: if (pgets(buf, sizeof buf, pfp) == NULL) {
1.17 deraadt 1337: next_intuit_at(beginning_of_this_line, p_input_line);
1338: break;
1339: }
1340: p_input_line++;
1.18 deraadt 1341: for (t = buf; isdigit(*t) || *t == ','; t++)
1342: ;
1.22 millert 1343: /* POSIX defines allowed commands as {a,c,d,i,s} */
1344: if (isdigit(*buf) && (*t == 'a' || *t == 'c' || *t == 'd' ||
1345: *t == 'i' || *t == 's')) {
1.28 otto 1346: if (pipefp != NULL)
1.17 deraadt 1347: fputs(buf, pipefp);
1348: if (*t != 'd') {
1.21 otto 1349: while (pgets(buf, sizeof buf, pfp) != NULL) {
1.17 deraadt 1350: p_input_line++;
1.28 otto 1351: if (pipefp != NULL)
1.17 deraadt 1352: fputs(buf, pipefp);
1353: if (strEQ(buf, ".\n"))
1354: break;
1355: }
1356: }
1357: } else {
1358: next_intuit_at(beginning_of_this_line, p_input_line);
1.1 deraadt 1359: break;
1360: }
1361: }
1.28 otto 1362: if (pipefp == NULL)
1.17 deraadt 1363: return;
1364: fprintf(pipefp, "w\n");
1365: fprintf(pipefp, "q\n");
1366: fflush(pipefp);
1367: pclose(pipefp);
1368: ignore_signals();
1369: if (!check_only) {
1370: if (move_file(TMPOUTNAME, outname) < 0) {
1.28 otto 1371: toutkeep = true;
1.17 deraadt 1372: chmod(TMPOUTNAME, filemode);
1373: } else
1374: chmod(outname, filemode);
1.1 deraadt 1375: }
1.17 deraadt 1376: set_signals(1);
1.1 deraadt 1377: }