From 7f6002caba3f0a6749820c2772161caf55b8d267 Mon Sep 17 00:00:00 2001 From: neonloop Date: Fri, 7 May 2021 20:00:12 +0000 Subject: Initial commit (uqm-0.8.0) --- src/libs/uio/match.c | 569 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 569 insertions(+) create mode 100644 src/libs/uio/match.c (limited to 'src/libs/uio/match.c') diff --git a/src/libs/uio/match.c b/src/libs/uio/match.c new file mode 100644 index 0000000..68e6897 --- /dev/null +++ b/src/libs/uio/match.c @@ -0,0 +1,569 @@ +/* + * Copyright (C) 2003 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * Nota bene: later versions of the GNU General Public License do not apply + * to this program. + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#ifdef DEBUG +# include +#endif + +#define match_INTERNAL + +#include "match.h" +#include "mem.h" +#include "uioport.h" + +#ifdef HAVE_GLOB +# include +#endif + + +static inline match_MatchContext *match_allocMatchContext(void); +static inline void match_freeMatchContext(match_MatchContext *context); + +static inline match_LiteralContext *match_newLiteralContext(char *pattern); +static inline match_LiteralContext *match_allocLiteralContext(void); +static inline void match_freeLiteralContext(match_LiteralContext *context); +static inline match_PrefixContext *match_newPrefixContext(char *pattern); +static inline match_PrefixContext *match_allocPrefixContext(void); +static inline void match_freePrefixContext(match_PrefixContext *context); +static inline match_SuffixContext *match_newSuffixContext( + char *pattern, size_t len); +static inline match_SuffixContext *match_allocSuffixContext(void); +static inline void match_freeSuffixContext(match_SuffixContext *context); +static inline match_SubStringContext *match_newSubStringContext( + char *pattern); +static inline match_SubStringContext *match_allocSubStringContext(void); +static inline void match_freeSubStringContext(match_SubStringContext *context); +#ifdef HAVE_GLOB +static inline match_GlobContext *match_newGlobContext(char *pattern); +static inline match_GlobContext *match_allocGlobContext(void); +static inline void match_freeGlobContext(match_GlobContext *context); +#endif /* HAVE_GLOB */ +#ifdef HAVE_REGEX +static inline match_RegexContext *match_newRegexContext(void); +static inline match_RegexContext *match_allocRegexContext(void); +static inline void match_freeRegexContext(match_RegexContext *context); +#endif /* HAVE_REGEX */ + + +// *** General part *** + +static inline match_MatchContext * +match_allocMatchContext(void) { + return uio_malloc(sizeof (match_MatchContext)); +} + +static inline void +match_freeMatchContext(match_MatchContext *context) { + uio_free(context); +} + +// NB: Even if this function fails, *contextPtr contains a context +// which needs to be freed. +match_Result +match_prepareContext(const char *pattern, match_MatchContext **contextPtr, + match_MatchType type) { + match_Result result; + + *contextPtr = match_allocMatchContext(); + (*contextPtr)->type = type; + switch (type) { + case match_MATCH_LITERAL: + result = match_prepareLiteral(pattern, + &(*contextPtr)->u.literal); + break; + case match_MATCH_PREFIX: + result = match_preparePrefix(pattern, &(*contextPtr)->u.prefix); + break; + case match_MATCH_SUFFIX: + result = match_prepareSuffix(pattern, &(*contextPtr)->u.suffix); + break; + case match_MATCH_SUBSTRING: + result = match_prepareSubString(pattern, + &(*contextPtr)->u.subString); + break; +#ifdef HAVE_GLOB + case match_MATCH_GLOB: + result = match_prepareGlob(pattern, &(*contextPtr)->u.glob); + break; +#endif +#ifdef HAVE_REGEX + case match_MATCH_REGEX: + result = match_prepareRegex(pattern, &(*contextPtr)->u.regex); + break; +#endif + default: +#ifdef DEBUG + fprintf(stderr, "match_prepareContext called with unsupported " + "type %d matching.\n", type); +#endif + return match_ENOSYS; + } + return result; +} + +match_Result +match_matchPattern(match_MatchContext *context, const char *string) { + switch (context->type) { + case match_MATCH_LITERAL: + return match_matchLiteral(context->u.literal, string); + case match_MATCH_PREFIX: + return match_matchPrefix(context->u.prefix, string); + case match_MATCH_SUFFIX: + return match_matchSuffix(context->u.suffix, string); + case match_MATCH_SUBSTRING: + return match_matchSubString(context->u.subString, string); +#ifdef HAVE_GLOB + case match_MATCH_GLOB: + return match_matchGlob(context->u.glob, string); +#endif +#ifdef HAVE_REGEX + case match_MATCH_REGEX: + return match_matchRegex(context->u.regex, string); +#endif + default: + abort(); + } +} + +// context may be NULL +const char * +match_errorString(match_MatchContext *context, match_Result result) { + switch (result) { + case match_OK: + case match_MATCH: +// case match_NOMATCH: // same value as match_OK + return "Success"; + case match_ENOSYS: + return "Not implemented"; + case match_ENOTINIT: + return "Uninitialised use"; + case match_ECUSTOM: + // Depends on match type. Printed below. + break; + default: + return "Unknown error"; + } + + if (context == NULL) + return "Unknown match-type specific error."; + // We can't be any more specific if no 'context' is supplied. + + switch (context->type) { +#if 0 + case match_MATCH_LITERAL: + return match_errorStringLiteral(context->u.literal, result); + case match_MATCH_PREFIX: + return match_errorStringPrefix(context->u.prefix, result); + case match_MATCH_SUFFIX: + return match_errorStringSuffix(context->u.suffix, result); + case match_MATCH_SUBSTRING: + return match_errorStringSubString(context->u.subString, result); +#ifdef HAVE_GLOB + case match_MATCH_GLOB: + return match_errorStringGlob(context->u.glob, result); +#endif +#endif +#ifdef HAVE_REGEX + case match_MATCH_REGEX: + return match_errorStringRegex(context->u.regex, result); +#endif + default: + abort(); + } +} + +void +match_freeContext(match_MatchContext *context) { + switch (context->type) { + case match_MATCH_LITERAL: + match_freeLiteral(context->u.literal); + break; + case match_MATCH_PREFIX: + match_freePrefix(context->u.prefix); + break; + case match_MATCH_SUFFIX: + match_freeSuffix(context->u.suffix); + break; + case match_MATCH_SUBSTRING: + match_freeSubString(context->u.subString); + break; +#ifdef HAVE_GLOB + case match_MATCH_GLOB: + match_freeGlob(context->u.glob); + break; +#endif +#ifdef HAVE_REGEX + case match_MATCH_REGEX: + match_freeRegex(context->u.regex); + break; +#endif + default: + abort(); + } + match_freeMatchContext(context); +} + +match_Result +match_matchPatternOnce(const char *pattern, match_MatchType type, + const char *string) { + match_MatchContext *context; + match_Result result; + + result = match_prepareContext(pattern, &context, type); + if (result != match_OK) + goto out; + + result = match_matchPattern(context, string); + +out: + match_freeContext(context); + return result; +} + + +// *** Literal part *** + +match_Result +match_prepareLiteral(const char *pattern, + match_LiteralContext **contextPtr) { + *contextPtr = match_newLiteralContext(uio_strdup(pattern)); + return match_OK; +} + +match_Result +match_matchLiteral(match_LiteralContext *context, const char *string) { + return (strcmp(context->pattern, string) == 0) ? + match_MATCH : match_NOMATCH; +} + +void +match_freeLiteral(match_LiteralContext *context) { + uio_free(context->pattern); + match_freeLiteralContext(context); +} + +static inline match_LiteralContext * +match_newLiteralContext(char *pattern) { + match_LiteralContext *result; + + result = match_allocLiteralContext(); + result->pattern = pattern; + return result; +} + +static inline match_LiteralContext * +match_allocLiteralContext(void) { + return uio_malloc(sizeof (match_LiteralContext)); +} + +static inline void +match_freeLiteralContext(match_LiteralContext *context) { + uio_free(context); +} + + +// *** Prefix part *** + +match_Result +match_preparePrefix(const char *pattern, + match_PrefixContext **contextPtr) { + *contextPtr = match_newPrefixContext(uio_strdup(pattern)); + return match_OK; +} + +match_Result +match_matchPrefix(match_PrefixContext *context, const char *string) { + char *patPtr; + + patPtr = context->pattern; + while (1) { + if (*patPtr == '\0') { + // prefix has completely matched + return match_MATCH; + } + if (*string == '\0') { + // no more string left, and still prefix to match + return match_NOMATCH; + } + if (*patPtr != *string) + return match_NOMATCH; + patPtr++; + string++; + } +} + +void +match_freePrefix(match_PrefixContext *context) { + uio_free(context->pattern); + match_freePrefixContext(context); +} + +static inline match_PrefixContext * +match_newPrefixContext(char *pattern) { + match_PrefixContext *result; + + result = match_allocPrefixContext(); + result->pattern = pattern; + return result; +} + +static inline match_PrefixContext * +match_allocPrefixContext(void) { + return uio_malloc(sizeof (match_PrefixContext)); +} + +static inline void +match_freePrefixContext(match_PrefixContext *context) { + uio_free(context); +} + + +// *** Suffix part *** + +match_Result +match_prepareSuffix(const char *pattern, + match_SuffixContext **contextPtr) { + *contextPtr = match_newSuffixContext( + uio_strdup(pattern), strlen(pattern)); + return match_OK; +} + +match_Result +match_matchSuffix(match_SuffixContext *context, const char *string) { + size_t stringLen; + + stringLen = strlen(string); + if (stringLen < context->len) { + // Supplied suffix is larger than string + return match_NOMATCH; + } + + return memcmp(string + stringLen - context->len, context->pattern, + context->len) == 0 ? match_MATCH : match_NOMATCH; +} + +void +match_freeSuffix(match_SuffixContext *context) { + uio_free(context->pattern); + match_freeSuffixContext(context); +} + +static inline match_SuffixContext * +match_newSuffixContext(char *pattern, size_t len) { + match_SuffixContext *result; + + result = match_allocSuffixContext(); + result->pattern = pattern; + result->len = len; + return result; +} + +static inline match_SuffixContext * +match_allocSuffixContext(void) { + return uio_malloc(sizeof (match_SuffixContext)); +} + +static inline void +match_freeSuffixContext(match_SuffixContext *context) { + uio_free(context); +} + + +// *** SubString part *** + +match_Result +match_prepareSubString(const char *pattern, + match_SubStringContext **contextPtr) { + *contextPtr = match_newSubStringContext(uio_strdup(pattern)); + return match_OK; +} + +match_Result +match_matchSubString(match_SubStringContext *context, const char *string) { + return strstr(string, context->pattern) != NULL; +} + +void +match_freeSubString(match_SubStringContext *context) { + uio_free(context->pattern); + match_freeSubStringContext(context); +} + +static inline match_SubStringContext * +match_newSubStringContext(char *pattern) { + match_SubStringContext *result; + + result = match_allocSubStringContext(); + result->pattern = pattern; + return result; +} + +static inline match_SubStringContext * +match_allocSubStringContext(void) { + return uio_malloc(sizeof (match_SubStringContext)); +} + +static inline void +match_freeSubStringContext(match_SubStringContext *context) { + uio_free(context); +} + + +// *** Glob part *** + +#ifdef HAVE_GLOB +match_Result +match_prepareGlob(const char *pattern, match_GlobContext **contextPtr) { + *contextPtr = match_newGlobContext(uio_strdup(pattern)); + return match_OK; +} + +match_Result +match_matchGlob(match_GlobContext *context, const char *string) { + int retval; + + retval = fnmatch(context->pattern, string, 0); + switch (retval) { + case 0: + return match_MATCH; + case FNM_NOMATCH: + return match_NOMATCH; +#if 0 + case FNM_NOSYS: + return match_ENOSYS; +#endif + default: + return match_EUNKNOWN; + } +} + +void +match_freeGlob(match_GlobContext *context) { + uio_free(context->pattern); + match_freeGlobContext(context); +} + +static inline match_GlobContext * +match_newGlobContext(char *pattern) { + match_GlobContext *result; + + result = match_allocGlobContext(); + result->pattern = pattern; + return result; +} + +static inline match_GlobContext * +match_allocGlobContext(void) { + return uio_malloc(sizeof (match_GlobContext)); +} + +static inline void +match_freeGlobContext(match_GlobContext *context) { + uio_free(context); +} +#endif /* HAVE_GLOB */ + + +// *** Regex part *** + +#ifdef HAVE_REGEX +match_Result +match_prepareRegex(const char *pattern, match_RegexContext **contextPtr) { + *contextPtr = match_newRegexContext(); + (*contextPtr)->errorCode = regcomp(&(*contextPtr)->native, pattern, + REG_EXTENDED | REG_NOSUB); + if ((*contextPtr)->errorCode == 0) { + (*contextPtr)->flags = match_REGEX_INITIALISED; + return match_OK; + } + return match_ECUSTOM; +} + +match_Result +match_matchRegex(match_RegexContext *context, const char *string) { + int retval; + + if ((context->flags & match_REGEX_INITIALISED) != + match_REGEX_INITIALISED) { + return match_ENOTINIT; + } + if (context->errorString) { + uio_free(context->errorString); + context->errorString = NULL; + } + retval = regexec(&context->native, string, 0, NULL, 0); + switch (retval) { + case 0: + return match_MATCH; + case REG_NOMATCH: + return match_NOMATCH; + default: + context->errorCode = retval; + return match_ECUSTOM; + } +} + +const char * +match_errorStringRegex(match_RegexContext *context, int errorCode) { + size_t errorStringLength; + + if (context->errorString != NULL) + uio_free(context->errorString); + + errorStringLength = regerror(context->errorCode, &context->native, + NULL, 0); + context->errorString = uio_malloc(errorStringLength); + regerror(context->errorCode, &context->native, + context->errorString, errorStringLength); + + (void) errorCode; + return context->errorString; +} + +void +match_freeRegex(match_RegexContext *context) { + regfree(&context->native); + if (context->errorString) + uio_free(context->errorString); + match_freeRegexContext(context); +} + +static inline match_RegexContext * +match_newRegexContext(void) { + match_RegexContext *result; + result = match_allocRegexContext(); + result->errorString = NULL; + result->errorCode = 0; + result->flags = 0; + return result; +} + +static inline match_RegexContext * +match_allocRegexContext(void) { + return uio_malloc(sizeof (match_RegexContext)); +} + +static inline void +match_freeRegexContext(match_RegexContext *context) { + uio_free(context); +} +#endif /* HAVE_REGEX */ + -- cgit v1.2.3