Support glob pattern for epicsEnvShow

Add epicsStrnGlobMatch with tests
This commit is contained in:
2021-04-18 18:04:48 +02:00
committed by Michael Davidsaver
parent 08b741ed05
commit b777233efb
7 changed files with 114 additions and 46 deletions

View File

@@ -17,6 +17,16 @@ should also be read to understand what has changed since earlier releases.
<!-- Insert new items immediately below here ... -->
### 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

View File

@@ -23,6 +23,15 @@
#include <errno.h>
#include <ctype.h>
#ifndef vxWorks
#include <stdint.h>
#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;

View File

@@ -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,

View File

@@ -15,11 +15,11 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#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);
}
}

View File

@@ -15,11 +15,11 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#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);
}
}

View File

@@ -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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <envLib.h>
#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);
}
}

View File

@@ -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();