# 2.11BSD#431 - /usr/src/usr.bin/patch/patch.c

##### Functions

    abort_hunk        X
    apply_hunk        X
    copy_till         X
    dump_line         X
    get_some_switches X
    init_output       X
    init_reject       X
    locate_hunk       X
    main              X
    my_exit           X
    patch_match       X
    reinitialize_almost_everythingX
    similar           X
    spew_output       X

##### Variables

    rcsid             X

##### Macros

    IN_ELSE           X
    IN_IFDEF          X
    IN_IFNDEF         X
    OUTSIDE           X

       1: char rcsid[] =
       2:     "$Header: patch.c,v 2.0.1.6 88/06/22 20:46:39 lwall Locked $";
       3:
       4: /* patch - a program to apply diffs to original files
       5:  *
       6:  * Copyright 1986, Larry Wall
       7:  *
       8:  * This program may be copied as long as you don't try to make any
       9:  * money off of it, or pretend that you wrote it.
      10:  *
      11:  * $Log:	patch.c,v $
      12:  * Revision 2.0.1.6  88/06/22  20:46:39  lwall
      13:  * patch12: rindex() wasn't declared
      14:  *
      15:  * Revision 2.0.1.5  88/06/03  15:09:37  lwall
      16:  * patch10: exit code improved.
      17:  * patch10: better support for non-flexfilenames.
      18:  *
      19:  * Revision 2.0.1.4  87/02/16  14:00:04  lwall
      20:  * Short replacement caused spurious "Out of sync" message.
      21:  *
      22:  * Revision 2.0.1.3  87/01/30  22:45:50  lwall
      23:  * Improved diagnostic on sync error.
      24:  * Moved do_ed_script() to pch.c.
      25:  *
      26:  * Revision 2.0.1.2  86/11/21  09:39:15  lwall
      27:  * Fuzz factor caused offset of installed lines.
      28:  *
      29:  * Revision 2.0.1.1  86/10/29  13:10:22  lwall
      30:  * Backwards search could terminate prematurely.
      31:  *
      32:  * Revision 2.0  86/09/17  15:37:32  lwall
      33:  * Baseline for netwide release.
      34:  *
      35:  * Revision 1.5  86/08/01  20:53:24  lwall
      36:  * Changed some %d's to %ld's.
      37:  * Linted.
      38:  *
      39:  * Revision 1.4  86/08/01  19:17:29  lwall
      40:  * Fixes for machines that can't vararg.
      41:  * Added fuzz factor.
      42:  * Generalized -p.
      43:  * General cleanup.
      44:  *
      45:  * 85/08/15 van%ucbmonet@berkeley
      46:  * Changes for 4.3bsd diff -c.
      47:  *
      48:  * Revision 1.3  85/03/26  15:07:43  lwall
      49:  * Frozen.
      50:  *
      51:  * Revision 1.2.1.9  85/03/12  17:03:35  lwall
      52:  * Changed pfp->_file to fileno(pfp).
      53:  *
      54:  * Revision 1.2.1.8  85/03/12  16:30:43  lwall
      55:  * Check i_ptr and i_womp to make sure they aren't null before freeing.
      56:  * Also allow ed output to be suppressed.
      57:  *
      58:  * Revision 1.2.1.7  85/03/12  15:56:13  lwall
      59:  * Added -p option from jromine@uci-750a.
      60:  *
      61:  * Revision 1.2.1.6  85/03/12  12:12:51  lwall
      62:  * Now checks for normalness of file to patch.
      63:  *
      64:  * Revision 1.2.1.5  85/03/12  11:52:12  lwall
      65:  * Added -D (#ifdef) option from joe@fluke.
      66:  *
      67:  * Revision 1.2.1.4  84/12/06  11:14:15  lwall
      68:  * Made smarter about SCCS subdirectories.
      69:  *
      70:  * Revision 1.2.1.3  84/12/05  11:18:43  lwall
      71:  * Added -l switch to do loose string comparison.
      72:  *
      73:  * Revision 1.2.1.2  84/12/04  09:47:13  lwall
      74:  * Failed hunk count not reset on multiple patch file.
      75:  *
      76:  * Revision 1.2.1.1  84/12/04  09:42:37  lwall
      77:  * Branch for sdcrdcf changes.
      78:  *
      79:  * Revision 1.2  84/11/29  13:29:51  lwall
      80:  * Linted.  Identifiers uniqified.  Fixed i_ptr malloc() bug.  Fixed
      81:  * multiple calls to mktemp().  Will now work on machines that can only
      82:  * read 32767 chars.  Added -R option for diffs with new and old swapped.
      83:  * Various cosmetic changes.
      84:  *
      85:  * Revision 1.1  84/11/09  17:03:58  lwall
      86:  * Initial revision
      87:  *
      88:  */
      89:
      90: #include "INTERN.h"
      91: #include "common.h"
      92: #include "EXTERN.h"
      93: #include "version.h"
      94: #include "util.h"
      95: #include "pch.h"
      96: #include "inp.h"
      97:
      98: /* procedures */
      99:
     100: void reinitialize_almost_everything();
     101: void get_some_switches();
     102: LINENUM locate_hunk();
     103: void abort_hunk();
     104: void apply_hunk();
     105: void init_output();
     106: void init_reject();
     107: void copy_till();
     108: void spew_output();
     109: void dump_line();
     110: bool patch_match();
     111: bool similar();
     112: void re_input();
     113: void my_exit();
     114:
     115: /* Apply a set of diffs as appropriate. */
     116:
     117: main(argc,argv)
     118: int argc;
     119: char **argv;
     120: {
     121:     LINENUM where;
     122:     LINENUM newwhere;
     123:     LINENUM fuzz;
     124:     LINENUM mymaxfuzz;
     125:     int hunk = 0;
     126:     int failed = 0;
     127:     int failtotal = 0;
     128:     int i;
     129:
     130:     setbuf(stderr, serrbuf);
     131:     for (i = 0; i<MAXFILEC; i++)
     132:     filearg[i] = Nullch;
     133:     Mktemp(TMPOUTNAME);
     134:     Mktemp(TMPINNAME);
     135:     Mktemp(TMPREJNAME);
     136:     Mktemp(TMPPATNAME);
     137:
     138:     /* parse switches */
     139:     Argc = argc;
     140:     Argv = argv;
     141:     get_some_switches();
     142:
     143:     /* make sure we clean up /tmp in case of disaster */
     144:     set_signals(0);
     145:
     146:     for (
     147:     open_patch_file(filearg[1]);
     148:     there_is_another_patch();
     149:     reinitialize_almost_everything()
     150:     ) {                 /* for each patch in patch file */
     151:
     152:     if (outname == Nullch)
     153:         outname = savestr(filearg[0]);
     154:
     155:     /* initialize the patched file */
     156:     if (!skip_rest_of_patch)
     157:         init_output(TMPOUTNAME);
     158:
     159:     /* for ed script just up and do it and exit */
     160:     if (diff_type == ED_DIFF) {
     161:         do_ed_script();
     162:         continue;
     163:     }
     164:
     165:     /* initialize reject file */
     166:     init_reject(TMPREJNAME);
     167:
     168:     /* find out where all the lines are */
     169:     if (!skip_rest_of_patch)
     170:         scan_input(filearg[0]);
     171:
     172:     /* from here on, open no standard i/o files, because malloc */
     173:     /* might misfire and we can't catch it easily */
     174:
     175:     /* apply each hunk of patch */
     176:     hunk = 0;
     177:     failed = 0;
     178:     out_of_mem = FALSE;
     179:     while (another_hunk()) {
     180:         hunk++;
     181:         fuzz = Nulline;
     182:         mymaxfuzz = pch_context();
     183:         if (maxfuzz < mymaxfuzz)
     184:         mymaxfuzz = maxfuzz;
     185:         if (!skip_rest_of_patch) {
     186:         do {
     187:             where = locate_hunk(fuzz);
     188:             if (hunk == 1 && where == Nulline && !force) {
     189:                         /* dwim for reversed patch? */
     190:             if (!pch_swap()) {
     191:                 if (fuzz == Nulline)
     192:                 say1(
     193: "Not enough memory to try swapped hunk!  Assuming unswapped.\n");
     194:                 continue;
     195:             }
     196:             reverse = !reverse;
     197:             where = locate_hunk(fuzz);  /* try again */
     198:             if (where == Nulline) {     /* didn't find it swapped */
     199:                 if (!pch_swap())         /* put it back to normal */
     200:                 fatal1("Lost hunk on alloc error!\n");
     201:                 reverse = !reverse;
     202:             }
     203:             else if (noreverse) {
     204:                 if (!pch_swap())         /* put it back to normal */
     205:                 fatal1("Lost hunk on alloc error!\n");
     206:                 reverse = !reverse;
     207:                 say1(
     208: "Ignoring previously applied (or reversed) patch.\n");
     209:                 skip_rest_of_patch = TRUE;
     210:             }
     211:             else {
     212:                 ask3(
     213: "%seversed (or previously applied) patch detected!  %s -R? [y] ",
     214:                 reverse ? "R" : "Unr",
     215:                 reverse ? "Assume" : "Ignore");
     216:                 if (*buf == 'n') {
     217:                 ask1("Apply anyway? [n] ");
     218:                 if (*buf != 'y')
     219:                     skip_rest_of_patch = TRUE;
     220:                 where = Nulline;
     221:                 reverse = !reverse;
     222:                 if (!pch_swap())  /* put it back to normal */
     223:                     fatal1("Lost hunk on alloc error!\n");
     224:                 }
     225:             }
     226:             }
     227:         } while (!skip_rest_of_patch && where == Nulline &&
     228:             ++fuzz <= mymaxfuzz);
     229:
     230:         if (skip_rest_of_patch) {       /* just got decided */
     231:             Fclose(ofp);
     232:             ofp = Nullfp;
     233:         }
     234:         }
     235:
     236:         newwhere = pch_newfirst() + last_offset;
     237:         if (skip_rest_of_patch) {
     238:         abort_hunk();
     239:         failed++;
     240:         if (verbose)
     241:             say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
     242:         }
     243:         else if (where == Nulline) {
     244:         abort_hunk();
     245:         failed++;
     246:         if (verbose)
     247:             say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
     248:         }
     249:         else {
     250:         apply_hunk(where);
     251:         if (verbose) {
     252:             say3("Hunk #%d succeeded at %ld", hunk, newwhere);
     253:             if (fuzz)
     254:             say2(" with fuzz %ld", fuzz);
     255:             if (last_offset)
     256:             say3(" (offset %ld line%s)",
     257:                 last_offset, last_offset==1L?"":"s");
     258:             say1(".\n");
     259:         }
     260:         }
     261:     }
     262:
     263:     if (out_of_mem && using_plan_a) {
     264:         Argc = Argc_last;
     265:         Argv = Argv_last;
     266:         say1("\n\nRan out of memory using Plan A--trying again...\n\n");
     267:         continue;
     268:     }
     269:
     270:     assert(hunk);
     271:
     272:     /* finish spewing out the new file */
     273:     if (!skip_rest_of_patch)
     274:         spew_output();
     275:
     276:     /* and put the output where desired */
     277:     ignore_signals();
     278:     if (!skip_rest_of_patch) {
     279:         if (move_file(TMPOUTNAME, outname) < 0) {
     280:         toutkeep = TRUE;
     281:         chmod(TMPOUTNAME, filemode);
     282:         }
     283:         else
     284:         chmod(outname, filemode);
     285:     }
     286:     Fclose(rejfp);
     287:     rejfp = Nullfp;
     288:     if (failed) {
     289:         failtotal += failed;
     290:         if (!*rejname) {
     291:         Strcpy(rejname, outname);
     292: #ifndef FLEXFILENAMES
     293:         {
     294:             char *rindex();
     295:             char *s = rindex(rejname,'/');
     296:
     297:             if (!s)
     298:             s = rejname;
     299:             if (strlen(s) > 13)
     300:             if (s[12] == '.')   /* try to preserve difference */
     301:                 s[12] = s[13];  /* between .h, .c, .y, etc. */
     302:             s[13] = '\0';
     303:         }
     304: #endif
     305:         Strcat(rejname, REJEXT);
     306:         }
     307:         if (skip_rest_of_patch) {
     308:         say4("%d out of %d hunks ignored--saving rejects to %s\n",
     309:             failed, hunk, rejname);
     310:         }
     311:         else {
     312:         say4("%d out of %d hunks failed--saving rejects to %s\n",
     313:             failed, hunk, rejname);
     314:         }
     315:         if (move_file(TMPREJNAME, rejname) < 0)
     316:         trejkeep = TRUE;
     317:     }
     318:     set_signals(1);
     319:     }
     320:     my_exit(failtotal);
     321: }
     322:
     323: /* Prepare to find the next patch to do in the patch file. */
     324:
     325: void
     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 && !out_of_mem) {
     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:     skip_rest_of_patch = FALSE;
     356:
     357:     get_some_switches();
     358:
     359:     if (filec >= 2)
     360:     fatal1("You may not change to a different patch file.\n");
     361: }
     362:
     363: /* Process switches and filenames up to next '+' or end of list. */
     364:
     365: void
     366: get_some_switches()
     367: {
     368:     Reg1 char *s;
     369:
     370:     rejname[0] = '\0';
     371:     Argc_last = Argc;
     372:     Argv_last = Argv;
     373:     if (!Argc)
     374:     return;
     375:     for (Argc--,Argv++; Argc; Argc--,Argv++) {
     376:     s = Argv[0];
     377:     if (strEQ(s, "+")) {
     378:         return;         /* + will be skipped by for loop */
     379:     }
     380:     if (*s != '-' || !s[1]) {
     381:         if (filec == MAXFILEC)
     382:         fatal1("Too many file arguments.\n");
     383:         filearg[filec++] = savestr(s);
     384:     }
     385:     else {
     386:         switch (*++s) {
     387:         case 'b':
     388:         origext = savestr(Argv[1]);
     389:         Argc--,Argv++;
     390:         break;
     391:         case 'B':
     392:         origprae = savestr(Argv[1]);
     393:         Argc--,Argv++;
     394:         break;
     395:         case 'c':
     396:         diff_type = CONTEXT_DIFF;
     397:         break;
     398:         case 'd':
     399:         if (!*++s) {
     400:             Argc--,Argv++;
     401:             s = Argv[0];
     402:         }
     403:         if (chdir(s) < 0)
     404:             fatal2("Can't cd to %s.\n", s);
     405:         break;
     406:         case 'D':
     407:             do_defines = TRUE;
     408:         if (!*++s) {
     409:             Argc--,Argv++;
     410:             s = Argv[0];
     411:         }
     412:         if (!isalpha(*s))
     413:             fatal1("Argument to -D not an identifier.\n");
     414:         Sprintf(if_defined, "#ifdef %s\n", s);
     415:         Sprintf(not_defined, "#ifndef %s\n", s);
     416:         Sprintf(end_defined, "#endif /* %s */\n", s);
     417:         break;
     418:         case 'e':
     419:         diff_type = ED_DIFF;
     420:         break;
     421:         case 'f':
     422:         force = TRUE;
     423:         break;
     424:         case 'F':
     425:         if (*++s == '=')
     426:             s++;
     427:         maxfuzz = atoi(s);
     428:         break;
     429:         case 'l':
     430:         canonicalize = TRUE;
     431:         break;
     432:         case 'n':
     433:         diff_type = NORMAL_DIFF;
     434:         break;
     435:         case 'N':
     436:         noreverse = TRUE;
     437:         break;
     438:         case 'o':
     439:         outname = savestr(Argv[1]);
     440:         Argc--,Argv++;
     441:         break;
     442:         case 'p':
     443:         if (*++s == '=')
     444:             s++;
     445:         strippath = atoi(s);
     446:         break;
     447:         case 'r':
     448:         Strcpy(rejname, Argv[1]);
     449:         Argc--,Argv++;
     450:         break;
     451:         case 'R':
     452:         reverse = TRUE;
     453:         break;
     454:         case 's':
     455:         verbose = FALSE;
     456:         break;
     457:         case 'S':
     458:         skip_rest_of_patch = TRUE;
     459:         break;
     460:         case 'v':
     461:         version();
     462:         break;
     463: #ifdef DEBUGGING
     464:         case 'x':
     465:         debug = atoi(s+1);
     466:         break;
     467: #endif
     468:         default:
     469:         fatal2("Unrecognized switch: %s\n", Argv[0]);
     470:         }
     471:     }
     472:     }
     473: }
     474:
     475: /* Attempt to find the right place to apply this hunk of patch. */
     476:
     477: LINENUM
     478: locate_hunk(fuzz)
     479: LINENUM fuzz;
     480: {
     481:     Reg1 LINENUM first_guess = pch_first() + last_offset;
     482:     Reg2 LINENUM offset;
     483:     LINENUM pat_lines = pch_ptrn_lines();
     484:     Reg3 LINENUM max_pos_offset = input_lines - first_guess
     485:                 - pat_lines + 1;
     486:     Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
     487:                 + pch_context();
     488:
     489:     if (!pat_lines)         /* null range matches always */
     490:     return first_guess;
     491:     if (max_neg_offset >= first_guess)  /* do not try lines < 0 */
     492:     max_neg_offset = first_guess - 1;
     493:     if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
     494:     return first_guess;
     495:     for (offset = 1; ; offset++) {
     496:     Reg5 bool check_after = (offset <= max_pos_offset);
     497:     Reg6 bool check_before = (offset <= max_neg_offset);
     498:
     499:     if (check_after && patch_match(first_guess, offset, fuzz)) {
     500: #ifdef DEBUGGING
     501:         if (debug & 1)
     502:         say3("Offset changing from %ld to %ld\n", last_offset, offset);
     503: #endif
     504:         last_offset = offset;
     505:         return first_guess+offset;
     506:     }
     507:     else if (check_before && patch_match(first_guess, -offset, fuzz)) {
     508: #ifdef DEBUGGING
     509:         if (debug & 1)
     510:         say3("Offset changing from %ld to %ld\n", last_offset, -offset);
     511: #endif
     512:         last_offset = -offset;
     513:         return first_guess-offset;
     514:     }
     515:     else if (!check_before && !check_after)
     516:         return Nulline;
     517:     }
     518: }
     519:
     520: /* We did not find the pattern, dump out the hunk so they can handle it. */
     521:
     522: void
     523: abort_hunk()
     524: {
     525:     Reg1 LINENUM i;
     526:     Reg2 LINENUM pat_end = pch_end();
     527:     /* add in last_offset to guess the same as the previous successful hunk */
     528:     LINENUM oldfirst = pch_first() + last_offset;
     529:     LINENUM newfirst = pch_newfirst() + last_offset;
     530:     LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
     531:     LINENUM newlast = newfirst + pch_repl_lines() - 1;
     532:     char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : "");
     533:     char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----");
     534:
     535:     fprintf(rejfp, "***************\n");
     536:     for (i=0; i<=pat_end; i++) {
     537:     switch (pch_char(i)) {
     538:     case '*':
     539:         if (oldlast < oldfirst)
     540:         fprintf(rejfp, "*** 0%s\n", stars);
     541:         else if (oldlast == oldfirst)
     542:         fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
     543:         else
     544:         fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
     545:         break;
     546:     case '=':
     547:         if (newlast < newfirst)
     548:         fprintf(rejfp, "--- 0%s\n", minuses);
     549:         else if (newlast == newfirst)
     550:         fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
     551:         else
     552:         fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
     553:         break;
     554:     case '\n':
     555:         fprintf(rejfp, "%s", pfetch(i));
     556:         break;
     557:     case ' ': case '-': case '+': case '!':
     558:         fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
     559:         break;
     560:     default:
     561:         say1("Fatal internal error in abort_hunk().\n");
     562:         abort();
     563:     }
     564:     }
     565: }
     566:
     567: /* We found where to apply it (we hope), so do it. */
     568:
     569: void
     570: apply_hunk(where)
     571: LINENUM where;
     572: {
     573:     Reg1 LINENUM old = 1;
     574:     Reg2 LINENUM lastline = pch_ptrn_lines();
     575:     Reg3 LINENUM new = lastline+1;
     576: #define OUTSIDE 0
     577: #define IN_IFNDEF 1
     578: #define IN_IFDEF 2
     579: #define IN_ELSE 3
     580:     Reg4 int def_state = OUTSIDE;
     581:     Reg5 bool R_do_defines = do_defines;
     582:     Reg6 LINENUM pat_end = pch_end();
     583:
     584:     where--;
     585:     while (pch_char(new) == '=' || pch_char(new) == '\n')
     586:     new++;
     587:
     588:     while (old <= lastline) {
     589:     if (pch_char(old) == '-') {
     590:         copy_till(where + old - 1);
     591:         if (R_do_defines) {
     592:         if (def_state == OUTSIDE) {
     593:             fputs(not_defined, ofp);
     594:             def_state = IN_IFNDEF;
     595:         }
     596:         else if (def_state == IN_IFDEF) {
     597:             fputs(else_defined, ofp);
     598:             def_state = IN_ELSE;
     599:         }
     600:         fputs(pfetch(old), ofp);
     601:         }
     602:         last_frozen_line++;
     603:         old++;
     604:     }
     605:     else if (new > pat_end)
     606:         break;
     607:     else if (pch_char(new) == '+') {
     608:         copy_till(where + old - 1);
     609:         if (R_do_defines) {
     610:         if (def_state == IN_IFNDEF) {
     611:             fputs(else_defined, ofp);
     612:             def_state = IN_ELSE;
     613:         }
     614:         else if (def_state == OUTSIDE) {
     615:             fputs(if_defined, ofp);
     616:             def_state = IN_IFDEF;
     617:         }
     618:         }
     619:         fputs(pfetch(new), ofp);
     620:         new++;
     621:     }
     622:     else {
     623:         if (pch_char(new) != pch_char(old)) {
     624:         say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
     625:             pch_hunk_beg() + old,
     626:             pch_hunk_beg() + new);
     627: #ifdef DEBUGGING
     628:         say3("oldchar = '%c', newchar = '%c'\n",
     629:             pch_char(old), pch_char(new));
     630: #endif
     631:         my_exit(1);
     632:         }
     633:         if (pch_char(new) == '!') {
     634:         copy_till(where + old - 1);
     635:         if (R_do_defines) {
     636:            fputs(not_defined, ofp);
     637:            def_state = IN_IFNDEF;
     638:         }
     639:         while (pch_char(old) == '!') {
     640:             if (R_do_defines) {
     641:             fputs(pfetch(old), ofp);
     642:             }
     643:             last_frozen_line++;
     644:             old++;
     645:         }
     646:         if (R_do_defines) {
     647:             fputs(else_defined, ofp);
     648:             def_state = IN_ELSE;
     649:         }
     650:         while (pch_char(new) == '!') {
     651:             fputs(pfetch(new), ofp);
     652:             new++;
     653:         }
     654:         if (R_do_defines) {
     655:             fputs(end_defined, ofp);
     656:             def_state = OUTSIDE;
     657:         }
     658:         }
     659:         else {
     660:         assert(pch_char(new) == ' ');
     661:         old++;
     662:         new++;
     663:         }
     664:     }
     665:     }
     666:     if (new <= pat_end && pch_char(new) == '+') {
     667:     copy_till(where + old - 1);
     668:     if (R_do_defines) {
     669:         if (def_state == OUTSIDE) {
     670:             fputs(if_defined, ofp);
     671:         def_state = IN_IFDEF;
     672:         }
     673:         else if (def_state == IN_IFNDEF) {
     674:         fputs(else_defined, ofp);
     675:         def_state = IN_ELSE;
     676:         }
     677:     }
     678:     while (new <= pat_end && pch_char(new) == '+') {
     679:         fputs(pfetch(new), ofp);
     680:         new++;
     681:     }
     682:     }
     683:     if (R_do_defines && def_state != OUTSIDE) {
     684:     fputs(end_defined, ofp);
     685:     }
     686: }
     687:
     688: /* Open the new file. */
     689:
     690: void
     691: init_output(name)
     692: char *name;
     693: {
     694:     ofp = fopen(name, "w");
     695:     if (ofp == Nullfp)
     696:     fatal2("patch: can't create %s.\n", name);
     697: }
     698:
     699: /* Open a file to put hunks we can't locate. */
     700:
     701: void
     702: init_reject(name)
     703: char *name;
     704: {
     705:     rejfp = fopen(name, "w");
     706:     if (rejfp == Nullfp)
     707:     fatal2("patch: can't create %s.\n", name);
     708: }
     709:
     710: /* Copy input file to output, up to wherever hunk is to be applied. */
     711:
     712: void
     713: copy_till(lastline)
     714: Reg1 LINENUM lastline;
     715: {
     716:     Reg2 LINENUM R_last_frozen_line = last_frozen_line;
     717:
     718:     if (R_last_frozen_line > lastline)
     719:     say1("patch: misordered hunks! output will be garbled.\n");
     720:     while (R_last_frozen_line < lastline) {
     721:     dump_line(++R_last_frozen_line);
     722:     }
     723:     last_frozen_line = R_last_frozen_line;
     724: }
     725:
     726: /* Finish copying the input file to the output file. */
     727:
     728: void
     729: spew_output()
     730: {
     731: #ifdef DEBUGGING
     732:     if (debug & 256)
     733:     say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
     734: #endif
     735:     if (input_lines)
     736:     copy_till(input_lines);     /* dump remainder of file */
     737:     Fclose(ofp);
     738:     ofp = Nullfp;
     739: }
     740:
     741: /* Copy one line from input to output. */
     742:
     743: void
     744: dump_line(line)
     745: LINENUM line;
     746: {
     747:     Reg1 char *s;
     748:     Reg2 char R_newline = '\n';
     749:
     750:     /* Note: string is not null terminated. */
     751:     for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
     752: }
     753:
     754: /* Does the patch pattern match at line base+offset? */
     755:
     756: bool
     757: patch_match(base, offset, fuzz)
     758: LINENUM base;
     759: LINENUM offset;
     760: LINENUM fuzz;
     761: {
     762:     Reg1 LINENUM pline = 1 + fuzz;
     763:     Reg2 LINENUM iline;
     764:     Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
     765:
     766:     for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
     767:     if (canonicalize) {
     768:         if (!similar(ifetch(iline, (offset >= 0)),
     769:              pfetch(pline),
     770:              pch_line_len(pline) ))
     771:         return FALSE;
     772:     }
     773:     else if (strnNE(ifetch(iline, (offset >= 0)),
     774:            pfetch(pline),
     775:            pch_line_len(pline) ))
     776:         return FALSE;
     777:     }
     778:     return TRUE;
     779: }
     780:
     781: /* Do two lines match with canonicalized white space? */
     782:
     783: bool
     784: similar(a,b,len)
     785: Reg1 char *a;
     786: Reg2 char *b;
     787: Reg3 int len;
     788: {
     789:     while (len) {
     790:     if (isspace(*b)) {      /* whitespace (or \n) to match? */
     791:         if (!isspace(*a))       /* no corresponding whitespace? */
     792:         return FALSE;
     793:         while (len && isspace(*b) && *b != '\n')
     794:         b++,len--;      /* skip pattern whitespace */
     795:         while (isspace(*a) && *a != '\n')
     796:         a++;            /* skip target whitespace */
     797:         if (*a == '\n' || *b == '\n')
     798:         return (*a == *b);  /* should end in sync */
     799:     }
     800:     else if (*a++ != *b++)      /* match non-whitespace chars */
     801:         return FALSE;
     802:     else
     803:         len--;          /* probably not necessary */
     804:     }
     805:     return TRUE;            /* actually, this is not reached */
     806:                     /* since there is always a \n */
     807: }
     808:
     809: /* Exit with cleanup. */
     810:
     811: void
     812: my_exit(status)
     813: int status;
     814: {
     815:     Unlink(TMPINNAME);
     816:     if (!toutkeep) {
     817:     Unlink(TMPOUTNAME);
     818:     }
     819:     if (!trejkeep) {
     820:     Unlink(TMPREJNAME);
     821:     }
     822:     Unlink(TMPPATNAME);
     823:     exit(status);
     824: }

#### Defined functions

abort_hunk defined in line 522; used 3 times

- in line 103, 238, 244

apply_hunk defined in line 569; used 2 times

- in line 104, 250

copy_till defined in line 712; used 6 times

- in line 107, 590, 608, 634, 667, 736

dump_line defined in line 743; used 2 times

- in line 109, 721

get_some_switches defined in line 365; used 3 times

- in line 101, 141, 357

init_output defined in line 690; used 2 times

- in line 105, 157

init_reject defined in line 701; used 2 times

- in line 106, 166

locate_hunk defined in line 477; used 3 times

- in line 102, 187, 197

main defined in line 117; never used
my_exit defined in line 811; used 12 times

- in line 113, 320, 631
- in /usr/src/usr.bin/patch/util.c line 177-183(3), 240-243(2), 251-260(4)

patch_match defined in line 756; used 4 times

- in line 110, 493, 499, 507

reinitialize_almost_everything defined in line 325; used 2 times

- in line 100, 149

similar defined in line 783; used 2 times

- in line 111, 768

spew_output defined in line 728; used 2 times

- in line 108, 274

#### Defined variables

rcsid defined in line 1; never used

#### Defined macros

IN_ELSE defined in line 579; used 4 times

- in line 598, 612, 648, 675

IN_IFDEF defined in line 578; used 3 times

- in line 596, 616, 671

IN_IFNDEF defined in line 577; used 4 times

- in line 594, 610, 637, 673

OUTSIDE defined in line 576; used 6 times

- in line 580, 592, 614, 656, 669, 683

Last modified: 1988-06-30 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2616 |