aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Mikhirev2014-12-17 18:34:27 +0300
committerDmitry Mikhirev2014-12-17 18:34:27 +0300
commit1433460dd96b393c8403a99a3a83608e4f07d025 (patch)
tree1435188d2bb9c86a702c24820340b99fce727cec
parent73f6057ab2601edfd281f29f7f08f9a0eb040b84 (diff)
downloadmake_pcre-1433460dd96b393c8403a99a3a83608e4f07d025.tar.gz
make_pcre-1433460dd96b393c8403a99a3a83608e4f07d025.tar.bz2
make_pcre-1433460dd96b393c8403a99a3a83608e4f07d025.tar.xz
make_pcre-1433460dd96b393c8403a99a3a83608e4f07d025.zip
added pcre_subst function
-rw-r--r--pcre.c141
-rw-r--r--tests.mk21
2 files changed, 159 insertions, 3 deletions
diff --git a/pcre.c b/pcre.c
index d39d219..46cc79f 100644
--- a/pcre.c
+++ b/pcre.c
@@ -30,6 +30,20 @@ const int MAX_CAP_LEN = 3; /* number of decimal digits in MAX_CAP */
const int MAX_MSG_LEN = 1024; /* max length of error/warning/info message */
+char *str_extend(char *old, size_t size)
+{
+ char *new = realloc(old, size);
+ if (new == NULL) { /* let make allocate memory or die */
+ new = gmk_alloc(size);
+ if (new == NULL) { /* should never happen */
+ return NULL;
+ }
+ strncpy(new, old, size);
+ gmk_free(old);
+ }
+ return new;
+}
+
/* esc_str() - escape string before assigning it to make variable */
char *esc_str(const char *str)
{
@@ -418,11 +432,138 @@ end_match:
return retstr;
}
+char *subst(const char *name, int argc, char **argv)
+{
+ char *pat = NULL; /* expanded pattern */
+ char *p; /* iteration pointer */
+ int global = 0; /* global search? */
+ int co = 0; /* pattern compilation options */
+ pcre *re = NULL; /* compiled regexp */
+ const char *err; /* compilation error */
+ int erroffset; /* offset in pattern where error occured */
+ pcre_extra *sd = NULL; /* pattern study data */
+ char *str = NULL; /* expanded subject string */
+ int subjlen; /* length of subject string */
+ int replen; /* length of replacement string */
+ int offset = 0; /* subject string offset */
+ int ncap = 0; /* number of captured substrings */
+ int ovec[MAX_CAP*3]; /* ovector */
+ char *retstr = NULL; /* string to be returned */
+ int retlen = 0; /* length of retstr */
+ int newlen; /* length of retstr after appending new part */
+ char *s; /* temporary string */
+
+ if (argc > 3) { /* options provided, parse them */
+ for (p = argv[3]; *p != '\0'; p++) {
+ switch (*p) {
+ case 'E': /* expand pattern */
+ pat = gmk_expand(argv[0]);
+ break;
+ case 'g': /* global search */
+ global = 1;
+ break;
+ default: /* not subst-specific option */
+ co |= parse_comp_opt(*p, name);
+ break;
+ }
+ }
+ }
+
+ if (pat == NULL) { /* compile unexpanded pattern */
+ re = pcre_compile(argv[0], co, &err, &erroffset, NULL);
+ } else { /* compile expanded pattern */
+ re = pcre_compile(pat, co, &err, &erroffset, NULL);
+ gmk_free(pat);
+ }
+ if (re == NULL) { /* compilation error */
+ mk_error("%s: %d: %s", name, erroffset, err);
+ goto end_subst;
+ }
+
+ if (global) { /* study compiled pattern */
+ sd = pcre_study(re, 0, &err);
+ if (err) {
+ mk_warning("%s: %s", name, err);
+ sd = NULL;
+ }
+ }
+
+ /* expand subject string */
+ str = gmk_expand(argv[2]);
+
+ subjlen = strlen(str);
+ replen = strlen(argv[1]);
+
+ do {
+ /* execute regexp */
+ ncap = pcre_exec(re, sd, str, subjlen, offset, 0,
+ ovec, MAX_CAP*3);
+ if ((ncap < 0) && (ncap != PCRE_ERROR_NOMATCH)) { /* error occured */
+ mk_error("%s: pattern matching error: %d\n", name, ncap);
+ goto end_subst;
+ }
+
+ if (ncap > 0) {
+ newlen = retlen + (ovec[0] - offset) + replen;
+ s = str_extend(retstr, newlen + 1);
+ if (s == NULL) {
+ goto end_subst;
+ }
+ retstr = s;
+
+ strncpy(retstr + retlen, str + offset, ovec[0] - offset);
+ strncpy(retstr + retlen + ovec[0] - offset, argv[1], replen + 1);
+ retlen += ovec[0] - offset + replen;
+
+ /* where to start next search */
+ offset = ovec[1];
+
+ /* set named make vars to captured substrings */
+ set_named_vars(re, str, ovec, ncap);
+ }
+ } while (global && (ncap != PCRE_ERROR_NOMATCH));
+
+ newlen = retlen + subjlen - offset;
+ s = str_extend(retstr, newlen + 1);
+ if (s == NULL) {
+ goto end_subst;
+ }
+ retstr = s;
+ strncpy(retstr + retlen, str + offset, subjlen - offset + 1);
+
+end_subst:
+ if (re != NULL) {
+ pcre_free(re);
+ }
+ if (sd != NULL) {
+ #if (PCRE_MAJOR < 8) || ((PCRE_MAJOR == 8) && (PCRE_MINOR < 20))
+ pcre_free(sd);
+ #else
+ pcre_free_study(sd);
+ #endif
+ }
+
+ /* set make vars to captured substrings */
+ set_vars(str, ovec, ncap);
+
+ if (str != NULL) {
+ gmk_free(str);
+ }
+ return retstr;
+
+}
+
int pcre_gmk_setup()
{
/* add function for pattern matching */
gmk_add_function("pcre_find", (gmk_func_ptr)match, 2, 3,
GMK_FUNC_NOEXPAND);
gmk_add_function("m", (gmk_func_ptr)match, 2, 3, GMK_FUNC_NOEXPAND);
+
+ /* add function for pattern substitution */
+ gmk_add_function("pcre_subst", (gmk_func_ptr)subst, 3, 4,
+ GMK_FUNC_NOEXPAND);
+ gmk_add_function("s", (gmk_func_ptr)subst, 3, 4, GMK_FUNC_NOEXPAND);
+
return 1;
}
diff --git a/tests.mk b/tests.mk
index dcbaa58..b131500 100644
--- a/tests.mk
+++ b/tests.mk
@@ -2,10 +2,10 @@ ifneq ($(findstring 4.,$(MAKE_VERSION)),4.)
$(error you need GNU make 4.x to run tests)
endif
-tests = test001 test002 test003 test004 test005 test006 test007 test008 \
- test009 test010
+NUMTESTS = 23
+tests := $(foreach num,$(shell seq -f%03g $(NUMTESTS)),test$(num))
--load pcre.so
+load pcre.so
all: $(tests)
@@ -55,6 +55,21 @@ test010 = -n "$(shell \
) | $(MAKE) -f - 2>&1 | \
fgrep Stop.)"
+# test pattern substitution
+test011 = "$(s a,x,a)" = "x"
+test012 = "$(s a,x,abcd)" = "xbcd"
+test013 = "$(s a,x,dcba)" = "dcbx"
+test014 = "$(s a,x,abba,g)" = "xbbx"
+test015 = "$(s a,xxx,a)" = "xxx"
+test016 = "$(s a,xxx,abcd)" = "xxxbcd"
+test017 = "$(s a,xxx,dcba)" = "dcbxxx"
+test018 = "$(s a,xxx,abba,g)" = "xxxbbxxx"
+test019 = "$(s aaa,x,aaa)" = "x"
+test020 = "$(s aaa,x,aaabcd)" = "xbcd"
+test021 = "$(s aaa,x,dcbaaa)" = "dcbx"
+test022 = "$(s aaa,x,aaabbaaa,g)" = "xbbx"
+test023 = "$(s a,x,aaa,g)" = "xxx"
+
### END OF TEST EXPRESSIONS ###
test%: