diff --git a/cmake/NeuronFileLists.cmake b/cmake/NeuronFileLists.cmake index c1beffb9fd..e42d769355 100644 --- a/cmake/NeuronFileLists.cmake +++ b/cmake/NeuronFileLists.cmake @@ -421,7 +421,7 @@ set(NMODL_FILES_LIST units.cpp version.cpp) -set(IVOS_FILES_LIST observe.cpp regexp.cpp resource.cpp) +set(IVOS_FILES_LIST observe.cpp resource.cpp) set(MPI_DYNAMIC_INCLUDE nrnmpi_dynam.h nrnmpi_dynam_cinc nrnmpi_dynam_wrappers.inc) diff --git a/share/lib/hoc/import3d/read_nlcda3.hoc b/share/lib/hoc/import3d/read_nlcda3.hoc index 142d78cd34..f1a2602ab5 100755 --- a/share/lib/hoc/import3d/read_nlcda3.hoc +++ b/share/lib/hoc/import3d/read_nlcda3.hoc @@ -545,7 +545,7 @@ proc b2soption_split() {local i, n, id, ip localobj p, newsec, tobj } proc remove_trailspace() { // yuck - hoc_sf_.head(line, " *$", line) + hoc_sf_.rtrim(line, line) sprint(line, "%s\n", line) } diff --git a/src/ivoc/strfun.cpp b/src/ivoc/strfun.cpp index f21820b2d8..cb5375eb82 100644 --- a/src/ivoc/strfun.cpp +++ b/src/ivoc/strfun.cpp @@ -1,10 +1,10 @@ #include <../../nrnconf.h> -#include #include #include #include "classreg.h" #include "oc2iv.h" #include +#include // for alias #include #include @@ -39,31 +39,52 @@ static double l_len(void*) { static double l_head(void*) { std::string text(gargstr(1)); - Regexp r(gargstr(2)); - r.Search(text.c_str(), text.size(), 0, text.size()); - int i = r.BeginningOfMatch(); - // text.set_to_left(i); doesnt work - char** head = hoc_pgargstr(3); - if (i > 0) { - hoc_assign_str(head, text.substr(0, i).c_str()); - } else { - hoc_assign_str(head, ""); + { // Clean the text so we keep only the first line + // Imitation of std::multiline in our case + std::regex r("^(.*)(\n|$)"); + std::smatch sm; + std::regex_search(text, sm, r); + text = sm[1]; } + int i = -1; + std::string result{}; + try { + std::regex r(gargstr(2), std::regex::egrep); + if (std::smatch sm; std::regex_search(text, sm, r)) { + i = sm.position(); + result = sm.prefix().str(); + } + } catch (const std::regex_error& e) { + std::cerr << e.what() << std::endl; + } + char** head = hoc_pgargstr(3); + hoc_assign_str(head, result.c_str()); hoc_return_type_code = 1; // integer return double(i); } static double l_tail(void*) { std::string text(gargstr(1)); - Regexp r(gargstr(2)); - r.Search(text.c_str(), text.size(), 0, text.size()); - int i = r.EndOfMatch(); - char** tail = hoc_pgargstr(3); - if (i >= 0) { - hoc_assign_str(tail, text.c_str() + i); - } else { - hoc_assign_str(tail, ""); + { // Clean the text so we keep only the first line + // Imitation of std::multiline in our case + std::regex r("^(.*)(\n|$)"); + std::smatch sm; + std::regex_search(text, sm, r); + text = sm[1]; } + int i = -1; + std::string result{}; + try { + std::regex r(gargstr(2), std::regex::egrep); + if (std::smatch sm; std::regex_search(text, sm, r)) { + i = sm.position() + sm.length(); + result = sm.suffix().str(); + } + } catch (const std::regex_error& e) { + std::cerr << e.what() << std::endl; + } + char** tail = hoc_pgargstr(3); + hoc_assign_str(tail, result.c_str()); hoc_return_type_code = 1; // integer return double(i); } diff --git a/src/ivos/InterViews/_defines.h b/src/ivos/InterViews/_defines.h index 7bb9234e5c..9b2a95fa6f 100755 --- a/src/ivos/InterViews/_defines.h +++ b/src/ivos/InterViews/_defines.h @@ -217,7 +217,6 @@ #define Raster _lib_iv(Raster) #define RasterRep _lib_iv(RasterRep) #define Reducer _lib_iv(Reducer) -#define Regexp _lib_iv(Regexp) #define ReqErr _lib_iv(ReqErr) #define Requirement _lib_iv(Requirement) #define Requisition _lib_iv(Requisition) diff --git a/src/ivos/InterViews/_undefs.h b/src/ivos/InterViews/_undefs.h index a93e162890..6891baa495 100755 --- a/src/ivos/InterViews/_undefs.h +++ b/src/ivos/InterViews/_undefs.h @@ -217,7 +217,6 @@ #undef Raster #undef RasterRep #undef Reducer -#undef Regexp #undef ReqErr #undef Requirement #undef Requisition diff --git a/src/ivos/InterViews/regexp.h b/src/ivos/InterViews/regexp.h deleted file mode 100755 index c1466fd7dc..0000000000 --- a/src/ivos/InterViews/regexp.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 1987, 1988, 1989, 1990, 1991 Stanford University - * Copyright (c) 1991 Silicon Graphics, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that (i) the above copyright notices and this permission notice appear in - * all copies of the software and related documentation, and (ii) the names of - * Stanford and Silicon Graphics may not be used in any advertising or - * publicity relating to the software without the specific, prior written - * permission of Stanford and Silicon Graphics. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL STANFORD OR SILICON GRAPHICS BE LIABLE FOR - * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, - * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF - * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - -/* - * Regexp - regular expression searching - */ - -#ifndef iv_regexp_h -#define iv_regexp_h - -#include - -/* - * These definitions are from Henry Spencers public-domain regular - * expression matching routines. - * - * Definitions etc. for regexp(3) routines. - * - * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], - * not the System V one. - */ -#define NSUBEXP 10 -struct regexp { - char *startp[NSUBEXP]; - char *endp[NSUBEXP]; - char *textStart; - char regstart; /* Internal use only. */ - char reganch; /* Internal use only. */ - char *regmust; /* Internal use only. */ - int regmlen; /* Internal use only. */ - char program[1]; /* Unwarranted chumminess with compiler. */ -}; - -/* - * The first byte of the regexp internal "program" is actually this magic - * number; the start node begins in the second byte. This used to be the octal - * integer literal 0234 = 156, which would be implicitly converted to -100 when - * narrowing to signed 8 bit char. This conversion was implementation defined - * before C++20. - */ -#define REGEXP_MAGIC static_cast(-100) - -class Regexp { -public: - Regexp(const char*); - Regexp(const char*, int length); - ~Regexp(); - - const char* pattern() const; - int Search(const char* text, int length, int index, int range); - int Match(const char* text, int length, int index); - int BeginningOfMatch(int subexp = 0); - int EndOfMatch(int subexp = 0); -private: - char* pattern_; - regexp* c_pattern; -}; - -#endif diff --git a/src/ivos/regexp.cpp b/src/ivos/regexp.cpp deleted file mode 100644 index ed96c43bcf..0000000000 --- a/src/ivos/regexp.cpp +++ /dev/null @@ -1,1219 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include <../../nrnconf.h> -#endif -/* - * Copyright (c) 1987, 1988, 1989, 1990, 1991 Stanford University - * Copyright (c) 1991 Silicon Graphics, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that (i) the above copyright notices and this permission notice appear in - * all copies of the software and related documentation, and (ii) the names of - * Stanford and Silicon Graphics may not be used in any advertising or - * publicity relating to the software without the specific, prior written - * permission of Stanford and Silicon Graphics. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL STANFORD OR SILICON GRAPHICS BE LIABLE FOR - * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, - * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF - * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - -/* - * Regexp - regular expression searching - */ - -#include -#include -#include - -/* - * This version is based on the Henry Spencers public domain reimplementation - * of the regular expression matching subroutines. They are included as - * static subroutines after the externally accessible routines. - */ - -/* - * Forward declarations for regcomp()'s friends. - */ -static regexp* regcomp(const char* exp); -static char* reg(int paren, int* flagp); -static char* regbranch(int* flagp); -static char* regpiece(int* flagp); -static char* regatom(int* flagp); -static char* regnode(char op); -static char* regnext(char* p); -static void regc(char b); -static void reginsert(char op, char* opnd); -static void regtail(char* p, char* val); -static void regoptail(char* p, char* val); -static void regerror(const char* s); -static int regexec(regexp* prog, char* string); -static int regtry(regexp* prog, char* string); -static int regmatch(char* prog); -static int regrepeat(char* p); - - -inline char * -FindNewline(char* s) { - return strchr(s, '\n'); -} - -inline char * -NextLine(char* s) { - char* newstart; - - if ((newstart = FindNewline(s)) != nil) - newstart++; - return newstart; -} - -Regexp::Regexp (const char* pat) { - int length = strlen(pat); - pattern_ = new char[length+1]; - strncpy(pattern_, pat, length); - pattern_[length] = '\0'; - c_pattern = regcomp(pattern_); - if (!c_pattern) { - delete [] pattern_; - pattern_ = nil; - } -} - -Regexp::Regexp (const char* pat, int length) { - pattern_ = new char[length+1]; - strncpy(pattern_, pat, length); - pattern_[length] = '\0'; - c_pattern = regcomp(pattern_); - if (!c_pattern) { - delete [] pattern_; - pattern_ = nil; - } -} - -Regexp::~Regexp () { - if (pattern_) { - delete [] pattern_; - } - if (c_pattern) { - delete [] c_pattern; - } -} - -const char* Regexp::pattern() const { return pattern_; } - -int Regexp::Search (const char* text, int length, int index, int range) { - bool forwardSearch; - bool frontAnchored; - bool endAnchored; - char* searchStart; - char* searchLimit; - char* endOfLine = nil; - char* lastMatch = nil; - char csave; - - /* - * A small sanity check. Otherwise length is unused in this function. - * This is really what the logic embedded in the old version of this - * routine enforced. - */ - if (index + range > length) { - range = length - index; - if (range < 0) - return -1; - } - - if (c_pattern == nil) { - return -1; - } - - c_pattern->startp[0] = nil; - - if (range < 0) { - forwardSearch = false; - searchLimit = (char *) text + index; - searchStart = (char *) searchLimit + range; /* range is negative */ - } else { - forwardSearch = true; - searchStart = (char *) text + index; - searchLimit = (char *) searchStart + range; - } - - /* Mark end of text string so search will stop */ - char save = *searchLimit; - *searchLimit = '\0'; - - frontAnchored = pattern_[0] == '^'; - endAnchored = pattern_[strlen(pattern_)-1] == '$'; - if (frontAnchored && (searchStart != text && searchStart[-1] != '\n')) { - searchStart = NextLine(searchStart); - } - - while (searchStart && searchStart < searchLimit) { - int result; - - if (endAnchored && (endOfLine = FindNewline(searchStart)) != nil) { - csave = *endOfLine; - *endOfLine = '\0'; - } - - result = regexec(c_pattern, searchStart); - - if (endOfLine) - *endOfLine = csave; - - if (result) { - /* Found a match */ - if (forwardSearch) - break; /* Done */ - else { - lastMatch = c_pattern->startp[0]; - searchStart = c_pattern->endp[0]; - if (frontAnchored) - searchStart = NextLine(searchStart); - continue; - } - } - /* Did not find a match */ - if (frontAnchored || endAnchored) - searchStart = NextLine(searchStart); - else - break; - } - - if (!forwardSearch && lastMatch) { - if (endAnchored && (endOfLine = FindNewline(lastMatch)) != nil) { - csave = *endOfLine; - *endOfLine = '\0'; - } - (void) regexec(c_pattern, lastMatch); /* Refill startp and endp */ - if (endOfLine) - *endOfLine = csave; - } - - *searchLimit = save; - c_pattern->textStart = (char *) text; - - return c_pattern->startp[0] - c_pattern->textStart; -} - -int Regexp::Match (const char* text, int length, int index) { - - if (c_pattern == nil) - return -1; - - c_pattern->startp[0] = nil; - - char save = *(text+length); - *(char*)(text+length) = '\0'; - - c_pattern->textStart = (char *) text; - (void) regexec(c_pattern, (char *) text + index); - - *(char*)(text+length) = save; - - if (c_pattern->startp[0] != nil) - return c_pattern->endp[0] - c_pattern->startp[0]; - else - return -1; -} - -int Regexp::BeginningOfMatch (int subexp) { - if (subexp < 0 || subexp > NSUBEXP || - c_pattern == nil || c_pattern->startp[0] == nil) - return -1; - return c_pattern->startp[subexp] - c_pattern->textStart; -} - -int Regexp::EndOfMatch (int subexp) { - if (subexp < 0 || subexp > NSUBEXP || - c_pattern == nil || c_pattern->startp[0] == nil) - return -1; - return c_pattern->endp[subexp] - c_pattern->textStart; -} - -/* - * regcomp and regexec - * - * Copyright (c) 1986 by University of Toronto. - * Written by Henry Spencer. Not derived from licensed software. - * - * Permission is granted to anyone to use this software for any - * purpose on any computer system, and to redistribute it freely, - * subject to the following restrictions: - * - * 1. The author is not responsible for the consequences of use of - * this software, no matter how awful, even if they arise - * from defects in it. - * - * 2. The origin of this software must not be misrepresented, either - * by explicit claim or by omission. - * - * 3. Altered versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * Beware that some of this code is subtly aware of the way operator - * precedence is structured in regular expressions. Serious changes in - * regular-expression syntax might require a total rethink. - */ - -/* - * The "internal use only" fields in regexp.h are present to pass info from - * compile to execute that permits the execute phase to run lots faster on - * simple cases. They are: - * - * regstart char that must begin a match; '\0' if none obvious - * reganch is the match anchored (at beginning-of-line only)? - * regmust string (pointer into program) that match must include, or nil - * regmlen length of regmust string - * - * Regstart and reganch permit very fast decisions on suitable starting points - * for a match, cutting down the work a lot. Regmust permits fast rejection - * of lines that cannot possibly match. The regmust tests are costly enough - * that regcomp() supplies a regmust only if the r.e. contains something - * potentially expensive (at present, the only such thing detected is * or + - * at the start of the r.e., which can involve a lot of backup). Regmlen is - * supplied because the test in regexec() needs it and regcomp() is computing - * it anyway. - */ - -/* - * Structure for regexp "program". This is essentially a linear encoding - * of a nondeterministic finite-state machine (aka syntax charts or - * "railroad normal form" in parsing technology). Each node is an opcode - * plus a "next" pointer, possibly plus an operand. "Next" pointers of - * all nodes except BRANCH implement concatenation; a "next" pointer with - * a BRANCH on both ends of it is connecting two alternatives. (Here we - * have one of the subtle syntax dependencies: an individual BRANCH (as - * opposed to a collection of them) is never concatenated with anything - * because of operator precedence.) The operand of some types of node is - * a literal string; for others, it is a node leading into a sub-FSM. In - * particular, the operand of a BRANCH node is the first node of the branch. - * (NB this is *not* a tree structure: the tail of the branch connects - * to the thing following the set of BRANCHes.) The opcodes are: - */ - -/* definition number opnd? meaning */ -#define END 0 /* no End of program. */ -#define BOL 1 /* no Match "" at beginning of line. */ -#define EOL 2 /* no Match "" at end of line. */ -#define ANY 3 /* no Match any one character. */ -#define ANYOF 4 /* str Match any character in this string. */ -#define ANYBUT 5 /* str Match any character not in this string. */ -#define BRANCH 6 /* node Match this alternative, or the next... */ -#define BACK 7 /* no Match "", "next" ptr points backward. */ -#define EXACTLY 8 /* str Match this string. */ -#define NOTHING 9 /* no Match empty string. */ -#define STAR 10 /* node Match this (simple) thing 0 or more times. */ -#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ -#define OPEN 20 /* no Mark this point in input as start of #n. */ - /* OPEN+1 is number 1, etc. */ -#define CLOSE 30 /* no Analogous to OPEN. */ - -/* - * Opcode notes: - * - * BRANCH The set of branches constituting a single choice are hooked - * together with their "next" pointers, since precedence prevents - * anything being concatenated to any individual branch. The - * "next" pointer of the last BRANCH in a choice points to the - * thing following the whole choice. This is also where the - * final "next" pointer of each individual branch points; each - * branch starts with the operand node of a BRANCH node. - * - * BACK Normal "next" pointers all implicitly point forward; BACK - * exists to make loop structures possible. - * - * STAR,PLUS '?', and complex '*' and '+', are implemented as circular - * BRANCH structures using BACK. Simple cases (one character - * per match) are implemented with STAR and PLUS for speed - * and to minimize recursive plunges. - * - * OPEN,CLOSE ...are numbered at compile time. - */ - -/* - * A node is one char of opcode followed by two chars of "next" pointer. - * "Next" pointers are stored as two 8-bit pieces, high order first. The - * value is a positive offset from the opcode of the node containing it. - * An operand, if any, simply follows the node. (Note that much of the - * code generation knows about this implicit relationship.) - * - * Using two bytes for the "next" pointer is vast overkill for most things, - * but allows patterns to get big without disasters. - */ -#define OP(p) (*(p)) -#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) -#define OPERAND(p) ((p) + 3) - -/* - * Utility definitions. - */ - -/** - * This replaces a macro of the same name with some bit manipulation magic in - * it. The does not seem well-suited now, but it's not clear that it was before - * either. - */ -inline int UCHARAT(const char* p) { - return *p; -} - -#define FAIL(m) { regerror(m); return(nil); } -#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') -#define META "^$.[()|?+*\\" - -/* - * Flags to be passed up and down. - */ -#define HASWIDTH 01 /* Known never to match null string. */ -#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ -#define SPSTART 04 /* Starts with * or +. */ -#define WORST 0 /* Worst case. */ - -/* - * Global work variables for regcomp(). - */ -static const char *regparse; /* Input-scan pointer. */ -static int regnpar; /* () count. */ -static char regdummy; -static char *regcode; /* Code-emit pointer; ®dummy = don't. */ -static long regsize; /* Code size. */ - -/* - - regcomp - compile a regular expression into internal code - * - * We can't allocate space until we know how big the compiled form will be, - * but we can't compile it (and thus know how big it is) until we've got a - * place to put the code. So we cheat: we compile it twice, once with code - * generation turned off and size counting turned on, and once "for real". - * This also means that we don't allocate space until we are sure that the - * thing really will compile successfully, and we never have to move the - * code and thus invalidate pointers into it. (Note that it has to be in - * one piece because free() must be able to free it all.) - * - * Beware that the optimization-preparation code in here knows about some - * of the structure of the compiled regexp. - */ -static regexp * -regcomp(const char* exp) { - regexp *r; - char *scan; - char *longest; - int len; - int flags; - - if (exp == nil) - FAIL("nil argument"); - - /* First pass: determine size, legality. */ - regparse = exp; - regnpar = 1; - regsize = 0L; - regcode = ®dummy; - regc(REGEXP_MAGIC); - if (reg(0, &flags) == nil) - return(nil); - - /* Small enough for pointer-storage convention? */ - if (regsize >= 32767L) /* Probably could be 65535L. */ - FAIL("regexp too big"); - - /* Allocate space. */ - r = (regexp *) new char[sizeof(regexp) + (unsigned)regsize]; - - /* Second pass: emit code. */ - regparse = exp; - regnpar = 1; - regcode = r->program; - regc(REGEXP_MAGIC); - if (reg(0, &flags) == nil) { - delete [] r; - return(nil); - } - - /* Dig out information for optimizations. */ - r->regstart = '\0'; /* Worst-case defaults. */ - r->reganch = 0; - r->regmust = nil; - r->regmlen = 0; - scan = r->program+1; /* First BRANCH. */ - if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ - scan = OPERAND(scan); - - /* Starting-point info. */ - if (OP(scan) == EXACTLY) - r->regstart = *OPERAND(scan); - else if (OP(scan) == BOL) - r->reganch++; - - /* - * If there's something expensive in the r.e., find the - * longest literal string that must appear and make it the - * regmust. Resolve ties in favor of later strings, since - * the regstart check works with the beginning of the r.e. - * and avoiding duplication strengthens checking. Not a - * strong reason, but sufficient in the absence of others. - */ - if (flags&SPSTART) { - longest = nil; - len = 0; - for (; scan != nil; scan = regnext(scan)) - if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { - longest = OPERAND(scan); - len = strlen(OPERAND(scan)); - } - r->regmust = longest; - r->regmlen = len; - } - } - - return(r); -} - -/* - - reg - regular expression, i.e. main body or parenthesized thing - * - * Caller must absorb opening parenthesis. - * - * Combining parenthesis handling with the base level of regular expression - * is a trifle forced, but the need to tie the tails of the branches to what - * follows makes it hard to avoid. - */ -static char * -reg(int paren, int* flagp) { - char *ret; - char *br; - char *ender; - int parno; - int flags; - - *flagp = HASWIDTH; /* Tentatively. */ - - /* Make an OPEN node, if parenthesized. */ - if (paren) { - if (regnpar >= NSUBEXP) - FAIL("too many ()"); - parno = regnpar; - regnpar++; - ret = regnode(OPEN+parno); - } else - ret = nil; - - /* Pick up the branches, linking them together. */ - br = regbranch(&flags); - if (br == nil) - return(nil); - if (ret != nil) - regtail(ret, br); /* OPEN -> first. */ - else - ret = br; - if (!(flags&HASWIDTH)) - *flagp &= ~HASWIDTH; - *flagp |= flags&SPSTART; - while (*regparse == '|') { - regparse++; - br = regbranch(&flags); - if (br == nil) - return(nil); - regtail(ret, br); /* BRANCH -> BRANCH. */ - if (!(flags&HASWIDTH)) - *flagp &= ~HASWIDTH; - *flagp |= flags&SPSTART; - } - - /* Make a closing node, and hook it on the end. */ - ender = regnode((paren) ? CLOSE+parno : END); - regtail(ret, ender); - - /* Hook the tails of the branches to the closing node. */ - for (br = ret; br != nil; br = regnext(br)) - regoptail(br, ender); - - /* Check for proper termination. */ - if (paren && *regparse++ != ')') { - FAIL("unmatched ()"); - } else if (!paren && *regparse != '\0') { - if (*regparse == ')') { - FAIL("unmatched ()"); - } else - FAIL("junk on end"); /* "Can't happen". */ - /* NOTREACHED */ - } - - return(ret); -} - -/* - - regbranch - one alternative of an | operator - * - * Implements the concatenation operator. - */ -static char * -regbranch(int* flagp) { - char *ret; - char *chain; - char *latest; - int flags; - - *flagp = WORST; /* Tentatively. */ - - ret = regnode(BRANCH); - chain = nil; - while (*regparse != '\0' && *regparse != '|') { - if (*regparse == '\\' && regparse[1] == ')') { - regparse++; - break; - } - latest = regpiece(&flags); - if (latest == nil) - return(nil); - *flagp |= flags&HASWIDTH; - if (chain == nil) /* First piece. */ - *flagp |= flags&SPSTART; - else - regtail(chain, latest); - chain = latest; - } - if (chain == nil) /* Loop ran zero times. */ - (void) regnode(NOTHING); - - return(ret); -} - -/* - - regpiece - something followed by possible [*+?] - * - * Note that the branching code sequences used for ? and the general cases - * of * and + are somewhat optimized: they use the same NOTHING node as - * both the endmarker for their branch list and the body of the last branch. - * It might seem that this node could be dispensed with entirely, but the - * endmarker role is not redundant. - */ -static char * -regpiece(int* flagp) { - char *ret; - char op; - char *next; - int flags; - - ret = regatom(&flags); - if (ret == nil) - return(nil); - - op = *regparse; - if (!ISMULT(op)) { - *flagp = flags; - return(ret); - } - - if (!(flags&HASWIDTH) && op != '?') - FAIL("*+ operand could be empty"); - *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); - - if (op == '*' && (flags&SIMPLE)) - reginsert(STAR, ret); - else if (op == '*') { - /* Emit x* as (x&|), where & means "self". */ - reginsert(BRANCH, ret); /* Either x */ - regoptail(ret, regnode(BACK)); /* and loop */ - regoptail(ret, ret); /* back */ - regtail(ret, regnode(BRANCH)); /* or */ - regtail(ret, regnode(NOTHING)); /* null. */ - } else if (op == '+' && (flags&SIMPLE)) - reginsert(PLUS, ret); - else if (op == '+') { - /* Emit x+ as x(&|), where & means "self". */ - next = regnode(BRANCH); /* Either */ - regtail(ret, next); - regtail(regnode(BACK), ret); /* loop back */ - regtail(next, regnode(BRANCH)); /* or */ - regtail(ret, regnode(NOTHING)); /* null. */ - } else if (op == '?') { - /* Emit x? as (x|) */ - reginsert(BRANCH, ret); /* Either x */ - regtail(ret, regnode(BRANCH)); /* or */ - next = regnode(NOTHING); /* null. */ - regtail(ret, next); - regoptail(ret, next); - } - regparse++; - if (ISMULT(*regparse)) - FAIL("nested *?+"); - - return(ret); -} - -/* - - regatom - the lowest level - * - * Optimization: gobbles an entire sequence of ordinary characters so that - * it can turn them into a single node, which is smaller to store and - * faster to run. Backslashed characters are exceptions, each becoming a - * separate node; the code is simpler that way and it's not worth fixing. - */ -static char * -regatom(int* flagp) { - char *ret; - int flags; - - *flagp = WORST; /* Tentatively. */ - - switch (*regparse++) { - case '^': - ret = regnode(BOL); - break; - case '$': - ret = regnode(EOL); - break; - case '.': - ret = regnode(ANY); - *flagp |= HASWIDTH|SIMPLE; - break; - case '[': { - int classbeg; - int classend; - - if (*regparse == '^') { /* Complement of range. */ - ret = regnode(ANYBUT); - regparse++; - } else - ret = regnode(ANYOF); - if (*regparse == ']' || *regparse == '-') - regc(*regparse++); - while (*regparse != '\0' && *regparse != ']') { - if (*regparse == '-') { - regparse++; - if (*regparse == ']' || *regparse == '\0') - regc('-'); - else { - classbeg = UCHARAT(regparse-2)+1; - classend = UCHARAT(regparse); - if (classbeg > classend+1) - FAIL("invalid [] range"); - for (; classbeg <= classend; classbeg++) - regc(classbeg); - regparse++; - } - } else - regc(*regparse++); - } - regc('\0'); - if (*regparse != ']') - FAIL("unmatched []"); - regparse++; - *flagp |= HASWIDTH|SIMPLE; - } - break; - case '\0': - case '|': - FAIL("internal urp"); /* Supposed to be caught earlier. */ - break; - case '?': - case '+': - case '*': - FAIL("?+* follows nothing"); - break; - case '\\': - if (*regparse == '\0') - FAIL("trailing \\"); - if (*regparse == '(') { - regparse++; - ret = reg(1, &flags); - if (ret == nil) - return(nil); - *flagp |= flags&(HASWIDTH|SPSTART); - } else { - ret = regnode(EXACTLY); - regc(*regparse++); - regc('\0'); - *flagp |= HASWIDTH|SIMPLE; - } - break; - default: { - int len; - char ender; - - regparse--; - len = strcspn(regparse, META); - if (len <= 0) - FAIL("internal disaster"); - ender = *(regparse+len); - if (len > 1 && ISMULT(ender)) - len--; /* Back off clear of ?+* operand. */ - *flagp |= HASWIDTH; - if (len == 1) - *flagp |= SIMPLE; - ret = regnode(EXACTLY); - while (len > 0) { - regc(*regparse++); - len--; - } - regc('\0'); - } - break; - } - - return(ret); -} - -/* - - regnode - emit a node - */ -static char * /* Location. */ -regnode(char op) { - char *ret; - char *ptr; - - ret = regcode; - if (ret == ®dummy) { - regsize += 3; - return(ret); - } - - ptr = ret; - *ptr++ = op; - *ptr++ = '\0'; /* Null "next" pointer. */ - *ptr++ = '\0'; - regcode = ptr; - - return(ret); -} - -/* - - regc - emit (if appropriate) a byte of code - */ -static void -regc(char b) { - if (regcode != ®dummy) - *regcode++ = b; - else - regsize++; -} - -/* - - reginsert - insert an operator in front of already-emitted operand - * - * Means relocating the operand. - */ -static void -reginsert(char op, char* opnd) { - char *src; - char *dst; - char *place; - - if (regcode == ®dummy) { - regsize += 3; - return; - } - - src = regcode; - regcode += 3; - dst = regcode; - while (src > opnd) - *--dst = *--src; - - place = opnd; /* Op node, where operand used to be. */ - *place++ = op; - *place++ = '\0'; - *place++ = '\0'; -} - -/* - - regtail - set the next-pointer at the end of a node chain - */ -static void -regtail(char* p, char* val) { - char *scan; - char *temp; - int offset; - - if (p == ®dummy) - return; - - /* Find last node. */ - scan = p; - for (;;) { - temp = regnext(scan); - if (temp == nil) - break; - scan = temp; - } - - if (OP(scan) == BACK) - offset = scan - val; - else - offset = val - scan; - *(scan+1) = (offset>>8)&0377; - *(scan+2) = offset&0377; -} - -/* - - regoptail - regtail on operand of first argument; nop if operandless - */ -static void -regoptail(char* p, char* val) { - /* "Operandless" and "op != BRANCH" are synonymous in practice. */ - if (p == nil || p == ®dummy || OP(p) != BRANCH) - return; - regtail(OPERAND(p), val); -} - -/* - * regexec and friends - */ - -/* - * Global work variables for regexec(). - */ -static char *reginput; /* String-input pointer. */ -static char *regbol; /* Beginning of input, for ^ check. */ -static char **regstartp; /* Pointer to startp array. */ -static char **regendp; /* Ditto for endp. */ - -/* - - regexec - match a regexp against a string - */ -static int -regexec(regexp* prog, char* string) { - char *s; - - /* Be paranoid... */ - if (prog == nil || string == nil) { - regerror("nil parameter"); - return(0); - } - - /* Check validity of program. */ - if (UCHARAT(prog->program) != REGEXP_MAGIC) { - regerror("corrupted program"); - return(0); - } - - /* If there is a "must appear" string, look for it. */ - if (prog->regmust != nil) { - s = string; - while ((s = strchr(s, prog->regmust[0])) != nil) { - if (strncmp(s, prog->regmust, prog->regmlen) == 0) - break; /* Found it. */ - s++; - } - if (s == nil) /* Not present. */ - return(0); - } - - /* Mark beginning of line for ^ . */ - regbol = string; - - /* Simplest case: anchored match need be tried only once. */ - if (prog->reganch) - return(regtry(prog, string)); - - /* Messy cases: unanchored match. */ - s = string; - if (prog->regstart != '\0') - /* We know what char it must start with. */ - while ((s = strchr(s, prog->regstart)) != nil) { - if (regtry(prog, s)) - return(1); - s++; - } - else - /* We don't -- general case. */ - do { - if (regtry(prog, s)) - return(1); - } while (*s++ != '\0'); - - /* Failure. */ - return(0); -} - -/* - - regtry - try match at specific point - */ -static int /* 0 failure, 1 success */ -regtry(regexp* prog, char* string) { - int i; - char **sp; - char **ep; - - reginput = string; - regstartp = prog->startp; - regendp = prog->endp; - - sp = prog->startp; - ep = prog->endp; - for (i = NSUBEXP; i > 0; i--) { - *sp++ = nil; - *ep++ = nil; - } - if (regmatch(prog->program + 1)) { - prog->startp[0] = string; - prog->endp[0] = reginput; - return(1); - } else - return(0); -} - -/* - - regmatch - main matching routine - * - * Conceptually the strategy is simple: check to see whether the current - * node matches, call self recursively to see whether the rest matches, - * and then act accordingly. In practice we make some effort to avoid - * recursion, in particular by going through "ordinary" nodes (that don't - * need to know whether the rest of the match failed) by a loop instead of - * by recursion. - */ -static int /* 0 failure, 1 success */ -regmatch(char* prog) { - char *scan; /* Current node. */ - char *next; /* Next node. */ - - scan = prog; - while (scan != nil) { - next = regnext(scan); - - switch (OP(scan)) { - case BOL: - if (reginput != regbol) - return(0); - break; - case EOL: - if (*reginput != '\0') - return(0); - break; - case ANY: - if (*reginput == '\0') - return(0); - reginput++; - break; - case EXACTLY: { - int len; - char *opnd; - - opnd = OPERAND(scan); - /* Inline the first character, for speed. */ - if (*opnd != *reginput) - return(0); - len = strlen(opnd); - if (len > 1 && strncmp(opnd, reginput, len) != 0) - return(0); - reginput += len; - } - break; - case ANYOF: - if (*reginput == '\0') - return(0); - if (strchr(OPERAND(scan), *reginput) == nil) - return(0); - reginput++; - break; - case ANYBUT: - if (*reginput == '\0') - return(0); - if (strchr(OPERAND(scan), *reginput) != nil) - return(0); - reginput++; - break; - case NOTHING: - break; - case BACK: - break; - case OPEN+1: - case OPEN+2: - case OPEN+3: - case OPEN+4: - case OPEN+5: - case OPEN+6: - case OPEN+7: - case OPEN+8: - case OPEN+9: { - int no; - char *save; - - no = OP(scan) - OPEN; - save = reginput; - - if (regmatch(next)) { - /* - * Don't set startp if some later - * invocation of the same parentheses - * already has. - */ - if (regstartp[no] == nil) - regstartp[no] = save; - return(1); - } else - return(0); - } - break; - case CLOSE+1: - case CLOSE+2: - case CLOSE+3: - case CLOSE+4: - case CLOSE+5: - case CLOSE+6: - case CLOSE+7: - case CLOSE+8: - case CLOSE+9: { - int no; - char *save; - - no = OP(scan) - CLOSE; - save = reginput; - - if (regmatch(next)) { - /* - * Don't set endp if some later - * invocation of the same parentheses - * already has. - */ - if (regendp[no] == nil) - regendp[no] = save; - return(1); - } else - return(0); - } - break; - case BRANCH: { - char *save; - - if (OP(next) != BRANCH) /* No choice. */ - next = OPERAND(scan); /* Avoid recursion. */ - else { - do { - save = reginput; - if (regmatch(OPERAND(scan))) - return(1); - reginput = save; - scan = regnext(scan); - } while (scan != nil && OP(scan) == BRANCH); - return(0); - /* NOTREACHED */ - } - } - break; - case STAR: - case PLUS: { - char nextch; - int no; - char *save; - int min; - - /* - * Lookahead to avoid useless match attempts - * when we know what character comes next. - */ - nextch = '\0'; - if (OP(next) == EXACTLY) - nextch = *OPERAND(next); - min = (OP(scan) == STAR) ? 0 : 1; - save = reginput; - no = regrepeat(OPERAND(scan)); - while (no >= min) { - /* If it could work, try it. */ - if (nextch == '\0' || *reginput == nextch) - if (regmatch(next)) - return(1); - /* Couldn't or didn't -- back up. */ - no--; - reginput = save + no; - } - return(0); - } - break; - case END: - return(1); /* Success! */ - default: - regerror("memory corruption"); - return(0); - } - - scan = next; - } - - /* - * We get here only if there's trouble -- normally "case END" is - * the terminating point. - */ - regerror("corrupted pointers"); - return(0); -} - -/* - - regrepeat - repeatedly match something simple, report how many - */ -static int -regrepeat(char* p) { - int count = 0; - char *scan; - char *opnd; - - scan = reginput; - opnd = OPERAND(p); - switch (OP(p)) { - case ANY: - count = strlen(scan); - scan += count; - break; - case EXACTLY: - while (*opnd == *scan) { - count++; - scan++; - } - break; - case ANYOF: - while (*scan != '\0' && strchr(opnd, *scan) != nil) { - count++; - scan++; - } - break; - case ANYBUT: - while (*scan != '\0' && strchr(opnd, *scan) == nil) { - count++; - scan++; - } - break; - default: /* Oh dear. Called inappropriately. */ - regerror("internal foulup"); - count = 0; /* Best compromise. */ - break; - } - reginput = scan; - - return(count); -} - -/* - - regnext - dig the "next" pointer out of a node - */ -static char * -regnext(char* p) { - int offset; - - if (p == ®dummy) - return(nil); - - offset = NEXT(p); - if (offset == 0) - return(nil); - - if (OP(p) == BACK) - return(p-offset); - else - return(p+offset); -} - -static void -regerror(const char* s) { - std::cerr << "regexp: " << s << "\n"; -} - diff --git a/src/nrncvode/netcvode.cpp b/src/nrncvode/netcvode.cpp index d2dd5ffcb5..f86afcfdce 100644 --- a/src/nrncvode/netcvode.cpp +++ b/src/nrncvode/netcvode.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "classreg.h" #include "nrnoc2iv.h" #include "parse.hpp" @@ -930,98 +930,74 @@ Object** NetCvode::netconlist() { Object** po = newoclist(4, o); Object *opre = nullptr, *opost = nullptr, *otar = nullptr; - Regexp *spre = nullptr, *spost = nullptr, *star = nullptr; - char* s; - int n; + std::regex spre, spost, star; if (hoc_is_object_arg(1)) { opre = *hoc_objgetarg(1); } else { - s = gargstr(1); - if (s[0] == '\0') { - spre = new Regexp(".*"); + std::string s(gargstr(1)); + if (s.empty()) { + spre = std::regex(".*"); } else { - spre = new Regexp(escape_bracket(s)); - } - if (!spre->pattern()) { - delete std::exchange(spre, nullptr); - hoc_execerror(gargstr(1), "not a valid regular expression"); + try { + spre = std::regex(escape_bracket(s.data())); + } catch (std::regex_error&) { + hoc_execerror(gargstr(1), "not a valid regular expression"); + } } } if (hoc_is_object_arg(2)) { opost = *hoc_objgetarg(2); } else { - s = gargstr(2); - if (s[0] == '\0') { - spost = new Regexp(".*"); + std::string s(gargstr(2)); + if (s.empty()) { + spost = std::regex(".*"); } else { - spost = new Regexp(escape_bracket(s)); - } - if (!spost->pattern()) { - delete std::exchange(spost, nullptr); - delete std::exchange(spre, nullptr); - hoc_execerror(gargstr(2), "not a valid regular expression"); + try { + spost = std::regex(escape_bracket(s.data())); + } catch (std::regex_error&) { + hoc_execerror(gargstr(2), "not a valid regular expression"); + } } } if (hoc_is_object_arg(3)) { otar = *hoc_objgetarg(3); } else { - s = gargstr(3); - if (s[0] == '\0') { - star = new Regexp(".*"); + std::string s(gargstr(3)); + if (s.empty()) { + star = std::regex(".*"); } else { - star = new Regexp(escape_bracket(s)); - } - if (!star->pattern()) { - delete std::exchange(star, nullptr); - delete std::exchange(spre, nullptr); - delete std::exchange(spost, nullptr); - hoc_execerror(gargstr(3), "not a valid regular expression"); + try { + star = std::regex(escape_bracket(s.data())); + } catch (std::regex_error&) { + hoc_execerror(gargstr(3), "not a valid regular expression"); + } } } - bool b; hoc_Item* q; if (psl_) { ITERATE(q, psl_) { PreSyn* ps = (PreSyn*) VOIDITM(q); - b = false; + bool b = false; if (ps->ssrc_) { Object* precell = nrn_sec2cell(ps->ssrc_); if (opre) { - if (precell == opre) { - b = true; - } else { - b = false; - } + b = precell == opre; } else { - s = hoc_object_name(precell); - n = strlen(s); - if (spre->Match(s, n, 0) > 0) { - b = true; - } else { - b = false; - } + std::string s(hoc_object_name(precell)); + b = std::regex_search(s, spre); } } else if (ps->osrc_) { Object* presyn = ps->osrc_; if (opre) { - if (presyn == opre) { - b = true; - } else { - b = false; - } + b = presyn == opre; } else { - s = hoc_object_name(presyn); - n = strlen(s); - if (spre->Match(s, n, 0) > 0) { - b = true; - } else { - b = false; - } + std::string s(hoc_object_name(presyn)); + b = std::regex_search(s, spre); } } - if (b == true) { + if (b) { for (const auto& d: ps->dil_) { Object* postcell = nullptr; Object* target = nullptr; @@ -1033,37 +1009,19 @@ Object** NetCvode::netconlist() { } } if (opost) { - if (postcell == opost) { - b = true; - } else { - b = false; - } + b = postcell == opost; } else { - s = hoc_object_name(postcell); - n = strlen(s); - if (spost->Match(s, n, 0) > 0) { - b = true; - } else { - b = false; - } + std::string s(hoc_object_name(postcell)); + b = std::regex_search(s, spost); } - if (b == true) { + if (b) { if (otar) { - if (target == otar) { - b = true; - } else { - b = false; - } + b = target == otar; } else { - s = hoc_object_name(target); - n = strlen(s); - if (star->Match(s, n, 0) > 0) { - b = true; - } else { - b = false; - } + std::string s(hoc_object_name(target)); + b = std::regex_search(s, star); } - if (b == true) { + if (b) { o->append(d->obj_); } } @@ -1071,9 +1029,6 @@ Object** NetCvode::netconlist() { } } } - delete std::exchange(spre, nullptr); - delete std::exchange(spost, nullptr); - delete std::exchange(star, nullptr); return po; }