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