diff options
author | Andreas Gruenbacher <agruen@suse.de> | 2009-03-12 15:15:17 +0100 |
---|---|---|
committer | Andreas Gruenbacher <agruen@suse.de> | 2009-03-12 15:15:17 +0100 |
commit | 6263c220df2b94ae8156c378dc5161779d894297 (patch) | |
tree | 52d1c3fd61d567edd0d9eab977f1acc44a7d754d /patch.c | |
parent | 1adb4535a31d825f10a5bd1ef10b52a7425073bd (diff) | |
download | patch-2.4.tar.gz |
Import of patch-2.4.tar.gzv2.4
Diffstat (limited to 'patch.c')
-rw-r--r-- | patch.c | 330 |
1 files changed, 220 insertions, 110 deletions
@@ -1,6 +1,6 @@ /* patch - a program to apply diffs to original files */ -/* $Id: patch.c,v 1.17 1997/05/26 05:34:43 eggert Exp $ */ +/* $Id: patch.c,v 1.22 1997/06/17 22:32:49 eggert Exp $ */ /* Copyright 1984, 1985, 1986, 1987, 1988 Larry Wall @@ -34,25 +34,46 @@ If not, write to the Free Software Foundation, #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_UTIMBUF +struct 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 ((bool *, LINENUM)); -static bool copy_till PARAMS ((bool *, 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 ((bool *)); +static bool spew_output PARAMS ((struct outstate *)); static char const *make_temp PARAMS ((int)); -static int numeric_optarg PARAMS ((char const *)); +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 *)); +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 backup_if_mismatch; static int remove_empty_files; /* TRUE if -R was specified on command line. */ @@ -70,10 +91,8 @@ static char const end_defined[] = "\n#endif /* %s */\n"; static int Argc; static char * const *Argv; -static FILE *ofp; /* output file pointer */ static FILE *rejfp; /* reject file pointer */ -static char *output; static char const *patchname; static char *rejname; static char const * volatile TMPREJNAME; @@ -94,7 +113,9 @@ main(argc,argv) int argc; char **argv; { + char const *val; bool somefailed = FALSE; + struct outstate outstate; init_time (); @@ -105,8 +126,11 @@ char **argv; strippath = INT_MAX; - patch_get = getenv ("PATCH_GET") != 0; 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; @@ -134,8 +158,7 @@ char **argv; Argv = argv; get_some_switches(); - if (output) - init_output (output); + init_output (outfile, &outstate); /* Make sure we clean up in case of disaster. */ set_signals(0); @@ -147,22 +170,32 @@ char **argv; ) { /* for each patch in patch file */ int hunk = 0; int failed = 0; - char *outname = output ? output : inname; + 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 (ofp); + { + 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; - bool after_newline = TRUE; /* initialize the patched file */ - if (!skip_rest_of_patch && !output) - init_output(TMPOUTNAME); + if (! skip_rest_of_patch && ! outfile) + init_output (TMPOUTNAME, &outstate); /* initialize reject file */ init_reject(TMPREJNAME); @@ -188,7 +221,10 @@ char **argv; if (!skip_rest_of_patch) { do { where = locate_hunk(fuzz); - if (hunk == 1 && !where && !(force|apply_anyway)) { + 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 ( @@ -221,10 +257,10 @@ char **argv; && ++fuzz <= mymaxfuzz); if (skip_rest_of_patch) { /* just got decided */ - if (ofp && !output) + if (outstate.ofp && ! outfile) { - fclose (ofp); - ofp = 0; + fclose (outstate.ofp); + outstate.ofp = 0; } } } @@ -233,26 +269,27 @@ char **argv; if (skip_rest_of_patch) { abort_hunk(); failed++; - if (verbosity != SILENT) + if (verbosity == VERBOSE) say ("Hunk #%d ignored at %ld.\n", hunk, newwhere); } else if (!where || (where == 1 && pch_says_nonexistent (reverse) - && input_lines)) { + && instat.st_size)) { if (where) - say ("\nPatch attempted to create file `%s', which already exists.\n", inname); + 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 (&after_newline, where)) { - abort_hunk (); - failed++; - if (verbosity != SILENT) - say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere); - } else if (verbosity == VERBOSE) { + 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); @@ -265,13 +302,13 @@ char **argv; } if (got_hunk < 0 && using_plan_a) { - if (output) + if (outfile) fatal ("out of memory using Plan A"); say ("\n\nRan out of memory using Plan A -- trying again...\n\n"); - if (ofp) + if (outstate.ofp) { - fclose (ofp); - ofp = 0; + fclose (outstate.ofp); + outstate.ofp = 0; } fclose (rejfp); continue; @@ -281,19 +318,21 @@ char **argv; if (!skip_rest_of_patch) { assert (hunk); - skip_rest_of_patch = ! spew_output (&after_newline); + 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 && !output) { - struct stat statbuf; - - if ((remove_empty_files - || (pch_says_nonexistent (reverse ^ 1) && !posixly_correct)) - && stat (TMPOUTNAME, &statbuf) == 0 - && statbuf.st_size == 0) + 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, @@ -301,16 +340,49 @@ char **argv; if (! dry_run) { move_file ((char *) 0, outname, (mode_t) 0, - backup_type != none); + (backup_type != none + || (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, - backup_type != none); + (backup_type != none + || (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); } @@ -348,7 +420,7 @@ char **argv; } set_signals (1); } - if (ofp && (ferror (ofp) || fclose (ofp) != 0)) + if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0)) write_fatal (); cleanup (); if (somefailed) @@ -385,7 +457,7 @@ reinitialize_almost_everything() skip_rest_of_patch = FALSE; } -static char const shortopts[] = "bB:cd:D:eEfF:gGi:lnNo:p:r:RstuvV:x:Y:z:"; +static char const shortopts[] = "bB:cd:D:eEfF:g:i:lnNo:p:r:RstTuvV:x:Y:z:Z"; static struct option const longopts[] = { {"backup", no_argument, NULL, 'b'}, @@ -398,7 +470,6 @@ static struct option const longopts[] = {"force", no_argument, NULL, 'f'}, {"fuzz", required_argument, NULL, 'F'}, {"get", no_argument, NULL, 'g'}, - {"no-get", no_argument, NULL, 'G'}, {"input", required_argument, NULL, 'i'}, {"ignore-whitespace", no_argument, NULL, 'l'}, {"normal", no_argument, NULL, 'n'}, @@ -410,16 +481,20 @@ static struct option const longopts[] = {"quiet", no_argument, NULL, 's'}, {"silent", no_argument, NULL, 's'}, {"batch", no_argument, NULL, 't'}, + {"set-time", no_argument, NULL, 'T'}, {"unified", no_argument, NULL, 'u'}, {"version", no_argument, NULL, 'v'}, {"version-control", required_argument, NULL, 'V'}, {"debug", required_argument, NULL, 'x'}, {"basename-prefix", required_argument, NULL, 'Y'}, {"suffix", required_argument, NULL, 'z'}, + {"set-utc", no_argument, NULL, 'Z'}, {"dry-run", no_argument, NULL, 129}, {"verbose", no_argument, NULL, 130}, {"binary", no_argument, NULL, 131}, {"help", no_argument, NULL, 132}, + {"backup-if-mismatch", no_argument, NULL, 133}, + {"no-backup-if-mismatch", no_argument, NULL, 134}, {NULL, no_argument, NULL, 0} }; @@ -449,18 +524,22 @@ static char const *const option_help[] = " -D NAME --ifdef=NAME Make merged if-then-else output using NAME.", " -E --remove-empty-files Remove output files that are empty after patching.", "", +" -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).", +" -T --set-time Likewise, assuming local time.", +"", "Backup and version control options:", "", " -V STYLE --version-control=STYLE Use STYLE version control.", " STYLE is either 'simple', 'numbered', or 'existing'.", "", -" -b --backup Save the original contents of each file F into F.orig.", +" -b --backup Back up the original contents of each file.", +" --backup-if-mismatch Back up if the patch does not match exactly.", +" --no-backup-if-mismatch Back up mismatches only if otherwise requested.", " -B PREFIX --prefix=PREFIX Prepend PREFIX to backup file names.", " -Y PREFIX --basename-prefix=PREFIX Prepend PREFIX to backup file basenames.", " -z SUFFIX --suffix=SUFFIX Append SUFFIX to backup file names.", "", -" -g --get Get files from RCS or SCCS.", -" -G --no-get Do not get files.", +" -g NUM --get=NUM Get files from RCS or SCCS if positive; ask if negative.", "", "Miscellaneous options:", "", @@ -544,7 +623,6 @@ get_some_switches() if (!*optarg) fatal ("backup prefix is empty"); origprae = savestr (optarg); - backup_type = simple; break; case 'c': diff_type = CONTEXT_DIFF; @@ -566,13 +644,10 @@ get_some_switches() force = TRUE; break; case 'F': - maxfuzz = numeric_optarg ("fuzz factor"); + maxfuzz = numeric_string (optarg, 0, "fuzz factor"); break; case 'g': - patch_get = 1; - break; - case 'G': - patch_get = 0; + patch_get = numeric_string (optarg, 1, "get option value"); break; case 'i': patchname = savestr (optarg); @@ -589,10 +664,10 @@ get_some_switches() case 'o': if (strcmp (optarg, "-") == 0) fatal ("can't output patches to standard output"); - output = savestr (optarg); + outfile = savestr (optarg); break; case 'p': - strippath = numeric_optarg ("strip count"); + strippath = numeric_string (optarg, 0, "strip count"); break; case 'r': rejname = savestr (optarg); @@ -607,6 +682,9 @@ get_some_switches() case 't': batch = TRUE; break; + case 'T': + set_time = 1; + break; case 'u': diff_type = UNI_DIFF; break; @@ -619,21 +697,22 @@ get_some_switches() break; #if DEBUGGING case 'x': - debug = numeric_optarg ("debugging option"); + debug = numeric_string (optarg, 1, "debugging option"); break; #endif case 'Y': if (!*optarg) fatal ("backup basename prefix is empty"); origbase = savestr (optarg); - backup_type = simple; break; case 'z': case_z: if (!*optarg) fatal ("backup suffix is empty"); simple_backup_suffix = savestr (optarg); - backup_type = simple; + break; + case 'Z': + set_utc = 1; break; case 129: dry_run = TRUE; @@ -648,6 +727,12 @@ get_some_switches() break; case 132: usage (stdout, 0); + case 133: + backup_if_mismatch = 1; + break; + case 134: + backup_if_mismatch = 0; + break; default: usage (stderr, 2); } @@ -657,6 +742,7 @@ get_some_switches() if (optind < Argc) { inname = savestr (Argv[optind++]); + invc = -1; if (optind < Argc) { patchname = savestr (Argv[optind++]); @@ -670,30 +756,41 @@ get_some_switches() } } -/* Handle a numeric option of type ARGTYPE_MSGID by converting - optarg to a nonnegative integer, returning the result. */ +/* Handle STRING (possibly negative if NEGATIVE_ALLOWED is nonzero) + of type ARGTYPE_MSGID by converting it to an integer, + returning the result. */ static int -numeric_optarg (argtype_msgid) +numeric_string (string, negative_allowed, argtype_msgid) + char const *string; + int negative_allowed; char const *argtype_msgid; { int value = 0; - char const *p = optarg; + char const *p = string; + int sign = *p == '-' ? -1 : 1; + + p += *p == '-' || *p == '+'; do { int v10 = value * 10; int digit = *p - '0'; + int signed_digit = sign * digit; + int next_value = v10 + signed_digit; if (9 < (unsigned) digit) - fatal ("%s `%s' is not a number", argtype_msgid, optarg); + fatal ("%s `%s' is not a number", argtype_msgid, string); - if (v10 / 10 != value || v10 + digit < v10) - fatal ("%s `%s' is too large", argtype_msgid, optarg); + if (v10 / 10 != value || (next_value < v10) != (signed_digit < 0)) + fatal ("%s `%s' is too large", argtype_msgid, string); - value = v10 + digit; + value = next_value; } while (*++p); + if (value < 0 && ! negative_allowed) + fatal ("%s `%s' is negative", argtype_msgid, string); + return value; } @@ -825,9 +922,9 @@ abort_hunk() /* We found where to apply it (we hope), so do it. */ static bool -apply_hunk (after_newline, where) -bool *after_newline; -LINENUM where; +apply_hunk (outstate, where) + struct outstate *outstate; + LINENUM where; { register LINENUM old = 1; register LINENUM lastline = pch_ptrn_lines (); @@ -835,7 +932,7 @@ LINENUM where; register enum {OUTSIDE, IN_IFNDEF, IN_IFDEF, IN_ELSE} def_state = OUTSIDE; register char const *R_do_defines = do_defines; register LINENUM pat_end = pch_end (); - register FILE *fp = ofp; + register FILE *fp = outstate->ofp; where--; while (pch_char(new) == '=' || pch_char(new) == '\n') @@ -843,21 +940,23 @@ LINENUM where; while (old <= lastline) { if (pch_char(old) == '-') { - assert (*after_newline); - if (! copy_till (after_newline, where + old - 1)) + assert (outstate->after_newline); + if (! copy_till (outstate, where + old - 1)) return FALSE; if (R_do_defines) { if (def_state == OUTSIDE) { - fprintf (fp, *after_newline + if_defined, R_do_defines); + fprintf (fp, outstate->after_newline + if_defined, + R_do_defines); def_state = IN_IFNDEF; } else if (def_state == IN_IFDEF) { - fprintf (fp, *after_newline + else_defined); + fprintf (fp, outstate->after_newline + else_defined); def_state = IN_ELSE; } if (ferror (fp)) write_fatal (); - *after_newline = pch_write_line (old, fp); + outstate->after_newline = pch_write_line (old, fp); + outstate->zero_output = 0; } last_frozen_line++; old++; @@ -866,21 +965,23 @@ LINENUM where; break; } else if (pch_char(new) == '+') { - if (! copy_till (after_newline, where + old - 1)) + if (! copy_till (outstate, where + old - 1)) return FALSE; if (R_do_defines) { if (def_state == IN_IFNDEF) { - fprintf (fp, *after_newline + else_defined); + fprintf (fp, outstate->after_newline + else_defined); def_state = IN_ELSE; } else if (def_state == OUTSIDE) { - fprintf (fp, *after_newline + if_defined, R_do_defines); + fprintf (fp, outstate->after_newline + if_defined, + R_do_defines); def_state = IN_IFDEF; } if (ferror (fp)) write_fatal (); } - *after_newline = pch_write_line (new, fp); + outstate->after_newline = pch_write_line (new, fp); + outstate->zero_output = 0; new++; } else if (pch_char(new) != pch_char(old)) { @@ -892,10 +993,10 @@ LINENUM where; pch_hunk_beg() + new); } else if (pch_char(new) == '!') { - assert (*after_newline); - if (! copy_till (after_newline, where + old - 1)) + assert (outstate->after_newline); + if (! copy_till (outstate, where + old - 1)) return FALSE; - assert (*after_newline); + assert (outstate->after_newline); if (R_do_defines) { fprintf (fp, not_defined, R_do_defines); if (ferror (fp)) @@ -906,7 +1007,7 @@ LINENUM where; do { if (R_do_defines) { - *after_newline = pch_write_line (old, fp); + outstate->after_newline = pch_write_line (old, fp); } last_frozen_line++; old++; @@ -914,7 +1015,7 @@ LINENUM where; while (pch_char (old) == '!'); if (R_do_defines) { - fprintf (fp, *after_newline + else_defined); + fprintf (fp, outstate->after_newline + else_defined); if (ferror (fp)) write_fatal (); def_state = IN_ELSE; @@ -922,54 +1023,59 @@ LINENUM where; do { - *after_newline = pch_write_line (new, fp); + outstate->after_newline = pch_write_line (new, fp); new++; } while (pch_char (new) == '!'); + outstate->zero_output = 0; } else { assert(pch_char(new) == ' '); old++; new++; if (R_do_defines && def_state != OUTSIDE) { - fprintf (fp, *after_newline + end_defined, R_do_defines); + fprintf (fp, outstate->after_newline + end_defined, + R_do_defines); if (ferror (fp)) write_fatal (); - *after_newline = TRUE; + outstate->after_newline = 1; def_state = OUTSIDE; } } } if (new <= pat_end && pch_char(new) == '+') { - if (! copy_till (after_newline, where + old - 1)) + if (! copy_till (outstate, where + old - 1)) return FALSE; if (R_do_defines) { if (def_state == OUTSIDE) { - fprintf (fp, *after_newline + if_defined, R_do_defines); + fprintf (fp, outstate->after_newline + if_defined, + R_do_defines); def_state = IN_IFDEF; } else if (def_state == IN_IFNDEF) { - fprintf (fp, *after_newline + else_defined); + fprintf (fp, outstate->after_newline + else_defined); def_state = IN_ELSE; } if (ferror (fp)) write_fatal (); + outstate->zero_output = 0; } do { - if (!*after_newline && putc ('\n', fp) == EOF) + if (! outstate->after_newline && putc ('\n', fp) == EOF) write_fatal (); - *after_newline = pch_write_line (new, fp); + outstate->after_newline = pch_write_line (new, fp); + outstate->zero_output = 0; new++; } while (new <= pat_end && pch_char (new) == '+'); } if (R_do_defines && def_state != OUTSIDE) { - fprintf (fp, *after_newline + end_defined, R_do_defines); + fprintf (fp, outstate->after_newline + end_defined, R_do_defines); if (ferror (fp)) write_fatal (); - *after_newline = TRUE; + outstate->after_newline = 1; } return TRUE; } @@ -990,10 +1096,13 @@ create_output_file (name) /* Open the new file. */ static void -init_output(name) +init_output (name, outstate) char const *name; + struct outstate *outstate; { - ofp = create_output_file (name); + outstate->ofp = name ? create_output_file (name) : (FILE *) 0; + outstate->after_newline = 1; + outstate->zero_output = 1; } /* Open a file to put hunks we can't locate. */ @@ -1008,12 +1117,12 @@ init_reject(name) /* Copy input file to output, up to wherever hunk is to be applied. */ static bool -copy_till (after_newline, lastline) - register bool *after_newline; +copy_till (outstate, lastline) + register struct outstate *outstate; register LINENUM lastline; { register LINENUM R_last_frozen_line = last_frozen_line; - register FILE *fp = ofp; + register FILE *fp = outstate->ofp; register char const *s; size_t size; @@ -1027,10 +1136,11 @@ copy_till (after_newline, lastline) s = ifetch (++R_last_frozen_line, 0, &size); if (size) { - if ((!*after_newline && putc ('\n', fp) == EOF) + if ((! outstate->after_newline && putc ('\n', fp) == EOF) || ! fwrite (s, sizeof *s, size, fp)) write_fatal (); - *after_newline = s[size - 1] == '\n'; + outstate->after_newline = s[size - 1] == '\n'; + outstate->zero_output = 0; } } last_frozen_line = R_last_frozen_line; @@ -1040,21 +1150,21 @@ copy_till (after_newline, lastline) /* Finish copying the input file to the output file. */ static bool -spew_output (after_newline) - bool *after_newline; +spew_output (outstate) + struct outstate *outstate; { if (debug & 256) say ("il=%ld lfl=%ld\n", input_lines, last_frozen_line); if (last_frozen_line < input_lines) - if (! copy_till (after_newline, input_lines)) + if (! copy_till (outstate, input_lines)) return FALSE; - if (ofp && !output) + if (outstate->ofp && ! outfile) { - if (fclose (ofp) != 0) + if (fclose (outstate->ofp) != 0) write_fatal (); - ofp = 0; + outstate->ofp = 0; } return TRUE; |