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