⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 patch.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
/* patch - a program to apply diffs to original files *//* $Id: patch.c,v 1.23 1997/07/05 10:32:23 eggert Exp $ *//*Copyright 1984, 1985, 1986, 1987, 1988 Larry WallCopyright 1989, 1990, 1991, 1992, 1993, 1997 Free Software Foundation, Inc.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; see the file COPYING.If not, write to the Free Software Foundation,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#define XTERN#include <common.h>#undef XTERN#define XTERN extern#include <argmatch.h>#include <backupfile.h>#include <getopt.h>#include <inp.h>#include <pch.h>#include <util.h>#include <version.h>#if HAVE_UTIME_H# include <utime.h>#endif/* Some nonstandard hosts don't declare this structure even in <utime.h>.  */#if ! HAVE_STRUCT_UTIMBUFstruct utimbuf{  time_t actime;  time_t modtime;};#endif/* Output stream state.  */struct outstate{  FILE *ofp;  int after_newline;  int zero_output;};/* procedures */static FILE *create_output_file PARAMS ((char const *));static LINENUM locate_hunk PARAMS ((LINENUM));static bool apply_hunk PARAMS ((struct outstate *, LINENUM));static bool copy_till PARAMS ((struct outstate *, LINENUM));static bool patch_match PARAMS ((LINENUM, LINENUM, LINENUM, LINENUM));static bool similar PARAMS ((char const *, size_t, char const *, size_t));static bool spew_output PARAMS ((struct outstate *));static char const *make_temp PARAMS ((int));static int numeric_string PARAMS ((char const *, int, char const *));static void abort_hunk PARAMS ((void));static void cleanup PARAMS ((void));static void get_some_switches PARAMS ((void));static void init_output PARAMS ((char const *, struct outstate *));static void init_reject PARAMS ((char const *));static void reinitialize_almost_everything PARAMS ((void));static void usage PARAMS ((FILE *, int)) __attribute__((noreturn));static int make_backups;static int backup_if_mismatch;static char const *version_control;static int remove_empty_files;/* TRUE if -R was specified on command line.  */static int reverse_flag_specified;/* how many input lines have been irretractably output */static LINENUM last_frozen_line;static char const *do_defines; /* symbol to patch using ifdef, ifndef, etc. */static char const if_defined[] = "\n#ifdef %s\n";static char const not_defined[] = "#ifndef %s\n";static char const else_defined[] = "\n#else\n";static char const end_defined[] = "\n#endif /* %s */\n";static int Argc;static char * const *Argv;static FILE *rejfp;  /* reject file pointer */static char const *patchname;static char *rejname;static char const * volatile TMPREJNAME;static LINENUM last_offset;static LINENUM maxfuzz = 2;static char serrbuf[BUFSIZ];char const program_name[] = "patch";/* Apply a set of diffs as appropriate. */int main PARAMS ((int, char **));intmain(argc,argv)int argc;char **argv;{    char const *val;    bool somefailed = FALSE;    struct outstate outstate;    init_time ();    setbuf(stderr, serrbuf);    bufsize = 8 * 1024;    buf = xmalloc (bufsize);    strippath = INT_MAX;    posixly_correct = getenv ("POSIXLY_CORRECT") != 0;    backup_if_mismatch = ! posixly_correct;    patch_get = ((val = getenv ("PATCH_GET"))		 ? numeric_string (val, 1, "PATCH_GET value")		 : posixly_correct - 1);    {      char const *v = getenv ("SIMPLE_BACKUP_SUFFIX");      if (v && *v)	simple_backup_suffix = v;    }    version_control = getenv ("PATCH_VERSION_CONTROL");    if (! version_control)      version_control = getenv ("VERSION_CONTROL");    /* Cons up the names of the global temporary files.       Do this before `cleanup' can possibly be called (e.g. by `pfatal').  */    TMPOUTNAME = make_temp ('o');    TMPINNAME = make_temp ('i');    TMPREJNAME = make_temp ('r');    TMPPATNAME = make_temp ('p');    /* parse switches */    Argc = argc;    Argv = argv;    get_some_switches();    if (make_backups | backup_if_mismatch)      backup_type = get_version (version_control);    init_output (outfile, &outstate);    /* Make sure we clean up in case of disaster.  */    set_signals(0);    for (	open_patch_file (patchname);	there_is_another_patch();	reinitialize_almost_everything()    ) {					/* for each patch in patch file */      int hunk = 0;      int failed = 0;      int mismatch = 0;      char *outname = outfile ? outfile : inname;      if (!skip_rest_of_patch)	get_input_file (inname, outname);      if (diff_type == ED_DIFF) {	outstate.zero_output = 0;	if (! dry_run)	  {	    do_ed_script (outstate.ofp);	    if (! outfile)	      {		struct stat statbuf;		if (stat (TMPOUTNAME, &statbuf) != 0)		  pfatal ("%s", TMPOUTNAME);		outstate.zero_output = statbuf.st_size == 0;	      }	  }      } else {	int got_hunk;	int apply_anyway = 0;	/* initialize the patched file */	if (! skip_rest_of_patch && ! outfile)	  init_output (TMPOUTNAME, &outstate);	/* initialize reject file */	init_reject(TMPREJNAME);	/* find out where all the lines are */	if (!skip_rest_of_patch)	    scan_input (inname);	/* 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 */	while (0 < (got_hunk = another_hunk (diff_type, reverse))) {	    LINENUM where = 0; /* Pacify `gcc -Wall'.  */	    LINENUM newwhere;	    LINENUM fuzz = 0;	    LINENUM prefix_context = pch_prefix_context ();	    LINENUM suffix_context = pch_suffix_context ();	    LINENUM context = (prefix_context < suffix_context			       ? suffix_context : prefix_context);	    LINENUM mymaxfuzz = (maxfuzz < context ? maxfuzz : context);	    hunk++;	    if (!skip_rest_of_patch) {		do {		    where = locate_hunk(fuzz);		    if (! where || fuzz || last_offset)		      mismatch = 1;		    if (hunk == 1 && ! where && ! (force | apply_anyway)			&& reverse == reverse_flag_specified) {						/* dwim for reversed patch? */			if (!pch_swap()) {			    say ("Not enough memory to try swapped hunk!  Assuming unswapped.\n");			    continue;			}			/* Try again.  */			where = locate_hunk (fuzz);			if (where			    && (ok_to_reverse				("%s patch detected!",				 (reverse				  ? "Unreversed"				  : "Reversed (or previously applied)"))))			  reverse ^= 1;			else			  {			    /* Put it back to normal.  */			    if (! pch_swap ())			      fatal ("lost hunk on alloc error!");			    if (where)			      {				apply_anyway = 1;				fuzz--; /* Undo `++fuzz' below.  */				where = 0;			      }			  }		    }		} while (!skip_rest_of_patch && !where			 && ++fuzz <= mymaxfuzz);		if (skip_rest_of_patch) {		/* just got decided */		  if (outstate.ofp && ! outfile)		    {		      fclose (outstate.ofp);		      outstate.ofp = 0;		    }		}	    }	    newwhere = pch_newfirst() + last_offset;	    if (skip_rest_of_patch) {		abort_hunk();		failed++;		if (verbosity == VERBOSE)		    say ("Hunk #%d ignored at %ld.\n", hunk, newwhere);	    }	    else if (!where		     || (where == 1 && pch_says_nonexistent (reverse)			 && instat.st_size)) {		if (where)		  say ("Patch attempted to create file `%s', which already exists.\n", inname);		abort_hunk();		failed++;		if (verbosity != SILENT)		    say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere);	    }	    else if (! apply_hunk (&outstate, where)) {		abort_hunk ();		failed++;		if (verbosity != SILENT)		    say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere);	    } else {		if (verbosity == VERBOSE		    || (verbosity != SILENT && (fuzz || last_offset))) {		    say ("Hunk #%d succeeded at %ld", hunk, newwhere);		    if (fuzz)			say (" with fuzz %ld", fuzz);		    if (last_offset)			say (" (offset %ld line%s)",			    last_offset, last_offset==1?"":"s");		    say (".\n");		}	    }	}	if (got_hunk < 0  &&  using_plan_a) {	    if (outfile)	      fatal ("out of memory using Plan A");	    say ("\n\nRan out of memory using Plan A -- trying again...\n\n");	    if (outstate.ofp)	      {		fclose (outstate.ofp);		outstate.ofp = 0;	      }	    fclose (rejfp);	    continue;	}	/* finish spewing out the new file */	if (!skip_rest_of_patch)	  {	    assert (hunk);	    if (! spew_output (&outstate))	      {		say ("Skipping patch.\n");		skip_rest_of_patch = TRUE;	      }	  }      }      /* and put the output where desired */      ignore_signals ();      if (! skip_rest_of_patch && ! outfile) {	  if (outstate.zero_output	      && (remove_empty_files		  || (pch_says_nonexistent (reverse ^ 1) == 2		      && ! posixly_correct)))	    {	      if (verbosity == VERBOSE)		say ("Removing file `%s'%s.\n", outname,		     dry_run ? " and any empty ancestor directories" : "");	      if (! dry_run)		{		  move_file ((char *) 0, outname, (mode_t) 0,			     (make_backups			      || (backup_if_mismatch && (mismatch | failed))));		  removedirs (outname);		}	    }	  else	    {	      if (! outstate.zero_output		  && pch_says_nonexistent (reverse ^ 1))		{		  mismatch = 1;		  if (verbosity != SILENT)		    say ("File `%s' is not empty after patch, as expected.\n",			 outname);		}	      if (! dry_run)		{		  time_t t;		  move_file (TMPOUTNAME, outname, instat.st_mode,			     (make_backups			      || (backup_if_mismatch && (mismatch | failed))));		  if ((set_time | set_utc)		      && (t = pch_timestamp (reverse ^ 1)) != (time_t) -1)		    {		      struct utimbuf utimbuf;		      utimbuf.actime = utimbuf.modtime = t;		      if (! force && ! inerrno			  && ! pch_says_nonexistent (reverse)			  && (t = pch_timestamp (reverse)) != (time_t) -1			  && t != instat.st_mtime)			say ("not setting time of file `%s' (time mismatch)\n",			     outname);		      else if (! force && (mismatch | failed))			say ("not setting time of file `%s' (contents mismatch)\n",			     outname);		      else if (utime (outname, &utimbuf) != 0)			pfatal ("can't set timestamp on file `%s'", outname);		    }		  if (! inerrno && chmod (outname, instat.st_mode) != 0)		    pfatal ("can't set permissions on file `%s'", outname);		}	    }      }      if (diff_type != ED_DIFF) {	if (fclose (rejfp) != 0)	    write_fatal ();	if (failed) {	    somefailed = TRUE;	    say ("%d out of %d hunk%s %s", failed, hunk, "s" + (hunk == 1),		 skip_rest_of_patch ? "ignored" : "FAILED");	    if (outname) {		char *rej = rejname;		if (!rejname) {		    rej = xmalloc (strlen (outname) + 5);		    strcpy (rej, outname);		    addext (rej, ".rej", '#');		}		say (" -- saving rejects to %s", rej);		if (! dry_run)		  {		    move_file (TMPREJNAME, rej, instat.st_mode, FALSE);		    if (! inerrno			&& (chmod (rej, (instat.st_mode					 & ~(S_IXUSR|S_IXGRP|S_IXOTH)))			    != 0))		      pfatal ("can't set permissions on file `%s'", rej);		  }		if (!rejname)		    free (rej);	    }	    say ("\n");	}      }      set_signals (1);    }    if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0))      write_fatal ();    cleanup ();    if (somefailed)      exit (1);    return 0;}/* Prepare to find the next patch to do in the patch file. */static voidreinitialize_almost_everything()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -