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