build CHANGE work with earlier pcre2 library version

- Commonly in use distros still use pcre2 < v10.30, adapt the code to
work with this version of pcre2 (e.g., Debian 9, Centos 7, and Ubuntu
16.04).

Signed-off-by: Christian Hopps <chopps@labn.net>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0e3fa94..61fce57 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -288,7 +288,7 @@
 
 # find PCRE2 library
 unset(PCRE2_LIBRARY CACHE)
-find_package(PCRE2 10.30 REQUIRED)
+find_package(PCRE2 10.21 REQUIRED)
 include_directories(${PCRE2_INCLUDE_DIRS})
 target_link_libraries(yang ${PCRE2_LIBRARIES})
 
diff --git a/src/plugins_types.c b/src/plugins_types.c
index a71d896..eed671d 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -454,7 +454,7 @@
 API LY_ERR
 ly_type_validate_patterns(struct lysc_pattern **patterns, const char *str, size_t str_len, struct ly_err_item **err)
 {
-    int rc;
+    int rc, match_opts;
     LY_ARRAY_COUNT_TYPE u;
     pcre2_match_data *match_data = NULL;
 
@@ -467,7 +467,13 @@
             return ly_err_new(err, LY_EMEM, 0, NULL, NULL, LY_EMEM_MSG);
         }
 
-        rc = pcre2_match(patterns[u]->code, (PCRE2_SPTR)str, str_len, 0, PCRE2_ANCHORED | PCRE2_ENDANCHORED, match_data, NULL);
+
+        match_opts = PCRE2_ANCHORED;
+#ifdef PCRE2_ENDANCHORED
+        /* PCRE2_ENDANCHORED was added in PCRE2 version 10.30 */
+        match_opts |= PCRE2_ENDANCHORED;
+#endif
+        rc = pcre2_match(patterns[u]->code, (PCRE2_SPTR)str, str_len, 0, match_opts, match_data, NULL);
         pcre2_match_data_free(match_data);
 
         if ((rc != PCRE2_ERROR_NOMATCH) && (rc < 0)) {
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 7c43d65..d638a8f 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -834,7 +834,7 @@
 {
     size_t idx, idx2, start, end, size, brack;
     char *perl_regex, *ptr;
-    int err_code;
+    int err_code, compile_opts;
     const char *orig_ptr;
     PCRE2_SIZE err_offset;
     pcre2_code *code_local;
@@ -933,6 +933,13 @@
 
     /* allocate space for the transformed pattern */
     size = strlen(pattern) + 1;
+    compile_opts = PCRE2_UTF | PCRE2_ANCHORED | PCRE2_DOLLAR_ENDONLY | PCRE2_NO_AUTO_CAPTURE;
+#ifdef PCRE2_ENDANCHORED
+    compile_opts |= PCRE2_ENDANCHORED;
+#else
+    /* add space for trailing $ anchor */
+    size++;
+#endif
     perl_regex = malloc(size);
     LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
     perl_regex[0] = '\0';
@@ -979,6 +986,10 @@
         ++idx;
         ++orig_ptr;
     }
+#ifndef PCRE2_ENDANCHORED
+    /* anchor match to end of subject */
+    perl_regex[idx++] = '$';
+#endif
     perl_regex[idx] = '\0';
 
     /* substitute Unicode Character Blocks with exact Character Ranges */
@@ -1032,8 +1043,7 @@
     }
 
     /* must return 0, already checked during parsing */
-    code_local = pcre2_compile((PCRE2_SPTR)perl_regex, PCRE2_ZERO_TERMINATED,
-            PCRE2_UTF | PCRE2_ANCHORED | PCRE2_ENDANCHORED | PCRE2_DOLLAR_ENDONLY | PCRE2_NO_AUTO_CAPTURE,
+    code_local = pcre2_compile((PCRE2_SPTR)perl_regex, PCRE2_ZERO_TERMINATED, compile_opts,
             &err_code, &err_offset, NULL);
     if (!code_local) {
         PCRE2_UCHAR err_msg[LY_PCRE2_MSG_LIMIT] = {0};