Browse Source
Upgraded the lib to use PHP memory allocation routines.
Upgraded the lib to use PHP memory allocation routines.
Fixed a crash caused by analysis of DEADJOE files A little bit of CS inside libmagicPECL
12 changed files with 132 additions and 1305 deletions
-
181ext/fileinfo/libmagic/apprentice.c
-
21ext/fileinfo/libmagic/ascmagic.c
-
19ext/fileinfo/libmagic/compress.c
-
11ext/fileinfo/libmagic/config.h
-
481ext/fileinfo/libmagic/file.c
-
7ext/fileinfo/libmagic/file.h
-
48ext/fileinfo/libmagic/file_opts.h
-
48ext/fileinfo/libmagic/funcs.c
-
482ext/fileinfo/libmagic/getopt_long.c
-
39ext/fileinfo/libmagic/magic.c
-
14ext/fileinfo/libmagic/readelf.c
-
86ext/fileinfo/libmagic/softmagic.c
@ -1,10 +1 @@ |
|||
#ifdef PHP_WIN32 |
|||
# include "config.w32.h" |
|||
#else |
|||
# include <php_config.h> |
|||
#endif |
|||
|
|||
#ifdef HAVE_CONFIG_H |
|||
#include "../config.h" |
|||
#endif |
|||
#define PHP_BUNDLE |
|||
#include "php.h" |
|||
@ -1,481 +0,0 @@ |
|||
/* |
|||
* Copyright (c) Ian F. Darwin 1986-1995. |
|||
* Software written by Ian F. Darwin and others; |
|||
* maintained 1995-present by Christos Zoulas and others. |
|||
* |
|||
* Redistribution and use in source and binary forms, with or without |
|||
* modification, are permitted provided that the following conditions |
|||
* are met: |
|||
* 1. Redistributions of source code must retain the above copyright |
|||
* notice immediately at the beginning of the file, without modification, |
|||
* this list of conditions, and the following disclaimer. |
|||
* 2. Redistributions in binary form must reproduce the above copyright |
|||
* notice, this list of conditions and the following disclaimer in the |
|||
* documentation and/or other materials provided with the distribution. |
|||
* |
|||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
|||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR |
|||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|||
* SUCH DAMAGE. |
|||
*/ |
|||
/* |
|||
* file - find type of a file or files - main program. |
|||
*/ |
|||
|
|||
#include "file.h" |
|||
#include "magic.h" |
|||
|
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <unistd.h> |
|||
#include <string.h> |
|||
#include <sys/types.h> |
|||
#include <sys/param.h> /* for MAXPATHLEN */ |
|||
#include <sys/stat.h> |
|||
#ifdef RESTORE_TIME |
|||
# if (__COHERENT__ >= 0x420) |
|||
# include <sys/utime.h> |
|||
# else |
|||
# ifdef USE_UTIMES |
|||
# include <sys/time.h> |
|||
# else |
|||
# include <utime.h> |
|||
# endif |
|||
# endif |
|||
#endif |
|||
#ifdef HAVE_UNISTD_H |
|||
#include <unistd.h> /* for read() */ |
|||
#endif |
|||
#ifdef HAVE_LOCALE_H |
|||
#include <locale.h> |
|||
#endif |
|||
#ifdef HAVE_WCHAR_H |
|||
#include <wchar.h> |
|||
#endif |
|||
|
|||
#include <getopt.h> |
|||
#ifndef HAVE_GETOPT_LONG |
|||
int getopt_long(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex); |
|||
#endif |
|||
|
|||
#include <netinet/in.h> /* for byte swapping */ |
|||
|
|||
#include "patchlevel.h" |
|||
|
|||
#ifndef lint |
|||
FILE_RCSID("@(#)$File: file.c,v 1.119 2008/02/07 00:58:52 christos Exp $") |
|||
#endif /* lint */ |
|||
|
|||
|
|||
#ifdef S_IFLNK |
|||
#define SYMLINKFLAG "Lh" |
|||
#else |
|||
#define SYMLINKFLAG "" |
|||
#endif |
|||
|
|||
# define USAGE "Usage: %s [-bcik" SYMLINKFLAG "nNrsvz0] [-e test] [-f namefile] [-F separator] [-m magicfiles] file...\n %s -C -m magicfiles\n" |
|||
|
|||
#ifndef MAXPATHLEN |
|||
#define MAXPATHLEN 512 |
|||
#endif |
|||
|
|||
private int /* Global command-line options */ |
|||
bflag = 0, /* brief output format */ |
|||
nopad = 0, /* Don't pad output */ |
|||
nobuffer = 0, /* Do not buffer stdout */ |
|||
nulsep = 0; /* Append '\0' to the separator */ |
|||
|
|||
private const char *magicfile = 0; /* where the magic is */ |
|||
private const char *default_magicfile = MAGIC; |
|||
private const char *separator = ":"; /* Default field separator */ |
|||
|
|||
private char *progname; /* used throughout */ |
|||
|
|||
private struct magic_set *magic; |
|||
|
|||
private void unwrap(char *); |
|||
private void usage(void); |
|||
private void help(void); |
|||
|
|||
int main(int, char *[]); |
|||
private void process(const char *, int); |
|||
private void load(const char *, int); |
|||
|
|||
|
|||
/* |
|||
* main - parse arguments and handle options |
|||
*/ |
|||
int |
|||
main(int argc, char *argv[]) |
|||
{ |
|||
int c; |
|||
size_t i; |
|||
int action = 0, didsomefiles = 0, errflg = 0; |
|||
int flags = 0; |
|||
char *home, *usermagic; |
|||
struct stat sb; |
|||
static const char hmagic[] = "/.magic"; |
|||
#define OPTSTRING "bcCde:f:F:hikLm:nNprsvz0" |
|||
int longindex; |
|||
static const struct option long_options[] = |
|||
{ |
|||
#define OPT(shortname, longname, opt, doc) \ |
|||
{longname, opt, NULL, shortname}, |
|||
#define OPT_LONGONLY(longname, opt, doc) \ |
|||
{longname, opt, NULL, 0}, |
|||
#include "file_opts.h" |
|||
#undef OPT |
|||
#undef OPT_LONGONLY |
|||
{0, 0, NULL, 0} |
|||
}; |
|||
|
|||
static const struct { |
|||
const char *name; |
|||
int value; |
|||
} nv[] = { |
|||
{ "apptype", MAGIC_NO_CHECK_APPTYPE }, |
|||
{ "ascii", MAGIC_NO_CHECK_ASCII }, |
|||
{ "compress", MAGIC_NO_CHECK_COMPRESS }, |
|||
{ "elf", MAGIC_NO_CHECK_ELF }, |
|||
{ "soft", MAGIC_NO_CHECK_SOFT }, |
|||
{ "tar", MAGIC_NO_CHECK_TAR }, |
|||
{ "tokens", MAGIC_NO_CHECK_TOKENS }, |
|||
}; |
|||
|
|||
/* makes islower etc work for other langs */ |
|||
(void)setlocale(LC_CTYPE, ""); |
|||
|
|||
#ifdef __EMX__ |
|||
/* sh-like wildcard expansion! Shouldn't hurt at least ... */ |
|||
_wildcard(&argc, &argv); |
|||
#endif |
|||
|
|||
if ((progname = strrchr(argv[0], '/')) != NULL) |
|||
progname++; |
|||
else |
|||
progname = argv[0]; |
|||
|
|||
magicfile = default_magicfile; |
|||
if ((usermagic = getenv("MAGIC")) != NULL) |
|||
magicfile = usermagic; |
|||
else |
|||
if ((home = getenv("HOME")) != NULL) { |
|||
if ((usermagic = malloc(strlen(home) |
|||
+ sizeof(hmagic))) != NULL) { |
|||
(void)strcpy(usermagic, home); |
|||
(void)strcat(usermagic, hmagic); |
|||
if (stat(usermagic, &sb)<0) |
|||
free(usermagic); |
|||
else |
|||
magicfile = usermagic; |
|||
} |
|||
} |
|||
|
|||
#ifdef S_IFLNK |
|||
flags |= getenv("POSIXLY_CORRECT") ? MAGIC_SYMLINK : 0; |
|||
#endif |
|||
while ((c = getopt_long(argc, argv, OPTSTRING, long_options, |
|||
&longindex)) != -1) |
|||
switch (c) { |
|||
case 0 : |
|||
switch (longindex) { |
|||
case 0: |
|||
help(); |
|||
break; |
|||
case 10: |
|||
flags |= MAGIC_MIME_TYPE; |
|||
break; |
|||
case 11: |
|||
flags |= MAGIC_MIME_ENCODING; |
|||
break; |
|||
} |
|||
break; |
|||
case '0': |
|||
nulsep = 1; |
|||
break; |
|||
case 'b': |
|||
bflag++; |
|||
break; |
|||
case 'c': |
|||
action = FILE_CHECK; |
|||
break; |
|||
case 'C': |
|||
action = FILE_COMPILE; |
|||
break; |
|||
case 'd': |
|||
flags |= MAGIC_DEBUG|MAGIC_CHECK; |
|||
break; |
|||
case 'e': |
|||
for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) |
|||
if (strcmp(nv[i].name, optarg) == 0) |
|||
break; |
|||
|
|||
if (i == sizeof(nv) / sizeof(nv[0])) |
|||
errflg++; |
|||
else |
|||
flags |= nv[i].value; |
|||
break; |
|||
|
|||
case 'f': |
|||
if(action) |
|||
usage(); |
|||
load(magicfile, flags); |
|||
unwrap(optarg); |
|||
++didsomefiles; |
|||
break; |
|||
case 'F': |
|||
separator = optarg; |
|||
break; |
|||
case 'i': |
|||
flags |= MAGIC_MIME; |
|||
break; |
|||
case 'k': |
|||
flags |= MAGIC_CONTINUE; |
|||
break; |
|||
case 'm': |
|||
magicfile = optarg; |
|||
break; |
|||
case 'n': |
|||
++nobuffer; |
|||
break; |
|||
case 'N': |
|||
++nopad; |
|||
break; |
|||
#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) |
|||
case 'p': |
|||
flags |= MAGIC_PRESERVE_ATIME; |
|||
break; |
|||
#endif |
|||
case 'r': |
|||
flags |= MAGIC_RAW; |
|||
break; |
|||
case 's': |
|||
flags |= MAGIC_DEVICES; |
|||
break; |
|||
case 'v': |
|||
(void)fprintf(stderr, "%s-%d.%.2d\n", progname, |
|||
FILE_VERSION_MAJOR, patchlevel); |
|||
(void)fprintf(stderr, "magic file from %s\n", |
|||
magicfile); |
|||
return 1; |
|||
case 'z': |
|||
flags |= MAGIC_COMPRESS; |
|||
break; |
|||
#ifdef S_IFLNK |
|||
case 'L': |
|||
flags |= MAGIC_SYMLINK; |
|||
break; |
|||
case 'h': |
|||
flags &= ~MAGIC_SYMLINK; |
|||
break; |
|||
#endif |
|||
case '?': |
|||
default: |
|||
errflg++; |
|||
break; |
|||
} |
|||
|
|||
if (errflg) { |
|||
usage(); |
|||
} |
|||
|
|||
switch(action) { |
|||
case FILE_CHECK: |
|||
case FILE_COMPILE: |
|||
magic = magic_open(flags|MAGIC_CHECK); |
|||
if (magic == NULL) { |
|||
(void)fprintf(stderr, "%s: %s\n", progname, |
|||
strerror(errno)); |
|||
return 1; |
|||
} |
|||
c = action == FILE_CHECK ? magic_check(magic, magicfile) : |
|||
magic_compile(magic, magicfile); |
|||
if (c == -1) { |
|||
(void)fprintf(stderr, "%s: %s\n", progname, |
|||
magic_error(magic)); |
|||
return -1; |
|||
} |
|||
return 0; |
|||
default: |
|||
load(magicfile, flags); |
|||
break; |
|||
} |
|||
|
|||
if (optind == argc) { |
|||
if (!didsomefiles) { |
|||
usage(); |
|||
} |
|||
} |
|||
else { |
|||
size_t j, wid, nw; |
|||
for (wid = 0, j = (size_t)optind; j < (size_t)argc; j++) { |
|||
nw = file_mbswidth(argv[j]); |
|||
if (nw > wid) |
|||
wid = nw; |
|||
} |
|||
/* |
|||
* If bflag is only set twice, set it depending on |
|||
* number of files [this is undocumented, and subject to change] |
|||
*/ |
|||
if (bflag == 2) { |
|||
bflag = optind >= argc - 1; |
|||
} |
|||
for (; optind < argc; optind++) |
|||
process(argv[optind], wid); |
|||
} |
|||
|
|||
c = magic->haderr ? 1 : 0; |
|||
magic_close(magic); |
|||
return c; |
|||
} |
|||
|
|||
|
|||
private void |
|||
/*ARGSUSED*/ |
|||
load(const char *m, int flags) |
|||
{ |
|||
if (magic || m == NULL) |
|||
return; |
|||
magic = magic_open(flags); |
|||
if (magic == NULL) { |
|||
(void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); |
|||
exit(1); |
|||
} |
|||
if (magic_load(magic, magicfile) == -1) { |
|||
(void)fprintf(stderr, "%s: %s\n", |
|||
progname, magic_error(magic)); |
|||
exit(1); |
|||
} |
|||
} |
|||
|
|||
/* |
|||
* unwrap -- read a file of filenames, do each one. |
|||
*/ |
|||
private void |
|||
unwrap(char *fn) |
|||
{ |
|||
char buf[MAXPATHLEN]; |
|||
FILE *f; |
|||
int wid = 0, cwid; |
|||
|
|||
if (strcmp("-", fn) == 0) { |
|||
f = stdin; |
|||
wid = 1; |
|||
} else { |
|||
if ((f = fopen(fn, "r")) == NULL) { |
|||
(void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", |
|||
progname, fn, strerror(errno)); |
|||
exit(1); |
|||
} |
|||
|
|||
while (fgets(buf, MAXPATHLEN, f) != NULL) { |
|||
buf[strcspn(buf, "\n")] = '\0'; |
|||
cwid = file_mbswidth(buf); |
|||
if (cwid > wid) |
|||
wid = cwid; |
|||
} |
|||
|
|||
rewind(f); |
|||
} |
|||
|
|||
while (fgets(buf, sizeof(buf), f) != NULL) { |
|||
buf[strcspn(buf, "\n")] = '\0'; |
|||
process(buf, wid); |
|||
if(nobuffer) |
|||
(void)fflush(stdout); |
|||
} |
|||
|
|||
(void)fclose(f); |
|||
} |
|||
|
|||
/* |
|||
* Called for each input file on the command line (or in a list of files) |
|||
*/ |
|||
private void |
|||
process(const char *inname, int wid) |
|||
{ |
|||
const char *type; |
|||
int std_in = strcmp(inname, "-") == 0; |
|||
|
|||
if (wid > 0 && !bflag) { |
|||
(void)printf("%s", std_in ? "/dev/stdin" : inname); |
|||
if (nulsep) |
|||
(void)putc('\0', stdout); |
|||
else |
|||
(void)printf("%s", separator); |
|||
(void)printf("%*s ", |
|||
(int) (nopad ? 0 : (wid - file_mbswidth(inname))), ""); |
|||
} |
|||
|
|||
type = magic_file(magic, std_in ? NULL : inname); |
|||
if (type == NULL) |
|||
(void)printf("ERROR: %s\n", magic_error(magic)); |
|||
else |
|||
(void)printf("%s\n", type); |
|||
} |
|||
|
|||
size_t |
|||
file_mbswidth(const char *s) |
|||
{ |
|||
#if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) |
|||
size_t bytesconsumed, old_n, n, width = 0; |
|||
mbstate_t state; |
|||
wchar_t nextchar; |
|||
(void)memset(&state, 0, sizeof(mbstate_t)); |
|||
old_n = n = strlen(s); |
|||
|
|||
while (n > 0) { |
|||
bytesconsumed = mbrtowc(&nextchar, s, n, &state); |
|||
if (bytesconsumed == (size_t)(-1) || |
|||
bytesconsumed == (size_t)(-2)) { |
|||
/* Something went wrong, return something reasonable */ |
|||
return old_n; |
|||
} |
|||
if (s[0] == '\n') { |
|||
/* |
|||
* do what strlen() would do, so that caller |
|||
* is always right |
|||
*/ |
|||
width++; |
|||
} else |
|||
width += wcwidth(nextchar); |
|||
|
|||
s += bytesconsumed, n -= bytesconsumed; |
|||
} |
|||
return width; |
|||
#else |
|||
return strlen(s); |
|||
#endif |
|||
} |
|||
|
|||
private void |
|||
usage(void) |
|||
{ |
|||
(void)fprintf(stderr, USAGE, progname, progname); |
|||
(void)fputs("Try `file --help' for more information.\n", stderr); |
|||
exit(1); |
|||
} |
|||
|
|||
private void |
|||
help(void) |
|||
{ |
|||
(void)fputs( |
|||
"Usage: file [OPTION...] [FILE...]\n" |
|||
"Determine type of FILEs.\n" |
|||
"\n", stderr); |
|||
#define OPT(shortname, longname, opt, doc) \ |
|||
fprintf(stderr, " -%c, --" longname doc, shortname); |
|||
#define OPT_LONGONLY(longname, opt, doc) \ |
|||
fprintf(stderr, " --" longname doc); |
|||
#include "file_opts.h" |
|||
#undef OPT |
|||
#undef OPT_LONGONLY |
|||
exit(0); |
|||
} |
|||
@ -1,48 +0,0 @@ |
|||
/* |
|||
* Table of command-line options |
|||
* |
|||
* The first column specifies the short name, if any, or 0 if none. |
|||
* The second column specifies the long name. |
|||
* The third column specifies whether it takes a parameter. |
|||
* The fourth column is the documentation. |
|||
* |
|||
* N.B. The long options' order must correspond to the code in file.c, |
|||
* and OPTSTRING must be kept up-to-date with the short options. |
|||
* Pay particular attention to the numbers of long-only options in the |
|||
* switch statement! |
|||
*/ |
|||
|
|||
OPT_LONGONLY("help", 0, " display this help and exit\n") |
|||
OPT('v', "version", 0, " output version information and exit\n") |
|||
OPT('m', "magic-file", 1, " LIST use LIST as a colon-separated list of magic\n" |
|||
" number files\n") |
|||
OPT('z', "uncompress", 0, " try to look inside compressed files\n") |
|||
OPT('b', "brief", 0, " do not prepend filenames to output lines\n") |
|||
OPT('c', "checking-printout", 0, " print the parsed form of the magic file, use in\n" |
|||
" conjunction with -m to debug a new magic file\n" |
|||
" before installing it\n") |
|||
OPT('e', "exclude", 1, " TEST exclude TEST from the list of test to be\n" |
|||
" performed for file. Valid tests are:\n" |
|||
" ascii, apptype, compress, elf, soft, tar, tokens, troff\n") |
|||
OPT('f', "files-from", 1, " FILE read the filenames to be examined from FILE\n") |
|||
OPT('F', "separator", 1, " STRING use string as separator instead of `:'\n") |
|||
OPT('i', "mime", 0, " output MIME type strings (--mime-type and\n" |
|||
" --mime-encoding)\n") |
|||
OPT_LONGONLY("mime-type", 0, " output the MIME type\n") |
|||
OPT_LONGONLY("mime-encoding", 0, " output the MIME encoding\n") |
|||
OPT('k', "keep-going", 0, " don't stop at the first match\n") |
|||
#ifdef S_IFLNK |
|||
OPT('L', "dereference", 0, " follow symlinks (default)\n") |
|||
OPT('h', "no-dereference", 0, " don't follow symlinks\n") |
|||
#endif |
|||
OPT('n', "no-buffer", 0, " do not buffer output\n") |
|||
OPT('N', "no-pad", 0, " do not pad output\n") |
|||
OPT('0', "print0", 0, " terminate filenames with ASCII NUL\n") |
|||
#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) |
|||
OPT('p', "preserve-date", 0, " preserve access times on files\n") |
|||
#endif |
|||
OPT('r', "raw", 0, " don't translate unprintable chars to \\ooo\n") |
|||
OPT('s', "special-files", 0, " treat special (block/char devices) files as\n" |
|||
" ordinary ones\n") |
|||
OPT('C', "compile", 0, " compile file specified by -m\n") |
|||
OPT('d', "debug", 0, " print debugging messages\n") |
|||
@ -1,482 +0,0 @@ |
|||
/* $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $ */ |
|||
|
|||
/*- |
|||
* Copyright (c) 2000 The NetBSD Foundation, Inc. |
|||
* All rights reserved. |
|||
* |
|||
* This code is derived from software contributed to The NetBSD Foundation |
|||
* by Dieter Baron and Thomas Klausner. |
|||
* |
|||
* Redistribution and use in source and binary forms, with or without |
|||
* modification, are permitted provided that the following conditions |
|||
* are met: |
|||
* 1. Redistributions of source code must retain the above copyright |
|||
* notice, this list of conditions and the following disclaimer. |
|||
* 2. Redistributions in binary form must reproduce the above copyright |
|||
* notice, this list of conditions and the following disclaimer in the |
|||
* documentation and/or other materials provided with the distribution. |
|||
* |
|||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
|||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
|||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
|||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|||
* POSSIBILITY OF SUCH DAMAGE. |
|||
*/ |
|||
|
|||
#include <assert.h> |
|||
#include <err.h> |
|||
#include <errno.h> |
|||
#include <getopt.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#define REPLACE_GETOPT |
|||
|
|||
#define _DIAGASSERT assert |
|||
|
|||
#ifdef REPLACE_GETOPT |
|||
#ifdef __weak_alias |
|||
__weak_alias(getopt,_getopt) |
|||
#endif |
|||
int opterr = 1; /* if error message should be printed */ |
|||
int optind = 1; /* index into parent argv vector */ |
|||
int optopt = '?'; /* character checked for validity */ |
|||
int optreset; /* reset getopt */ |
|||
char *optarg; /* argument associated with option */ |
|||
#elif HAVE_NBTOOL_CONFIG_H && !HAVE_DECL_OPTRESET |
|||
static int optreset; |
|||
#endif |
|||
|
|||
#ifdef __weak_alias |
|||
__weak_alias(getopt_long,_getopt_long) |
|||
#endif |
|||
|
|||
#define IGNORE_FIRST (*options == '-' || *options == '+') |
|||
#define PRINT_ERROR ((opterr) && ((*options != ':') \ |
|||
|| (IGNORE_FIRST && options[1] != ':'))) |
|||
#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) |
|||
#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) |
|||
/* XXX: GNU ignores PC if *options == '-' */ |
|||
#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') |
|||
|
|||
/* return values */ |
|||
#define BADCH (int)'?' |
|||
#define BADARG ((IGNORE_FIRST && options[1] == ':') \ |
|||
|| (*options == ':') ? (int)':' : (int)'?') |
|||
#define INORDER (int)1 |
|||
|
|||
#define EMSG "" |
|||
|
|||
static int getopt_internal __P((int, char **, const char *)); |
|||
static int gcd __P((int, int)); |
|||
static void permute_args __P((int, int, int, char **)); |
|||
|
|||
static const char *place = EMSG; /* option letter processing */ |
|||
|
|||
/* XXX: set optreset to 1 rather than these two */ |
|||
static int nonopt_start = -1; /* first non option argument (for permute) */ |
|||
static int nonopt_end = -1; /* first option after non options (for permute) */ |
|||
|
|||
/* Error messages */ |
|||
static const char recargchar[] = "option requires an argument -- %c"; |
|||
static const char recargstring[] = "option requires an argument -- %s"; |
|||
static const char ambig[] = "ambiguous option -- %.*s"; |
|||
static const char noarg[] = "option doesn't take an argument -- %.*s"; |
|||
static const char illoptchar[] = "unknown option -- %c"; |
|||
static const char illoptstring[] = "unknown option -- %s"; |
|||
|
|||
|
|||
/* |
|||
* Compute the greatest common divisor of a and b. |
|||
*/ |
|||
static int |
|||
gcd(a, b) |
|||
int a; |
|||
int b; |
|||
{ |
|||
int c; |
|||
|
|||
c = a % b; |
|||
while (c != 0) { |
|||
a = b; |
|||
b = c; |
|||
c = a % b; |
|||
} |
|||
|
|||
return b; |
|||
} |
|||
|
|||
/* |
|||
* Exchange the block from nonopt_start to nonopt_end with the block |
|||
* from nonopt_end to opt_end (keeping the same order of arguments |
|||
* in each block). |
|||
*/ |
|||
static void |
|||
permute_args(panonopt_start, panonopt_end, opt_end, nargv) |
|||
int panonopt_start; |
|||
int panonopt_end; |
|||
int opt_end; |
|||
char **nargv; |
|||
{ |
|||
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; |
|||
char *swap; |
|||
|
|||
_DIAGASSERT(nargv != NULL); |
|||
|
|||
/* |
|||
* compute lengths of blocks and number and size of cycles |
|||
*/ |
|||
nnonopts = panonopt_end - panonopt_start; |
|||
nopts = opt_end - panonopt_end; |
|||
ncycle = gcd(nnonopts, nopts); |
|||
cyclelen = (opt_end - panonopt_start) / ncycle; |
|||
|
|||
for (i = 0; i < ncycle; i++) { |
|||
cstart = panonopt_end+i; |
|||
pos = cstart; |
|||
for (j = 0; j < cyclelen; j++) { |
|||
if (pos >= panonopt_end) |
|||
pos -= nnonopts; |
|||
else |
|||
pos += nopts; |
|||
swap = nargv[pos]; |
|||
nargv[pos] = nargv[cstart]; |
|||
nargv[cstart] = swap; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* |
|||
* getopt_internal -- |
|||
* Parse argc/argv argument vector. Called by user level routines. |
|||
* Returns -2 if -- is found (can be long option or end of options marker). |
|||
*/ |
|||
static int |
|||
getopt_internal(nargc, nargv, options) |
|||
int nargc; |
|||
char **nargv; |
|||
const char *options; |
|||
{ |
|||
char *oli; /* option letter list index */ |
|||
int optchar; |
|||
|
|||
_DIAGASSERT(nargv != NULL); |
|||
_DIAGASSERT(options != NULL); |
|||
|
|||
optarg = NULL; |
|||
|
|||
/* |
|||
* XXX Some programs (like rsyncd) expect to be able to |
|||
* XXX re-initialize optind to 0 and have getopt_long(3) |
|||
* XXX properly function again. Work around this braindamage. |
|||
*/ |
|||
if (optind == 0) |
|||
optind = 1; |
|||
|
|||
if (optreset) |
|||
nonopt_start = nonopt_end = -1; |
|||
start: |
|||
if (optreset || !*place) { /* update scanning pointer */ |
|||
optreset = 0; |
|||
if (optind >= nargc) { /* end of argument vector */ |
|||
place = EMSG; |
|||
if (nonopt_end != -1) { |
|||
/* do permutation, if we have to */ |
|||
permute_args(nonopt_start, nonopt_end, |
|||
optind, nargv); |
|||
optind -= nonopt_end - nonopt_start; |
|||
} |
|||
else if (nonopt_start != -1) { |
|||
/* |
|||
* If we skipped non-options, set optind |
|||
* to the first of them. |
|||
*/ |
|||
optind = nonopt_start; |
|||
} |
|||
nonopt_start = nonopt_end = -1; |
|||
return -1; |
|||
} |
|||
if ((*(place = nargv[optind]) != '-') |
|||
|| (place[1] == '\0')) { /* found non-option */ |
|||
place = EMSG; |
|||
if (IN_ORDER) { |
|||
/* |
|||
* GNU extension: |
|||
* return non-option as argument to option 1 |
|||
*/ |
|||
optarg = nargv[optind++]; |
|||
return INORDER; |
|||
} |
|||
if (!PERMUTE) { |
|||
/* |
|||
* if no permutation wanted, stop parsing |
|||
* at first non-option |
|||
*/ |
|||
return -1; |
|||
} |
|||
/* do permutation */ |
|||
if (nonopt_start == -1) |
|||
nonopt_start = optind; |
|||
else if (nonopt_end != -1) { |
|||
permute_args(nonopt_start, nonopt_end, |
|||
optind, nargv); |
|||
nonopt_start = optind - |
|||
(nonopt_end - nonopt_start); |
|||
nonopt_end = -1; |
|||
} |
|||
optind++; |
|||
/* process next argument */ |
|||
goto start; |
|||
} |
|||
if (nonopt_start != -1 && nonopt_end == -1) |
|||
nonopt_end = optind; |
|||
if (place[1] && *++place == '-') { /* found "--" */ |
|||
place++; |
|||
return -2; |
|||
} |
|||
} |
|||
if ((optchar = (int)*place++) == (int)':' || |
|||
(oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { |
|||
/* option letter unknown or ':' */ |
|||
if (!*place) |
|||
++optind; |
|||
if (PRINT_ERROR) |
|||
warnx(illoptchar, optchar); |
|||
optopt = optchar; |
|||
return BADCH; |
|||
} |
|||
if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ |
|||
/* XXX: what if no long options provided (called by getopt)? */ |
|||
if (*place) |
|||
return -2; |
|||
|
|||
if (++optind >= nargc) { /* no arg */ |
|||
place = EMSG; |
|||
if (PRINT_ERROR) |
|||
warnx(recargchar, optchar); |
|||
optopt = optchar; |
|||
return BADARG; |
|||
} else /* white space */ |
|||
place = nargv[optind]; |
|||
/* |
|||
* Handle -W arg the same as --arg (which causes getopt to |
|||
* stop parsing). |
|||
*/ |
|||
return -2; |
|||
} |
|||
if (*++oli != ':') { /* doesn't take argument */ |
|||
if (!*place) |
|||
++optind; |
|||
} else { /* takes (optional) argument */ |
|||
optarg = NULL; |
|||
if (*place) /* no white space */ |
|||
optarg = (char *)place; |
|||
/* XXX: disable test for :: if PC? (GNU doesn't) */ |
|||
else if (oli[1] != ':') { /* arg not optional */ |
|||
if (++optind >= nargc) { /* no arg */ |
|||
place = EMSG; |
|||
if (PRINT_ERROR) |
|||
warnx(recargchar, optchar); |
|||
optopt = optchar; |
|||
return BADARG; |
|||
} else |
|||
optarg = nargv[optind]; |
|||
} |
|||
place = EMSG; |
|||
++optind; |
|||
} |
|||
/* dump back option letter */ |
|||
return optchar; |
|||
} |
|||
|
|||
#ifdef REPLACE_GETOPT |
|||
/* |
|||
* getopt -- |
|||
* Parse argc/argv argument vector. |
|||
* |
|||
* [eventually this will replace the real getopt] |
|||
*/ |
|||
int |
|||
getopt(nargc, nargv, options) |
|||
int nargc; |
|||
char * const *nargv; |
|||
const char *options; |
|||
{ |
|||
int retval; |
|||
|
|||
_DIAGASSERT(nargv != NULL); |
|||
_DIAGASSERT(options != NULL); |
|||
|
|||
retval = getopt_internal(nargc, (char **)nargv, options); |
|||
if (retval == -2) { |
|||
++optind; |
|||
/* |
|||
* We found an option (--), so if we skipped non-options, |
|||
* we have to permute. |
|||
*/ |
|||
if (nonopt_end != -1) { |
|||
permute_args(nonopt_start, nonopt_end, optind, |
|||
(char **)nargv); |
|||
optind -= nonopt_end - nonopt_start; |
|||
} |
|||
nonopt_start = nonopt_end = -1; |
|||
retval = -1; |
|||
} |
|||
return retval; |
|||
} |
|||
#endif |
|||
|
|||
/* |
|||
* getopt_long -- |
|||
* Parse argc/argv argument vector. |
|||
*/ |
|||
int |
|||
getopt_long(nargc, nargv, options, long_options, idx) |
|||
int nargc; |
|||
char * const *nargv; |
|||
const char *options; |
|||
const struct option *long_options; |
|||
int *idx; |
|||
{ |
|||
int retval; |
|||
|
|||
#define IDENTICAL_INTERPRETATION(_x, _y) \ |
|||
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ |
|||
long_options[(_x)].flag == long_options[(_y)].flag && \ |
|||
long_options[(_x)].val == long_options[(_y)].val) |
|||
|
|||
_DIAGASSERT(nargv != NULL); |
|||
_DIAGASSERT(options != NULL); |
|||
_DIAGASSERT(long_options != NULL); |
|||
/* idx may be NULL */ |
|||
|
|||
retval = getopt_internal(nargc, (char **)nargv, options); |
|||
if (retval == -2) { |
|||
char *current_argv, *has_equal; |
|||
size_t current_argv_len; |
|||
int i, ambiguous, match; |
|||
|
|||
current_argv = (char *)place; |
|||
match = -1; |
|||
ambiguous = 0; |
|||
|
|||
optind++; |
|||
place = EMSG; |
|||
|
|||
if (*current_argv == '\0') { /* found "--" */ |
|||
/* |
|||
* We found an option (--), so if we skipped |
|||
* non-options, we have to permute. |
|||
*/ |
|||
if (nonopt_end != -1) { |
|||
permute_args(nonopt_start, nonopt_end, |
|||
optind, (char **)nargv); |
|||
optind -= nonopt_end - nonopt_start; |
|||
} |
|||
nonopt_start = nonopt_end = -1; |
|||
return -1; |
|||
} |
|||
if ((has_equal = strchr(current_argv, '=')) != NULL) { |
|||
/* argument found (--option=arg) */ |
|||
current_argv_len = has_equal - current_argv; |
|||
has_equal++; |
|||
} else |
|||
current_argv_len = strlen(current_argv); |
|||
|
|||
for (i = 0; long_options[i].name; i++) { |
|||
/* find matching long option */ |
|||
if (strncmp(current_argv, long_options[i].name, |
|||
current_argv_len)) |
|||
continue; |
|||
|
|||
if (strlen(long_options[i].name) == |
|||
(unsigned)current_argv_len) { |
|||
/* exact match */ |
|||
match = i; |
|||
ambiguous = 0; |
|||
break; |
|||
} |
|||
if (match == -1) /* partial match */ |
|||
match = i; |
|||
else if (!IDENTICAL_INTERPRETATION(i, match)) |
|||
ambiguous = 1; |
|||
} |
|||
if (ambiguous) { |
|||
/* ambiguous abbreviation */ |
|||
if (PRINT_ERROR) |
|||
warnx(ambig, (int)current_argv_len, |
|||
current_argv); |
|||
optopt = 0; |
|||
return BADCH; |
|||
} |
|||
if (match != -1) { /* option found */ |
|||
if (long_options[match].has_arg == no_argument |
|||
&& has_equal) { |
|||
if (PRINT_ERROR) |
|||
warnx(noarg, (int)current_argv_len, |
|||
current_argv); |
|||
/* |
|||
* XXX: GNU sets optopt to val regardless of |
|||
* flag |
|||
*/ |
|||
if (long_options[match].flag == NULL) |
|||
optopt = long_options[match].val; |
|||
else |
|||
optopt = 0; |
|||
return BADARG; |
|||
} |
|||
if (long_options[match].has_arg == required_argument || |
|||
long_options[match].has_arg == optional_argument) { |
|||
if (has_equal) |
|||
optarg = has_equal; |
|||
else if (long_options[match].has_arg == |
|||
required_argument) { |
|||
/* |
|||
* optional argument doesn't use |
|||
* next nargv |
|||
*/ |
|||
optarg = nargv[optind++]; |
|||
} |
|||
} |
|||
if ((long_options[match].has_arg == required_argument) |
|||
&& (optarg == NULL)) { |
|||
/* |
|||
* Missing argument; leading ':' |
|||
* indicates no error should be generated |
|||
*/ |
|||
if (PRINT_ERROR) |
|||
warnx(recargstring, current_argv); |
|||
/* |
|||
* XXX: GNU sets optopt to val regardless |
|||
* of flag |
|||
*/ |
|||
if (long_options[match].flag == NULL) |
|||
optopt = long_options[match].val; |
|||
else |
|||
optopt = 0; |
|||
--optind; |
|||
return BADARG; |
|||
} |
|||
} else { /* unknown option */ |
|||
if (PRINT_ERROR) |
|||
warnx(illoptstring, current_argv); |
|||
optopt = 0; |
|||
return BADCH; |
|||
} |
|||
if (long_options[match].flag) { |
|||
*long_options[match].flag = long_options[match].val; |
|||
retval = 0; |
|||
} else |
|||
retval = long_options[match].val; |
|||
if (idx) |
|||
*idx = match; |
|||
} |
|||
return retval; |
|||
#undef IDENTICAL_INTERPRETATION |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue