patch.c

Go to the documentation of this file.
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 /* patch - a program to apply diffs to original files
00005  *
00006  * Copyright 1986, Larry Wall
00007  *
00008  * This program may be copied as long as you don't try to make any
00009  * money off of it, or pretend that you wrote it.
00010  *
00011  * $Log: patch.c,v $
00012  * Revision 1.1.1.1  2005/04/21 14:55:10  beng
00013  * Initial import of pre-3.0.1
00014  *
00015  * Revision 1.1.1.1  2005/04/20 13:33:19  beng
00016  * Initial import of minix 2.0.4
00017  *
00018  * Revision 2.0.1.6  88/06/22  20:46:39  lwall
00019  * patch12: rindex() wasn't declared
00020  * 
00021  * Revision 2.0.1.5  88/06/03  15:09:37  lwall
00022  * patch10: exit code improved.
00023  * patch10: better support for non-flexfilenames.
00024  * 
00025  * Revision 2.0.1.4  87/02/16  14:00:04  lwall
00026  * Short replacement caused spurious "Out of sync" message.
00027  * 
00028  * Revision 2.0.1.3  87/01/30  22:45:50  lwall
00029  * Improved diagnostic on sync error.
00030  * Moved do_ed_script() to pch.c.
00031  * 
00032  * Revision 2.0.1.2  86/11/21  09:39:15  lwall
00033  * Fuzz factor caused offset of installed lines.
00034  * 
00035  * Revision 2.0.1.1  86/10/29  13:10:22  lwall
00036  * Backwards search could terminate prematurely.
00037  * 
00038  * Revision 2.0  86/09/17  15:37:32  lwall
00039  * Baseline for netwide release.
00040  * 
00041  * Revision 1.5  86/08/01  20:53:24  lwall
00042  * Changed some %d's to %ld's.
00043  * Linted.
00044  * 
00045  * Revision 1.4  86/08/01  19:17:29  lwall
00046  * Fixes for machines that can't vararg.
00047  * Added fuzz factor.
00048  * Generalized -p.
00049  * General cleanup.
00050  * 
00051  * 85/08/15 van%ucbmonet@berkeley
00052  * Changes for 4.3bsd diff -c.
00053  *
00054  * Revision 1.3  85/03/26  15:07:43  lwall
00055  * Frozen.
00056  * 
00057  * Revision 1.2.1.9  85/03/12  17:03:35  lwall
00058  * Changed pfp->_file to fileno(pfp).
00059  * 
00060  * Revision 1.2.1.8  85/03/12  16:30:43  lwall
00061  * Check i_ptr and i_womp to make sure they aren't null before freeing.
00062  * Also allow ed output to be suppressed.
00063  * 
00064  * Revision 1.2.1.7  85/03/12  15:56:13  lwall
00065  * Added -p option from jromine@uci-750a.
00066  * 
00067  * Revision 1.2.1.6  85/03/12  12:12:51  lwall
00068  * Now checks for normalness of file to patch.
00069  * 
00070  * Revision 1.2.1.5  85/03/12  11:52:12  lwall
00071  * Added -D (#ifdef) option from joe@fluke.
00072  * 
00073  * Revision 1.2.1.4  84/12/06  11:14:15  lwall
00074  * Made smarter about SCCS subdirectories.
00075  * 
00076  * Revision 1.2.1.3  84/12/05  11:18:43  lwall
00077  * Added -l switch to do loose string comparison.
00078  * 
00079  * Revision 1.2.1.2  84/12/04  09:47:13  lwall
00080  * Failed hunk count not reset on multiple patch file.
00081  * 
00082  * Revision 1.2.1.1  84/12/04  09:42:37  lwall
00083  * Branch for sdcrdcf changes.
00084  * 
00085  * Revision 1.2  84/11/29  13:29:51  lwall
00086  * Linted.  Identifiers uniqified.  Fixed i_ptr malloc() bug.  Fixed
00087  * multiple calls to mktemp().  Will now work on machines that can only
00088  * read 32767 chars.  Added -R option for diffs with new and old swapped.
00089  * Various cosmetic changes.
00090  * 
00091  * Revision 1.1  84/11/09  17:03:58  lwall
00092  * Initial revision
00093  * 
00094  */
00095 /*
00096  * 1992-01-15
00097  * Modified by Saeko & Kouichi Hirabayashi to fit small memory (64K+64K)
00098  * system by adding "#if[n]def SMALL" parts.
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 /* procedures */
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 /* Apply a set of diffs as appropriate. */
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     /* parse switches */
00152     Argc = argc;
00153     Argv = argv;
00154     get_some_switches();
00155     
00156     /* make sure we clean up /tmp in case of disaster */
00157     set_signals(0);
00158 
00159     for (
00160         open_patch_file(filearg[1]);
00161         there_is_another_patch();
00162         reinitialize_almost_everything()
00163     ) {                                 /* for each patch in patch file */
00164 
00165         if (outname == Nullch)
00166             outname = savestr(filearg[0]);
00167     
00168         /* initialize the patched file */
00169         if (!skip_rest_of_patch)
00170             init_output(TMPOUTNAME);
00171     
00172         /* for ed script just up and do it and exit */
00173         if (diff_type == ED_DIFF) {
00174             do_ed_script();
00175             continue;
00176         }
00177     
00178         /* initialize reject file */
00179         init_reject(TMPREJNAME);
00180     
00181         /* find out where all the lines are */
00182         if (!skip_rest_of_patch)
00183             scan_input(filearg[0]);
00184     
00185         /* from here on, open no standard i/o files, because malloc */
00186         /* might misfire and we can't catch it easily */
00187     
00188         /* apply each hunk of patch */
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                                                 /* dwim for reversed patch? */
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);  /* try again */
00211                         if (where == Nulline) {     /* didn't find it swapped */
00212                             if (!pch_swap())         /* put it back to normal */
00213                                 fatal1("Lost hunk on alloc error!\n");
00214                             reverse = !reverse;
00215                         }
00216                         else if (noreverse) {
00217                             if (!pch_swap())         /* put it back to normal */
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())  /* put it back to normal */
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) {               /* just got decided */
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         /* finish spewing out the new file */
00286         if (!skip_rest_of_patch)
00287             spew_output();
00288         
00289         /* and put the output where desired */
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] == '.')       /* try to preserve difference */
00313                             s[12] = s[13];      /* between .h, .c, .y, etc. */
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 /* Prepare to find the next patch to do in the patch file. */
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 /* Process switches and filenames up to next '+' or end of list. */
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;                     /* + will be skipped by for loop */
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 /* Attempt to find the right place to apply this hunk of patch. */
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)                     /* null range matches always */
00506         return first_guess;
00507     if (max_neg_offset >= first_guess)  /* do not try lines < 0 */
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 /* We did not find the pattern, dump out the hunk so they can handle it. */
00537 
00538 void
00539 abort_hunk()
00540 {
00541     Reg1 LINENUM i;
00542     Reg2 LINENUM pat_end = pch_end();
00543     /* add in last_offset to guess the same as the previous successful hunk */
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 /* We found where to apply it (we hope), so do it. */
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 /* Open the new file. */
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 /* Open a file to put hunks we can't locate. */
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 /* Copy input file to output, up to wherever hunk is to be applied. */
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 /* Finish copying the input file to the output file. */
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);         /* dump remainder of file */
00753     Fclose(ofp);
00754     ofp = Nullfp;
00755 }
00756 
00757 /* Copy one line from input to output. */
00758 
00759 void
00760 dump_line(line)
00761 LINENUM line;
00762 {
00763     Reg1 char *s;
00764     Reg2 char R_newline = '\n';
00765 
00766     /* Note: string is not null terminated. */
00767     for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
00768 }
00769 
00770 /* Does the patch pattern match at line base+offset? */
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 /* Do two lines match with canonicalized white space? */
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)) {              /* whitespace (or \n) to match? */
00807             if (!isspace(*a))           /* no corresponding whitespace? */
00808                 return FALSE;
00809             while (len && isspace(*b) && *b != '\n')
00810                 b++,len--;              /* skip pattern whitespace */
00811             while (isspace(*a) && *a != '\n')
00812                 a++;                    /* skip target whitespace */
00813             if (*a == '\n' || *b == '\n')
00814                 return (*a == *b);      /* should end in sync */
00815         }
00816         else if (*a++ != *b++)          /* match non-whitespace chars */
00817             return FALSE;
00818         else
00819             len--;                      /* probably not necessary */
00820     }
00821     return TRUE;                        /* actually, this is not reached */
00822                                         /* since there is always a \n */
00823 }
00824 
00825 /* Exit with cleanup. */
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 }

Generated on Fri Apr 14 22:57:01 2006 for minix by  doxygen 1.4.6