diff options
Diffstat (limited to 'extension/fnmatch.c')
-rw-r--r-- | extension/fnmatch.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/extension/fnmatch.c b/extension/fnmatch.c new file mode 100644 index 00000000..727c9daf --- /dev/null +++ b/extension/fnmatch.c @@ -0,0 +1,186 @@ +/* + * fnmatch.c - Provide an interface to fnmatch(3) routine + * + * Arnold Robbins + * arnold@skeeve.com + * Written 7/2012 + */ + +/* + * Copyright (C) 2012 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Programming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include "gawkapi.h" + +#include "gettext.h" +#define _(msgid) gettext(msgid) +#define N_(msgid) msgid + +#ifdef HAVE_FNMATCH_H +#define _GNU_SOURCE 1 /* use GNU extensions if they're there */ +#include <fnmatch.h> +#endif + +/* Provide GNU extensions as no-ops if not defined */ +#ifndef FNM_CASEFOLD +#define FNM_CASEFOLD 0 +#endif +#ifndef FNM_LEADING_DIR +#define FNM_LEADING_DIR 0 +#endif +#ifndef FNM_FILE_NAME +#define FNM_FILE_NAME 0 +#endif + +static const gawk_api_t *api; /* for convenience macros to work */ +static awk_ext_id_t *ext_id; +static const char *ext_version = "fnmatch extension: version 1.0"; + +static awk_bool_t init_fnmatch(void); +static awk_bool_t (*init_func)(void) = init_fnmatch; + +int plugin_is_GPL_compatible; + + +/* do_fnmatch --- implement the fnmatch interface */ + +static awk_value_t * +do_fnmatch(int nargs, awk_value_t *result) +{ +#ifdef HAVE_FNMATCH_H + static int flags_mask = + FNM_CASEFOLD | FNM_FILE_NAME | + FNM_LEADING_DIR | FNM_NOESCAPE | + FNM_PATHNAME | FNM_PERIOD ; +#endif + awk_value_t pattern, string, flags; + int int_flags, retval; + + make_number(-1.0, result); /* default return */ +#ifdef HAVE_FNMATCH + if (nargs < 3) { + warning(ext_id, _("fnmatch: called with less than three arguments")); + goto out; + } else if (do_lint && nargs > 3) + lintwarn(ext_id, _("fnmatch: called with more than three arguments")); + + if (! get_argument(0, AWK_STRING, & pattern)) { + warning(ext_id, _("fnmatch: could not get first argument")); + goto out; + } + + if (! get_argument(1, AWK_STRING, & string)) { + warning(ext_id, _("fnmatch: could not get second argument")); + goto out; + } + + if (! get_argument(2, AWK_NUMBER, & flags)) { + warning(ext_id, _("fnmatch: could not get third argument")); + goto out; + } + + int_flags = flags.num_value; + int_flags &= flags_mask; + + retval = fnmatch(pattern.str_value.str, + string.str_value.str, int_flags); + make_number((double) retval, result); + +out: +#else + fatal(ext_id, _("fnmatch is not implemented on this system\n")); +#endif + return result; +} + +#define ENTRY(x) { #x, FNM_##x } + +static struct fnmflags { + const char *name; + int value; +} flagtable[] = { + ENTRY(CASEFOLD), + ENTRY(FILE_NAME), + ENTRY(LEADING_DIR), + ENTRY(NOESCAPE), + ENTRY(PATHNAME), + ENTRY(PERIOD), + { NULL, 0 } +}; + +/* init_fnmatch --- load array with flags */ + +static awk_bool_t +init_fnmatch(void) +{ + int errors = 0; +#ifdef HAVE_FNMATCH + awk_value_t index, value, the_array; + awk_array_t new_array; + int i; + + if (! sym_constant("FNM_NOMATCH", make_number(FNM_NOMATCH, & value))) { + warning(ext_id, _("fnmatch init: could not add FNM_NOMATCH variable")); + errors++; + } + + new_array = create_array(); + for (i = 0; flagtable[i].name != NULL; i++) { + (void) make_const_string(flagtable[i].name, + strlen(flagtable[i].name), & index); + (void) make_number(flagtable[i].value, & value); + if (! set_array_element(new_array, & index, & value)) { + warning(ext_id, _("fnmatch init: could not set array element %s"), + flagtable[i].name); + errors++; + } + } + + the_array.val_type = AWK_ARRAY; + the_array.array_cookie = new_array; + + if (! sym_update("FNM", & the_array)) { + warning(ext_id, _("fnmatch init: could not install FNM array")); + errors++; + } + +#endif + return errors == 0; +} + +static awk_ext_func_t func_table[] = { + { "fnmatch", do_fnmatch, 3 }, +}; + +/* define the dl_load function using the boilerplate macro */ + +dl_load_func(func_table, fnmatch, "") |