diff --git a/Makefile.am b/Makefile.am index 6c237a428e..74dd4e1632 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,18 +1,18 @@ AM_CFLAGS=-O3 -std=gnu99 -Wall -I$(srcdir)/libyara/include # Build the library in the hand subdirectory first. -SUBDIRS = libyara argparse -DIST_SUBDIRS = libyara argparse +SUBDIRS = libyara +DIST_SUBDIRS = libyara ACLOCAL_AMFLAGS=-I m4 bin_PROGRAMS = yara yarac -yara_SOURCES = threading.c threading.h yara.c -yara_LDADD = libyara/.libs/libyara.a argparse/libargparse.a +yara_SOURCES = args.c args.h threading.c threading.h yara.c +yara_LDADD = libyara/.libs/libyara.a -yarac_SOURCES = yarac.c -yarac_LDADD = libyara/.libs/libyara.a argparse/libargparse.a +yarac_SOURCES = args.c args.h yarac.c +yarac_LDADD = libyara/.libs/libyara.a # man pages man1_MANS = yara.man yarac.man diff --git a/argparse/.gitignore b/argparse/.gitignore deleted file mode 100755 index fb716d29b2..0000000000 --- a/argparse/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -tags -test_argparse -*.[ao] -*.dylib -*.so diff --git a/argparse/.travis.yml b/argparse/.travis.yml deleted file mode 100755 index 41bac87a48..0000000000 --- a/argparse/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: c -compiler: - - gcc - - clang -script: make test diff --git a/argparse/LICENSE b/argparse/LICENSE deleted file mode 100755 index 3c77749764..0000000000 --- a/argparse/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2012-2013 Yecheng Fu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/argparse/README.md b/argparse/README.md deleted file mode 100755 index 6d2ee873f5..0000000000 --- a/argparse/README.md +++ /dev/null @@ -1,89 +0,0 @@ -NAME -==== - -argparse - A command line arguments parsing library. - -[![Build Status](https://travis-ci.org/Cofyc/argparse.png)](https://travis-ci.org/Cofyc/argparse) - -DESCRIPTION -=========== - -This module is inspired by parse-options.c (git) and python's argparse -module. - -Arguments parsing is common task in cli program, but traditional `getopt` -libraries are not easy to use. This library provides high-level arguments -parsing solutions. - -The program defines what arguments it requires, and `argparse` will figure -out how to parse those out of `argc` and `argv`, it also automatically -generates help and usage messages and issues errors when users give the -program invalid arguments. - -Features -======== - - - handles both optional and positional arguments - - produces highly informative usage messages - - issures errors when given invalid arguments - -There are basically three types of options: - - - boolean options - - options with mandatory argument - - options with optional argument - -There are basically two forms of options: - - - short option consist of one dash (`-`) and one alphanumeric character. - - long option begin with two dashes (`--`) and some alphanumeric characters. - -Short options may be bundled, e.g. `-a -b` can be specified as `-ab`. - -Options are case-sensitive. - -Options and non-option arguments can clearly be separated using the `--` option. - -Examples -======== - -```c -#include "argparse.h" - -static const char *const usage[] = { - "test_argparse [options] [[--] args]", - NULL, -}; - -int -main(int argc, const char **argv) -{ - int force = 0; - int num = 0; - const char *path = NULL; - struct argparse_option options[] = { - OPT_HELP(), - OPT_BOOLEAN('f', "force", &force, "force to do", NULL), - OPT_STRING('p', "path", &path, "path to read", NULL), - OPT_INTEGER('n', "num", &num, "selected num", NULL), - OPT_END(), - }; - struct argparse argparse; - argparse_init(&argparse, options, usage, 0); - argc = argparse_parse(&argparse, argc, argv); - if (force != 0) - printf("force: %d\n", force); - if (path != NULL) - printf("path: %s\n", path); - if (num != 0) - printf("num: %d\n", num); - if (argc != 0) { - printf("argc: %d\n", argc); - int i; - for (i = 0; i < argc; i++) { - printf("argv[%d]: %s\n", i, *(argv + i)); - } - } - return 0; -} -``` diff --git a/argparse/argparse.c b/argparse/argparse.c deleted file mode 100755 index e60b76cf4d..0000000000 --- a/argparse/argparse.c +++ /dev/null @@ -1,366 +0,0 @@ -#include "argparse.h" - -#define OPT_UNSET 1 - -static const char * -prefix_skip(const char *str, const char *prefix) -{ - size_t len = strlen(prefix); - return strncmp(str, prefix, len) ? NULL : str + len; -} - -int -prefix_cmp(const char *str, const char *prefix) -{ - for (;; str++, prefix++) - if (!*prefix) - return 0; - else if (*str != *prefix) - return (unsigned char)*prefix - (unsigned char)*str; -} - -static void -argparse_error(struct argparse *self, struct argparse_option *opt, - const char *reason) -{ - if (!strncmp(self->argv[0], "--", 2)) { - fprintf(stderr, "error: option `%s` %s\n", opt->long_name, reason); - exit(1); - } else { - fprintf(stderr, "error: option `%c` %s\n", opt->short_name, reason); - exit(1); - } -} - -static int -argparse_getvalue(struct argparse *self, struct argparse_option *opt, - int flags) -{ - const char *s = NULL; - - if (opt->count == opt->max_count) - argparse_error(self, opt, "repeated too many times"); - - if (!opt->value) - goto skipped; - - switch (opt->type) { - case ARGPARSE_OPT_BOOLEAN: - if (flags & OPT_UNSET) { - *(int *)opt->value = *(int *)opt->value - 1; - } else { - *(int *)opt->value = *(int *)opt->value + 1; - } - if (*(int *)opt->value < 0) { - *(int *)opt->value = 0; - } - break; - case ARGPARSE_OPT_BIT: - if (flags & OPT_UNSET) { - *(int *)opt->value &= ~opt->data; - } else { - *(int *)opt->value |= opt->data; - } - break; - case ARGPARSE_OPT_STRING: - if (self->optvalue) { - *(const char **)opt->value = self->optvalue; - self->optvalue = NULL; - } else if (self->argc > 1) { - self->argc--; - if (opt->max_count > 1) { - ((const char**)opt->value)[opt->count] = *++self->argv; - } - else { - *(const char **)opt->value = *++self->argv; - } - } else { - argparse_error(self, opt, "requires a value"); - } - break; - case ARGPARSE_OPT_INTEGER: - if (self->optvalue) { - *(int *)opt->value = strtol(self->optvalue, (char **)&s, 0); - self->optvalue = NULL; - } else if (self->argc > 1) { - self->argc--; - if (opt->max_count > 1) { - ((int*)opt->value)[opt->count] = strtol(*++self->argv, (char **)&s, 0); - } - else { - *(int *)opt->value = strtol(*++self->argv, (char **)&s, 0); - } - } else { - argparse_error(self, opt, "requires a value"); - } - if (s[0] != '\0') - argparse_error(self, opt, "expects a numerical value"); - break; - default: - assert(0); - } - - opt->count++; - -skipped: - if (opt->callback) { - return opt->callback(self, opt); - } - - return 0; -} - -static void -argparse_options_check(struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - switch (options->type) { - case ARGPARSE_OPT_END: - case ARGPARSE_OPT_BOOLEAN: - case ARGPARSE_OPT_BIT: - case ARGPARSE_OPT_INTEGER: - case ARGPARSE_OPT_STRING: - case ARGPARSE_OPT_GROUP: - continue; - default: - fprintf(stderr, "wrong option type: %d", options->type); - break; - } - } -} - -static int -argparse_short_opt(struct argparse *self, struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - if (options->short_name == *self->optvalue) { - self->optvalue = self->optvalue[1] ? self->optvalue + 1 : NULL; - return argparse_getvalue(self, options, 0); - } - } - return -2; -} - -static int -argparse_long_opt(struct argparse *self, struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - const char *rest; - int opt_flags = 0; - if (!options->long_name) - continue; - - rest = prefix_skip(self->argv[0] + 2, options->long_name); - if (!rest) { - // Negation allowed? - if (options->flags & OPT_NONEG) { - continue; - } - // Only boolean/bit allow negation. - if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != ARGPARSE_OPT_BIT) { - continue; - } - - if (!prefix_cmp(self->argv[0] + 2, "no-")) { - rest = prefix_skip(self->argv[0] + 2 + 3, options->long_name); - if (!rest) - continue; - opt_flags |= OPT_UNSET; - } else { - continue; - } - } - if (*rest) { - if (*rest != '=') - continue; - self->optvalue = rest + 1; - } - return argparse_getvalue(self, options, opt_flags); - } - return -2; -} - -int -argparse_init(struct argparse *self, struct argparse_option *options, - const char *const *usage, int flags) -{ - memset(self, 0, sizeof(*self)); - self->options = options; - self->usage = usage; - self->flags = flags; - - for (; options->type != ARGPARSE_OPT_END; options++) - options->count = 0; - - return 0; -} - -int -argparse_parse(struct argparse *self, int argc, const char **argv) -{ - self->argc = argc - 1; - self->argv = argv + 1; - self->out = argv; - - argparse_options_check(self->options); - - for (; self->argc; self->argc--, self->argv++) { - const char *arg = self->argv[0]; - if (arg[0] != '-' || !arg[1]) { - if (self->flags & ARGPARSE_STOP_AT_NON_OPTION) { - goto end; - } - // if it's not option or is a single char '-', copy verbatimly - self->out[self->cpidx++] = self->argv[0]; - continue; - } - // short option - if (arg[1] != '-') { - self->optvalue = arg + 1; - switch (argparse_short_opt(self, self->options)) { - case -1: - break; - case -2: - goto unknown; - } - while (self->optvalue) { - switch (argparse_short_opt(self, self->options)) { - case -1: - break; - case -2: - goto unknown; - } - } - continue; - } - // if '--' presents - if (!arg[2]) { - self->argc--; - self->argv++; - break; - } - // long option - switch (argparse_long_opt(self, self->options)) { - case -1: - break; - case -2: - goto unknown; - } - continue; - -unknown: - fprintf(stderr, "error: unknown option `%s`\n", self->argv[0]); - argparse_usage(self); - exit(1); - } - -end: - memmove(self->out + self->cpidx, self->argv, - self->argc * sizeof(*self->out)); - self->out[self->cpidx + self->argc] = NULL; - - return self->cpidx + self->argc; -} - -void -argparse_usage(struct argparse *self) -{ - fprintf(stdout, "Usage: %s\n", *self->usage++); - while (*self->usage && **self->usage) - fprintf(stdout, " or: %s\n", *self->usage++); - fputc('\n', stdout); - - struct argparse_option *options; - - // figure out best width - size_t usage_opts_width = 0; - size_t len; - options = self->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - len = 0; - if ((options)->short_name) { - len += 2; - } - if ((options)->short_name && (options)->long_name) { - len += 2; // separator ", " - } - if ((options)->long_name) { - len += strlen((options)->long_name) + 2; - } - if (options->type == ARGPARSE_OPT_INTEGER) { - len++; // equal sign "=" or space - if (options->type_help != NULL) - len += strlen(options->type_help); - else - len += strlen(""); - } else if (options->type == ARGPARSE_OPT_STRING) { - len++; // equal sign "=" or space - if (options->type_help != NULL) - len += strlen(options->type_help); - else - len += strlen(""); - } - len = (len / 4) * 4 + 4; - if (usage_opts_width < len) { - usage_opts_width = len; - } - } - usage_opts_width += 4; // 4 spaces prefix - - options = self->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - size_t pos = 0; - size_t pad = 0; - if (options->type == ARGPARSE_OPT_GROUP) { - fputc('\n', stdout); - fprintf(stdout, "%s", options->help); - fputc('\n', stdout); - continue; - } - pos = fprintf(stdout, " "); - if (options->short_name) { - pos += fprintf(stdout, "-%c", options->short_name); - } - if (options->long_name && options->short_name) { - pos += fprintf(stdout, ", "); - } - if (options->long_name) { - pos += fprintf(stdout, "--%s", options->long_name); - } - if (options->type == ARGPARSE_OPT_INTEGER) { - if (options->long_name) - pos += fprintf(stdout, "="); - else - pos += fprintf(stdout, " "); - if (options->type_help != NULL) - pos += fprintf(stdout, "%s", options->type_help); - else - pos += fprintf(stdout, ""); - } else if (options->type == ARGPARSE_OPT_STRING) { - if (options->long_name) - pos += fprintf(stdout, "="); - else - pos += fprintf(stdout, " "); - if (options->type_help != NULL) - pos += fprintf(stdout, "%s", options->type_help); - else - pos += fprintf(stdout, ""); - } - if (pos <= usage_opts_width) { - pad = usage_opts_width - pos; - } else { - fputc('\n', stdout); - pad = usage_opts_width; - } - fprintf(stdout, "%*s%s\n", pad + 2, "", options->help); - } -} - -int -argparse_help_cb(struct argparse *self, const struct argparse_option *option) -{ - (void)option; - argparse_usage(self); - exit(0); - return 0; -} diff --git a/argparse/argparse.h b/argparse/argparse.h deleted file mode 100755 index 183be46f97..0000000000 --- a/argparse/argparse.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef ARGPARSE_H -#define ARGPARSE_H -/** - * Command-line arguments parsing library. - * - * This module is inspired by parse-options.c (git) and python's argparse - * module. - * - * Arguments parsing is common task in cli program, but traditional `getopt` - * libraries are not easy to use. This library provides high-level arguments - * parsing solutions. - * - * The program defines what arguments it requires, and `argparse` will figure - * out how to parse those out of `argc` and `argv`, it also automatically - * generates help and usage messages and issues errors when users give the - * program invalid arguments. - * - * Reserved namespaces: - * argparse - * OPT - * Author: Yecheng Fu - */ - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct argparse; -struct argparse_option; - -typedef int argparse_callback(struct argparse *self, - const struct argparse_option *option); - -enum argparse_flag { - ARGPARSE_STOP_AT_NON_OPTION = 1, -}; - -enum argparse_option_type { - /* special */ - ARGPARSE_OPT_END, - ARGPARSE_OPT_GROUP, - /* options with no arguments */ - ARGPARSE_OPT_BOOLEAN, - ARGPARSE_OPT_BIT, - /* options with arguments (optional or required) */ - ARGPARSE_OPT_INTEGER, - ARGPARSE_OPT_STRING, - /* repetable options */ - ARGPARSE_OPT_INTEGER_MULTI, - ARGPARSE_OPT_STRING_MULTI, -}; - -enum argparse_option_flags { - OPT_NONEG = 1, /* Negation disabled. */ -}; - -/* - * Argparse option struct. - * - * `type`: - * holds the type of the option, you must have an ARGPARSE_OPT_END last in your - * array. - * - * `short_name`: - * the character to use as a short option name, '\0' if none. - * - * `long_name`: - * the long option name, without the leading dash, NULL if none. - * - * `value`: - * stores pointer to the value to be filled. - * - * `max_count`: - * - * maximum number of times self option can appear in the command line. - * - * `help`: - * the short help message associated to what the option does. - * Must never be NULL (except for ARGPARSE_OPT_END). - * - * `callback`: - * function is called when corresponding argument is parsed. - * - * `data`: - * associated data. Callbacks can use it like they want. - * - * `flags`: - * option flags. - * - * - * - */ -struct argparse_option { - enum argparse_option_type type; - const char short_name; - const char *long_name; - void *value; - int max_count; - const char *help; - const char *type_help; - argparse_callback *callback; - intptr_t data; - int flags; - int count; -}; - -/* - * argpparse - */ -struct argparse { - // user supplied - struct argparse_option *options; - const char *const *usage; - int flags; - // internal context - int argc; - const char **argv; - const char **out; - int cpidx; - const char *optvalue; // current option value -}; - -// builtin callbacks -int argparse_help_cb(struct argparse *self, - const struct argparse_option *option); - -// builtin option macros -#define OPT_BIT(short_name, long_name, value, ...) \ - { ARGPARSE_OPT_BIT, short_name, long_name, value, 1, __VA_ARGS__ } - -#define OPT_BOOLEAN(short_name, long_name, value, ...) \ - { ARGPARSE_OPT_BOOLEAN, short_name, long_name, value, 1, __VA_ARGS__ } - -#define OPT_INTEGER(short_name, long_name, value, ...) \ - { ARGPARSE_OPT_INTEGER, short_name, long_name, value, 1, __VA_ARGS__ } - -#define OPT_STRING_MULTI(short_name, long_name, value, max_count, ...) \ - { ARGPARSE_OPT_STRING, short_name, long_name, value, max_count, __VA_ARGS__ } - -#define OPT_STRING(short_name, long_name, value, ...) \ - OPT_STRING_MULTI(short_name, long_name, value, 1, __VA_ARGS__) - - -#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h } -#define OPT_END() { ARGPARSE_OPT_END, 0 } - -#define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, "show self help message and exit", NULL, argparse_help_cb) - - -int argparse_init(struct argparse *self, struct argparse_option *options, - const char *const *usage, int flags); -int argparse_parse(struct argparse *self, int argc, const char **argv); -void argparse_usage(struct argparse *self); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/argparse/tap-functions b/argparse/tap-functions deleted file mode 100755 index 84f700e644..0000000000 --- a/argparse/tap-functions +++ /dev/null @@ -1,445 +0,0 @@ -#!/bin/bash - - -_version='1.02' - -_plan_set=0 -_no_plan=0 -_skip_all=0 -_test_died=0 -_expected_tests=0 -_executed_tests=0 -_failed_tests=0 -TODO= - - -usage(){ - cat <<'USAGE' -tap-functions: A TAP-producing BASH library - -PLAN: - plan_no_plan - plan_skip_all [REASON] - plan_tests NB_TESTS - -TEST: - ok RESULT [NAME] - okx COMMAND - is RESULT EXPECTED [NAME] - isnt RESULT EXPECTED [NAME] - like RESULT PATTERN [NAME] - unlike RESULT PATTERN [NAME] - pass [NAME] - fail [NAME] - -SKIP: - skip [CONDITION] [REASON] [NB_TESTS=1] - - skip $feature_not_present "feature not present" 2 || { - is $a "a" - is $b "b" - } - -TODO: - Specify TODO mode by setting $TODO: - TODO="not implemented yet" - ok $result "some not implemented test" - unset TODO - -OTHER: - diag MSG - -EXAMPLE: - #!/bin/bash - - . tap-functions - - plan_tests 7 - - me=$USER - is $USER $me "I am myself" - like $HOME $me "My home is mine" - like "`id`" $me "My id matches myself" - - /bin/ls $HOME 1>&2 - ok $? "/bin/ls $HOME" - # Same thing using okx shortcut - okx /bin/ls $HOME - - [[ "`id -u`" != "0" ]] - i_am_not_root=$? - skip $i_am_not_root "Must be root" || { - okx ls /root - } - - TODO="figure out how to become root..." - okx [ "$HOME" == "/root" ] - unset TODO -USAGE - exit -} - -opt= -set_u= -while getopts ":sx" opt ; do - case $_opt in - u) set_u=1 ;; - *) usage ;; - esac -done -shift $(( OPTIND - 1 )) -# Don't allow uninitialized variables if requested -[[ -n "$set_u" ]] && set -u -unset opt set_u - -# Used to call _cleanup on shell exit -trap _exit EXIT - - - -plan_no_plan(){ - (( _plan_set != 0 )) && "You tried to plan twice!" - - _plan_set=1 - _no_plan=1 - - return 0 -} - - -plan_skip_all(){ - local reason=${1:-''} - - (( _plan_set != 0 )) && _die "You tried to plan twice!" - - _print_plan 0 "Skip $reason" - - _skip_all=1 - _plan_set=1 - _exit 0 - - return 0 -} - - -plan_tests(){ - local tests=${1:?} - - (( _plan_set != 0 )) && _die "You tried to plan twice!" - (( tests == 0 )) && _die "You said to run 0 tests! You've got to run something." - - _print_plan $tests - _expected_tests=$tests - _plan_set=1 - - return $tests -} - - -_print_plan(){ - local tests=${1:?} - local directive=${2:-''} - - echo -n "1..$tests" - [[ -n "$directive" ]] && echo -n " # $directive" - echo -} - - -pass(){ - local name=$1 - ok 0 "$name" -} - - -fail(){ - local name=$1 - ok 1 "$name" -} - - -# This is the workhorse method that actually -# prints the tests result. -ok(){ - local result=${1:?} - local name=${2:-''} - - (( _plan_set == 0 )) && _die "You tried to run a test without a plan! Gotta have a plan." - - _executed_tests=$(( $_executed_tests + 1 )) - - if [[ -n "$name" ]] ; then - if _matches "$name" "^[0-9]+$" ; then - diag " You named your test '$name'. You shouldn't use numbers for your test names." - diag " Very confusing." - fi - fi - - if (( result != 0 )) ; then - echo -n "not " - _failed_tests=$(( _failed_tests + 1 )) - fi - echo -n "ok $_executed_tests" - - if [[ -n "$name" ]] ; then - local ename=${name//\#/\\#} - echo -n " - $ename" - fi - - if [[ -n "$TODO" ]] ; then - echo -n " # TODO $TODO" ; - if (( result != 0 )) ; then - _failed_tests=$(( _failed_tests - 1 )) - fi - fi - - echo - if (( result != 0 )) ; then - local file='tap-functions' - local func= - local line= - - local i=0 - local bt=$(caller $i) - while _matches "$bt" "tap-functions$" ; do - i=$(( $i + 1 )) - bt=$(caller $i) - done - local backtrace= - eval $(caller $i | (read line func file ; echo "backtrace=\"$file:$func() at line $line.\"")) - - local t= - [[ -n "$TODO" ]] && t="(TODO) " - - if [[ -n "$name" ]] ; then - diag " Failed ${t}test '$name'" - diag " in $backtrace" - else - diag " Failed ${t}test in $backtrace" - fi - fi - - return $result -} - - -okx(){ - local command="$@" - - local line= - diag "Output of '$command':" - $command | while read line ; do - diag "$line" - done - ok ${PIPESTATUS[0]} "$command" -} - - -_equals(){ - local result=${1:?} - local expected=${2:?} - - if [[ "$result" == "$expected" ]] ; then - return 0 - else - return 1 - fi -} - - -# Thanks to Aaron Kangas for the patch to allow regexp matching -# under bash < 3. - _bash_major_version=${BASH_VERSION%%.*} -_matches(){ - local result=${1:?} - local pattern=${2:?} - - if [[ -z "$result" || -z "$pattern" ]] ; then - return 1 - else - if (( _bash_major_version >= 3 )) ; then - eval '[[ "$result" =~ "$pattern" ]]' - else - echo "$result" | egrep -q "$pattern" - fi - fi -} - - -_is_diag(){ - local result=${1:?} - local expected=${2:?} - - diag " got: '$result'" - diag " expected: '$expected'" -} - - -is(){ - local result=${1:?} - local expected=${2:?} - local name=${3:-''} - - _equals "$result" "$expected" - (( $? == 0 )) - ok $? "$name" - local r=$? - (( r != 0 )) && _is_diag "$result" "$expected" - return $r -} - - -isnt(){ - local result=${1:?} - local expected=${2:?} - local name=${3:-''} - - _equals "$result" "$expected" - (( $? != 0 )) - ok $? "$name" - local r=$? - (( r != 0 )) && _is_diag "$result" "$expected" - return $r -} - - -like(){ - local result=${1:?} - local pattern=${2:?} - local name=${3:-''} - - _matches "$result" "$pattern" - (( $? == 0 )) - ok $? "$name" - local r=$? - (( r != 0 )) && diag " '$result' doesn't match '$pattern'" - return $r -} - - -unlike(){ - local result=${1:?} - local pattern=${2:?} - local name=${3:-''} - - _matches "$result" "$pattern" - (( $? != 0 )) - ok $? "$name" - local r=$? - (( r != 0 )) && diag " '$result' matches '$pattern'" - return $r -} - - -skip(){ - local condition=${1:?} - local reason=${2:-''} - local n=${3:-1} - - if (( condition == 0 )) ; then - local i= - for (( i=0 ; i<$n ; i++ )) ; do - _executed_tests=$(( _executed_tests + 1 )) - echo "ok $_executed_tests # skip: $reason" - done - return 0 - else - return - fi -} - - -diag(){ - local msg=${1:?} - - if [[ -n "$msg" ]] ; then - echo "# $msg" - fi - - return 1 -} - - -_die(){ - local reason=${1:-''} - - echo "$reason" >&2 - _test_died=1 - _exit 255 -} - - -BAIL_OUT(){ - local reason=${1:-''} - - echo "Bail out! $reason" >&2 - _exit 255 -} - - -_cleanup(){ - local rc=0 - - if (( _plan_set == 0 )) ; then - diag "Looks like your test died before it could output anything." - return $rc - fi - - if (( _test_died != 0 )) ; then - diag "Looks like your test died just after $_executed_tests." - return $rc - fi - - if (( _skip_all == 0 && _no_plan != 0 )) ; then - _print_plan $_executed_tests - fi - - local s= - if (( _no_plan == 0 && _expected_tests < _executed_tests )) ; then - s= ; (( _expected_tests > 1 )) && s=s - local extra=$(( _executed_tests - _expected_tests )) - diag "Looks like you planned $_expected_tests test$s but ran $extra extra." - rc=-1 ; - fi - - if (( _no_plan == 0 && _expected_tests > _executed_tests )) ; then - s= ; (( _expected_tests > 1 )) && s=s - diag "Looks like you planned $_expected_tests test$s but only ran $_executed_tests." - fi - - if (( _failed_tests > 0 )) ; then - s= ; (( _failed_tests > 1 )) && s=s - diag "Looks like you failed $_failed_tests test$s of $_executed_tests." - fi - - return $rc -} - - -_exit_status(){ - if (( _no_plan != 0 || _plan_set == 0 )) ; then - return $_failed_tests - fi - - if (( _expected_tests < _executed_tests )) ; then - return $(( _executed_tests - _expected_tests )) - fi - - return $(( _failed_tests + ( _expected_tests - _executed_tests ))) -} - - -_exit(){ - local rc=${1:-''} - if [[ -z "$rc" ]] ; then - _exit_status - rc=$? - fi - - _cleanup - local alt_rc=$? - (( alt_rc != 0 )) && rc=$alt_rc - trap - EXIT - exit $rc -} - diff --git a/argparse/test.sh b/argparse/test.sh deleted file mode 100755 index fdb430a923..0000000000 --- a/argparse/test.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -. tap-functions -plan_no_plan - -is "$(./test_argparse -f --path=/path/to/file a 2>&1)" 'force: 1 -path: /path/to/file -argc: 1 -argv[0]: a' - -is "$(./test_argparse -f -f --force --no-force 2>&1)" 'force: 2' - -is "$(./test_argparse -n 2>&1)" 'error: option `n` requires a value' - -is "$(./test_argparse -n 2 2>&1)" 'num: 2' - -is "$(./test_argparse -n2 2>&1)" 'num: 2' - -is "$(./test_argparse -na 2>&1)" 'error: option `n` expects a numerical value' - -is "$(./test_argparse -f -- do -f -h 2>&1)" 'force: 1 -argc: 3 -argv[0]: do -argv[1]: -f -argv[2]: -h' - -is "$(./test_argparse -tf 2>&1)" 'force: 1 -test: 1' - -is "$(./test_argparse --read --write 2>&1)" 'perms: 3' - -is "$(./test_argparse -h)" 'Usage: test_argparse [options] [[--] args] - or: test_argparse [options] - - -h, --help show this help message and exit - -OPTIONS - -f, --force force to do - -t, --test test only - -p, --path= path to read - -n, --num= selected num - -BITS - --read read perm - --write write perm - --exec exec perm' diff --git a/argparse/test_argparse.c b/argparse/test_argparse.c deleted file mode 100755 index 6d95d35cf1..0000000000 --- a/argparse/test_argparse.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "argparse.h" - -static const char *const usage[] = { - "test_argparse [options] [[--] args]", - "test_argparse [options]", - NULL, -}; - -#define PERM_READ (1<<0) -#define PERM_WRITE (1<<1) -#define PERM_EXEC (1<<2) - -int -main(int argc, const char **argv) -{ - int force = 0; - int test = 0; - int num = 0; - const char *path = NULL; - int perms = 0; - struct argparse_option options[] = { - OPT_HELP(), - OPT_GROUP("OPTIONS"), - OPT_BOOLEAN('f', "force", &force, "force to do"), - OPT_BOOLEAN('t', "test", &test, "test only"), - OPT_STRING('p', "path", &path, "path to read"), - OPT_INTEGER('n', "num", &num, "selected num"), - OPT_GROUP("BITS"), - OPT_BIT(0, "read", &perms, "read perm", NULL, PERM_READ, OPT_NONEG), - OPT_BIT(0, "write", &perms, "write perm", NULL, PERM_WRITE), - OPT_BIT(0, "exec", &perms, "exec perm", NULL, PERM_EXEC), - OPT_END(), - }; - - struct argparse argparse; - argparse_init(&argparse, options, usage, 0); - argc = argparse_parse(&argparse, argc, argv); - if (force != 0) - printf("force: %d\n", force); - if (test != 0) - printf("test: %d\n", test); - if (path != NULL) - printf("path: %s\n", path); - if (num != 0) - printf("num: %d\n", num); - if (argc != 0) { - printf("argc: %d\n", argc); - int i; - for (i = 0; i < argc; i++) { - printf("argv[%d]: %s\n", i, *(argv + i)); - } - } - if (perms) { - printf("perms: %d\n", perms); - } - return 0; -} diff --git a/args.c b/args.c new file mode 100755 index 0000000000..45f11ecee9 --- /dev/null +++ b/args.c @@ -0,0 +1,278 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include + +#include "args.h" + +#define args_is_long_arg(arg) \ + (arg[0] == '-' && arg[1] == '-' && arg[2] != '\0') + + +#define args_is_short_arg(arg) \ + (arg[0] == '-' && arg[1] != '-' && arg[1] != '\0') + + +args_option_t* args_get_short_option( + args_option_t *options, + const char opt) +{ + while (options->type != ARGS_OPT_END) + { + if (opt == options->short_name) + return options; + + options++; + } + + return NULL; +} + + +args_option_t* args_get_long_option( + args_option_t *options, + const char* arg) +{ + arg += 2; // skip starting -- + + while (options->type != ARGS_OPT_END) + { + if (options->long_name != NULL) + { + int l = strlen(options->long_name); + + if ((arg[l] == '\0' || arg[l] == '=') && + strstr(arg, options->long_name) == arg) + { + return options; + } + } + + options++; + } + + return NULL; +} + + +args_error_type_t args_parse_option( + args_option_t* opt, + const char* opt_arg, + int* opt_arg_was_used) +{ + char *endptr = NULL; + + if (opt_arg_was_used != NULL) + *opt_arg_was_used = 0; + + if (opt->count == opt->max_count) + return ARGS_ERROR_TOO_MANY; + + switch (opt->type) + { + case ARGS_OPT_BOOLEAN: + *(int*) opt->value = 1; + break; + + case ARGS_OPT_INTEGER: + + if (opt_arg == NULL) + return ARGS_ERROR_REQUIRED_INTEGER_ARG; + + *(int*) opt->value = strtol(opt_arg, &endptr, 0); + + if (*endptr != '\0') + return ARGS_ERROR_REQUIRED_INTEGER_ARG; + + if (opt_arg_was_used != NULL) + *opt_arg_was_used = 1; + + break; + + case ARGS_OPT_STRING: + + if (opt_arg == NULL) + return ARGS_ERROR_REQUIRED_STRING_ARG; + + if (opt->max_count > 1) + ((const char**)opt->value)[opt->count] = opt_arg; + else + *(const char**) opt->value = opt_arg; + + if (opt_arg_was_used != NULL) + *opt_arg_was_used = 1; + + break; + + default: + assert(0); + } + + opt->count++; + + return ARGS_ERROR_OK; +} + + +void args_print_error( + args_error_type_t error, + const char* option) +{ + switch(error) + { + case ARGS_ERROR_UKNOWN_OPT: + fprintf(stderr, "unknown option `%s`\n", option); + break; + case ARGS_ERROR_TOO_MANY: + fprintf(stderr, "too many `%s` options\n", option); + break; + case ARGS_ERROR_REQUIRED_INTEGER_ARG: + fprintf(stderr, "option `%s` requieres an integer argument\n", option); + break; + case ARGS_ERROR_REQUIRED_STRING_ARG: + fprintf(stderr, "option `%s` requieres a string argument\n", option); + break; + case ARGS_ERROR_UNEXPECTED_ARG: + fprintf(stderr, "option `%s` doesn't expect an argument\n", option); + break; + default: + return; + } +} + + +int args_parse( + args_option_t *options, + int argc, + const char **argv) +{ + args_error_type_t error = ARGS_ERROR_OK; + + int i = 1; // start with i = 1, argv[0] is the program name + int o = 0; + + while (i < argc) + { + const char* arg = argv[i]; + + if (args_is_long_arg(arg)) + { + args_option_t* opt = args_get_long_option(options, arg); + + if (opt != NULL) + { + const char* equal = strchr(arg, '='); + + if (equal) + error = args_parse_option(opt, equal + 1, NULL); + else + error = args_parse_option(opt, NULL, NULL); + } + else + { + error = ARGS_ERROR_UKNOWN_OPT; + } + } + else if (args_is_short_arg(arg)) + { + for (int j = 1; arg[j] != '\0'; j++) + { + args_option_t* opt = args_get_short_option(options, arg[j]); + + if (opt != NULL) + { + if (arg[j + 1] == '\0') + { + int arg_used; + + // short option followed by a space, argv[i + 1] could be + // an argument for the option (i.e: -a ) + error = args_parse_option(opt, argv[i + 1], &arg_used); + + // argv[i + 1] was actually an argument to the option, skip it. + if (arg_used) + i++; + } + else + { + // short option followed by another option (i.e: -ab), no + // argument for this option + error = args_parse_option(opt, NULL, NULL); + } + } + else + { + error = ARGS_ERROR_UKNOWN_OPT; + } + + if (error != ARGS_ERROR_OK) + break; + } + } + else + { + argv[o++] = arg; + } + + if (error != ARGS_ERROR_OK) + { + args_print_error(error, arg); + exit(1); + } + + i++; + } + + return o; +} + + +void args_print_usage( + args_option_t *options, + int help_alignment) +{ + char buffer[128]; + + for (; options->type != ARGS_OPT_END; options++) + { + int len = sprintf(buffer, " "); + + if (options->short_name != '\0') + len += sprintf(buffer + len, "-%c", options->short_name); + else + len += sprintf(buffer + len, " "); + + if (options->short_name != '\0' && options->long_name != NULL) + len += sprintf(buffer + len, ", "); + + if (options->long_name != NULL) + len += sprintf(buffer + len, "--%s", options->long_name); + + if (options->type == ARGS_OPT_STRING || + options->type == ARGS_OPT_INTEGER) + { + len += sprintf( + buffer + len, + "%s%s", + (options->long_name != NULL) ? "=" : " ", + options->type_help); + } + + printf("%-*s%s\n", help_alignment, buffer, options->help); + } +} diff --git a/args.h b/args.h new file mode 100755 index 0000000000..eec36a3484 --- /dev/null +++ b/args.h @@ -0,0 +1,92 @@ +/* +Copyright (c) 2014. The YARA Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef ARGPARSE_H +#define ARGPARSE_H + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum _args_error_type { + ARGS_ERROR_OK, + ARGS_ERROR_UKNOWN_OPT, + ARGS_ERROR_TOO_MANY, + ARGS_ERROR_REQUIRED_INTEGER_ARG, + ARGS_ERROR_REQUIRED_STRING_ARG, + ARGS_ERROR_UNEXPECTED_ARG, +} args_error_type_t; + + +typedef enum _args_option_type { + // special + ARGS_OPT_END, + ARGS_OPT_GROUP, + // options with no arguments + ARGS_OPT_BOOLEAN, + // options with arguments (optional or required) + ARGS_OPT_INTEGER, + ARGS_OPT_STRING, +} args_option_type_t; + + +typedef struct _args_option { + args_option_type_t type; + const char short_name; + const char *long_name; + void *value; + int max_count; + const char *help; + const char *type_help; + int count; +} args_option_t; + + +#define OPT_BOOLEAN(short_name, long_name, value, ...) \ + { ARGS_OPT_BOOLEAN, short_name, long_name, value, 1, __VA_ARGS__ } + +#define OPT_INTEGER(short_name, long_name, value, ...) \ + { ARGS_OPT_INTEGER, short_name, long_name, value, 1, __VA_ARGS__ } + +#define OPT_STRING_MULTI(short_name, long_name, value, max_count, ...) \ + { ARGS_OPT_STRING, short_name, long_name, value, max_count, __VA_ARGS__ } + +#define OPT_STRING(short_name, long_name, value, ...) \ + OPT_STRING_MULTI(short_name, long_name, value, 1, __VA_ARGS__) + +#define OPT_END() { ARGS_OPT_END, 0 } + + +int args_parse( + args_option_t *options, + int argc, + const char **argv); + + +void args_print_usage( + args_option_t *options, + int aligment); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/yara.c b/yara.c index f34a3cf9c5..e28b53813a 100644 --- a/yara.c +++ b/yara.c @@ -35,9 +35,9 @@ limitations under the License. #include #include -#include #include +#include "args.h" #include "threading.h" #include "config.h" @@ -93,6 +93,8 @@ int show_specified_rules = FALSE; int show_strings = FALSE; int show_meta = FALSE; int show_namespace = FALSE; +int show_version = FALSE; +int show_help = FALSE; int ignore_warnings = FALSE; int fast_scan = FALSE; int negate = FALSE; @@ -102,22 +104,20 @@ int timeout = 0; int threads = 8; -static const char *const usage[] = { - "yara [OPTION]... RULES_FILE FILE | DIRECTORY | PID", - NULL, -}; +#define USAGE_STRING \ + "Usage: yara [OPTION]... RULES_FILE FILE | DIR | PID" -struct argparse_option options[] = +args_option_t options[] = { OPT_STRING_MULTI('t', "tag", &tags, MAX_ARGS_TAG, - "only print rules tagged as .", ""), + "print only rules tagged as TAG", "TAG"), OPT_STRING_MULTI('i', "identifier", &identifiers, MAX_ARGS_IDENTIFIER, - "only print rules named .", ""), + "print only rules named IDENTIFIER", "IDENTIFIER"), OPT_BOOLEAN('n', "negate", &negate, - "only print not satisfied rules (negate)", NULL), + "print only not satisfied rules (negate)", NULL), OPT_BOOLEAN('g', "print-tags", &show_tags, "print tags"), @@ -132,19 +132,19 @@ struct argparse_option options[] = "print rules' namespace"), OPT_INTEGER('p', "threads", &threads, - "use the specified number of threads to scan a directory", ""), + "use the specified NUMBER of threads to scan a directory", "NUMBER"), OPT_INTEGER('l', "max-rules", &limit, - "abort scanning after matching a number rules", ""), + "abort scanning after matching a NUMBER of rules", "NUMBER"), OPT_STRING_MULTI('d', NULL, &ext_vars, MAX_ARGS_EXT_VAR, - "define external variable", "="), + "define external variable", "VAR=VALUE"), OPT_STRING_MULTI('x', NULL, &modules_data, MAX_ARGS_MODULE_DATA, - "pass file's content as extra data to module", "="), + "pass FILE's content as extra data to MODULE", "MODULE=FILE"), OPT_INTEGER('a', "timeout", &timeout, - "abort scanning after matching a number of rules", ""), + "abort scanning after the given number of SECONDS", "SECONDS"), OPT_BOOLEAN('r', "recursive", &recursive_search, "recursively search directories"), @@ -155,7 +155,12 @@ struct argparse_option options[] = OPT_BOOLEAN('w', "no-warnings", &ignore_warnings, "disable warnings"), - OPT_HELP(), + OPT_BOOLEAN('v', "version", &show_version, + "show version information"), + + OPT_BOOLEAN('h', "help", &show_help, + "show this help and exit"), + OPT_END() }; @@ -800,12 +805,29 @@ int main( YR_COMPILER* compiler = NULL; YR_RULES* rules = NULL; - struct argparse argparse; int result; - argparse_init(&argparse, options, usage, 0); + argc = args_parse(options, argc, argv); - argc = argparse_parse(&argparse, argc, argv); + if (show_version) + { + printf("%s\n", PACKAGE_STRING); + return EXIT_FAILURE; + } + + if (show_help) + { + printf( + "YARA %s, the pattern matching swiss army knife.\n" + "%s\n\n" + "Mandatory arguments to long options are mandatory for " + "short options too.\n\n", PACKAGE_VERSION, USAGE_STRING); + + args_print_usage(options, 35); + printf("\nSend bug reports and suggestions to: %s.\n", PACKAGE_BUGREPORT); + + return EXIT_FAILURE; + } if (argc != 2) { @@ -813,8 +835,10 @@ int main( // arguments, the rules file and the target file, directory or pid to // be scanned. - fprintf(stderr, "error: wrong number of arguments\n"); - argparse_usage(&argparse); + fprintf(stderr, "yara: wrong number of arguments\n"); + fprintf(stderr, "%s\n\n", USAGE_STRING); + fprintf(stderr, "Try `--help` for more options\n"); + return EXIT_FAILURE; } diff --git a/yarac.c b/yarac.c index 4402c48421..e0eb000882 100644 --- a/yarac.c +++ b/yarac.c @@ -31,9 +31,9 @@ limitations under the License. #include #include #include -#include #include +#include "args.h" #include "config.h" #ifndef MAX_PATH @@ -45,23 +45,27 @@ limitations under the License. char* ext_vars[MAX_ARGS_EXT_VAR + 1]; int ignore_warnings = FALSE; +int show_version = FALSE; +int show_help = FALSE; -static const char *const usage[] = { - "yarac [option]... [namespace:]rules_file... output_file", - NULL, -}; - +#define USAGE_STRING \ + "Usage: yarac [OPTION]... [NAMESPACE:]SOURCE_FILE... OUTPUT_FILE" -struct argparse_option options[] = +args_option_t options[] = { OPT_STRING_MULTI('d', NULL, &ext_vars, MAX_ARGS_EXT_VAR, - "define external variable"), + "define external variable", "VAR=VALUE"), OPT_BOOLEAN('w', "no-warnings", &ignore_warnings, - "disable warnings", NULL), + "disable warnings"), + + OPT_BOOLEAN('v', "version", &show_version, + "show version information"), + + OPT_BOOLEAN('h', "help", &show_help, + "show this help and exit"), - OPT_HELP(), OPT_END() }; @@ -156,16 +160,34 @@ int main( YR_COMPILER* compiler = NULL; YR_RULES* rules = NULL; - struct argparse argparse; int result; - argparse_init(&argparse, options, usage, 0); + argc = args_parse(options, argc, argv); - argc = argparse_parse(&argparse, argc, argv); + if (show_version) + { + printf("%s\n", PACKAGE_STRING); + printf("\nSend bug reports and suggestions to: %s.\n", PACKAGE_BUGREPORT); + + return EXIT_FAILURE; + } + + if (show_help) + { + printf("%s\n\n", USAGE_STRING); + + args_print_usage(options, 25); + printf("\nSend bug reports and suggestions to: %s.\n", PACKAGE_BUGREPORT); + + return EXIT_FAILURE; + } if (argc < 2) { - fprintf(stderr, "error: wrong number of arguments\n"); + fprintf(stderr, "yarac: wrong number of arguments\n"); + fprintf(stderr, "%s\n\n", USAGE_STRING); + fprintf(stderr, "Try `--help` for more options\n"); + exit_with_code(EXIT_FAILURE); }