00001 char rcsid[] =
00002 "$Header: /opt/proj/minix/cvsroot/src/commands/patch/patch.c,v 1.1.1.1 2005/04/21 14:55:10 beng Exp $";
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 #include "INTERN.h"
00102 #include "common.h"
00103 #include "EXTERN.h"
00104 #include "version.h"
00105 #include "util.h"
00106 #include "pch.h"
00107 #include "inp.h"
00108
00109
00110
00111 _PROTOTYPE(int main , (int argc , char **argv ));
00112 _PROTOTYPE(void reinitialize_almost_everything , (void));
00113 _PROTOTYPE(void get_some_switches , (void));
00114 _PROTOTYPE(LINENUM locate_hunk , (LINENUM fuzz ));
00115 _PROTOTYPE(void abort_hunk , (void));
00116 _PROTOTYPE(void apply_hunk , (LINENUM where ));
00117 _PROTOTYPE(void init_output , (char *name ));
00118 _PROTOTYPE(void init_reject , (char *name ));
00119 _PROTOTYPE(void copy_till , (Reg1 LINENUM lastline ));
00120 _PROTOTYPE(void spew_output , (void));
00121 _PROTOTYPE(void dump_line , (LINENUM line ));
00122 _PROTOTYPE(bool patch_match , (LINENUM base , LINENUM offset , LINENUM fuzz ));
00123 _PROTOTYPE(bool similar , (Reg1 char *a , Reg2 char *b , Reg3 int len ));
00124
00125
00126
00127 int main(argc,argv)
00128 int argc;
00129 char **argv;
00130 {
00131 LINENUM where;
00132 LINENUM newwhere;
00133 LINENUM fuzz;
00134 LINENUM mymaxfuzz;
00135 int hunk = 0;
00136 int failed = 0;
00137 int failtotal = 0;
00138 int i;
00139
00140 setbuf(stderr, serrbuf);
00141 for (i = 0; i<MAXFILEC; i++)
00142 filearg[i] = Nullch;
00143 Mktemp(TMPOUTNAME);
00144 Mktemp(TMPINNAME);
00145 Mktemp(TMPREJNAME);
00146 Mktemp(TMPPATNAME);
00147 #ifdef SMALL
00148 Mktemp(TMPSTRNAME);
00149 #endif
00150
00151
00152 Argc = argc;
00153 Argv = argv;
00154 get_some_switches();
00155
00156
00157 set_signals(0);
00158
00159 for (
00160 open_patch_file(filearg[1]);
00161 there_is_another_patch();
00162 reinitialize_almost_everything()
00163 ) {
00164
00165 if (outname == Nullch)
00166 outname = savestr(filearg[0]);
00167
00168
00169 if (!skip_rest_of_patch)
00170 init_output(TMPOUTNAME);
00171
00172
00173 if (diff_type == ED_DIFF) {
00174 do_ed_script();
00175 continue;
00176 }
00177
00178
00179 init_reject(TMPREJNAME);
00180
00181
00182 if (!skip_rest_of_patch)
00183 scan_input(filearg[0]);
00184
00185
00186
00187
00188
00189 hunk = 0;
00190 failed = 0;
00191 out_of_mem = FALSE;
00192 while (another_hunk()) {
00193 hunk++;
00194 fuzz = Nulline;
00195 mymaxfuzz = pch_context();
00196 if (maxfuzz < mymaxfuzz)
00197 mymaxfuzz = maxfuzz;
00198 if (!skip_rest_of_patch) {
00199 do {
00200 where = locate_hunk(fuzz);
00201 if (hunk == 1 && where == Nulline && !force) {
00202
00203 if (!pch_swap()) {
00204 if (fuzz == Nulline)
00205 say1(
00206 "Not enough memory to try swapped hunk! Assuming unswapped.\n");
00207 continue;
00208 }
00209 reverse = !reverse;
00210 where = locate_hunk(fuzz);
00211 if (where == Nulline) {
00212 if (!pch_swap())
00213 fatal1("Lost hunk on alloc error!\n");
00214 reverse = !reverse;
00215 }
00216 else if (noreverse) {
00217 if (!pch_swap())
00218 fatal1("Lost hunk on alloc error!\n");
00219 reverse = !reverse;
00220 say1(
00221 "Ignoring previously applied (or reversed) patch.\n");
00222 skip_rest_of_patch = TRUE;
00223 }
00224 else {
00225 ask3(
00226 "%seversed (or previously applied) patch detected! %s -R? [y] ",
00227 reverse ? "R" : "Unr",
00228 reverse ? "Assume" : "Ignore");
00229 if (*buf == 'n') {
00230 ask1("Apply anyway? [n] ");
00231 if (*buf != 'y')
00232 skip_rest_of_patch = TRUE;
00233 where = Nulline;
00234 reverse = !reverse;
00235 if (!pch_swap())
00236 fatal1("Lost hunk on alloc error!\n");
00237 }
00238 }
00239 }
00240 } while (!skip_rest_of_patch && where == Nulline &&
00241 ++fuzz <= mymaxfuzz);
00242
00243 if (skip_rest_of_patch) {
00244 Fclose(ofp);
00245 ofp = Nullfp;
00246 }
00247 }
00248
00249 newwhere = pch_newfirst() + last_offset;
00250 if (skip_rest_of_patch) {
00251 abort_hunk();
00252 failed++;
00253 if (verbose)
00254 say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
00255 }
00256 else if (where == Nulline) {
00257 abort_hunk();
00258 failed++;
00259 if (verbose)
00260 say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
00261 }
00262 else {
00263 apply_hunk(where);
00264 if (verbose) {
00265 say3("Hunk #%d succeeded at %ld", hunk, newwhere);
00266 if (fuzz)
00267 say2(" with fuzz %ld", fuzz);
00268 if (last_offset)
00269 say3(" (offset %ld line%s)",
00270 last_offset, last_offset==1L?"":"s");
00271 say1(".\n");
00272 }
00273 }
00274 }
00275
00276 if (out_of_mem && using_plan_a) {
00277 Argc = Argc_last;
00278 Argv = Argv_last;
00279 say1("\n\nRan out of memory using Plan A--trying again...\n\n");
00280 continue;
00281 }
00282
00283 assert(hunk);
00284
00285
00286 if (!skip_rest_of_patch)
00287 spew_output();
00288
00289
00290 ignore_signals();
00291 if (!skip_rest_of_patch) {
00292 if (move_file(TMPOUTNAME, outname) < 0) {
00293 toutkeep = TRUE;
00294 chmod(TMPOUTNAME, filemode);
00295 }
00296 else
00297 chmod(outname, filemode);
00298 }
00299 Fclose(rejfp);
00300 rejfp = Nullfp;
00301 if (failed) {
00302 failtotal += failed;
00303 if (!*rejname) {
00304 Strcpy(rejname, outname);
00305 #ifndef FLEXFILENAMES
00306 {
00307 char *s = rindex(rejname,'/');
00308
00309 if (!s)
00310 s = rejname;
00311 if (strlen(s) > 13)
00312 if (s[12] == '.')
00313 s[12] = s[13];
00314 s[13] = '\0';
00315 }
00316 #endif
00317 Strcat(rejname, REJEXT);
00318 }
00319 if (skip_rest_of_patch) {
00320 say4("%d out of %d hunks ignored--saving rejects to %s\n",
00321 failed, hunk, rejname);
00322 }
00323 else {
00324 say4("%d out of %d hunks failed--saving rejects to %s\n",
00325 failed, hunk, rejname);
00326 }
00327 if (move_file(TMPREJNAME, rejname) < 0)
00328 trejkeep = TRUE;
00329 }
00330 set_signals(1);
00331 }
00332 #ifdef SMALL
00333 if (sfp != Nullfp)
00334 Fclose(sfp);
00335 #endif
00336 my_exit(failtotal);
00337 }
00338
00339
00340
00341 void
00342 reinitialize_almost_everything()
00343 {
00344 re_patch();
00345 re_input();
00346
00347 input_lines = 0;
00348 last_frozen_line = 0;
00349
00350 filec = 0;
00351 if (filearg[0] != Nullch && !out_of_mem) {
00352 free(filearg[0]);
00353 filearg[0] = Nullch;
00354 }
00355
00356 if (outname != Nullch) {
00357 free(outname);
00358 outname = Nullch;
00359 }
00360
00361 last_offset = 0;
00362
00363 diff_type = 0;
00364
00365 if (revision != Nullch) {
00366 free(revision);
00367 revision = Nullch;
00368 }
00369
00370 reverse = FALSE;
00371 skip_rest_of_patch = FALSE;
00372
00373 get_some_switches();
00374
00375 if (filec >= 2)
00376 fatal1("You may not change to a different patch file.\n");
00377 }
00378
00379
00380
00381 void
00382 get_some_switches()
00383 {
00384 Reg1 char *s;
00385
00386 rejname[0] = '\0';
00387 Argc_last = Argc;
00388 Argv_last = Argv;
00389 if (!Argc)
00390 return;
00391 for (Argc--,Argv++; Argc; Argc--,Argv++) {
00392 s = Argv[0];
00393 if (strEQ(s, "+")) {
00394 return;
00395 }
00396 if (*s != '-' || !s[1]) {
00397 if (filec == MAXFILEC)
00398 fatal1("Too many file arguments.\n");
00399 filearg[filec++] = savestr(s);
00400 }
00401 else {
00402 switch (*++s) {
00403 case 'b':
00404 origext = savestr(Argv[1]);
00405 Argc--,Argv++;
00406 break;
00407 case 'B':
00408 origprae = savestr(Argv[1]);
00409 Argc--,Argv++;
00410 break;
00411 case 'c':
00412 diff_type = CONTEXT_DIFF;
00413 break;
00414 case 'd':
00415 if (!*++s) {
00416 Argc--,Argv++;
00417 s = Argv[0];
00418 }
00419 if (chdir(s) < 0)
00420 fatal2("Can't cd to %s.\n", s);
00421 break;
00422 case 'D':
00423 do_defines = TRUE;
00424 if (!*++s) {
00425 Argc--,Argv++;
00426 s = Argv[0];
00427 }
00428 if (!isalpha(*s))
00429 fatal1("Argument to -D not an identifier.\n");
00430 Sprintf(if_defined, "#ifdef %s\n", s);
00431 Sprintf(not_defined, "#ifndef %s\n", s);
00432 Sprintf(end_defined, "#endif /* %s */\n", s);
00433 break;
00434 case 'e':
00435 diff_type = ED_DIFF;
00436 break;
00437 case 'f':
00438 force = TRUE;
00439 break;
00440 case 'F':
00441 if (*++s == '=')
00442 s++;
00443 maxfuzz = atoi(s);
00444 break;
00445 case 'l':
00446 canonicalize = TRUE;
00447 break;
00448 case 'n':
00449 diff_type = NORMAL_DIFF;
00450 break;
00451 case 'N':
00452 noreverse = TRUE;
00453 break;
00454 case 'o':
00455 outname = savestr(Argv[1]);
00456 Argc--,Argv++;
00457 break;
00458 case 'p':
00459 if (*++s == '=')
00460 s++;
00461 strippath = atoi(s);
00462 break;
00463 case 'r':
00464 Strcpy(rejname, Argv[1]);
00465 Argc--,Argv++;
00466 break;
00467 case 'R':
00468 reverse = TRUE;
00469 break;
00470 case 's':
00471 verbose = FALSE;
00472 break;
00473 case 'S':
00474 skip_rest_of_patch = TRUE;
00475 break;
00476 case 'v':
00477 version();
00478 break;
00479 #ifdef DEBUGGING
00480 case 'x':
00481 debug = atoi(s+1);
00482 break;
00483 #endif
00484 default:
00485 fatal2("Unrecognized switch: %s\n", Argv[0]);
00486 }
00487 }
00488 }
00489 }
00490
00491
00492
00493 LINENUM
00494 locate_hunk(fuzz)
00495 LINENUM fuzz;
00496 {
00497 Reg1 LINENUM first_guess = pch_first() + last_offset;
00498 Reg2 LINENUM offset;
00499 LINENUM pat_lines = pch_ptrn_lines();
00500 Reg3 LINENUM max_pos_offset = input_lines - first_guess
00501 - pat_lines + 1;
00502 Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
00503 + pch_context();
00504
00505 if (!pat_lines)
00506 return first_guess;
00507 if (max_neg_offset >= first_guess)
00508 max_neg_offset = first_guess - 1;
00509 if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
00510 return first_guess;
00511 for (offset = 1; ; offset++) {
00512 Reg5 bool check_after = (offset <= max_pos_offset);
00513 Reg6 bool check_before = (offset <= max_neg_offset);
00514
00515 if (check_after && patch_match(first_guess, offset, fuzz)) {
00516 #ifdef DEBUGGING
00517 if (debug & 1)
00518 say3("Offset changing from %ld to %ld\n", last_offset, offset);
00519 #endif
00520 last_offset = offset;
00521 return first_guess+offset;
00522 }
00523 else if (check_before && patch_match(first_guess, -offset, fuzz)) {
00524 #ifdef DEBUGGING
00525 if (debug & 1)
00526 say3("Offset changing from %ld to %ld\n", last_offset, -offset);
00527 #endif
00528 last_offset = -offset;
00529 return first_guess-offset;
00530 }
00531 else if (!check_before && !check_after)
00532 return Nulline;
00533 }
00534 }
00535
00536
00537
00538 void
00539 abort_hunk()
00540 {
00541 Reg1 LINENUM i;
00542 Reg2 LINENUM pat_end = pch_end();
00543
00544 LINENUM oldfirst = pch_first() + last_offset;
00545 LINENUM newfirst = pch_newfirst() + last_offset;
00546 LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
00547 LINENUM newlast = newfirst + pch_repl_lines() - 1;
00548 char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : "");
00549 char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----");
00550
00551 fprintf(rejfp, "***************\n");
00552 for (i=0; i<=pat_end; i++) {
00553 switch (pch_char(i)) {
00554 case '*':
00555 if (oldlast < oldfirst)
00556 fprintf(rejfp, "*** 0%s\n", stars);
00557 else if (oldlast == oldfirst)
00558 fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
00559 else
00560 fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
00561 break;
00562 case '=':
00563 if (newlast < newfirst)
00564 fprintf(rejfp, "--- 0%s\n", minuses);
00565 else if (newlast == newfirst)
00566 fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
00567 else
00568 fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
00569 break;
00570 case '\n':
00571 fprintf(rejfp, "%s", pfetch(i));
00572 break;
00573 case ' ': case '-': case '+': case '!':
00574 fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
00575 break;
00576 default:
00577 say1("Fatal internal error in abort_hunk().\n");
00578 abort();
00579 }
00580 }
00581 }
00582
00583
00584
00585 void
00586 apply_hunk(where)
00587 LINENUM where;
00588 {
00589 Reg1 LINENUM old = 1;
00590 Reg2 LINENUM lastline = pch_ptrn_lines();
00591 Reg3 LINENUM new = lastline+1;
00592 #define OUTSIDE 0
00593 #define IN_IFNDEF 1
00594 #define IN_IFDEF 2
00595 #define IN_ELSE 3
00596 Reg4 int def_state = OUTSIDE;
00597 Reg5 bool R_do_defines = do_defines;
00598 Reg6 LINENUM pat_end = pch_end();
00599
00600 where--;
00601 while (pch_char(new) == '=' || pch_char(new) == '\n')
00602 new++;
00603
00604 while (old <= lastline) {
00605 if (pch_char(old) == '-') {
00606 copy_till(where + old - 1);
00607 if (R_do_defines) {
00608 if (def_state == OUTSIDE) {
00609 fputs(not_defined, ofp);
00610 def_state = IN_IFNDEF;
00611 }
00612 else if (def_state == IN_IFDEF) {
00613 fputs(else_defined, ofp);
00614 def_state = IN_ELSE;
00615 }
00616 fputs(pfetch(old), ofp);
00617 }
00618 last_frozen_line++;
00619 old++;
00620 }
00621 else if (new > pat_end)
00622 break;
00623 else if (pch_char(new) == '+') {
00624 copy_till(where + old - 1);
00625 if (R_do_defines) {
00626 if (def_state == IN_IFNDEF) {
00627 fputs(else_defined, ofp);
00628 def_state = IN_ELSE;
00629 }
00630 else if (def_state == OUTSIDE) {
00631 fputs(if_defined, ofp);
00632 def_state = IN_IFDEF;
00633 }
00634 }
00635 fputs(pfetch(new), ofp);
00636 new++;
00637 }
00638 else {
00639 if (pch_char(new) != pch_char(old)) {
00640 say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
00641 pch_hunk_beg() + old,
00642 pch_hunk_beg() + new);
00643 #ifdef DEBUGGING
00644 say3("oldchar = '%c', newchar = '%c'\n",
00645 pch_char(old), pch_char(new));
00646 #endif
00647 my_exit(1);
00648 }
00649 if (pch_char(new) == '!') {
00650 copy_till(where + old - 1);
00651 if (R_do_defines) {
00652 fputs(not_defined, ofp);
00653 def_state = IN_IFNDEF;
00654 }
00655 while (pch_char(old) == '!') {
00656 if (R_do_defines) {
00657 fputs(pfetch(old), ofp);
00658 }
00659 last_frozen_line++;
00660 old++;
00661 }
00662 if (R_do_defines) {
00663 fputs(else_defined, ofp);
00664 def_state = IN_ELSE;
00665 }
00666 while (pch_char(new) == '!') {
00667 fputs(pfetch(new), ofp);
00668 new++;
00669 }
00670 if (R_do_defines) {
00671 fputs(end_defined, ofp);
00672 def_state = OUTSIDE;
00673 }
00674 }
00675 else {
00676 assert(pch_char(new) == ' ');
00677 old++;
00678 new++;
00679 }
00680 }
00681 }
00682 if (new <= pat_end && pch_char(new) == '+') {
00683 copy_till(where + old - 1);
00684 if (R_do_defines) {
00685 if (def_state == OUTSIDE) {
00686 fputs(if_defined, ofp);
00687 def_state = IN_IFDEF;
00688 }
00689 else if (def_state == IN_IFNDEF) {
00690 fputs(else_defined, ofp);
00691 def_state = IN_ELSE;
00692 }
00693 }
00694 while (new <= pat_end && pch_char(new) == '+') {
00695 fputs(pfetch(new), ofp);
00696 new++;
00697 }
00698 }
00699 if (R_do_defines && def_state != OUTSIDE) {
00700 fputs(end_defined, ofp);
00701 }
00702 }
00703
00704
00705
00706 void
00707 init_output(name)
00708 char *name;
00709 {
00710 ofp = fopen(name, "w");
00711 if (ofp == Nullfp)
00712 fatal2("patch: can't create %s.\n", name);
00713 }
00714
00715
00716
00717 void
00718 init_reject(name)
00719 char *name;
00720 {
00721 rejfp = fopen(name, "w");
00722 if (rejfp == Nullfp)
00723 fatal2("patch: can't create %s.\n", name);
00724 }
00725
00726
00727
00728 void
00729 copy_till(lastline)
00730 Reg1 LINENUM lastline;
00731 {
00732 Reg2 LINENUM R_last_frozen_line = last_frozen_line;
00733
00734 if (R_last_frozen_line > lastline)
00735 say1("patch: misordered hunks! output will be garbled.\n");
00736 while (R_last_frozen_line < lastline) {
00737 dump_line(++R_last_frozen_line);
00738 }
00739 last_frozen_line = R_last_frozen_line;
00740 }
00741
00742
00743
00744 void
00745 spew_output()
00746 {
00747 #ifdef DEBUGGING
00748 if (debug & 256)
00749 say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
00750 #endif
00751 if (input_lines)
00752 copy_till(input_lines);
00753 Fclose(ofp);
00754 ofp = Nullfp;
00755 }
00756
00757
00758
00759 void
00760 dump_line(line)
00761 LINENUM line;
00762 {
00763 Reg1 char *s;
00764 Reg2 char R_newline = '\n';
00765
00766
00767 for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
00768 }
00769
00770
00771
00772 bool
00773 patch_match(base, offset, fuzz)
00774 LINENUM base;
00775 LINENUM offset;
00776 LINENUM fuzz;
00777 {
00778 Reg1 LINENUM pline = 1 + fuzz;
00779 Reg2 LINENUM iline;
00780 Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
00781
00782 for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
00783 if (canonicalize) {
00784 if (!similar(ifetch(iline, (offset >= 0)),
00785 pfetch(pline),
00786 pch_line_len(pline) ))
00787 return FALSE;
00788 }
00789 else if (strnNE(ifetch(iline, (offset >= 0)),
00790 pfetch(pline),
00791 pch_line_len(pline) ))
00792 return FALSE;
00793 }
00794 return TRUE;
00795 }
00796
00797
00798
00799 bool
00800 similar(a,b,len)
00801 Reg1 char *a;
00802 Reg2 char *b;
00803 Reg3 int len;
00804 {
00805 while (len) {
00806 if (isspace(*b)) {
00807 if (!isspace(*a))
00808 return FALSE;
00809 while (len && isspace(*b) && *b != '\n')
00810 b++,len--;
00811 while (isspace(*a) && *a != '\n')
00812 a++;
00813 if (*a == '\n' || *b == '\n')
00814 return (*a == *b);
00815 }
00816 else if (*a++ != *b++)
00817 return FALSE;
00818 else
00819 len--;
00820 }
00821 return TRUE;
00822
00823 }
00824
00825
00826
00827 void
00828 my_exit(status)
00829 int status;
00830 {
00831 Unlink(TMPINNAME);
00832 if (!toutkeep) {
00833 Unlink(TMPOUTNAME);
00834 }
00835 if (!trejkeep) {
00836 Unlink(TMPREJNAME);
00837 }
00838 Unlink(TMPPATNAME);
00839 #ifdef SMALL
00840 Unlink(TMPSTRNAME);
00841 #endif
00842 exit(status);
00843 }