From b777233efb06fa4e988c4f0738b0270dd3d095a3 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Sun, 18 Apr 2021 18:04:48 +0200 Subject: [PATCH] Support glob pattern for epicsEnvShow Add epicsStrnGlobMatch with tests --- documentation/RELEASE_NOTES.md | 10 ++++++ modules/libcom/src/misc/epicsString.c | 34 +++++++++++++------ modules/libcom/src/misc/epicsString.h | 23 +++++++++++++ modules/libcom/src/osi/os/WIN32/osdEnv.c | 16 +++------ modules/libcom/src/osi/os/default/osdEnv.c | 17 +++------- modules/libcom/src/osi/os/vxWorks/osdEnv.c | 21 ++++++------ modules/libcom/test/epicsStringTest.c | 39 +++++++++++++++++++++- 7 files changed, 114 insertions(+), 46 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 8e17ce35d..c9272f3c7 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -17,6 +17,16 @@ should also be read to understand what has changed since earlier releases. +### epicsEnvShow accepts glob pattern + +The optional argument to epicsEnvShow can now be a glob pattern. + +### New function `epicsStrnGlobMatch()` + +The function `epicsStrnGlobMatch(char* str, size_t len, char* pattern)` +works exactly the same as `epicsStrGlobMatch()` but takes an additional +length arguments which limits the number of characters of `str` to match. + ### Automatic fallback to thread when unable to exec caRepeater A process using libca which does not find an existing caRepeater process diff --git a/modules/libcom/src/misc/epicsString.c b/modules/libcom/src/misc/epicsString.c index e18d9214a..be6463438 100644 --- a/modules/libcom/src/misc/epicsString.c +++ b/modules/libcom/src/misc/epicsString.c @@ -23,6 +23,15 @@ #include #include +#ifndef vxWorks +#include +#else +/* VxWorks automaticaly includes stdint.h defining SIZE_MAX in 6.9 but not earlier */ +#ifndef SIZE_MAX +#define SIZE_MAX (size_t)-1 +#endif +#endif + #include "epicsAssert.h" #include "epicsStdio.h" #include "cantProceed.h" @@ -259,30 +268,31 @@ size_t epicsStrnLen(const char *s, size_t maxlen) return i; } -int epicsStrGlobMatch(const char *str, const char *pattern) +int epicsStrnGlobMatch(const char *str, size_t len, const char *pattern) { - const char *cp = NULL, *mp = NULL; + const char *mp = NULL; + size_t cp = 0, i = 0; - while ((*str) && (*pattern != '*')) { - if ((*pattern != *str) && (*pattern != '?')) + while ((i < len) && (str[i]) && (*pattern != '*')) { + if ((*pattern != str[i]) && (*pattern != '?')) return 0; pattern++; - str++; + i++; } - while (*str) { + while ((i < len) && str[i]) { if (*pattern == '*') { if (!*++pattern) return 1; mp = pattern; - cp = str+1; + cp = i+1; } - else if ((*pattern == *str) || (*pattern == '?')) { + else if ((*pattern == str[i]) || (*pattern == '?')) { pattern++; - str++; + i++; } else { pattern = mp; - str = cp++; + i = cp++; } } while (*pattern == '*') @@ -290,6 +300,10 @@ int epicsStrGlobMatch(const char *str, const char *pattern) return !*pattern; } +int epicsStrGlobMatch(const char *str, const char *pattern) { + return epicsStrnGlobMatch(str, SIZE_MAX, pattern); +} + char * epicsStrtok_r(char *s, const char *delim, char **lasts) { const char *spanp; diff --git a/modules/libcom/src/misc/epicsString.h b/modules/libcom/src/misc/epicsString.h index 854b552c6..5bb8c87c1 100644 --- a/modules/libcom/src/misc/epicsString.h +++ b/modules/libcom/src/misc/epicsString.h @@ -36,7 +36,30 @@ LIBCOM_API char * epicsStrnDup(const char *s, size_t len); LIBCOM_API int epicsStrPrintEscaped(FILE *fp, const char *s, size_t n); #define epicsStrSnPrintEscaped epicsStrnEscapedFromRaw LIBCOM_API size_t epicsStrnLen(const char *s, size_t maxlen); + +/** Matches a string against a pattern. + * + * Checks if str matches the glob style pattern, which may contain ? or * wildcards. + * A ? matches any single character. + * A * matched any sub-string. + * + * @returns 1 if str matches the pattern, 0 if not. + * + * @since EPICS 3.14.7 + */ LIBCOM_API int epicsStrGlobMatch(const char *str, const char *pattern); + +/** Matches a string against a pattern. + * + * Like epicsStrGlobMatch but with limited string length. + * If the length of str is less than len, the full string is matched. + * + * @returns 1 if the first len characters of str match the pattern, 0 if not. + * + * @since UNRELEASED + */ +LIBCOM_API int epicsStrnGlobMatch(const char *str, size_t len, const char *pattern); + LIBCOM_API char * epicsStrtok_r(char *s, const char *delim, char **lasts); LIBCOM_API unsigned int epicsStrHash(const char *str, unsigned int seed); LIBCOM_API unsigned int epicsMemHash(const char *str, size_t length, diff --git a/modules/libcom/src/osi/os/WIN32/osdEnv.c b/modules/libcom/src/osi/os/WIN32/osdEnv.c index adc40b58c..18e66cb6b 100644 --- a/modules/libcom/src/osi/os/WIN32/osdEnv.c +++ b/modules/libcom/src/osi/os/WIN32/osdEnv.c @@ -15,11 +15,11 @@ #include #include -#include #include #include #include "epicsStdio.h" +#include "epicsString.h" #include "errlog.h" #include "envDefs.h" #include "osiUnistd.h" @@ -61,18 +61,10 @@ LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name) */ LIBCOM_API void epicsStdCall epicsEnvShow (const char *name) { - if (name == NULL) { - extern char **environ; - char **sp; + char **sp; - for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) + for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) { + if (!name || epicsStrnGlobMatch(*sp, strchr(*sp, '=') - *sp, name)) printf ("%s\n", *sp); } - else { - const char *cp = getenv (name); - if (cp == NULL) - printf ("%s is not an environment variable.\n", name); - else - printf ("%s=%s\n", name, cp); - } } diff --git a/modules/libcom/src/osi/os/default/osdEnv.c b/modules/libcom/src/osi/os/default/osdEnv.c index 7ece253c7..74b5b8041 100644 --- a/modules/libcom/src/osi/os/default/osdEnv.c +++ b/modules/libcom/src/osi/os/default/osdEnv.c @@ -15,11 +15,11 @@ #include #include -#include #include #include #include "epicsStdio.h" +#include "epicsString.h" #include "epicsVersion.h" #include "errlog.h" #include "envDefs.h" @@ -68,18 +68,11 @@ LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name) */ LIBCOM_API void epicsStdCall epicsEnvShow (const char *name) { - if (name == NULL) { - extern char **environ; - char **sp; + extern char **environ; + char **sp; - for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) + for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) { + if (!name || epicsStrnGlobMatch(*sp, strchr(*sp, '=') - *sp, name)) printf ("%s\n", *sp); } - else { - const char *cp = getenv (name); - if (cp == NULL) - printf ("%s is not an environment variable.\n", name); - else - printf ("%s=%s\n", name, cp); - } } diff --git a/modules/libcom/src/osi/os/vxWorks/osdEnv.c b/modules/libcom/src/osi/os/vxWorks/osdEnv.c index d91208f4c..517bb2bd6 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdEnv.c +++ b/modules/libcom/src/osi/os/vxWorks/osdEnv.c @@ -16,17 +16,18 @@ /* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */ #define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h> -#include #include -#include +#include #include #include #include "epicsFindSymbol.h" #include "epicsStdio.h" +#include "epicsString.h" #include "errlog.h" #include "iocsh.h" + /* * Set the value of an environment variable * Leaks memory, but the assumption is that this routine won't be @@ -86,14 +87,12 @@ LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name) */ LIBCOM_API void epicsStdCall epicsEnvShow (const char *name) { - if (name == NULL) { - envShow (0); - } - else { - const char *cp = getenv (name); - if (cp == NULL) - printf ("%s is not an environment variable.\n", name); - else - printf ("%s=%s\n", name, cp); + extern char **ppGlobalEnviron; /* Used in 'environ' macro but not declared in envLib.h */ + char **sp; + + for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) { + if (!**sp) continue; /* skip unset environment variables */ + if (!name || epicsStrnGlobMatch(*sp, strchr(*sp, '=') - *sp, name)) + printf ("%s\n", *sp); } } diff --git a/modules/libcom/test/epicsStringTest.c b/modules/libcom/test/epicsStringTest.c index e4e95c998..7abffa3da 100644 --- a/modules/libcom/test/epicsStringTest.c +++ b/modules/libcom/test/epicsStringTest.c @@ -73,6 +73,43 @@ void testGlob(void) { testOk1(epicsStrGlobMatch("hello","he*")); testOk1(epicsStrGlobMatch("hello","*lo")); testOk1(epicsStrGlobMatch("hello","*")); + +/* epicsStrnGlobMatch */ + + testOk1(epicsStrnGlobMatch("xyzq",3,"xyz")); + testOk1(!epicsStrnGlobMatch("xyzq",3,"xyzm")); + testOk1(!epicsStrnGlobMatch("xyzm",3,"xyzm")); + testOk1(!epicsStrnGlobMatch("xyzm",0,"xyzm")); + testOk1(!epicsStrnGlobMatch("xyzq",3,"")); + testOk1(epicsStrnGlobMatch("xyz",0,"")); + + testOk1(epicsStrnGlobMatch("xyz",0,"*")); + testOk1(!epicsStrnGlobMatch("xyz",0,"?")); + testOk1(!epicsStrnGlobMatch("xyz",0,"?*")); + + testOk1(epicsStrnGlobMatch("hello!",5,"h*o")); + testOk1(!epicsStrnGlobMatch("hello!",5,"h*x")); + testOk1(!epicsStrnGlobMatch("hellxo",5,"h*o")); + + testOk1(epicsStrnGlobMatch("hello!",5,"he?lo")); + testOk1(!epicsStrnGlobMatch("hello!",5,"he?xo")); + testOk1(epicsStrnGlobMatch("hello!",5,"he??o")); + testOk1(!epicsStrnGlobMatch("helllo!",5,"he?lo")); + + testOk1(!epicsStrnGlobMatch("hello world!",10,"he*o w*d")); + testOk1(epicsStrnGlobMatch("hello world!",11,"he*o w*d")); + testOk1(!epicsStrnGlobMatch("hello world!",12,"he*o w*d")); + testOk1(!epicsStrnGlobMatch("hello_world!",11,"he*o w*d")); + testOk1(epicsStrnGlobMatch("hello world!",11,"he**d")); + + testOk1(epicsStrnGlobMatch("hello hello world!!!!!!!!!!!!!!!!!!!!",17,"he*o w*d")); + + testOk1(!epicsStrnGlobMatch("hello hello world",15,"he*o w*d")); + + testOk1(epicsStrnGlobMatch("hello!!",5,"he*")); + testOk1(epicsStrnGlobMatch("hello!!",5,"*lo")); + testOk1(epicsStrnGlobMatch("hello!!",5,"*")); + } static @@ -118,7 +155,7 @@ MAIN(epicsStringTest) char *s; int status; - testPlan(401); + testPlan(427); testChars();