version 1.23, 2003/07/22 17:18:49 |
version 1.24, 2003/07/22 20:17:06 |
|
|
|
|
#include <assert.h> |
#include <assert.h> |
#include <ctype.h> |
#include <ctype.h> |
|
#include <getopt.h> |
#include <string.h> |
#include <string.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
|
|
|
static void dump_line(LINENUM); |
static void dump_line(LINENUM); |
static bool patch_match(LINENUM, LINENUM, LINENUM); |
static bool patch_match(LINENUM, LINENUM, LINENUM); |
static bool similar(char *, char *, int); |
static bool similar(char *, char *, int); |
static int optcmp(const void *, const void *); |
static __dead void usage(void); |
static char decode_long_option(char *); |
|
|
|
/* TRUE if -E was specified on command line. */ |
/* TRUE if -E was specified on command line. */ |
static int remove_empty_files = FALSE; |
static int remove_empty_files = FALSE; |
|
|
skip_rest_of_patch = FALSE; |
skip_rest_of_patch = FALSE; |
|
|
get_some_switches(); |
get_some_switches(); |
|
|
if (filec >= 2) |
|
fatal("you may not change to a different patch file\n"); |
|
} |
} |
|
|
static char * |
/* Process switches and filenames. */ |
nextarg(void) |
|
{ |
|
if (!--Argc) |
|
fatal("missing argument after `%s'\n", *Argv); |
|
return *++Argv; |
|
} |
|
|
|
/* Module for handling of long options. */ |
|
|
|
struct option { |
|
char *long_opt; |
|
char short_opt; |
|
}; |
|
|
|
static int |
|
optcmp(const void *v1, const void *v2) |
|
{ |
|
const struct option *a = v1, *b = v2; |
|
|
|
return strcmp(a->long_opt, b->long_opt); |
|
} |
|
|
|
/* Decode Long options beginning with "--" to their short equivalents. */ |
|
|
|
static char |
|
decode_long_option(char *opt) |
|
{ |
|
/* |
|
* This table must be sorted on the first field. We also decode |
|
* unimplemented options as those will be handled later anyway. |
|
*/ |
|
static struct option options[] = { |
|
{"batch", 't'}, |
|
{"check", 'C'}, |
|
{"context", 'c'}, |
|
{"debug", 'x'}, |
|
{"directory", 'd'}, |
|
{"ed", 'e'}, |
|
{"force", 'f'}, |
|
{"forward", 'N'}, |
|
{"fuzz", 'F'}, |
|
{"ifdef", 'D'}, |
|
{"ignore-whitespace", 'l'}, |
|
{"normal", 'n'}, |
|
{"output", 'o'}, |
|
{"prefix", 'B'}, |
|
{"quiet", 's'}, |
|
{"reject-file", 'r'}, |
|
{"remove-empty-files", 'E'}, |
|
{"reverse", 'R'}, |
|
{"silent", 's'}, |
|
{"skip", 'S'}, |
|
{"strip", 'p'}, |
|
{"suffix", 'b'}, |
|
{"unified", 'u'}, |
|
{"version", 'v'}, |
|
{"version-control", 'V'}, |
|
}; |
|
struct option key, *found; |
|
|
|
key.long_opt = opt; |
|
found = (struct option *) bsearch(&key, options, |
|
sizeof(options) / sizeof(options[0]), |
|
sizeof(options[0]), optcmp); |
|
return found ? found->short_opt : '\0'; |
|
} |
|
|
|
/* Process switches and filenames up to next '+' or end of list. */ |
|
|
|
static void |
static void |
get_some_switches(void) |
get_some_switches(void) |
{ |
{ |
char *s; |
const char *options = "b:B:cCd:D:eEfF:lnNo:p::r:RstuvV:x:"; |
|
static struct option longopts[] = { |
|
{"batch", no_argument, 0, 't'}, |
|
{"check", no_argument, 0, 'C'}, |
|
{"context", no_argument, 0, 'c'}, |
|
{"debug", required_argument, 0, 'x'}, |
|
{"directory", required_argument, 0, 'd'}, |
|
{"ed", no_argument, 0, 'e'}, |
|
{"force", no_argument, 0, 'f'}, |
|
{"forward", no_argument, 0, 'N'}, |
|
{"fuzz", required_argument, 0, 'F'}, |
|
{"ifdef", required_argument, 0, 'D'}, |
|
{"ignore-whitespace", no_argument, 0, 'l'}, |
|
{"normal", no_argument, 0, 'n'}, |
|
{"output", required_argument, 0, 'o'}, |
|
{"prefix", required_argument, 0, 'B'}, |
|
{"quiet", no_argument, 0, 's'}, |
|
{"reject-file", required_argument, 0, 'r'}, |
|
{"remove-empty-files", no_argument, 0, 'E'}, |
|
{"reverse", no_argument, 0, 'R'}, |
|
{"silent", no_argument, 0, 's'}, |
|
{"strip", optional_argument, 0, 'p'}, |
|
{"suffix", required_argument, 0, 'b'}, |
|
{"unified", no_argument, 0, 'u'}, |
|
{"version", no_argument, 0, 'v'}, |
|
{"version-control", required_argument, 0, 'V'}, |
|
{NULL, 0, 0, 0} |
|
}; |
|
int ch; |
|
|
rejname[0] = '\0'; |
rejname[0] = '\0'; |
Argc_last = Argc; |
Argc_last = Argc; |
Argv_last = Argv; |
Argv_last = Argv; |
if (!Argc) |
if (!Argc) |
return; |
return; |
for (Argc--, Argv++; Argc; Argc--, Argv++) { |
optreset = optind = 1; |
s = Argv[0]; |
while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) { |
if (strEQ(s, "+")) { |
switch (ch) { |
return; /* + will be skipped by for loop */ |
case 'b': |
} |
simple_backup_suffix = savestr(optarg); |
if (*s != '-' || !s[1]) { |
break; |
if (filec == MAXFILEC) |
case 'B': |
fatal("too many file arguments\n"); |
origprae = savestr(optarg); |
filearg[filec++] = savestr(s); |
break; |
} else { |
case 'c': |
char opt; |
diff_type = CONTEXT_DIFF; |
|
break; |
if (*(s + 1) == '-') { |
case 'C': |
opt = decode_long_option(s + 2); |
check_only = TRUE; |
s += strlen(s) - 1; |
break; |
} else |
case 'd': |
opt = *++s; |
if (chdir(optarg) < 0) |
switch (opt) { |
pfatal("can't cd to %s", optarg); |
case 'b': |
break; |
simple_backup_suffix = savestr(nextarg()); |
case 'D': |
break; |
do_defines = TRUE; |
case 'B': |
if (!isalpha(*optarg) && *optarg != '_') |
origprae = savestr(nextarg()); |
fatal("argument to -D is not an identifier\n"); |
break; |
snprintf(if_defined, sizeof if_defined, |
case 'c': |
"#ifdef %s\n", optarg); |
diff_type = CONTEXT_DIFF; |
snprintf(not_defined, sizeof not_defined, |
break; |
"#ifndef %s\n", optarg); |
case 'C': |
snprintf(end_defined, sizeof end_defined, |
check_only = TRUE; |
"#endif /* %s */\n", optarg); |
break; |
break; |
case 'd': |
case 'e': |
if (!*++s) |
diff_type = ED_DIFF; |
s = nextarg(); |
break; |
if (chdir(s) < 0) |
case 'E': |
pfatal("can't cd to %s", s); |
remove_empty_files = TRUE; |
break; |
break; |
case 'D': |
case 'f': |
do_defines = TRUE; |
force = TRUE; |
if (!*++s) |
break; |
s = nextarg(); |
case 'F': |
if (!isalpha(*s) && '_' != *s) |
maxfuzz = atoi(optarg); |
fatal("argument to -D is not an identifier\n"); |
break; |
snprintf(if_defined, sizeof if_defined, |
case 'l': |
"#ifdef %s\n", s); |
canonicalize = TRUE; |
snprintf(not_defined, sizeof not_defined, |
break; |
"#ifndef %s\n", s); |
case 'n': |
snprintf(end_defined, sizeof end_defined, |
diff_type = NORMAL_DIFF; |
"#endif /* %s */\n", s); |
break; |
break; |
case 'N': |
case 'e': |
noreverse = TRUE; |
diff_type = ED_DIFF; |
break; |
break; |
case 'o': |
case 'E': |
outname = savestr(optarg); |
remove_empty_files = TRUE; |
break; |
break; |
case 'p': |
case 'f': |
strippath = optarg ? atoi(optarg) : 0; |
force = TRUE; |
break; |
break; |
case 'r': |
case 'F': |
if (strlcpy(rejname, optarg, |
if (!*++s) |
sizeof(rejname)) >= sizeof(rejname)) |
s = nextarg(); |
fatal("argument for -r is too long\n"); |
else if (*s == '=') |
break; |
s++; |
case 'R': |
maxfuzz = atoi(s); |
reverse = TRUE; |
break; |
reverse_flag_specified = TRUE; |
case 'l': |
break; |
canonicalize = TRUE; |
case 's': |
break; |
verbose = FALSE; |
case 'n': |
break; |
diff_type = NORMAL_DIFF; |
case 't': |
break; |
batch = TRUE; |
case 'N': |
break; |
noreverse = TRUE; |
case 'u': |
break; |
diff_type = UNI_DIFF; |
case 'o': |
break; |
outname = savestr(nextarg()); |
case 'v': |
break; |
version(); |
case 'p': |
break; |
if (!*++s) |
case 'V': |
s = nextarg(); |
backup_type = get_version(optarg); |
else if (*s == '=') |
break; |
s++; |
|
strippath = atoi(s); |
|
break; |
|
case 'r': |
|
if (strlcpy(rejname, nextarg(), |
|
sizeof(rejname)) >= sizeof(rejname)) |
|
fatal("argument for -r is too long\n"); |
|
break; |
|
case 'R': |
|
reverse = TRUE; |
|
reverse_flag_specified = TRUE; |
|
break; |
|
case 's': |
|
verbose = FALSE; |
|
break; |
|
case 'S': |
|
skip_rest_of_patch = TRUE; |
|
break; |
|
case 't': |
|
batch = TRUE; |
|
break; |
|
case 'u': |
|
diff_type = UNI_DIFF; |
|
break; |
|
case 'v': |
|
version(); |
|
break; |
|
case 'V': |
|
backup_type = get_version(nextarg()); |
|
break; |
|
#ifdef DEBUGGING |
#ifdef DEBUGGING |
case 'x': |
case 'x': |
if (!*++s) |
debug = atoi(optarg); |
s = nextarg(); |
break; |
debug = atoi(s); |
|
break; |
|
#endif |
#endif |
default: |
default: |
fprintf(stderr, "patch: unrecognized option `%s'\n", |
usage(); |
Argv[0]); |
break; |
fprintf(stderr, "\ |
|
Usage: patch [options] [origfile [patchfile]] [+ [options] [origfile]]...\n\ |
|
Options:\n\ |
|
[-cCeEflnNRsStuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n\ |
|
[-D symbol] [-Fmax-fuzz] [-o out-file] [-p[strip-count]]\n\ |
|
[-r rej-name] [-V {numbered,existing,simple}]\n"); |
|
my_exit(1); |
|
} |
|
} |
} |
} |
} |
|
Argc -= optind; |
|
Argv += optind; |
|
|
|
while (Argc > 0) { |
|
if (filec == MAXFILEC) |
|
fatal("too many file arguments\n"); |
|
filearg[filec++] = savestr(*Argv++); |
|
Argc--; |
|
} |
|
} |
|
|
|
static __dead void |
|
usage(void) |
|
{ |
|
fprintf(stderr, |
|
"usage: patch [-cCeEflnNRstuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n" |
|
" [-D symbol] [-Fmax-fuzz] [-o out-file] [-p[strip-count]]\n" |
|
" [-r rej-name] [-V {numbered,existing,simple}]\n" |
|
" [origfile [patchfile]]\n"); |
|
my_exit(1); |
} |
} |
|
|
/* |
/* |