libyang BUGFIX fix inverted pattern when string data is parsing
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 643d144..c11dafd 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -489,7 +489,6 @@
 API LY_ERR
 ly_type_validate_patterns(struct lysc_pattern **patterns, const char *str, size_t str_len, struct ly_err_item **err)
 {
-    LY_ERR ret = LY_SUCCESS;
     int rc;
     LY_ARRAY_COUNT_TYPE u;
     char *errmsg;
@@ -506,33 +505,30 @@
         }
 
         rc = pcre2_match(patterns[u]->code, (PCRE2_SPTR)str, str_len, 0, PCRE2_ANCHORED | PCRE2_ENDANCHORED, match_data, NULL);
-        if (rc == PCRE2_ERROR_NOMATCH) {
-            if (asprintf(&errmsg, "String \"%.*s\" does not conform to the pattern \"%s\".", (int)str_len, str, patterns[u]->expr) == -1) {
+        pcre2_match_data_free(match_data);
+
+        if ((rc != PCRE2_ERROR_NOMATCH) && (rc < 0)) {
+            PCRE2_UCHAR pcre2_errmsg[LY_PCRE2_MSG_LIMIT] = {0};
+            pcre2_get_error_message(rc, pcre2_errmsg, LY_PCRE2_MSG_LIMIT);
+
+            *err = ly_err_new(LY_LLERR, LY_ESYS, 0, strdup((const char *)pcre2_errmsg), NULL, NULL);
+            return LY_ESYS;
+        } else if (((rc == PCRE2_ERROR_NOMATCH) && (patterns[u]->inverted == 0)) ||
+                  ((rc != PCRE2_ERROR_NOMATCH) && (patterns[u]->inverted == 1))) {
+            LY_ERR ret = 0;
+            const char *inverted = patterns[u]->inverted == 0 ? " " : " inverted ";
+            if (asprintf(&errmsg, "String \"%.*s\" does not conform to the%spattern \"%s\".",
+                    (int)str_len, str, inverted, patterns[u]->expr) == -1) {
                 *err = ly_err_new(LY_LLERR, LY_EMEM, 0, LY_EMEM_MSG, NULL, NULL);
                 ret = LY_EMEM;
             } else {
                 *err = ly_err_new(LY_LLERR, LY_ESYS, 0, errmsg, NULL, NULL);
                 ret = LY_EVALID;
             }
-            goto cleanup;
-        } else if (rc < 0) {
-            /* error */
-            PCRE2_UCHAR pcre2_errmsg[LY_PCRE2_MSG_LIMIT] = {0};
-            pcre2_get_error_message(rc, pcre2_errmsg, LY_PCRE2_MSG_LIMIT);
-
-            *err = ly_err_new(LY_LLERR, LY_ESYS, 0, strdup((const char *)pcre2_errmsg), NULL, NULL);
-            ret = LY_ESYS;
-            goto cleanup;
-        }
-
-cleanup:
-        pcre2_match_data_free(match_data);
-        if (ret) {
-            break;
+            return ret;
         }
     }
-
-    return ret;
+    return LY_SUCCESS;
 }
 
 API LY_ERR
diff --git a/tests/utests/data/test_types.c b/tests/utests/data/test_types.c
index 8c47f32..08c4142 100644
--- a/tests/utests/data/test_types.c
+++ b/tests/utests/data/test_types.c
@@ -52,6 +52,7 @@
         "leaf dec64 {type decimal64 {fraction-digits 1; range 1.5..10;}}"
         "leaf dec64-norestr {type decimal64 {fraction-digits 18;}}"
         "leaf str {type string {length 8..10; pattern '[a-z ]*';}}"
+        "leaf str-invert {type string {pattern '[a-z ]*' {modifier invert-match;}}}"
         "leaf str-norestr {type string;}"
         "leaf str-utf8 {type string{length 2..5; pattern '€*';}}"
         "leaf bool {type boolean;}"
@@ -253,6 +254,16 @@
     TEST_PATTERN_1(tree, "str", 1, STRING, "teststring");
     lyd_free_all(tree);
 
+    /* inverted match */
+    CHECK_PARSE_LYD("<str-invert xmlns=\"urn:tests:types\">TESTSTRING</str-invert>", tree);
+    assert_non_null(tree);
+    tree = tree->next;
+    TEST_PATTERN_1(tree, "str-invert", 1, STRING, "TESTSTRING");
+    lyd_free_all(tree);
+
+    TEST_TYPE_ERROR("str-invert", "teststring",
+            "String \"teststring\" does not conform to the inverted pattern \"[a-z ]*\".", "1");
+
     /* multibyte characters (€ encodes as 3-byte UTF8 character, length restriction is 2-5) */
     CHECK_PARSE_LYD("<str-utf8 xmlns=\"urn:tests:types\">€€</str-utf8>", tree);
     assert_non_null(tree);