Support glob pattern for epicsEnvShow
Add epicsStrnGlobMatch with tests
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user