|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)patch.c 5.3 (Berkeley) 8/16/85"; ! 3: #endif not lint ! 4: ! 5: /* patch - a program to apply diffs to original files ! 6: * ! 7: * $Header: patch.c,v 1.3 85/03/26 15:07:43 lwall Exp $ ! 8: * ! 9: * Copyright 1984, Larry Wall ! 10: * ! 11: * This program may be copied as long as you don't try to make any ! 12: * money off of it, or pretend that you wrote it. ! 13: * ! 14: * $Log: patch.c,v $ ! 15: * 85/08/15 van%ucbmonet@berkeley ! 16: * Changes for 4.3bsd diff -c. ! 17: * ! 18: * Revision 1.3 85/03/26 15:07:43 lwall ! 19: * Frozen. ! 20: * ! 21: * Revision 1.2.1.9 85/03/12 17:03:35 lwall ! 22: * Changed pfp->_file to fileno(pfp). ! 23: * ! 24: * Revision 1.2.1.8 85/03/12 16:30:43 lwall ! 25: * Check i_ptr and i_womp to make sure they aren't null before freeing. ! 26: * Also allow ed output to be suppressed. ! 27: * ! 28: * Revision 1.2.1.7 85/03/12 15:56:13 lwall ! 29: * Added -p option from jromine@uci-750a. ! 30: * ! 31: * Revision 1.2.1.6 85/03/12 12:12:51 lwall ! 32: * Now checks for normalness of file to patch. ! 33: * ! 34: * Revision 1.2.1.5 85/03/12 11:52:12 lwall ! 35: * Added -D (#ifdef) option from joe@fluke. ! 36: * ! 37: * Revision 1.2.1.4 84/12/06 11:14:15 lwall ! 38: * Made smarter about SCCS subdirectories. ! 39: * ! 40: * Revision 1.2.1.3 84/12/05 11:18:43 lwall ! 41: * Added -l switch to do loose string comparison. ! 42: * ! 43: * Revision 1.2.1.2 84/12/04 09:47:13 lwall ! 44: * Failed hunk count not reset on multiple patch file. ! 45: * ! 46: * Revision 1.2.1.1 84/12/04 09:42:37 lwall ! 47: * Branch for sdcrdcf changes. ! 48: * ! 49: * Revision 1.2 84/11/29 13:29:51 lwall ! 50: * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed ! 51: * multiple calls to mktemp(). Will now work on machines that can only ! 52: * read 32767 chars. Added -R option for diffs with new and old swapped. ! 53: * Various cosmetic changes. ! 54: * ! 55: * Revision 1.1 84/11/09 17:03:58 lwall ! 56: * Initial revision ! 57: * ! 58: */ ! 59: ! 60: #define DEBUGGING ! 61: ! 62: /* shut lint up about the following when return value ignored */ ! 63: ! 64: #define Signal (void)signal ! 65: #define Unlink (void)unlink ! 66: #define Lseek (void)lseek ! 67: #define Fseek (void)fseek ! 68: #define Fstat (void)fstat ! 69: #define Pclose (void)pclose ! 70: #define Close (void)close ! 71: #define Fclose (void)fclose ! 72: #define Fflush (void)fflush ! 73: #define Sprintf (void)sprintf ! 74: #define Mktemp (void)mktemp ! 75: #define Strcpy (void)strcpy ! 76: #define Strcat (void)strcat ! 77: ! 78: #include <stdio.h> ! 79: #include <assert.h> ! 80: #include <sys/types.h> ! 81: #include <sys/stat.h> ! 82: #include <ctype.h> ! 83: #include <signal.h> ! 84: ! 85: /* constants */ ! 86: ! 87: #define TRUE (1) ! 88: #define FALSE (0) ! 89: ! 90: #define MAXHUNKSIZE 500 ! 91: #define MAXLINELEN 1024 ! 92: #define BUFFERSIZE 1024 ! 93: #define ORIGEXT ".orig" ! 94: #define SCCSPREFIX "s." ! 95: #define GET "get -e %s" ! 96: #define RCSSUFFIX ",v" ! 97: #define CHECKOUT "co -l %s" ! 98: ! 99: /* handy definitions */ ! 100: ! 101: #define Null(t) ((t)0) ! 102: #define Nullch Null(char *) ! 103: #define Nullfp Null(FILE *) ! 104: ! 105: #define Ctl(ch) (ch & 037) ! 106: ! 107: #define strNE(s1,s2) (strcmp(s1,s2)) ! 108: #define strEQ(s1,s2) (!strcmp(s1,s2)) ! 109: #define strnNE(s1,s2,l) (strncmp(s1,s2,l)) ! 110: #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l)) ! 111: ! 112: /* typedefs */ ! 113: ! 114: typedef char bool; ! 115: typedef long LINENUM; /* must be signed */ ! 116: typedef unsigned MEM; /* what to feed malloc */ ! 117: ! 118: /* globals */ ! 119: ! 120: int Argc; /* guess */ ! 121: char **Argv; ! 122: ! 123: struct stat filestat; /* file statistics area */ ! 124: ! 125: char serrbuf[BUFSIZ]; /* buffer for stderr */ ! 126: char buf[MAXLINELEN]; /* general purpose buffer */ ! 127: FILE *pfp = Nullfp; /* patch file pointer */ ! 128: FILE *ofp = Nullfp; /* output file pointer */ ! 129: FILE *rejfp = Nullfp; /* reject file pointer */ ! 130: ! 131: LINENUM input_lines = 0; /* how long is input file in lines */ ! 132: LINENUM last_frozen_line = 0; /* how many input lines have been */ ! 133: /* irretractibly output */ ! 134: ! 135: #define MAXFILEC 2 ! 136: int filec = 0; /* how many file arguments? */ ! 137: char *filearg[MAXFILEC]; ! 138: ! 139: char *outname = Nullch; ! 140: char rejname[128]; ! 141: ! 142: char *origext = Nullch; ! 143: ! 144: char TMPOUTNAME[] = "/tmp/patchoXXXXXX"; ! 145: char TMPINNAME[] = "/tmp/patchiXXXXXX"; /* you might want /usr/tmp here */ ! 146: char TMPREJNAME[] = "/tmp/patchrXXXXXX"; ! 147: char TMPPATNAME[] = "/tmp/patchpXXXXXX"; ! 148: ! 149: LINENUM last_offset = 0; ! 150: #ifdef DEBUGGING ! 151: int debug = 0; ! 152: #endif ! 153: bool verbose = TRUE; ! 154: bool reverse = FALSE; ! 155: bool usepath = FALSE; ! 156: bool canonicalize = FALSE; ! 157: ! 158: #define CONTEXT_DIFF 1 ! 159: #define NORMAL_DIFF 2 ! 160: #define ED_DIFF 3 ! 161: #define NEW_CONTEXT_DIFF 4 ! 162: int diff_type = 0; ! 163: ! 164: int do_defines = 0; /* patch using ifdef, ifndef, etc. */ ! 165: char if_defined[128]; /* #ifdef xyzzy */ ! 166: char not_defined[128]; /* #ifndef xyzzy */ ! 167: char else_defined[] = "#else\n"; /* #else */ ! 168: char end_defined[128]; /* #endif xyzzy */ ! 169: ! 170: char *revision = Nullch; /* prerequisite revision, if any */ ! 171: ! 172: /* procedures */ ! 173: ! 174: LINENUM locate_hunk(); ! 175: bool patch_match(); ! 176: bool similar(); ! 177: char *malloc(); ! 178: char *savestr(); ! 179: char *strcpy(); ! 180: char *strcat(); ! 181: char *sprintf(); /* usually */ ! 182: int my_exit(); ! 183: bool rev_in_string(); ! 184: char *fetchname(); ! 185: long atol(); ! 186: long lseek(); ! 187: char *mktemp(); ! 188: ! 189: /* patch type */ ! 190: ! 191: bool there_is_another_patch(); ! 192: bool another_hunk(); ! 193: char *pfetch(); ! 194: int pch_line_len(); ! 195: LINENUM pch_first(); ! 196: LINENUM pch_ptrn_lines(); ! 197: LINENUM pch_newfirst(); ! 198: LINENUM pch_repl_lines(); ! 199: LINENUM pch_end(); ! 200: LINENUM pch_context(); ! 201: LINENUM pch_hunk_beg(); ! 202: char pch_char(); ! 203: char *pfetch(); ! 204: char *pgets(); ! 205: ! 206: /* input file type */ ! 207: ! 208: char *ifetch(); ! 209: ! 210: /* apply a context patch to a named file */ ! 211: ! 212: main(argc,argv) ! 213: int argc; ! 214: char **argv; ! 215: { ! 216: LINENUM where; ! 217: int hunk = 0; ! 218: int failed = 0; ! 219: int i; ! 220: ! 221: setbuf(stderr,serrbuf); ! 222: for (i = 0; i<MAXFILEC; i++) ! 223: filearg[i] = Nullch; ! 224: Mktemp(TMPOUTNAME); ! 225: Mktemp(TMPINNAME); ! 226: Mktemp(TMPREJNAME); ! 227: Mktemp(TMPPATNAME); ! 228: ! 229: /* parse switches */ ! 230: Argc = argc; ! 231: Argv = argv; ! 232: get_some_switches(); ! 233: ! 234: /* make sure we clean up /tmp in case of disaster */ ! 235: set_signals(); ! 236: ! 237: for ( ! 238: open_patch_file(filearg[1]); ! 239: there_is_another_patch(); ! 240: reinitialize_almost_everything() ! 241: ) { /* for each patch in patch file */ ! 242: ! 243: if (outname == Nullch) ! 244: outname = savestr(filearg[0]); ! 245: ! 246: /* initialize the patched file */ ! 247: init_output(TMPOUTNAME); ! 248: ! 249: /* for ed script just up and do it and exit */ ! 250: if (diff_type == ED_DIFF) { ! 251: do_ed_script(); ! 252: continue; ! 253: } ! 254: ! 255: /* initialize reject file */ ! 256: init_reject(TMPREJNAME); ! 257: ! 258: /* find out where all the lines are */ ! 259: scan_input(filearg[0]); ! 260: ! 261: /* from here on, open no standard i/o files, because malloc */ ! 262: /* might misfire */ ! 263: ! 264: /* apply each hunk of patch */ ! 265: hunk = 0; ! 266: failed = 0; ! 267: while (another_hunk()) { ! 268: hunk++; ! 269: where = locate_hunk(); ! 270: if (hunk == 1 && where == Null(LINENUM)) { ! 271: /* dwim for reversed patch? */ ! 272: pch_swap(); ! 273: reverse = !reverse; ! 274: where = locate_hunk(); /* try again */ ! 275: if (where == Null(LINENUM)) { ! 276: pch_swap(); /* no, put it back to normal */ ! 277: reverse = !reverse; ! 278: } ! 279: else { ! 280: say("%seversed (or previously applied) patch detected! %s -R.\n", ! 281: reverse ? "R" : "Unr", ! 282: reverse ? "Assuming" : "Ignoring"); ! 283: } ! 284: } ! 285: if (where == Null(LINENUM)) { ! 286: abort_hunk(); ! 287: failed++; ! 288: if (verbose) ! 289: say("Hunk #%d failed.\n",hunk); ! 290: } ! 291: else { ! 292: apply_hunk(where); ! 293: if (verbose) ! 294: if (last_offset) ! 295: say("Hunk #%d succeeded (offset %d line%s).\n", ! 296: hunk,last_offset,last_offset==1?"":"s"); ! 297: else ! 298: say("Hunk #%d succeeded.\n", hunk); ! 299: } ! 300: } ! 301: ! 302: assert(hunk); ! 303: ! 304: /* finish spewing out the new file */ ! 305: spew_output(); ! 306: ! 307: /* and put the output where desired */ ! 308: ignore_signals(); ! 309: move_file(TMPOUTNAME,outname); ! 310: Fclose(rejfp); ! 311: rejfp = Nullfp; ! 312: if (failed) { ! 313: if (!*rejname) { ! 314: Strcpy(rejname, outname); ! 315: Strcat(rejname, ".rej"); ! 316: } ! 317: say("%d out of %d hunks failed--saving rejects to %s\n", ! 318: failed, hunk, rejname); ! 319: move_file(TMPREJNAME,rejname); ! 320: } ! 321: set_signals(); ! 322: } ! 323: my_exit(0); ! 324: } ! 325: ! 326: reinitialize_almost_everything() ! 327: { ! 328: re_patch(); ! 329: re_input(); ! 330: ! 331: input_lines = 0; ! 332: last_frozen_line = 0; ! 333: ! 334: filec = 0; ! 335: if (filearg[0] != Nullch) { ! 336: free(filearg[0]); ! 337: filearg[0] = Nullch; ! 338: } ! 339: ! 340: if (outname != Nullch) { ! 341: free(outname); ! 342: outname = Nullch; ! 343: } ! 344: ! 345: last_offset = 0; ! 346: ! 347: diff_type = 0; ! 348: ! 349: if (revision != Nullch) { ! 350: free(revision); ! 351: revision = Nullch; ! 352: } ! 353: ! 354: reverse = FALSE; ! 355: ! 356: get_some_switches(); ! 357: ! 358: if (filec >= 2) ! 359: fatal("You may not change to a different patch file.\n"); ! 360: } ! 361: ! 362: get_some_switches() ! 363: { ! 364: register char *s; ! 365: ! 366: rejname[0] = '\0'; ! 367: if (!Argc) ! 368: return; ! 369: for (Argc--,Argv++; Argc; Argc--,Argv++) { ! 370: s = Argv[0]; ! 371: if (strEQ(s,"+")) { ! 372: return; /* + will be skipped by for loop */ ! 373: } ! 374: if (*s != '-' || !s[1]) { ! 375: if (filec == MAXFILEC) ! 376: fatal("Too many file arguments.\n"); ! 377: filearg[filec++] = savestr(s); ! 378: } ! 379: else { ! 380: switch (*++s) { ! 381: case 'b': ! 382: origext = savestr(Argv[1]); ! 383: Argc--,Argv++; ! 384: break; ! 385: case 'c': ! 386: diff_type = CONTEXT_DIFF; ! 387: break; ! 388: case 'd': ! 389: if (chdir(Argv[1]) < 0) ! 390: fatal("Can't cd to %s.\n",Argv[1]); ! 391: Argc--,Argv++; ! 392: break; ! 393: case 'D': ! 394: do_defines++; ! 395: Sprintf(if_defined, "#ifdef %s\n", Argv[1]); ! 396: Sprintf(not_defined, "#ifndef %s\n", Argv[1]); ! 397: Sprintf(end_defined, "#endif %s\n", Argv[1]); ! 398: Argc--,Argv++; ! 399: break; ! 400: case 'e': ! 401: diff_type = ED_DIFF; ! 402: break; ! 403: case 'l': ! 404: canonicalize = TRUE; ! 405: break; ! 406: case 'n': ! 407: diff_type = NORMAL_DIFF; ! 408: break; ! 409: case 'o': ! 410: outname = savestr(Argv[1]); ! 411: Argc--,Argv++; ! 412: break; ! 413: case 'p': ! 414: usepath = TRUE; /* do not strip path names */ ! 415: break; ! 416: case 'r': ! 417: Strcpy(rejname,Argv[1]); ! 418: Argc--,Argv++; ! 419: break; ! 420: case 'R': ! 421: reverse = TRUE; ! 422: break; ! 423: case 's': ! 424: verbose = FALSE; ! 425: break; ! 426: #ifdef DEBUGGING ! 427: case 'x': ! 428: debug = atoi(s+1); ! 429: break; ! 430: #endif ! 431: default: ! 432: fatal("Unrecognized switch: %s\n",Argv[0]); ! 433: } ! 434: } ! 435: } ! 436: } ! 437: ! 438: LINENUM ! 439: locate_hunk() ! 440: { ! 441: register LINENUM first_guess = pch_first() + last_offset; ! 442: register LINENUM offset; ! 443: LINENUM pat_lines = pch_ptrn_lines(); ! 444: register LINENUM max_pos_offset = input_lines - first_guess ! 445: - pat_lines + 1; ! 446: register LINENUM max_neg_offset = first_guess - last_frozen_line - 1 ! 447: - pch_context(); ! 448: ! 449: if (!pat_lines) /* null range matches always */ ! 450: return first_guess; ! 451: if (max_neg_offset >= first_guess) /* do not try lines < 0 */ ! 452: max_neg_offset = first_guess - 1; ! 453: if (first_guess <= input_lines && patch_match(first_guess,(LINENUM)0)) ! 454: return first_guess; ! 455: for (offset = 1; ; offset++) { ! 456: bool check_after = (offset <= max_pos_offset); ! 457: bool check_before = (offset <= max_pos_offset); ! 458: ! 459: if (check_after && patch_match(first_guess,offset)) { ! 460: #ifdef DEBUGGING ! 461: if (debug & 1) ! 462: printf("Offset changing from %d to %d\n",last_offset,offset); ! 463: #endif ! 464: last_offset = offset; ! 465: return first_guess+offset; ! 466: } ! 467: else if (check_before && patch_match(first_guess,-offset)) { ! 468: #ifdef DEBUGGING ! 469: if (debug & 1) ! 470: printf("Offset changing from %d to %d\n",last_offset,-offset); ! 471: #endif ! 472: last_offset = -offset; ! 473: return first_guess-offset; ! 474: } ! 475: else if (!check_before && !check_after) ! 476: return Null(LINENUM); ! 477: } ! 478: } ! 479: ! 480: /* we did not find the pattern, dump out the hunk so they can handle it */ ! 481: ! 482: abort_hunk() ! 483: { ! 484: register LINENUM i; ! 485: register LINENUM pat_end = pch_end(); ! 486: /* add in last_offset to guess the same as the previous successful hunk */ ! 487: int oldfirst = pch_first() + last_offset; ! 488: int newfirst = pch_newfirst() + last_offset; ! 489: int oldlast = oldfirst + pch_ptrn_lines() - 1; ! 490: int newlast = newfirst + pch_repl_lines() - 1; ! 491: ! 492: fprintf(rejfp,"***************\n"); ! 493: for (i=0; i<=pat_end; i++) { ! 494: switch (pch_char(i)) { ! 495: case '*': ! 496: fprintf(rejfp,"*** %d,%d\n", oldfirst, oldlast); ! 497: break; ! 498: case '=': ! 499: fprintf(rejfp,"--- %d,%d -----\n", newfirst, newlast); ! 500: break; ! 501: case '\n': ! 502: fprintf(rejfp,"%s", pfetch(i)); ! 503: break; ! 504: case ' ': case '-': case '+': case '!': ! 505: fprintf(rejfp,"%c %s", pch_char(i), pfetch(i)); ! 506: break; ! 507: default: ! 508: say("Fatal internal error in abort_hunk().\n"); ! 509: abort(); ! 510: } ! 511: } ! 512: } ! 513: ! 514: /* we found where to apply it (we hope), so do it */ ! 515: ! 516: apply_hunk(where) ! 517: LINENUM where; ! 518: { ! 519: register LINENUM old = 1; ! 520: register LINENUM lastline = pch_ptrn_lines(); ! 521: register LINENUM new = lastline+1; ! 522: register int def_state = 0; /* -1 = ifndef, 1 = ifdef */ ! 523: ! 524: where--; ! 525: while (pch_char(new) == '=' || pch_char(new) == '\n') ! 526: new++; ! 527: ! 528: while (old <= lastline) { ! 529: if (pch_char(old) == '-') { ! 530: copy_till(where + old - 1); ! 531: if (do_defines) { ! 532: if (def_state == 0) { ! 533: fputs(not_defined, ofp); ! 534: def_state = -1; ! 535: } else ! 536: if (def_state == 1) { ! 537: fputs(else_defined, ofp); ! 538: def_state = 2; ! 539: } ! 540: fputs(pfetch(old), ofp); ! 541: } ! 542: last_frozen_line++; ! 543: old++; ! 544: } ! 545: else if (pch_char(new) == '+') { ! 546: copy_till(where + old - 1); ! 547: if (do_defines) { ! 548: if (def_state == -1) { ! 549: fputs(else_defined, ofp); ! 550: def_state = 2; ! 551: } else ! 552: if (def_state == 0) { ! 553: fputs(if_defined, ofp); ! 554: def_state = 1; ! 555: } ! 556: } ! 557: fputs(pfetch(new),ofp); ! 558: new++; ! 559: } ! 560: else { ! 561: if (pch_char(new) != pch_char(old)) { ! 562: say("Out-of-sync patch, lines %d,%d\n", ! 563: pch_hunk_beg() + old - 1, ! 564: pch_hunk_beg() + new - 1); ! 565: #ifdef DEBUGGING ! 566: printf("oldchar = '%c', newchar = '%c'\n", ! 567: pch_char(old), pch_char(new)); ! 568: #endif ! 569: my_exit(1); ! 570: } ! 571: if (pch_char(new) == '!') { ! 572: copy_till(where + old - 1); ! 573: if (do_defines) { ! 574: fputs(not_defined,ofp); ! 575: def_state = -1; ! 576: } ! 577: while (pch_char(old) == '!') { ! 578: if (do_defines) { ! 579: fputs(pfetch(old),ofp); ! 580: } ! 581: last_frozen_line++; ! 582: old++; ! 583: } ! 584: if (do_defines) { ! 585: fputs(else_defined, ofp); ! 586: def_state = 2; ! 587: } ! 588: while (pch_char(new) == '!') { ! 589: fputs(pfetch(new),ofp); ! 590: new++; ! 591: } ! 592: if (do_defines) { ! 593: fputs(end_defined, ofp); ! 594: def_state = 0; ! 595: } ! 596: } ! 597: else { ! 598: assert(pch_char(new) == ' '); ! 599: old++; ! 600: new++; ! 601: } ! 602: } ! 603: } ! 604: if (new <= pch_end() && pch_char(new) == '+') { ! 605: copy_till(where + old - 1); ! 606: if (do_defines) { ! 607: if (def_state == 0) { ! 608: fputs(if_defined, ofp); ! 609: def_state = 1; ! 610: } else ! 611: if (def_state == -1) { ! 612: fputs(else_defined, ofp); ! 613: def_state = 2; ! 614: } ! 615: } ! 616: while (new <= pch_end() && pch_char(new) == '+') { ! 617: fputs(pfetch(new),ofp); ! 618: new++; ! 619: } ! 620: } ! 621: if (do_defines && def_state) { ! 622: fputs(end_defined, ofp); ! 623: } ! 624: } ! 625: ! 626: do_ed_script() ! 627: { ! 628: FILE *pipefp, *popen(); ! 629: bool this_line_is_command = FALSE; ! 630: register char *t; ! 631: long beginning_of_this_line; ! 632: ! 633: Unlink(TMPOUTNAME); ! 634: copy_file(filearg[0],TMPOUTNAME); ! 635: if (verbose) ! 636: Sprintf(buf,"/bin/ed %s",TMPOUTNAME); ! 637: else ! 638: Sprintf(buf,"/bin/ed - %s",TMPOUTNAME); ! 639: pipefp = popen(buf,"w"); ! 640: for (;;) { ! 641: beginning_of_this_line = ftell(pfp); ! 642: if (pgets(buf,sizeof buf,pfp) == Nullch) { ! 643: next_intuit_at(beginning_of_this_line); ! 644: break; ! 645: } ! 646: for (t=buf; isdigit(*t) || *t == ','; t++) ; ! 647: this_line_is_command = (isdigit(*buf) && ! 648: (*t == 'd' || *t == 'c' || *t == 'a') ); ! 649: if (this_line_is_command) { ! 650: fputs(buf,pipefp); ! 651: if (*t != 'd') { ! 652: while (pgets(buf,sizeof buf,pfp) != Nullch) { ! 653: fputs(buf,pipefp); ! 654: if (strEQ(buf,".\n")) ! 655: break; ! 656: } ! 657: } ! 658: } ! 659: else { ! 660: next_intuit_at(beginning_of_this_line); ! 661: break; ! 662: } ! 663: } ! 664: fprintf(pipefp,"w\n"); ! 665: fprintf(pipefp,"q\n"); ! 666: Fflush(pipefp); ! 667: Pclose(pipefp); ! 668: ignore_signals(); ! 669: move_file(TMPOUTNAME,outname); ! 670: set_signals(); ! 671: } ! 672: ! 673: init_output(name) ! 674: char *name; ! 675: { ! 676: ofp = fopen(name,"w"); ! 677: if (ofp == Nullfp) ! 678: fatal("patch: can't create %s.\n",name); ! 679: } ! 680: ! 681: init_reject(name) ! 682: char *name; ! 683: { ! 684: rejfp = fopen(name,"w"); ! 685: if (rejfp == Nullfp) ! 686: fatal("patch: can't create %s.\n",name); ! 687: } ! 688: ! 689: move_file(from,to) ! 690: char *from, *to; ! 691: { ! 692: char bakname[512]; ! 693: register char *s; ! 694: int fromfd; ! 695: register int i; ! 696: ! 697: /* to stdout? */ ! 698: ! 699: if (strEQ(to,"-")) { ! 700: #ifdef DEBUGGING ! 701: if (debug & 4) ! 702: say("Moving %s to stdout.\n",from); ! 703: #endif ! 704: fromfd = open(from,0); ! 705: if (fromfd < 0) ! 706: fatal("patch: internal error, can't reopen %s\n",from); ! 707: while ((i=read(fromfd,buf,sizeof buf)) > 0) ! 708: if (write(1,buf,i) != 1) ! 709: fatal("patch: write failed\n"); ! 710: Close(fromfd); ! 711: return; ! 712: } ! 713: ! 714: Strcpy(bakname,to); ! 715: Strcat(bakname,origext?origext:ORIGEXT); ! 716: if (stat(to,&filestat) >= 0) { /* output file exists */ ! 717: dev_t to_device = filestat.st_dev; ! 718: ino_t to_inode = filestat.st_ino; ! 719: char *simplename = bakname; ! 720: ! 721: for (s=bakname; *s; s++) { ! 722: if (*s == '/') ! 723: simplename = s+1; ! 724: } ! 725: /* find a backup name that is not the same file */ ! 726: while (stat(bakname,&filestat) >= 0 && ! 727: to_device == filestat.st_dev && to_inode == filestat.st_ino) { ! 728: for (s=simplename; *s && !islower(*s); s++) ; ! 729: if (*s) ! 730: *s = toupper(*s); ! 731: else ! 732: Strcpy(simplename, simplename+1); ! 733: } ! 734: while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */ ! 735: #ifdef DEBUGGING ! 736: if (debug & 4) ! 737: say("Moving %s to %s.\n",to,bakname); ! 738: #endif ! 739: if (link(to,bakname) < 0) { ! 740: say("patch: can't backup %s, output is in %s\n", ! 741: to,from); ! 742: return; ! 743: } ! 744: while (unlink(to) >= 0) ; ! 745: } ! 746: #ifdef DEBUGGING ! 747: if (debug & 4) ! 748: say("Moving %s to %s.\n",from,to); ! 749: #endif ! 750: if (link(from,to) < 0) { /* different file system? */ ! 751: int tofd; ! 752: ! 753: tofd = creat(to,0666); ! 754: if (tofd < 0) { ! 755: say("patch: can't create %s, output is in %s.\n", ! 756: to, from); ! 757: return; ! 758: } ! 759: fromfd = open(from,0); ! 760: if (fromfd < 0) ! 761: fatal("patch: internal error, can't reopen %s\n",from); ! 762: while ((i=read(fromfd,buf,sizeof buf)) > 0) ! 763: if (write(tofd,buf,i) != i) ! 764: fatal("patch: write failed\n"); ! 765: Close(fromfd); ! 766: Close(tofd); ! 767: } ! 768: Unlink(from); ! 769: } ! 770: ! 771: copy_file(from,to) ! 772: char *from, *to; ! 773: { ! 774: int tofd; ! 775: int fromfd; ! 776: register int i; ! 777: ! 778: tofd = creat(to,0666); ! 779: if (tofd < 0) ! 780: fatal("patch: can't create %s.\n", to); ! 781: fromfd = open(from,0); ! 782: if (fromfd < 0) ! 783: fatal("patch: internal error, can't reopen %s\n",from); ! 784: while ((i=read(fromfd,buf,sizeof buf)) > 0) ! 785: if (write(tofd,buf,i) != i) ! 786: fatal("patch: write (%s) failed\n", to); ! 787: Close(fromfd); ! 788: Close(tofd); ! 789: } ! 790: ! 791: copy_till(lastline) ! 792: register LINENUM lastline; ! 793: { ! 794: if (last_frozen_line > lastline) ! 795: say("patch: misordered hunks! output will be garbled.\n"); ! 796: while (last_frozen_line < lastline) { ! 797: dump_line(++last_frozen_line); ! 798: } ! 799: } ! 800: ! 801: spew_output() ! 802: { ! 803: copy_till(input_lines); /* dump remainder of file */ ! 804: Fclose(ofp); ! 805: ofp = Nullfp; ! 806: } ! 807: ! 808: dump_line(line) ! 809: LINENUM line; ! 810: { ! 811: register char *s; ! 812: ! 813: for (s=ifetch(line,0); putc(*s,ofp) != '\n'; s++) ; ! 814: } ! 815: ! 816: /* does the patch pattern match at line base+offset? */ ! 817: ! 818: bool ! 819: patch_match(base,offset) ! 820: LINENUM base; ! 821: LINENUM offset; ! 822: { ! 823: register LINENUM pline; ! 824: register LINENUM iline; ! 825: register LINENUM pat_lines = pch_ptrn_lines(); ! 826: ! 827: for (pline = 1, iline=base+offset; pline <= pat_lines; pline++,iline++) { ! 828: if (canonicalize) { ! 829: if (!similar(ifetch(iline,(offset >= 0)), ! 830: pfetch(pline), ! 831: pch_line_len(pline) )) ! 832: return FALSE; ! 833: } ! 834: else if (strnNE(ifetch(iline,(offset >= 0)), ! 835: pfetch(pline), ! 836: pch_line_len(pline) )) ! 837: return FALSE; ! 838: } ! 839: return TRUE; ! 840: } ! 841: ! 842: /* match two lines with canonicalized white space */ ! 843: ! 844: bool ! 845: similar(a,b,len) ! 846: register char *a, *b; ! 847: register int len; ! 848: { ! 849: while (len) { ! 850: if (isspace(*b)) { /* whitespace (or \n) to match? */ ! 851: if (!isspace(*a)) /* no corresponding whitespace? */ ! 852: return FALSE; ! 853: while (len && isspace(*b) && *b != '\n') ! 854: b++,len--; /* skip pattern whitespace */ ! 855: while (isspace(*a) && *a != '\n') ! 856: a++; /* skip target whitespace */ ! 857: if (*a == '\n' || *b == '\n') ! 858: return (*a == *b); /* should end in sync */ ! 859: } ! 860: else if (*a++ != *b++) /* match non-whitespace chars */ ! 861: return FALSE; ! 862: else ! 863: len--; /* probably not necessary */ ! 864: } ! 865: return TRUE; /* actually, this is not reached */ ! 866: /* since there is always a \n */ ! 867: } ! 868: ! 869: /* input file with indexable lines abstract type */ ! 870: ! 871: bool using_plan_a = TRUE; ! 872: static long i_size; /* size of the input file */ ! 873: static char *i_womp; /* plan a buffer for entire file */ ! 874: static char **i_ptr; /* pointers to lines in i_womp */ ! 875: ! 876: static int tifd = -1; /* plan b virtual string array */ ! 877: static char *tibuf[2]; /* plan b buffers */ ! 878: static LINENUM tiline[2] = {-1,-1}; /* 1st line in each buffer */ ! 879: static LINENUM lines_per_buf; /* how many lines per buffer */ ! 880: static int tireclen; /* length of records in tmp file */ ! 881: ! 882: re_input() ! 883: { ! 884: if (using_plan_a) { ! 885: i_size = 0; ! 886: /*NOSTRICT*/ ! 887: if (i_ptr != Null(char**)) ! 888: free((char *)i_ptr); ! 889: if (i_womp != Nullch) ! 890: free(i_womp); ! 891: i_womp = Nullch; ! 892: i_ptr = Null(char **); ! 893: } ! 894: else { ! 895: using_plan_a = TRUE; /* maybe the next one is smaller */ ! 896: Close(tifd); ! 897: tifd = -1; ! 898: free(tibuf[0]); ! 899: free(tibuf[1]); ! 900: tibuf[0] = tibuf[1] = Nullch; ! 901: tiline[0] = tiline[1] = -1; ! 902: tireclen = 0; ! 903: } ! 904: } ! 905: ! 906: scan_input(filename) ! 907: char *filename; ! 908: { ! 909: bool plan_a(); ! 910: ! 911: if (!plan_a(filename)) ! 912: plan_b(filename); ! 913: } ! 914: ! 915: /* try keeping everything in memory */ ! 916: ! 917: bool ! 918: plan_a(filename) ! 919: char *filename; ! 920: { ! 921: int ifd; ! 922: register char *s; ! 923: register LINENUM iline; ! 924: ! 925: if (stat(filename,&filestat) < 0) { ! 926: Sprintf(buf,"RCS/%s%s",filename,RCSSUFFIX); ! 927: if (stat(buf,&filestat) >= 0 || stat(buf+4,&filestat) >= 0) { ! 928: Sprintf(buf,CHECKOUT,filename); ! 929: if (verbose) ! 930: say("Can't find %s--attempting to check it out from RCS.\n", ! 931: filename); ! 932: if (system(buf) || stat(filename,&filestat)) ! 933: fatal("Can't check out %s.\n",filename); ! 934: } ! 935: else { ! 936: Sprintf(buf,"SCCS/%s%s",SCCSPREFIX,filename); ! 937: if (stat(buf,&filestat) >= 0 || stat(buf+5,&filestat) >= 0) { ! 938: Sprintf(buf,GET,filename); ! 939: if (verbose) ! 940: say("Can't find %s--attempting to get it from SCCS.\n", ! 941: filename); ! 942: if (system(buf) || stat(filename,&filestat)) ! 943: fatal("Can't get %s.\n",filename); ! 944: } ! 945: else ! 946: fatal("Can't find %s.\n",filename); ! 947: } ! 948: } ! 949: if ((filestat.st_mode & S_IFMT) & ~S_IFREG) ! 950: fatal("%s is not a normal file--can't patch.\n",filename); ! 951: i_size = filestat.st_size; ! 952: /*NOSTRICT*/ ! 953: i_womp = malloc((MEM)(i_size+2)); ! 954: if (i_womp == Nullch) ! 955: return FALSE; ! 956: if ((ifd = open(filename,0)) < 0) ! 957: fatal("Can't open file %s\n",filename); ! 958: /*NOSTRICT*/ ! 959: if (read(ifd,i_womp,(int)i_size) != i_size) { ! 960: Close(ifd); ! 961: free(i_womp); ! 962: return FALSE; ! 963: } ! 964: Close(ifd); ! 965: if (i_womp[i_size-1] != '\n') ! 966: i_womp[i_size++] = '\n'; ! 967: i_womp[i_size] = '\0'; ! 968: ! 969: /* count the lines in the buffer so we know how many pointers we need */ ! 970: ! 971: iline = 0; ! 972: for (s=i_womp; *s; s++) { ! 973: if (*s == '\n') ! 974: iline++; ! 975: } ! 976: /*NOSTRICT*/ ! 977: i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *))); ! 978: if (i_ptr == Null(char **)) { /* shucks, it was a near thing */ ! 979: free((char *)i_womp); ! 980: return FALSE; ! 981: } ! 982: ! 983: /* now scan the buffer and build pointer array */ ! 984: ! 985: iline = 1; ! 986: i_ptr[iline] = i_womp; ! 987: for (s=i_womp; *s; s++) { ! 988: if (*s == '\n') ! 989: i_ptr[++iline] = s+1; /* these are NOT null terminated */ ! 990: } ! 991: input_lines = iline - 1; ! 992: ! 993: /* now check for revision, if any */ ! 994: ! 995: if (revision != Nullch) { ! 996: if (!rev_in_string(i_womp)) { ! 997: ask("This file doesn't appear to be the %s version--patch anyway? [n] ", ! 998: revision); ! 999: if (*buf != 'y') ! 1000: fatal("Aborted.\n"); ! 1001: } ! 1002: else if (verbose) ! 1003: say("Good. This file appears to be the %s version.\n", ! 1004: revision); ! 1005: } ! 1006: return TRUE; /* plan a will work */ ! 1007: } ! 1008: ! 1009: /* keep (virtually) nothing in memory */ ! 1010: ! 1011: plan_b(filename) ! 1012: char *filename; ! 1013: { ! 1014: FILE *ifp; ! 1015: register int i = 0; ! 1016: register int maxlen = 1; ! 1017: bool found_revision = (revision == Nullch); ! 1018: ! 1019: using_plan_a = FALSE; ! 1020: if ((ifp = fopen(filename,"r")) == Nullfp) ! 1021: fatal("Can't open file %s\n",filename); ! 1022: if ((tifd = creat(TMPINNAME,0666)) < 0) ! 1023: fatal("Can't open file %s\n",TMPINNAME); ! 1024: while (fgets(buf,sizeof buf, ifp) != Nullch) { ! 1025: if (revision != Nullch && !found_revision && rev_in_string(buf)) ! 1026: found_revision = TRUE; ! 1027: if ((i = strlen(buf)) > maxlen) ! 1028: maxlen = i; /* find longest line */ ! 1029: } ! 1030: if (revision != Nullch) { ! 1031: if (!found_revision) { ! 1032: ask("This file doesn't appear to be the %s version--patch anyway? [n] ", ! 1033: revision); ! 1034: if (*buf != 'y') ! 1035: fatal("Aborted.\n"); ! 1036: } ! 1037: else if (verbose) ! 1038: say("Good. This file appears to be the %s version.\n", ! 1039: revision); ! 1040: } ! 1041: Fseek(ifp,0L,0); /* rewind file */ ! 1042: lines_per_buf = BUFFERSIZE / maxlen; ! 1043: tireclen = maxlen; ! 1044: tibuf[0] = malloc((MEM)(BUFFERSIZE + 1)); ! 1045: tibuf[1] = malloc((MEM)(BUFFERSIZE + 1)); ! 1046: if (tibuf[1] == Nullch) ! 1047: fatal("Can't seem to get enough memory.\n"); ! 1048: for (i=1; ; i++) { ! 1049: if (! (i % lines_per_buf)) /* new block */ ! 1050: if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE) ! 1051: fatal("patch: can't write temp file.\n"); ! 1052: if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp) ! 1053: == Nullch) { ! 1054: input_lines = i - 1; ! 1055: if (i % lines_per_buf) ! 1056: if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE) ! 1057: fatal("patch: can't write temp file.\n"); ! 1058: break; ! 1059: } ! 1060: } ! 1061: Fclose(ifp); ! 1062: Close(tifd); ! 1063: if ((tifd = open(TMPINNAME,0)) < 0) { ! 1064: fatal("Can't reopen file %s\n",TMPINNAME); ! 1065: } ! 1066: } ! 1067: ! 1068: /* fetch a line from the input file, \n terminated, not necessarily \0 */ ! 1069: char * ! 1070: ifetch(line,whichbuf) ! 1071: register LINENUM line; ! 1072: int whichbuf; /* ignored when file in memory */ ! 1073: { ! 1074: if (line < 1 || line > input_lines) ! 1075: return ""; ! 1076: if (using_plan_a) ! 1077: return i_ptr[line]; ! 1078: else { ! 1079: LINENUM offline = line % lines_per_buf; ! 1080: LINENUM baseline = line - offline; ! 1081: ! 1082: if (tiline[0] == baseline) ! 1083: whichbuf = 0; ! 1084: else if (tiline[1] == baseline) ! 1085: whichbuf = 1; ! 1086: else { ! 1087: tiline[whichbuf] = baseline; ! 1088: Lseek(tifd,(long)baseline / lines_per_buf * BUFFERSIZE,0); ! 1089: if (read(tifd,tibuf[whichbuf],BUFFERSIZE) < 0) ! 1090: fatal("Error reading tmp file %s.\n",TMPINNAME); ! 1091: } ! 1092: return tibuf[whichbuf] + (tireclen*offline); ! 1093: } ! 1094: } ! 1095: ! 1096: /* patch abstract type */ ! 1097: ! 1098: static long p_filesize; /* size of the patch file */ ! 1099: static LINENUM p_first; /* 1st line number */ ! 1100: static LINENUM p_newfirst; /* 1st line number of replacement */ ! 1101: static LINENUM p_ptrn_lines; /* # lines in pattern */ ! 1102: static LINENUM p_repl_lines; /* # lines in replacement text */ ! 1103: static LINENUM p_end = -1; /* last line in hunk */ ! 1104: static LINENUM p_max; /* max allowed value of p_end */ ! 1105: static LINENUM p_context = 3; /* # of context lines */ ! 1106: static LINENUM p_input_line = 0; /* current line # from patch file */ ! 1107: static char *p_line[MAXHUNKSIZE]; /* the text of the hunk */ ! 1108: static char p_char[MAXHUNKSIZE]; /* +, -, and ! */ ! 1109: static int p_len[MAXHUNKSIZE]; /* length of each line */ ! 1110: static int p_indent; /* indent to patch */ ! 1111: static long p_base; /* where to intuit this time */ ! 1112: static long p_start; /* where intuit found a patch */ ! 1113: ! 1114: re_patch() ! 1115: { ! 1116: p_first = (LINENUM)0; ! 1117: p_newfirst = (LINENUM)0; ! 1118: p_ptrn_lines = (LINENUM)0; ! 1119: p_repl_lines = (LINENUM)0; ! 1120: p_end = (LINENUM)-1; ! 1121: p_max = (LINENUM)0; ! 1122: p_indent = 0; ! 1123: } ! 1124: ! 1125: open_patch_file(filename) ! 1126: char *filename; ! 1127: { ! 1128: if (filename == Nullch || !*filename || strEQ(filename,"-")) { ! 1129: pfp = fopen(TMPPATNAME,"w"); ! 1130: if (pfp == Nullfp) ! 1131: fatal("patch: can't create %s.\n",TMPPATNAME); ! 1132: while (fgets(buf,sizeof buf,stdin) != NULL) ! 1133: fputs(buf,pfp); ! 1134: Fclose(pfp); ! 1135: filename = TMPPATNAME; ! 1136: } ! 1137: pfp = fopen(filename,"r"); ! 1138: if (pfp == Nullfp) ! 1139: fatal("patch file %s not found\n",filename); ! 1140: Fstat(fileno(pfp), &filestat); ! 1141: p_filesize = filestat.st_size; ! 1142: next_intuit_at(0L); /* start at the beginning */ ! 1143: } ! 1144: ! 1145: bool ! 1146: there_is_another_patch() ! 1147: { ! 1148: bool no_input_file = (filearg[0] == Nullch); ! 1149: ! 1150: if (p_base != 0L && p_base >= p_filesize) { ! 1151: if (verbose) ! 1152: say("done\n"); ! 1153: return FALSE; ! 1154: } ! 1155: if (verbose) ! 1156: say("Hmm..."); ! 1157: diff_type = intuit_diff_type(); ! 1158: if (!diff_type) { ! 1159: if (p_base != 0L) { ! 1160: if (verbose) ! 1161: say(" Ignoring the trailing garbage.\ndone\n"); ! 1162: } ! 1163: else ! 1164: say(" I can't seem to find a patch in there anywhere.\n"); ! 1165: return FALSE; ! 1166: } ! 1167: if (verbose) ! 1168: say(" %sooks like %s to me...\n", ! 1169: (p_base == 0L ? "L" : "The next patch l"), ! 1170: diff_type == CONTEXT_DIFF ? "a context diff" : ! 1171: diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : ! 1172: diff_type == NORMAL_DIFF ? "a normal diff" : ! 1173: "an ed script" ); ! 1174: if (p_indent && verbose) ! 1175: say("(Patch is indented %d space%s.)\n",p_indent,p_indent==1?"":"s"); ! 1176: skip_to(p_start); ! 1177: if (no_input_file) { ! 1178: if (filearg[0] == Nullch) { ! 1179: ask("File to patch: "); ! 1180: filearg[0] = fetchname(buf); ! 1181: } ! 1182: else if (verbose) { ! 1183: say("Patching file %s...\n",filearg[0]); ! 1184: } ! 1185: } ! 1186: return TRUE; ! 1187: } ! 1188: ! 1189: intuit_diff_type() ! 1190: { ! 1191: long this_line = 0; ! 1192: long previous_line; ! 1193: long first_command_line = -1; ! 1194: bool last_line_was_command = FALSE; ! 1195: bool this_line_is_command = FALSE; ! 1196: bool last_line_was_stars = FALSE; ! 1197: bool this_line_is_stars = FALSE; ! 1198: register int indent; ! 1199: register char *s, *t; ! 1200: char *oldname = Nullch; ! 1201: char *newname = Nullch; ! 1202: bool no_filearg = (filearg[0] == Nullch); ! 1203: ! 1204: Fseek(pfp,p_base,0); ! 1205: for (;;) { ! 1206: previous_line = this_line; ! 1207: last_line_was_command = this_line_is_command; ! 1208: last_line_was_stars = this_line_is_stars; ! 1209: this_line = ftell(pfp); ! 1210: indent = 0; ! 1211: if (fgets(buf,sizeof buf,pfp) == Nullch) { ! 1212: if (first_command_line >= 0L) { ! 1213: /* nothing but deletes!? */ ! 1214: p_start = first_command_line; ! 1215: return ED_DIFF; ! 1216: } ! 1217: else { ! 1218: p_start = this_line; ! 1219: return 0; ! 1220: } ! 1221: } ! 1222: for (s = buf; *s == ' ' || *s == '\t'; s++) { ! 1223: if (*s == '\t') ! 1224: indent += 8 - (indent % 8); ! 1225: else ! 1226: indent++; ! 1227: } ! 1228: for (t=s; isdigit(*t) || *t == ','; t++) ; ! 1229: this_line_is_command = (isdigit(*s) && ! 1230: (*t == 'd' || *t == 'c' || *t == 'a') ); ! 1231: if (first_command_line < 0L && this_line_is_command) { ! 1232: first_command_line = this_line; ! 1233: p_indent = indent; /* assume this for now */ ! 1234: } ! 1235: if (strnEQ(s,"*** ",4)) ! 1236: oldname = fetchname(s+4); ! 1237: else if (strnEQ(s,"--- ",4)) { ! 1238: newname = fetchname(s+4); ! 1239: if (no_filearg) { ! 1240: if (oldname && newname) { ! 1241: if (strlen(oldname) < strlen(newname)) ! 1242: filearg[0] = oldname; ! 1243: else ! 1244: filearg[0] = newname; ! 1245: } ! 1246: else if (oldname) ! 1247: filearg[0] = oldname; ! 1248: else if (newname) ! 1249: filearg[0] = newname; ! 1250: } ! 1251: } ! 1252: else if (strnEQ(s,"Index:",6)) { ! 1253: if (no_filearg) ! 1254: filearg[0] = fetchname(s+6); ! 1255: /* this filearg might get limboed */ ! 1256: } ! 1257: else if (strnEQ(s,"Prereq:",7)) { ! 1258: for (t=s+7; isspace(*t); t++) ; ! 1259: revision = savestr(t); ! 1260: for (t=revision; *t && !isspace(*t); t++) ; ! 1261: *t = '\0'; ! 1262: if (!*revision) { ! 1263: free(revision); ! 1264: revision = Nullch; ! 1265: } ! 1266: } ! 1267: if ((!diff_type || diff_type == ED_DIFF) && ! 1268: first_command_line >= 0L && ! 1269: strEQ(s,".\n") ) { ! 1270: p_indent = indent; ! 1271: p_start = first_command_line; ! 1272: return ED_DIFF; ! 1273: } ! 1274: this_line_is_stars = strnEQ(s,"********",8); ! 1275: if ((!diff_type || diff_type == CONTEXT_DIFF) && last_line_was_stars && ! 1276: strnEQ(s,"*** ",4)) { ! 1277: /* if this is a new context diff the character just before */ ! 1278: /* the newline is a '*'. */ ! 1279: while (*s != '\n') ! 1280: s++; ! 1281: p_indent = indent; ! 1282: p_start = previous_line; ! 1283: return (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); ! 1284: } ! 1285: if ((!diff_type || diff_type == NORMAL_DIFF) && ! 1286: last_line_was_command && ! 1287: (strnEQ(s,"< ",2) || strnEQ(s,"> ",2)) ) { ! 1288: p_start = previous_line; ! 1289: p_indent = indent; ! 1290: return NORMAL_DIFF; ! 1291: } ! 1292: } ! 1293: } ! 1294: ! 1295: char * ! 1296: fetchname(at) ! 1297: char *at; ! 1298: { ! 1299: char *s = savestr(at); ! 1300: char *name; ! 1301: register char *t; ! 1302: char tmpbuf[200]; ! 1303: ! 1304: for (t=s; isspace(*t); t++) ; ! 1305: name = t; ! 1306: for (; *t && !isspace(*t); t++) ! 1307: if (!usepath) ! 1308: if (*t == '/') ! 1309: name = t+1; ! 1310: *t = '\0'; ! 1311: name = savestr(name); ! 1312: Sprintf(tmpbuf,"RCS/%s",name); ! 1313: free(s); ! 1314: if (stat(name,&filestat) < 0) { ! 1315: Strcat(tmpbuf,RCSSUFFIX); ! 1316: if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+4,&filestat) < 0) { ! 1317: Sprintf(tmpbuf,"SCCS/%s%s",SCCSPREFIX,name); ! 1318: if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+5,&filestat) < 0) { ! 1319: free(name); ! 1320: name = Nullch; ! 1321: } ! 1322: } ! 1323: } ! 1324: return name; ! 1325: } ! 1326: ! 1327: next_intuit_at(file_pos) ! 1328: long file_pos; ! 1329: { ! 1330: p_base = file_pos; ! 1331: } ! 1332: ! 1333: skip_to(file_pos) ! 1334: long file_pos; ! 1335: { ! 1336: char *ret; ! 1337: ! 1338: assert(p_base <= file_pos); ! 1339: if (verbose && p_base < file_pos) { ! 1340: Fseek(pfp,p_base,0); ! 1341: say("The text leading up to this was:\n--------------------------\n"); ! 1342: while (ftell(pfp) < file_pos) { ! 1343: ret = fgets(buf,sizeof buf,pfp); ! 1344: assert(ret != Nullch); ! 1345: say("|%s",buf); ! 1346: } ! 1347: say("--------------------------\n"); ! 1348: } ! 1349: else ! 1350: Fseek(pfp,file_pos,0); ! 1351: } ! 1352: ! 1353: bool ! 1354: another_hunk() ! 1355: { ! 1356: register char *s; ! 1357: char *ret; ! 1358: register int context = 0; ! 1359: ! 1360: while (p_end >= 0) { ! 1361: free(p_line[p_end--]); ! 1362: } ! 1363: assert(p_end == -1); ! 1364: ! 1365: p_max = MAXHUNKSIZE; /* gets reduced when --- found */ ! 1366: if (diff_type == CONTEXT_DIFF) { ! 1367: long line_beginning = ftell(pfp); ! 1368: LINENUM repl_beginning = 0; ! 1369: ! 1370: ret = pgets(buf,sizeof buf, pfp); ! 1371: if (ret == Nullch || strnNE(buf,"********",8)) { ! 1372: next_intuit_at(line_beginning); ! 1373: return FALSE; ! 1374: } ! 1375: p_context = 100; ! 1376: while (p_end < p_max) { ! 1377: ret = pgets(buf,sizeof buf, pfp); ! 1378: if (ret == Nullch) { ! 1379: if (p_max - p_end < 4) ! 1380: Strcpy(buf," \n"); /* assume blank lines got chopped */ ! 1381: else ! 1382: fatal("Unexpected end of file in patch.\n"); ! 1383: } ! 1384: p_input_line++; ! 1385: if (strnEQ(buf,"********",8)) ! 1386: fatal("Unexpected end of hunk at line %d.\n", ! 1387: p_input_line); ! 1388: p_char[++p_end] = *buf; ! 1389: switch (*buf) { ! 1390: case '*': ! 1391: if (p_end != 0) ! 1392: fatal("Unexpected *** at line %d: %s", p_input_line, buf); ! 1393: context = 0; ! 1394: p_line[p_end] = savestr(buf); ! 1395: for (s=buf; *s && !isdigit(*s); s++) ; ! 1396: p_first = (LINENUM) atol(s); ! 1397: while (isdigit(*s)) s++; ! 1398: for (; *s && !isdigit(*s); s++) ; ! 1399: p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; ! 1400: break; ! 1401: case '-': ! 1402: if (buf[1] == '-') { ! 1403: if (p_end != p_ptrn_lines + 1 && ! 1404: p_end != p_ptrn_lines + 2) ! 1405: fatal("Unexpected --- at line %d: %s", ! 1406: p_input_line,buf); ! 1407: repl_beginning = p_end; ! 1408: context = 0; ! 1409: p_line[p_end] = savestr(buf); ! 1410: p_char[p_end] = '='; ! 1411: for (s=buf; *s && !isdigit(*s); s++) ; ! 1412: p_newfirst = (LINENUM) atol(s); ! 1413: while (isdigit(*s)) s++; ! 1414: for (; *s && !isdigit(*s); s++) ; ! 1415: p_max = ((LINENUM)atol(s)) - p_newfirst + 1 + p_end; ! 1416: break; ! 1417: } ! 1418: /* FALL THROUGH */ ! 1419: case '+': case '!': ! 1420: if (context > 0) { ! 1421: if (context < p_context) ! 1422: p_context = context; ! 1423: context = -100; ! 1424: } ! 1425: p_line[p_end] = savestr(buf+2); ! 1426: break; ! 1427: case '\t': case '\n': /* assume the 2 spaces got eaten */ ! 1428: p_line[p_end] = savestr(buf); ! 1429: if (p_end != p_ptrn_lines + 1) { ! 1430: context++; ! 1431: p_char[p_end] = ' '; ! 1432: } ! 1433: break; ! 1434: case ' ': ! 1435: context++; ! 1436: p_line[p_end] = savestr(buf+2); ! 1437: break; ! 1438: default: ! 1439: fatal("Malformed patch at line %d: %s",p_input_line,buf); ! 1440: } ! 1441: p_len[p_end] = 0; ! 1442: if (p_line[p_end] != 0) ! 1443: p_len[p_end] = strlen(p_line[p_end]); ! 1444: /* for strncmp() so we do not have */ ! 1445: /* to assume null termination */ ! 1446: } ! 1447: if (p_end >=0 && !p_ptrn_lines) ! 1448: fatal("No --- found in patch at line %d\n", pch_hunk_beg()); ! 1449: p_repl_lines = p_end - repl_beginning; ! 1450: } ! 1451: else if (diff_type == NEW_CONTEXT_DIFF) { ! 1452: long line_beginning = ftell(pfp); ! 1453: LINENUM repl_beginning = 0; ! 1454: LINENUM fillcnt = 0; ! 1455: LINENUM fillsrc; ! 1456: LINENUM filldst; ! 1457: ! 1458: ret = pgets(buf,sizeof buf, pfp); ! 1459: if (ret == Nullch || strnNE(buf,"********",8)) { ! 1460: next_intuit_at(line_beginning); ! 1461: return FALSE; ! 1462: } ! 1463: p_context = 0; ! 1464: while (p_end < p_max) { ! 1465: line_beginning = ftell(pfp); ! 1466: ret = pgets(buf,sizeof buf, pfp); ! 1467: if (ret == Nullch) { ! 1468: if (p_max - p_end < 4) ! 1469: Strcpy(buf," \n"); /* assume blank lines got chopped */ ! 1470: else ! 1471: fatal("Unexpected end of file in patch.\n"); ! 1472: } ! 1473: p_input_line++; ! 1474: p_char[++p_end] = *buf; ! 1475: switch (*buf) { ! 1476: case '*': ! 1477: if (strnEQ(buf,"********",8)) { ! 1478: if (p_end != repl_beginning + 1) ! 1479: fatal("Unexpected end of hunk at line %d.\n", ! 1480: p_input_line); ! 1481: /* redundant 'new' context lines were omitted - set up */ ! 1482: /* to fill them in from the the old file's context */ ! 1483: fillsrc = 1; ! 1484: filldst = p_end; ! 1485: fillcnt = p_max - repl_beginning; ! 1486: p_end = p_max; ! 1487: Fseek(pfp, line_beginning, 0); /* backup the diff input */ ! 1488: break; ! 1489: } ! 1490: if (p_end != 0) ! 1491: fatal("Unexpected *** at line %d: %s", p_input_line, buf); ! 1492: context = 0; ! 1493: p_line[p_end] = savestr(buf); ! 1494: for (s=buf; *s && !isdigit(*s); s++) ; ! 1495: p_first = (LINENUM) atol(s); ! 1496: while (isdigit(*s)) s++; ! 1497: for (; *s && !isdigit(*s); s++) ; ! 1498: p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; ! 1499: break; ! 1500: case '-': ! 1501: if (buf[1] == '-') { ! 1502: if (p_end != p_ptrn_lines + 1) { ! 1503: if (p_end == 1) { ! 1504: /* `old' lines were omitted - set up to fill them */ ! 1505: /* in from 'new' context lines. */ ! 1506: p_end = p_ptrn_lines + 1; ! 1507: fillsrc = p_end + 1; ! 1508: filldst = 1; ! 1509: fillcnt = p_ptrn_lines; ! 1510: } else ! 1511: fatal("Unexpected --- at line %d: %s", ! 1512: p_input_line,buf); ! 1513: } ! 1514: repl_beginning = p_end; ! 1515: p_line[p_end] = savestr(buf); ! 1516: p_char[p_end] = '='; ! 1517: for (s=buf; *s && !isdigit(*s); s++) ; ! 1518: p_newfirst = (LINENUM) atol(s); ! 1519: while (isdigit(*s)) s++; ! 1520: for (; *s && !isdigit(*s); s++) ; ! 1521: p_max = ((LINENUM)atol(s)) - p_newfirst + 1 + p_end; ! 1522: break; ! 1523: } ! 1524: /* FALL THROUGH */ ! 1525: case '+': case '!': ! 1526: if (context > 0 && p_context == 0) { ! 1527: p_context = context; ! 1528: } ! 1529: p_line[p_end] = savestr(buf+2); ! 1530: break; ! 1531: case '\t': case '\n': /* assume the 2 spaces got eaten */ ! 1532: p_line[p_end] = savestr(buf); ! 1533: if (p_end != p_ptrn_lines + 1) { ! 1534: context++; ! 1535: p_char[p_end] = ' '; ! 1536: } ! 1537: break; ! 1538: case ' ': ! 1539: context++; ! 1540: p_line[p_end] = savestr(buf+2); ! 1541: break; ! 1542: default: ! 1543: fatal("Malformed patch at line %d: %s",p_input_line,buf); ! 1544: } ! 1545: p_len[p_end] = 0; ! 1546: if (p_line[p_end] != 0) ! 1547: p_len[p_end] = strlen(p_line[p_end]); ! 1548: /* for strncmp() so we do not have */ ! 1549: /* to assume null termination */ ! 1550: } ! 1551: if (p_end >=0 && !p_ptrn_lines) ! 1552: fatal("No --- found in patch at line %d\n", pch_hunk_beg()); ! 1553: ! 1554: /* if there were omitted context lines, fill them in */ ! 1555: if (fillcnt) { ! 1556: while (fillcnt-- > 0) { ! 1557: while (p_char[fillsrc] != ' ') ! 1558: fillsrc++; ! 1559: p_line[filldst] = p_line[fillsrc]; ! 1560: p_char[filldst] = p_char[fillsrc]; ! 1561: p_len[filldst] = p_len[fillsrc]; ! 1562: fillsrc++; filldst++; ! 1563: } ! 1564: assert(fillsrc==p_end+1 || fillsrc==repl_beginning); ! 1565: assert(filldst==p_end+1 || filldst==repl_beginning); ! 1566: } ! 1567: p_repl_lines = p_end - repl_beginning; ! 1568: } ! 1569: else { /* normal diff--fake it up */ ! 1570: char hunk_type; ! 1571: register int i; ! 1572: LINENUM min, max; ! 1573: long line_beginning = ftell(pfp); ! 1574: ! 1575: p_context = 0; ! 1576: ret = pgets(buf,sizeof buf, pfp); ! 1577: p_input_line++; ! 1578: if (ret == Nullch || !isdigit(*buf)) { ! 1579: next_intuit_at(line_beginning); ! 1580: return FALSE; ! 1581: } ! 1582: p_first = (LINENUM)atol(buf); ! 1583: for (s=buf; isdigit(*s); s++) ; ! 1584: if (*s == ',') { ! 1585: p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1; ! 1586: while (isdigit(*s)) s++; ! 1587: } ! 1588: else ! 1589: p_ptrn_lines = (*s != 'a'); ! 1590: hunk_type = *s; ! 1591: if (hunk_type == 'a') ! 1592: p_first++; /* do append rather than insert */ ! 1593: min = (LINENUM)atol(++s); ! 1594: for (; isdigit(*s); s++) ; ! 1595: if (*s == ',') ! 1596: max = (LINENUM)atol(++s); ! 1597: else ! 1598: max = min; ! 1599: if (hunk_type == 'd') ! 1600: min++; ! 1601: p_end = p_ptrn_lines + 1 + max - min + 1; ! 1602: p_newfirst = min; ! 1603: p_repl_lines = max - min + 1; ! 1604: Sprintf(buf,"*** %d,%d\n", p_first, p_first + p_ptrn_lines - 1); ! 1605: p_line[0] = savestr(buf); ! 1606: p_char[0] = '*'; ! 1607: for (i=1; i<=p_ptrn_lines; i++) { ! 1608: ret = pgets(buf,sizeof buf, pfp); ! 1609: p_input_line++; ! 1610: if (ret == Nullch) ! 1611: fatal("Unexpected end of file in patch at line %d.\n", ! 1612: p_input_line); ! 1613: if (*buf != '<') ! 1614: fatal("< expected at line %d of patch.\n", p_input_line); ! 1615: p_line[i] = savestr(buf+2); ! 1616: p_len[i] = 0; ! 1617: if (p_line[i] != 0) ! 1618: p_len[i] = strlen(p_line[i]); ! 1619: p_char[i] = '-'; ! 1620: } ! 1621: if (hunk_type == 'c') { ! 1622: ret = pgets(buf,sizeof buf, pfp); ! 1623: p_input_line++; ! 1624: if (ret == Nullch) ! 1625: fatal("Unexpected end of file in patch at line %d.\n", ! 1626: p_input_line); ! 1627: if (*buf != '-') ! 1628: fatal("--- expected at line %d of patch.\n", p_input_line); ! 1629: } ! 1630: Sprintf(buf,"--- %d,%d\n",min,max); ! 1631: p_line[i] = savestr(buf); ! 1632: p_char[i] = '='; ! 1633: for (i++; i<=p_end; i++) { ! 1634: ret = pgets(buf,sizeof buf, pfp); ! 1635: p_input_line++; ! 1636: if (ret == Nullch) ! 1637: fatal("Unexpected end of file in patch at line %d.\n", ! 1638: p_input_line); ! 1639: if (*buf != '>') ! 1640: fatal("> expected at line %d of patch.\n", p_input_line); ! 1641: p_line[i] = savestr(buf+2); ! 1642: p_len[i] = 0; ! 1643: if (p_line[i] != 0) ! 1644: p_len[i] = strlen(p_line[i]); ! 1645: p_char[i] = '+'; ! 1646: } ! 1647: } ! 1648: if (reverse) /* backwards patch? */ ! 1649: pch_swap(); ! 1650: #ifdef DEBUGGING ! 1651: if (debug & 2) { ! 1652: int i; ! 1653: char special; ! 1654: ! 1655: for (i=0; i <= p_end; i++) { ! 1656: if (i == p_ptrn_lines) ! 1657: special = '^'; ! 1658: else ! 1659: special = ' '; ! 1660: printf("%3d %c %c %s",i,p_char[i],special,p_line[i]); ! 1661: } ! 1662: } ! 1663: #endif ! 1664: return TRUE; ! 1665: } ! 1666: ! 1667: char * ! 1668: pgets(bf,sz,fp) ! 1669: char *bf; ! 1670: int sz; ! 1671: FILE *fp; ! 1672: { ! 1673: char *ret = fgets(bf,sz,fp); ! 1674: register char *s; ! 1675: register int indent = 0; ! 1676: ! 1677: if (p_indent && ret != Nullch) { ! 1678: for (s=buf; indent < p_indent && (*s == ' ' || *s == '\t'); s++) { ! 1679: if (*s == '\t') ! 1680: indent += 8 - (indent % 7); ! 1681: else ! 1682: indent++; ! 1683: } ! 1684: if (buf != s) ! 1685: Strcpy(buf,s); ! 1686: } ! 1687: return ret; ! 1688: } ! 1689: ! 1690: pch_swap() ! 1691: { ! 1692: char *tp_line[MAXHUNKSIZE]; /* the text of the hunk */ ! 1693: char tp_char[MAXHUNKSIZE]; /* +, -, and ! */ ! 1694: int tp_len[MAXHUNKSIZE]; /* length of each line */ ! 1695: register LINENUM i, n; ! 1696: bool blankline = FALSE; ! 1697: register char *s; ! 1698: ! 1699: i = p_first; ! 1700: p_first = p_newfirst; ! 1701: p_newfirst = i; ! 1702: ! 1703: /* make a scratch copy */ ! 1704: ! 1705: for (i=0; i<=p_end; i++) { ! 1706: tp_line[i] = p_line[i]; ! 1707: tp_char[i] = p_char[i]; ! 1708: tp_len[i] = p_len[i]; ! 1709: } ! 1710: ! 1711: /* now turn the new into the old */ ! 1712: ! 1713: i = p_ptrn_lines + 1; ! 1714: if (tp_char[i] == '\n') { /* account for possible blank line */ ! 1715: blankline = TRUE; ! 1716: i++; ! 1717: } ! 1718: for (n=0; i <= p_end; i++,n++) { ! 1719: p_line[n] = tp_line[i]; ! 1720: p_char[n] = tp_char[i]; ! 1721: if (p_char[n] == '+') ! 1722: p_char[n] = '-'; ! 1723: p_len[n] = tp_len[i]; ! 1724: } ! 1725: if (blankline) { ! 1726: i = p_ptrn_lines + 1; ! 1727: p_line[n] = tp_line[i]; ! 1728: p_char[n] = tp_char[i]; ! 1729: p_len[n] = tp_len[i]; ! 1730: n++; ! 1731: } ! 1732: assert(p_char[0] == '='); ! 1733: p_char[0] = '*'; ! 1734: for (s=p_line[0]; *s; s++) ! 1735: if (*s == '-') ! 1736: *s = '*'; ! 1737: ! 1738: /* now turn the old into the new */ ! 1739: ! 1740: assert(tp_char[0] == '*'); ! 1741: tp_char[0] = '='; ! 1742: for (s=tp_line[0]; *s; s++) ! 1743: if (*s == '*') ! 1744: *s = '-'; ! 1745: for (i=0; n <= p_end; i++,n++) { ! 1746: p_line[n] = tp_line[i]; ! 1747: p_char[n] = tp_char[i]; ! 1748: if (p_char[n] == '-') ! 1749: p_char[n] = '+'; ! 1750: p_len[n] = tp_len[i]; ! 1751: } ! 1752: assert(i == p_ptrn_lines + 1); ! 1753: i = p_ptrn_lines; ! 1754: p_ptrn_lines = p_repl_lines; ! 1755: p_repl_lines = i; ! 1756: } ! 1757: ! 1758: LINENUM ! 1759: pch_first() ! 1760: { ! 1761: return p_first; ! 1762: } ! 1763: ! 1764: LINENUM ! 1765: pch_ptrn_lines() ! 1766: { ! 1767: return p_ptrn_lines; ! 1768: } ! 1769: ! 1770: LINENUM ! 1771: pch_newfirst() ! 1772: { ! 1773: return p_newfirst; ! 1774: } ! 1775: ! 1776: LINENUM ! 1777: pch_repl_lines() ! 1778: { ! 1779: return p_repl_lines; ! 1780: } ! 1781: ! 1782: LINENUM ! 1783: pch_end() ! 1784: { ! 1785: return p_end; ! 1786: } ! 1787: ! 1788: LINENUM ! 1789: pch_context() ! 1790: { ! 1791: return p_context; ! 1792: } ! 1793: ! 1794: pch_line_len(line) ! 1795: LINENUM line; ! 1796: { ! 1797: return p_len[line]; ! 1798: } ! 1799: ! 1800: char ! 1801: pch_char(line) ! 1802: LINENUM line; ! 1803: { ! 1804: return p_char[line]; ! 1805: } ! 1806: ! 1807: char * ! 1808: pfetch(line) ! 1809: LINENUM line; ! 1810: { ! 1811: return p_line[line]; ! 1812: } ! 1813: ! 1814: LINENUM ! 1815: pch_hunk_beg() ! 1816: { ! 1817: return p_input_line - p_end - 1; ! 1818: } ! 1819: ! 1820: char * ! 1821: savestr(s) ! 1822: register char *s; ! 1823: { ! 1824: register char *rv, ! 1825: *t; ! 1826: ! 1827: t = s; ! 1828: while (*t++); ! 1829: rv = malloc((MEM) (t - s)); ! 1830: if (rv == NULL) ! 1831: fatal ("patch: out of memory (savestr)\n"); ! 1832: t = rv; ! 1833: while (*t++ = *s++); ! 1834: return rv; ! 1835: } ! 1836: ! 1837: my_exit(status) ! 1838: int status; ! 1839: { ! 1840: Unlink(TMPINNAME); ! 1841: Unlink(TMPOUTNAME); ! 1842: Unlink(TMPREJNAME); ! 1843: Unlink(TMPPATNAME); ! 1844: exit(status); ! 1845: } ! 1846: ! 1847: #ifdef lint ! 1848: ! 1849: /*VARARGS ARGSUSED*/ ! 1850: say(pat) char *pat; { ; } ! 1851: /*VARARGS ARGSUSED*/ ! 1852: fatal(pat) char *pat; { ; } ! 1853: /*VARARGS ARGSUSED*/ ! 1854: ask(pat) char *pat; { ; } ! 1855: ! 1856: #else lint ! 1857: ! 1858: say(pat,arg1,arg2,arg3) ! 1859: char *pat; ! 1860: int arg1,arg2,arg3; ! 1861: { ! 1862: fprintf(stderr,pat,arg1,arg2,arg3); ! 1863: Fflush(stderr); ! 1864: } ! 1865: ! 1866: fatal(pat,arg1,arg2,arg3) ! 1867: char *pat; ! 1868: int arg1,arg2,arg3; ! 1869: { ! 1870: say(pat,arg1,arg2,arg3); ! 1871: my_exit(1); ! 1872: } ! 1873: ! 1874: ask(pat,arg1,arg2,arg3) ! 1875: char *pat; ! 1876: int arg1,arg2,arg3; ! 1877: { ! 1878: int ttyfd = open("/dev/tty",2); ! 1879: int r; ! 1880: ! 1881: say(pat,arg1,arg2,arg3); ! 1882: if (ttyfd >= 0) { ! 1883: r = read(ttyfd, buf, sizeof buf); ! 1884: Close(ttyfd); ! 1885: } ! 1886: else ! 1887: r = read(2, buf, sizeof buf); ! 1888: if (r <= 0) ! 1889: buf[0] = 0; ! 1890: } ! 1891: #endif lint ! 1892: ! 1893: bool ! 1894: rev_in_string(string) ! 1895: char *string; ! 1896: { ! 1897: register char *s; ! 1898: register int patlen; ! 1899: ! 1900: if (revision == Nullch) ! 1901: return TRUE; ! 1902: patlen = strlen(revision); ! 1903: for (s = string; *s; s++) { ! 1904: if (isspace(*s) && strnEQ(s+1,revision,patlen) && ! 1905: isspace(s[patlen+1] )) { ! 1906: return TRUE; ! 1907: } ! 1908: } ! 1909: return FALSE; ! 1910: } ! 1911: ! 1912: set_signals() ! 1913: { ! 1914: /*NOSTRICT*/ ! 1915: if (signal(SIGHUP, SIG_IGN) != SIG_IGN) ! 1916: Signal(SIGHUP, my_exit); ! 1917: /*NOSTRICT*/ ! 1918: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 1919: Signal(SIGINT, my_exit); ! 1920: } ! 1921: ! 1922: ignore_signals() ! 1923: { ! 1924: /*NOSTRICT*/ ! 1925: Signal(SIGHUP, SIG_IGN); ! 1926: /*NOSTRICT*/ ! 1927: Signal(SIGINT, SIG_IGN); ! 1928: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.