📄 patch.c
字号:
char rcsid[] = "$Header: patch.c,v 2.0.2.0 90/05/01 22:17:50 davison Locked $";/* patch - a program to apply diffs to original files * * Copyright 1986, Larry Wall * * This program may be copied as long as you don't try to make any * money off of it, or pretend that you wrote it. * * $Log: patch.c,v $ * Revision 2.0.2.0 90/05/01 22:17:50 davison * patch12u: unidiff support added * * Revision 2.0.1.6 88/06/22 20:46:39 lwall * patch12: rindex() wasn't declared * * Revision 2.0.1.5 88/06/03 15:09:37 lwall * patch10: exit code improved. * patch10: better support for non-flexfilenames. * * Revision 2.0.1.4 87/02/16 14:00:04 lwall * Short replacement caused spurious "Out of sync" message. * * Revision 2.0.1.3 87/01/30 22:45:50 lwall * Improved diagnostic on sync error. * Moved do_ed_script() to pch.c. * * Revision 2.0.1.2 86/11/21 09:39:15 lwall * Fuzz factor caused offset of installed lines. * * Revision 2.0.1.1 86/10/29 13:10:22 lwall * Backwards search could terminate prematurely. * * Revision 2.0 86/09/17 15:37:32 lwall * Baseline for netwide release. * * Revision 1.5 86/08/01 20:53:24 lwall * Changed some %d's to %ld's. * Linted. * * Revision 1.4 86/08/01 19:17:29 lwall * Fixes for machines that can't vararg. * Added fuzz factor. * Generalized -p. * General cleanup. * * 85/08/15 van%ucbmonet@berkeley * Changes for 4.3bsd diff -c. * * Revision 1.3 85/03/26 15:07:43 lwall * Frozen. * * Revision 1.2.1.9 85/03/12 17:03:35 lwall * Changed pfp->_file to fileno(pfp). * * Revision 1.2.1.8 85/03/12 16:30:43 lwall * Check i_ptr and i_womp to make sure they aren't null before freeing. * Also allow ed output to be suppressed. * * Revision 1.2.1.7 85/03/12 15:56:13 lwall * Added -p option from jromine@uci-750a. * * Revision 1.2.1.6 85/03/12 12:12:51 lwall * Now checks for normalness of file to patch. * * Revision 1.2.1.5 85/03/12 11:52:12 lwall * Added -D (#ifdef) option from joe@fluke. * * Revision 1.2.1.4 84/12/06 11:14:15 lwall * Made smarter about SCCS subdirectories. * * Revision 1.2.1.3 84/12/05 11:18:43 lwall * Added -l switch to do loose string comparison. * * Revision 1.2.1.2 84/12/04 09:47:13 lwall * Failed hunk count not reset on multiple patch file. * * Revision 1.2.1.1 84/12/04 09:42:37 lwall * Branch for sdcrdcf changes. * * Revision 1.2 84/11/29 13:29:51 lwall * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed * multiple calls to mktemp(). Will now work on machines that can only * read 32767 chars. Added -R option for diffs with new and old swapped. * Various cosmetic changes. * * Revision 1.1 84/11/09 17:03:58 lwall * Initial revision * */#include "INTERN.h"#include "common.h"#include "EXTERN.h"#include "version.h"#include "util.h"#include "pch.h"#include "inp.h"#include "backupfile.h"/* procedures */void reinitialize_almost_everything();void get_some_switches();LINENUM locate_hunk();void abort_hunk();void apply_hunk();void init_output();void init_reject();void copy_till();void spew_output();void dump_line();bool patch_match();bool similar();void re_input();void my_exit();/* TRUE if -E was specified on command line. */static int remove_empty_files = FALSE;/* TRUE if -R was specified on command line. */static int reverse_flag_specified = FALSE;/* Apply a set of diffs as appropriate. */intmain(argc,argv)int argc;char **argv;{ LINENUM where; LINENUM newwhere; LINENUM fuzz; LINENUM mymaxfuzz; int hunk = 0; int failed = 0; int failtotal = 0; int i; setbuf(stderr, serrbuf); for (i = 0; i<MAXFILEC; i++) filearg[i] = Nullch; myuid = getuid(); /* Cons up the names of the temporary files. */ { /* Directory for temporary files. */ char *tmpdir; int tmpname_len; tmpdir = getenv ("TMPDIR"); if (tmpdir == NULL) { tmpdir = "/tmp"; } tmpname_len = strlen (tmpdir) + 20; TMPOUTNAME = (char *) malloc (tmpname_len); strcpy (TMPOUTNAME, tmpdir); strcat (TMPOUTNAME, "/patchoXXXXXX"); Mktemp(TMPOUTNAME); TMPINNAME = (char *) malloc (tmpname_len); strcpy (TMPINNAME, tmpdir); strcat (TMPINNAME, "/patchiXXXXXX"); Mktemp(TMPINNAME); TMPREJNAME = (char *) malloc (tmpname_len); strcpy (TMPREJNAME, tmpdir); strcat (TMPREJNAME, "/patchrXXXXXX"); Mktemp(TMPREJNAME); TMPPATNAME = (char *) malloc (tmpname_len); strcpy (TMPPATNAME, tmpdir); strcat (TMPPATNAME, "/patchpXXXXXX"); Mktemp(TMPPATNAME); } { char *v; v = getenv ("SIMPLE_BACKUP_SUFFIX"); if (v) simple_backup_suffix = v; else simple_backup_suffix = ORIGEXT;#ifndef NODIR v = getenv ("VERSION_CONTROL"); backup_type = get_version (v); /* OK to pass NULL. */#endif } /* parse switches */ Argc = argc; Argv = argv; get_some_switches(); /* make sure we clean up /tmp in case of disaster */ set_signals(0); for ( open_patch_file(filearg[1]); there_is_another_patch(); reinitialize_almost_everything() ) { /* for each patch in patch file */ if (outname == Nullch) outname = savestr(filearg[0]); /* for ed script just up and do it and exit */ if (diff_type == ED_DIFF) { do_ed_script(); continue; } /* initialize the patched file */ if (!skip_rest_of_patch) init_output(TMPOUTNAME); /* initialize reject file */ init_reject(TMPREJNAME); /* find out where all the lines are */ if (!skip_rest_of_patch) scan_input(filearg[0]); /* from here on, open no standard i/o files, because malloc */ /* might misfire and we can't catch it easily */ /* apply each hunk of patch */ hunk = 0; failed = 0; out_of_mem = FALSE; while (another_hunk()) { hunk++; fuzz = Nulline; mymaxfuzz = pch_context(); if (maxfuzz < mymaxfuzz) mymaxfuzz = maxfuzz; if (!skip_rest_of_patch) { do { where = locate_hunk(fuzz); if (hunk == 1 && where == Nulline && !force) { /* dwim for reversed patch? */ if (!pch_swap()) { if (fuzz == Nulline) say1("Not enough memory to try swapped hunk! Assuming unswapped.\n"); continue; } reverse = !reverse; where = locate_hunk(fuzz); /* try again */ if (where == Nulline) { /* didn't find it swapped */ if (!pch_swap()) /* put it back to normal */ fatal1("lost hunk on alloc error!\n"); reverse = !reverse; } else if (noreverse) { if (!pch_swap()) /* put it back to normal */ fatal1("lost hunk on alloc error!\n"); reverse = !reverse; say1("Ignoring previously applied (or reversed) patch.\n"); skip_rest_of_patch = TRUE; } else if (batch) { if (verbose) say3("%seversed (or previously applied) patch detected! %s -R.", reverse ? "R" : "Unr", reverse ? "Assuming" : "Ignoring"); } else { ask3("%seversed (or previously applied) patch detected! %s -R? [y] ", reverse ? "R" : "Unr", reverse ? "Assume" : "Ignore"); if (*buf == 'n') { ask1("Apply anyway? [n] "); if (*buf != 'y') skip_rest_of_patch = TRUE; where = Nulline; reverse = !reverse; if (!pch_swap()) /* put it back to normal */ fatal1("lost hunk on alloc error!\n"); } } } } while (!skip_rest_of_patch && where == Nulline && ++fuzz <= mymaxfuzz); if (skip_rest_of_patch) { /* just got decided */ Fclose(ofp); ofp = Nullfp; } } newwhere = pch_newfirst() + last_offset; if (skip_rest_of_patch) { abort_hunk(); failed++; if (verbose) say3("Hunk #%d ignored at %ld.\n", hunk, newwhere); } else if (where == Nulline) { abort_hunk(); failed++; if (verbose) say3("Hunk #%d failed at %ld.\n", hunk, newwhere); } else { apply_hunk(where); if (verbose) { say3("Hunk #%d succeeded at %ld", hunk, newwhere); if (fuzz) say2(" with fuzz %ld", fuzz); if (last_offset) say3(" (offset %ld line%s)", last_offset, last_offset==1L?"":"s"); say1(".\n"); } } } if (out_of_mem && using_plan_a) { Argc = Argc_last; Argv = Argv_last; say1("\n\nRan out of memory using Plan A--trying again...\n\n"); if (ofp) Fclose(ofp); ofp = Nullfp; if (rejfp) Fclose(rejfp); rejfp = Nullfp; continue; } assert(hunk); /* finish spewing out the new file */ if (!skip_rest_of_patch) spew_output(); /* and put the output where desired */ ignore_signals(); if (!skip_rest_of_patch) { struct stat statbuf; char *realout = outname; if (move_file(TMPOUTNAME, outname) < 0) { toutkeep = TRUE; realout = TMPOUTNAME; chmod(TMPOUTNAME, filemode); } else chmod(outname, filemode); if (remove_empty_files && stat(realout, &statbuf) == 0 && statbuf.st_size == 0) { if (verbose) say2("Removing %s (empty after patching).\n", realout); while (unlink(realout) >= 0) ; /* while is for Eunice. */ } } Fclose(rejfp); rejfp = Nullfp; if (failed) { failtotal += failed; if (!*rejname) { Strcpy(rejname, outname);#ifndef FLEXFILENAMES { char *s = rindex(rejname,'/'); if (!s) s = rejname; if (strlen(s) > 13) if (s[12] == '.') /* try to preserve difference */ s[12] = s[13]; /* between .h, .c, .y, etc. */ s[13] = '\0'; }#endif Strcat(rejname, REJEXT); } if (skip_rest_of_patch) { say4("%d out of %d hunks ignored--saving rejects to %s\n", failed, hunk, rejname); } else { say4("%d out of %d hunks failed--saving rejects to %s\n", failed, hunk, rejname); } if (move_file(TMPREJNAME, rejname) < 0) trejkeep = TRUE; } set_signals(1); } my_exit(failtotal);}/* Prepare to find the next patch to do in the patch file. */voidreinitialize_almost_everything(){ re_patch(); re_input(); input_lines = 0; last_frozen_line = 0; filec = 0; if (filearg[0] != Nullch && !out_of_mem) { free(filearg[0]); filearg[0] = Nullch; } if (outname != Nullch) { free(outname); outname = Nullch; } last_offset = 0; diff_type = 0; if (revision != Nullch) { free(revision); revision = Nullch; } reverse = reverse_flag_specified; skip_rest_of_patch = FALSE; get_some_switches(); if (filec >= 2) fatal1("you may not change to a different patch file\n");}static char *nextarg(){ if (!--Argc) fatal2("missing argument after `%s'\n", *Argv); return *++Argv;}/* Process switches and filenames up to next '+' or end of list. */voidget_some_switches(){ Reg1 char *s; rejname[0] = '\0'; Argc_last = Argc; Argv_last = Argv; if (!Argc) return; for (Argc--,Argv++; Argc; Argc--,Argv++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -