diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index e4c30be..52a9fb7 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -4,7 +4,9 @@ CA Gateway Release Notes
## 2.1.4 (not released yet)
[View diff](https://github.com/epics-extensions/ca-gateway/compare/R2-1-3-0...master)
-* Ehhh...
+* Support for pcre2 added
+* Fix some compiler warnings
+* Ensure that ASL defaults to 1
## 2.1.3 (15 Dec 2021)
[View diff](https://github.com/epics-extensions/ca-gateway/compare/R2-1-2-0...R2-1-3-0)
diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE
index 5dee672..e440778 100644
--- a/configure/CONFIG_SITE
+++ b/configure/CONFIG_SITE
@@ -13,15 +13,12 @@
#######################################################################
# Use Perl compatible regular expressions (PCRE) instead of basic regex
-#USE_PCRE=YES
-
-# For PCRE on Linux
-# requires package pcre-devel (or libpcre3-dev) for compiling
-# requires package pcre (or libpcre3) for running the Gateway
+#USE_PCRE=2
+# For PCRE on Linux make sure PCRE 1 or 2 deveopment packeges are installed.
ifeq ($(OS_CLASS),WIN32)
- # For PCRE on Windows
+ # For PCRE 1 on Windows
# install libraries and includes from
# https://sourceforge.net/projects/gnuwin32/files/pcre/7.0/pcre-7.0.exe/download
# and set the install location here
@@ -29,7 +26,7 @@ ifeq ($(OS_CLASS),WIN32)
# For REGEX on Windows
# compile gnuregex inside an EPICS support module from the sources at
- # http://www.aps.anl.gov/epics/download/extensions/gnuregex0_13.tar.gz
+ # https://epics.anl.gov/download/extensions/gnuregex0_13.tar.gz
# and set the module location here
REGEX_DIR=C:/epics/modules/regex
diff --git a/docs/Gateway.html b/docs/Gateway.html
index ff1e0fe..1642369 100644
--- a/docs/Gateway.html
+++ b/docs/Gateway.html
@@ -625,12 +625,16 @@
what process variable name patterns are allowed or denied and to optionally
associate patterns with access security groups and security levels in the
access file. The patterns are either Perl compatible regular expressions
-(PCRE) or GNU-style regular expressions, depending on the USE_PCRE variable
-in Makefile. (See a UNIX book for more information about regular expressions.)
-In addition, inverted regular experessions (starting with !) are supported
-depending on the USE_NEG_REGEXP variable in Makefile. For compatibility
-with earlier versions of the gateway, PCRE and inverted regular expressions
-are disable by default. There is a sample file,
+(PCRE or PCRE2) or GNU-style regular expressions, depending on the
+USE_PCRE variable defined in CONFIG_SITE.
+Set USE_PCRE=1 (or for backward compatibility
+USE_PCRE=YES) to use obsolete PCRE version 1 or set
+USE_PCRE=2 to use modern PCRE2.
+
+In addition, inverted regular experessions (starting with !)
+are supported depending on the USE_NEG_REGEXP variable in Makefile.
+For compatibility with earlier versions of the gateway, PCRE and inverted
+regular expressions are disable by default. There is a sample file,
gateway.pvlist, in the source distribution and reproduced here to get you started. The version in the
distribution may be more recent. Directions for this file are in the sample
diff --git a/src/Makefile b/src/Makefile
index 755724b..940b5e9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -25,8 +25,8 @@ ifeq ($(CMPLR_CLASS),msvc)
USR_LDFLAGS_WIN32 += /SUBSYSTEM:CONSOLE
endif
-ifeq ($(USE_PCRE),YES)
- USR_CXXFLAGS += -DUSE_PCRE
+ifneq ($(filter YES 1 2,$(USE_PCRE)),)
+ gateAs_CPPFLAGS += -DUSE_PCRE=$(patsubst YES,1,$(USE_PCRE))
ifeq ($(OS_CLASS),WIN32)
ifneq (,$(wildcard $(PCRE_DIR)/inc/*.h))
# Legacy nonstandard pcre3 download and manual install
@@ -53,7 +53,7 @@ ifeq ($(USE_PCRE),YES)
endif
endif
else
- USR_SYS_LIBS += pcre
+ USR_SYS_LIBS += $(if $(filter 2,$(USE_PCRE)), pcre2-8, pcre)
endif
else
# On Linux basic regex is part of libc
diff --git a/src/gateAs.cc b/src/gateAs.cc
index 962347d..c4c22e7 100644
--- a/src/gateAs.cc
+++ b/src/gateAs.cc
@@ -82,8 +82,13 @@ gateAsEntry::gateAsEntry(const char* pattern, const char* realname, const char*
{
#ifdef USE_PCRE
pat_buff = NULL;
+#if USE_PCRE == 1
ovector = NULL;
ovecsize = 0;
+#endif
+#if USE_PCRE == 2
+ match_data = NULL;
+#endif
#else
// Set pointers in the pattern buffer
pat_buff.buffer=NULL;
@@ -99,8 +104,14 @@ gateAsEntry::~gateAsEntry(void)
{
// Free allocated stuff in the pattern buffer
#ifdef USE_PCRE
+#if USE_PCRE == 1
pcre_free(pat_buff);
pcre_free(ovector);
+#endif
+#if USE_PCRE == 2
+ pcre2_code_free(pat_buff);
+ pcre2_match_data_free(match_data);
+#endif
#else
regfree(&pat_buff);
// Free allocted stuff in registers
@@ -124,10 +135,11 @@ long gateAsEntry::removeMember(void)
return rc;
}
-void gateAsEntry::getRealName(const char* pv, char* rname, int len)
+void gateAsEntry::getRealName(const char* pv, char* rname, size_t len)
{
char c;
- int in, ir, j, n;
+ size_t in, ir, j;
+ int n;
if (alias) { // Build real name from substitution pattern
ir = 0;
@@ -139,7 +151,7 @@ void gateAsEntry::getRealName(const char* pv, char* rname, int len)
#ifdef USE_PCRE
if(n < substrings && ovector[2*n] >= 0) {
for(j=ovector[2*n];
- ir= 0) {
for(j=regs.start[n];
- ir pi = list.firstIter();
while(pi.pointer()) {
- int len = (int) strlen(pv);
+ size_t len = strlen(pv);
#ifdef USE_PCRE
+#if USE_PCRE == 1
pi->substrings=pcre_exec(pi->pat_buff, NULL,
- pv, len, 0, PCRE_ANCHORED, pi->ovector, 30);
- if((pi->substrings>=0 && pi->ovector[1] == len)
+ pv, len, 0, PCRE_ANCHORED, pi->ovector, pi->ovecsize); // max 10 captures
+#endif
+#if USE_PCRE == 2
+ pi->substrings=pcre2_match(pi->pat_buff,
+ (PCRE2_SPTR)pv, len, 0, PCRE2_ANCHORED, pi->match_data, NULL);
+#endif
+ if((pi->substrings>=0 && (size_t)(pi->ovector[1]) == len)
#ifdef USE_NEG_REGEXP
- ^ pi->negate_pattern
+ ^ pi->negate_pattern
#endif
) break;
#else
- if((re_match(&pi->pat_buff, pv, len, 0, &pi->regs) == len)
+ if((re_match(&pi->pat_buff, pv, len, 0, &pi->regs) == (regoff_t)len)
#ifdef USE_NEG_REGEXP
^ pi->negate_pattern
#endif
@@ -411,7 +450,6 @@ gateAsEntry* gateAs::findEntryInList(const char* pv, gateAsList& list) const
int gateAs::readPvList(const char* lfile)
{
- int lev;
int line=0;
FILE* fd;
char inbuf[GATE_MAX_PVLIST_LINE_LENGTH];
@@ -448,15 +486,15 @@ int gateAs::readPvList(const char* lfile)
// Read all PV file lines
while(fgets(inbuf,sizeof(inbuf),fd)) {
-
+ int lev=1;
++line;
pattern=rname=hname=NULL;
#ifdef USE_DENYFROM
//All deny from rules with host names will be conveted to ip addresses
- strncpy(tempInbuf,inbuf,strlen(inbuf));
- tempInbuf[strlen(inbuf)-1]='\0';
+ strncpy(tempInbuf,inbuf,sizeof(tempInbuf)-1);
+ tempInbuf[sizeof(tempInbuf)-1]='\0';
if((ptr=strchr(inbuf,'#'))) *ptr='\0'; // Take care of comments
@@ -495,7 +533,7 @@ int gateAs::readPvList(const char* lfile)
ch=strchr(hostname,':');
if(ch != NULL) hostname[ch-hostname]=0;
- strncpy(pIPInput,hostname,strlen(hostname));
+ strncpy(pIPInput,hostname,sizeof(inbufWithIPs)-1-(inbufWithIPs-pIPInput));
*(pIPInput+strlen(hostname)) = ' ';
pIPInput = pIPInput + strlen(hostname) + 1;
}
@@ -510,20 +548,20 @@ int gateAs::readPvList(const char* lfile)
}else
{
- strncpy(inbufWithIPs,tempInbuf,strlen(tempInbuf));
- inbufWithIPs[strlen(tempInbuf)]='\0';
+ strncpy(inbufWithIPs,tempInbuf,sizeof(inbufWithIPs)-1);
+ inbufWithIPs[sizeof(inbufWithIPs)-1]='\0';
}
}else
{
- strncpy(inbufWithIPs,tempInbuf,strlen(tempInbuf));
- inbufWithIPs[strlen(tempInbuf)]='\0';
+ strncpy(inbufWithIPs,tempInbuf,sizeof(inbufWithIPs)-1);
+ inbufWithIPs[sizeof(inbufWithIPs)-1]='\0';
}
- pl=new gateAsLine(inbufWithIPs,strlen(inbufWithIPs),line_list);
+ pl=new gateAsLine(inbufWithIPs,line_list);
#else
if((ptr=strchr(inbuf,'#'))) *ptr='\0'; // Take care of comments
- pl=new gateAsLine(inbuf,strlen(inbuf),line_list);
+ pl=new gateAsLine(inbuf,line_list);
#endif
if(!(pattern=strtok(pl->buf," \t\n"))) continue;
diff --git a/src/gateAs.h b/src/gateAs.h
index 374ecc3..4eb45dc 100644
--- a/src/gateAs.h
+++ b/src/gateAs.h
@@ -46,7 +46,16 @@ extern "C" {
#include "aitTypes.h"
#ifdef USE_PCRE
+
+#if USE_PCRE == 1
#include
+#endif
+
+#if USE_PCRE == 2
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include
+#endif
+
#else
extern "C" {
@@ -121,7 +130,7 @@ class gateAsEntry : public tsSLNode
#endif
long removeMember(void);
- void getRealName(const char* pv, char* real, int len);
+ void getRealName(const char* pv, char* real, size_t len);
const char* pattern;
const char* alias;
@@ -129,10 +138,17 @@ class gateAsEntry : public tsSLNode
int level;
ASMEMBERPVT asmemberpvt;
#ifdef USE_PCRE
- pcre* pat_buff;
int substrings;
+#if USE_PCRE == 1
+ pcre* pat_buff;
int ovecsize;
int *ovector;
+#endif
+#if USE_PCRE == 2
+ pcre2_code* pat_buff;
+ pcre2_match_data* match_data;
+ PCRE2_SIZE *ovector;
+#endif
#else
char pat_valid;
struct re_pattern_buffer pat_buff;
@@ -192,11 +208,10 @@ class gateAsLine : public tsSLNode
{
public:
gateAsLine(void) : buf(NULL) { }
- gateAsLine(const char* line, size_t len, tsSLList& n) :
- buf(new char[len+1])
+ gateAsLine(const char* line, tsSLList& n) :
+ buf(new char[strlen(line)+1])
{
- strncpy(buf,line,len+1);
- buf[len] = '\0';
+ strcpy(buf,line);
n.add(*this);
}
~gateAsLine(void)
diff --git a/src/gateAsCa.cc b/src/gateAsCa.cc
index 20cbd28..7bc3349 100644
--- a/src/gateAsCa.cc
+++ b/src/gateAsCa.cc
@@ -19,6 +19,24 @@
#include "alarm.h"
#include "cadef.h"
#include "epicsPrint.h"
+#include "epicsVersion.h"
+#ifdef VERSION_INT
+#include "epicsAtomic.h"
+#else
+// Have no epicsAtomic.h
+#if __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+#define epicsAtomicSetIntT(pv,x) ({ (*(pv))=(x); __sync_synchronize (); })
+#define epicsAtomicGetIntT(pv) ({ __sync_synchronize (); (*(pv)); })
+#define epicsAtomicIncrIntT(pv) __sync_add_and_fetch((pv),1)
+#define epicsAtomicDecrIntT(pv) __sync_sub_and_fetch((pv),1)
+#else
+// Hope for the best
+#define epicsAtomicSetIntT(pv,x) (*(pv))=(x)
+#define epicsAtomicGetIntT(pv) (*(pv))
+#define epicsAtomicIncrIntT(pv) (++*(pv))
+#define epicsAtomicDecrIntT(pv) (--*(pv))
+#endif
+#endif
epicsShareExtern volatile ASBASE *pasbase;
@@ -31,7 +49,7 @@ typedef struct _capvt {
} CAPVT;
static volatile int ready = 0;
-static volatile int count = 0;
+static int count = 0;
static time_t start_time;
extern "C" {
@@ -77,15 +95,15 @@ static void eventCB(struct event_handler_args arg)
#endif
if (!ready && !pcapvt->gotFirstEvent)
{
- --count;
+ epicsAtomicDecrIntT(&count);
#if DEBUG_DELAY
- printf(" !ready && !pcapvt->gotFirstEvent count=%d\n",count);
+ printf(" !ready && !pcapvt->gotFirstEvent count=%d\n", epicsAtomicGetIntT(&count));
#endif
pcapvt->gotFirstEvent=TRUE;
}
if(ca_state(chid)!=cs_conn || !ca_read_access(chid)) {
#if DEBUG_DELAY
- printf(" ca_state(chid)!=cs_conn || !ca_read_access(chid) count=%d\n",count);
+ printf(" ca_state(chid)!=cs_conn || !ca_read_access(chid) count=%d\n", epicsAtomicGetIntT(&count));
#endif
if(!(pasg->inpBad & (1<inpIndex))) {
// was good so lets make it bad
@@ -95,12 +113,12 @@ static void eventCB(struct event_handler_args arg)
} else {
if(caStatus!=ECA_NORMAL) {
#if DEBUG_DELAY
- printf(" caStatus!=ECA_NORMAL count=%d\n",count);
+ printf(" caStatus!=ECA_NORMAL count=%d\n", epicsAtomicGetIntT(&count));
#endif
epicsPrintf("asCa: eventCallback error %s\n",ca_message(caStatus));
} else {
#if DEBUG_DELAY
- printf(" caStatus == ECA_NORMAL count=%d\n",count);
+ printf(" caStatus == ECA_NORMAL count=%d\n", epicsAtomicGetIntT(&count));
#endif
pcapvt->rtndata = *pdata; // structure copy
if(pdata->severity==INVALID_ALARM) {
@@ -126,7 +144,7 @@ void gateAsCa(void)
time_t cur_time;
ready=0;
- count=0;
+ epicsAtomicSetIntT(&count,0);
time(&start_time);
// CA must be initialized by this time - hackery
@@ -144,7 +162,7 @@ void gateAsCa(void)
pasg->inpBad |= (1<inpIndex);
pasginp->capvt=(CAPVT*)asCalloc(1,sizeof(CAPVT));
pcapvt=(CAPVT*)pasginp->capvt;
- ++count;
+ epicsAtomicIncrIntT(&count);
gateDebug1(11,"Access security searching for %s\n",pasginp->inp);
// Note calls gateAsCB immediately called for local Pvs
@@ -169,7 +187,7 @@ void gateAsCa(void)
}
time(&cur_time);
- while(count>0 && (cur_time-start_time)<4)
+ while(epicsAtomicGetIntT(&count)>0 && (cur_time-start_time)<4)
{
ca_pend_event(1.0);
time(&cur_time);
diff --git a/src/gateway.cc b/src/gateway.cc
index 9096da0..b56d879 100644
--- a/src/gateway.cc
+++ b/src/gateway.cc
@@ -1606,7 +1606,7 @@ static int setEnv(const char *var, int ival, char **envString)
}
#else
char *pVal=strchr(*envString,'=');
- if(!pVal || !(pVal+1)) {
+ if(!pVal || !pVal[1]) {
epicsEnvSet(var,"");
} else {
epicsEnvSet(var,pVal+1);
diff --git a/testTop/pyTestsApp/Makefile b/testTop/pyTestsApp/Makefile
index 5d343dc..114d3c5 100644
--- a/testTop/pyTestsApp/Makefile
+++ b/testTop/pyTestsApp/Makefile
@@ -23,9 +23,7 @@ TESTFILES += test.db
TESTFILES += access.txt
# Which pvlist.txt file depends on USE_PCRE
-USE_PCRE ?= NO
-PVLIST_YES = pvlist_pcre.txt
-PVLIST_NO = pvlist_bre.txt
+PVLIST = $(if $(filter YES 1 2,$(USE_PCRE)),pvlist_pcre.txt,pvlist_bre.txt)
CLEANS += *.pyc $(TESTFILES) pvlist.txt gateway.* *.tap
@@ -58,7 +56,7 @@ testfiles: $(TESTFILES:%=../%)
$(ECHO) "Copying test files $(TESTFILES)"
@$(CP) $^ .
-pvlist.txt: ../$(PVLIST_$(USE_PCRE))
+pvlist.txt: ../$(PVLIST)
$(ECHO) "Copying $< to $@ (USE_PCRE: $(USE_PCRE))"
@$(CP) $< $@